diff --git a/forge-ai/pom.xml b/forge-ai/pom.xml index 4598d8cf7e6..73c7046402a 100644 --- a/forge-ai/pom.xml +++ b/forge-ai/pom.xml @@ -6,7 +6,7 @@ forge forge - 1.6.43-SNAPSHOT + 1.6.44-SNAPSHOT forge-ai diff --git a/forge-ai/src/main/java/forge/ai/AiController.java b/forge-ai/src/main/java/forge/ai/AiController.java index 45d40041ace..5ea2c1be35e 100644 --- a/forge-ai/src/main/java/forge/ai/AiController.java +++ b/forge-ai/src/main/java/forge/ai/AiController.java @@ -510,7 +510,6 @@ public class AiController { landList = unreflectedLands; } - //try to skip lands that enter the battlefield tapped if (!nonLandsInHand.isEmpty()) { CardCollection nonTappedLands = new CardCollection(); @@ -534,6 +533,7 @@ public class AiController { } } + // TODO if this is the only source for a color we need badly prioritize it instead if (foundTapped) { continue; } @@ -813,7 +813,7 @@ public class AiController { } else { Cost payCosts = sa.getPayCosts(); - if(payCosts != null) { + if (payCosts != null) { ManaCost mana = payCosts.getTotalMana(); if (mana != null) { if (mana.countX() > 0) { @@ -879,7 +879,7 @@ public class AiController { public boolean isNonDisabledCardInPlay(final String cardName) { for (Card card : player.getCardsIn(ZoneType.Battlefield)) { if (card.getName().equals(cardName)) { - // TODO - Better logic to detemine if a permanent is disabled by local effects + // TODO - Better logic to determine if a permanent is disabled by local effects // currently assuming any permanent enchanted by another player // is disabled and a second copy is necessary // will need actual logic that determines if the enchantment is able @@ -1916,7 +1916,7 @@ public class AiController { if (sa.hasParam("AIMaxAmount")) { max = AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("AIMaxAmount"), sa); } - switch(sa.getApi()) { + switch (sa.getApi()) { case TwoPiles: // TODO: improve AI Card biggest = null; @@ -2013,7 +2013,7 @@ public class AiController { final CardCollection library = new CardCollection(in); CardLists.shuffle(library); - + // remove all land, keep non-basicland in there, shuffled CardCollection land = CardLists.filter(library, CardPredicates.Presets.LANDS); for (Card c : land) { @@ -2021,7 +2021,7 @@ public class AiController { library.remove(c); } } - + try { // mana weave, total of 7 land // The Following have all been reduced by 1, to account for the @@ -2038,19 +2038,14 @@ public class AiController { System.err.println("Error: cannot smooth mana curve, not enough land"); return in; } - + // add the rest of land to the end of the deck for (int i = 0; i < land.size(); i++) { if (!library.contains(land.get(i))) { library.add(land.get(i)); } } - - // check - for (int i = 0; i < library.size(); i++) { - System.out.println(library.get(i)); - } - + return library; } // smoothComputerManaCurve() @@ -2224,7 +2219,7 @@ public class AiController { } return ComputerUtil.chooseSacrificeType(player, type, ability, ability.getTargetCard(), amount); } - + private boolean checkAiSpecificRestrictions(final SpellAbility sa) { // AI-specific restrictions specified as activation parameters in spell abilities @@ -2276,5 +2271,5 @@ public class AiController { // AI logic for choosing which replacement effect to apply happens here. return Iterables.getFirst(list, null); } - + } diff --git a/forge-ai/src/main/java/forge/ai/AiCostDecision.java b/forge-ai/src/main/java/forge/ai/AiCostDecision.java index b147420577f..2126230fedb 100644 --- a/forge-ai/src/main/java/forge/ai/AiCostDecision.java +++ b/forge-ai/src/main/java/forge/ai/AiCostDecision.java @@ -78,15 +78,13 @@ public class AiCostDecision extends CostDecisionMakerBase { return null; } return PaymentDecision.card(player.getLastDrawnCard()); - } - else if (cost.payCostFromSource()) { + } else if (cost.payCostFromSource()) { if (!hand.contains(source)) { return null; } return PaymentDecision.card(source); - } - else if (type.equals("Hand")) { + } else if (type.equals("Hand")) { if (hand.size() > 1 && ability.getActivatingPlayer() != null) { hand = ability.getActivatingPlayer().getController().orderMoveToZoneList(hand, ZoneType.Graveyard, ability); } @@ -107,8 +105,7 @@ public class AiCostDecision extends CostDecisionMakerBase { randomSubset = ability.getActivatingPlayer().getController().orderMoveToZoneList(randomSubset, ZoneType.Graveyard, ability); } return PaymentDecision.card(randomSubset); - } - else if (type.equals("DifferentNames")) { + } else if (type.equals("DifferentNames")) { CardCollection differentNames = new CardCollection(); CardCollection discardMe = CardLists.filter(hand, CardPredicates.hasSVar("DiscardMe")); while (c > 0) { @@ -125,8 +122,7 @@ public class AiCostDecision extends CostDecisionMakerBase { c--; } return PaymentDecision.card(differentNames); - } - else { + } else { final AiController aic = ((PlayerControllerAi)player.getController()).getAi(); CardCollection result = aic.getCardsToDiscard(c, type.split(";"), ability, discarded); @@ -183,8 +179,7 @@ public class AiCostDecision extends CostDecisionMakerBase { else if (cost.sameZone) { // TODO Determine exile from same zone for AI return null; - } - else { + } else { CardCollectionView chosen = ComputerUtil.chooseExileFrom(player, cost.getFrom(), cost.getType(), source, ability.getTargetCard(), c, ability); return null == chosen ? null : PaymentDecision.card(chosen); } @@ -267,6 +262,15 @@ public class AiCostDecision extends CostDecisionMakerBase { return PaymentDecision.number(c); } + @Override + public PaymentDecision visit(CostRollDice cost) { + Integer c = cost.convertAmount(); + if (c == null) { + c = AbilityUtils.calculateAmount(source, cost.getAmount(), ability); + } + return PaymentDecision.number(c); + } + @Override public PaymentDecision visit(CostGainControl cost) { if (cost.payCostFromSource()) { @@ -366,8 +370,7 @@ public class AiCostDecision extends CostDecisionMakerBase { if (cost.isSameZone()) { list = new CardCollection(game.getCardsIn(cost.getFrom())); - } - else { + } else { list = new CardCollection(player.getCardsIn(cost.getFrom())); } @@ -862,4 +865,3 @@ public class AiCostDecision extends CostDecisionMakerBase { return false; } } - diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtil.java b/forge-ai/src/main/java/forge/ai/ComputerUtil.java index e537d3c6972..6acf36772da 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtil.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtil.java @@ -947,7 +947,7 @@ public class ComputerUtil { canRegen = true; } - } catch (final Exception ex) { + } catch (final Exception ex) { throw new RuntimeException(TextUtil.concatNoSpace("There is an error in the card code for ", c.getName(), ":", ex.getMessage()), ex); } } @@ -2832,7 +2832,6 @@ public class ComputerUtil { } public static boolean lifegainPositive(final Player player, final Card source) { - if (!player.canGainLife()) { return false; } diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java b/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java index e3234956d5c..da29e0a265b 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java @@ -716,6 +716,7 @@ public class ComputerUtilCard { int bigCMC = -1; for (final Card card : all) { + // TODO when PlayAi can consider MDFC this should also look at the back face (if not on stack or battlefield) int curCMC = card.getCMC(); // Add all cost of all auras with the same controller diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java b/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java index ae0f0251c90..470460f4e64 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java @@ -1899,8 +1899,7 @@ public class ComputerUtilMana { if (!res.contains(a)) { if (cost.isReusuableResource()) { res.add(0, a); - } - else { + } else { res.add(res.size(), a); } } diff --git a/forge-ai/src/main/java/forge/ai/SpellApiToAi.java b/forge-ai/src/main/java/forge/ai/SpellApiToAi.java index 61fe79ba314..c04f5ce1816 100644 --- a/forge-ai/src/main/java/forge/ai/SpellApiToAi.java +++ b/forge-ai/src/main/java/forge/ai/SpellApiToAi.java @@ -143,6 +143,7 @@ public enum SpellApiToAi { .put(ApiType.ReplaceEffect, AlwaysPlayAi.class) .put(ApiType.ReplaceDamage, AlwaysPlayAi.class) .put(ApiType.ReplaceSplitDamage, AlwaysPlayAi.class) + .put(ApiType.ReplaceToken, AlwaysPlayAi.class) .put(ApiType.RestartGame, RestartGameAi.class) .put(ApiType.Reveal, RevealAi.class) .put(ApiType.RevealHand, RevealHandAi.class) diff --git a/forge-ai/src/main/java/forge/ai/ability/AmassAi.java b/forge-ai/src/main/java/forge/ai/ability/AmassAi.java index 2e8066cb5bd..b7a649acfb3 100644 --- a/forge-ai/src/main/java/forge/ai/ability/AmassAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/AmassAi.java @@ -34,7 +34,7 @@ public class AmassAi extends SpellAbilityAi { final String tokenScript = "b_0_0_zombie_army"; final int amount = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("Num", "1"), sa); - Card token = TokenInfo.getProtoType(tokenScript, sa, false); + Card token = TokenInfo.getProtoType(tokenScript, sa, ai, false); if (token == null) { return false; diff --git a/forge-ai/src/main/java/forge/ai/ability/ChooseTypeAi.java b/forge-ai/src/main/java/forge/ai/ability/ChooseTypeAi.java index 91690a61212..c6eba2b0c10 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ChooseTypeAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ChooseTypeAi.java @@ -34,6 +34,7 @@ public class ChooseTypeAi extends SpellAbilityAi { if (ComputerUtilAbility.getAbilitySourceName(sa).equals("Mirror Entity Avatar")) { return doMirrorEntityLogic(aiPlayer, sa); } + return !chooseType(sa, aiPlayer.getCardsIn(ZoneType.Battlefield)).isEmpty(); } else if ("MostProminentOppControls".equals(sa.getParam("AILogic"))) { return !chooseType(sa, aiPlayer.getOpponents().getCardsIn(ZoneType.Battlefield)).isEmpty(); } diff --git a/forge-ai/src/main/java/forge/ai/ability/PlayAi.java b/forge-ai/src/main/java/forge/ai/ability/PlayAi.java index 1d92c736965..2d64e10bced 100644 --- a/forge-ai/src/main/java/forge/ai/ability/PlayAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/PlayAi.java @@ -1,48 +1,33 @@ package forge.ai.ability; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - import com.google.common.base.Predicate; import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; - -import forge.ai.AiController; -import forge.ai.AiPlayDecision; -import forge.ai.AiProps; -import forge.ai.ComputerUtil; -import forge.ai.ComputerUtilCard; -import forge.ai.PlayerControllerAi; -import forge.ai.SpellAbilityAi; +import forge.ai.*; import forge.card.CardStateName; import forge.card.CardTypeView; +import forge.card.mana.ManaCost; import forge.game.Game; import forge.game.GameType; import forge.game.ability.AbilityUtils; -import forge.game.card.Card; -import forge.game.card.CardCollection; -import forge.game.card.CardCollectionView; -import forge.game.card.CardLists; -import forge.game.card.CardPredicates; +import forge.game.card.*; import forge.game.cost.Cost; import forge.game.keyword.Keyword; import forge.game.player.Player; import forge.game.player.PlayerActionConfirmMode; -import forge.game.spellability.Spell; -import forge.game.spellability.SpellAbility; -import forge.game.spellability.SpellAbilityPredicates; -import forge.game.spellability.SpellPermanent; -import forge.game.spellability.TargetRestrictions; +import forge.game.spellability.*; import forge.game.zone.ZoneType; import forge.util.MyRandom; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + public class PlayAi extends SpellAbilityAi { @Override protected boolean checkApiLogic(final Player ai, final SpellAbility sa) { final String logic = sa.hasParam("AILogic") ? sa.getParam("AILogic") : ""; - + final Game game = ai.getGame(); final Card source = sa.getHostCard(); // don't use this as a response (ReplaySpell logic is an exception, might be called from a subability @@ -70,13 +55,12 @@ public class PlayAi extends SpellAbilityAi { } } - if (sa.hasParam("ValidSA")) { + if (cards != null & sa.hasParam("ValidSA")) { final String valid[] = {sa.getParam("ValidSA")}; final Iterator itr = cards.iterator(); while (itr.hasNext()) { final Card c = itr.next(); - final List validSA = Lists.newArrayList(Iterables.filter(AbilityUtils.getBasicSpellsFromPlayEffect(c, ai), SpellAbilityPredicates.isValid(valid, ai , c, sa))); - if (validSA.size() == 0) { + if (!Iterables.any(AbilityUtils.getBasicSpellsFromPlayEffect(c, ai), SpellAbilityPredicates.isValid(valid, ai , c, sa))) { itr.remove(); } } @@ -112,7 +96,7 @@ public class PlayAi extends SpellAbilityAi { } if ("ReplaySpell".equals(logic)) { - return ComputerUtil.targetPlayableSpellCard(ai, cards, sa, sa.hasParam("WithoutManaCost")); + return ComputerUtil.targetPlayableSpellCard(ai, cards, sa, sa.hasParam("WithoutManaCost")); } else if (logic.startsWith("NeedsChosenCard")) { int minCMC = 0; if (sa.getPayCosts().getCostMana() != null) { @@ -120,6 +104,23 @@ public class PlayAi extends SpellAbilityAi { } validOpts = CardLists.filter(validOpts, CardPredicates.greaterCMC(minCMC)); return chooseSingleCard(ai, sa, validOpts, sa.hasParam("Optional"), null, null) != null; + } else if ("WithTotalCMC".equals(logic)) { + // Try to play only when there are more than three playable cards. + if (cards.size() < 3) + return false; + ManaCost mana = sa.getPayCosts().getTotalMana(); + if (mana.countX() > 0) { + int amount = ComputerUtilCost.getMaxXValue(sa, ai); + if (amount < ComputerUtilCard.getBestAI(cards).getCMC()) + return false; + int totalCMC = 0; + for (Card c : cards) { + totalCMC += c.getCMC(); + } + if (amount > totalCMC) + amount = totalCMC; + sa.setXManaCostPaid(amount); + } } if (source != null && source.hasKeyword(Keyword.HIDEAWAY) && source.hasRemembered()) { @@ -134,7 +135,7 @@ public class PlayAi extends SpellAbilityAi { return true; } - + /** *

* doTriggerAINoCost @@ -152,7 +153,7 @@ public class PlayAi extends SpellAbilityAi { if (!sa.hasParam("AILogic")) { return false; } - + return checkApiLogic(ai, sa); } @@ -173,12 +174,19 @@ public class PlayAi extends SpellAbilityAi { List tgtCards = CardLists.filter(options, new Predicate() { @Override public boolean apply(final Card c) { + // TODO needs to be aligned for MDFC along with getAbilityToPlay so the knowledge + // of which spell was the reason for the choice can be used there for (SpellAbility s : c.getBasicSpells(c.getState(CardStateName.Original))) { Spell spell = (Spell) s; s.setActivatingPlayer(ai); // timing restrictions still apply if (!s.getRestrictions().checkTimingRestrictions(c, s)) continue; + if (params != null && params.containsKey("CMCLimit")) { + Integer cmcLimit = (Integer) params.get("CMCLimit"); + if (spell.getPayCosts().getTotalMana().getCMC() > cmcLimit) + continue; + } if (sa.hasParam("WithoutManaCost")) { // Try to avoid casting instants and sorceries with X in their cost, since X will be assumed to be 0. if (!(spell instanceof SpellPermanent)) { diff --git a/forge-ai/src/main/java/forge/ai/ability/TokenAi.java b/forge-ai/src/main/java/forge/ai/ability/TokenAi.java index 411291947a8..4a88345ddae 100644 --- a/forge-ai/src/main/java/forge/ai/ability/TokenAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/TokenAi.java @@ -95,7 +95,7 @@ public class TokenAi extends SpellAbilityAi { if (sa.getSVar("X").equals("Count$xPaid")) { // Set PayX here to maximum value. x = ComputerUtilCost.getMaxXValue(sa, ai); - sa.setXManaCostPaid(x); + sa.getRootAbility().setXManaCostPaid(x); } if (x <= 0) { return false; // 0 tokens or 0 toughness token(s) @@ -358,7 +358,7 @@ public class TokenAi extends SpellAbilityAi { if (!sa.hasParam("TokenScript")) { throw new RuntimeException("Spell Ability has no TokenScript: " + sa); } - Card result = TokenInfo.getProtoType(sa.getParam("TokenScript"), sa); + Card result = TokenInfo.getProtoType(sa.getParam("TokenScript"), sa, ai); if (result == null) { throw new RuntimeException("don't find Token for TokenScript: " + sa.getParam("TokenScript")); diff --git a/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java b/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java index 251dc8796f2..5950f124f0f 100644 --- a/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java +++ b/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java @@ -229,12 +229,12 @@ public class GameCopier { private static final boolean USE_FROM_PAPER_CARD = true; private Card createCardCopy(Game newGame, Player newOwner, Card c) { - if (c.isToken() && !c.isEmblem()) { + if (c.isToken() && !c.isImmutable()) { Card result = new TokenInfo(c).makeOneToken(newOwner); CardFactory.copyCopiableCharacteristics(c, result); return result; } - if (USE_FROM_PAPER_CARD && !c.isEmblem() && c.getPaperCard() != null) { + if (USE_FROM_PAPER_CARD && !c.isImmutable() && c.getPaperCard() != null) { Card newCard = Card.fromPaperCard(c.getPaperCard(), newOwner); newCard.setCommander(c.isCommander()); return newCard; diff --git a/forge-core/pom.xml b/forge-core/pom.xml index 1508c2e0070..bd5bc37a59d 100644 --- a/forge-core/pom.xml +++ b/forge-core/pom.xml @@ -6,7 +6,7 @@ forge forge - 1.6.43-SNAPSHOT + 1.6.44-SNAPSHOT forge-core diff --git a/forge-core/src/main/java/forge/card/CardRules.java b/forge-core/src/main/java/forge/card/CardRules.java index 38fb81ae0fd..c490bbd781a 100644 --- a/forge-core/src/main/java/forge/card/CardRules.java +++ b/forge-core/src/main/java/forge/card/CardRules.java @@ -424,9 +424,9 @@ public final class CardRules implements ICardCharacteristics { value = colonPos > 0 ? value.substring(1+colonPos) : null; if ( "RemoveDeck".equals(variable) ) { - this.removedFromAIDecks = "All".equalsIgnoreCase(value); - this.removedFromRandomDecks = "Random".equalsIgnoreCase(value); - this.removedFromNonCommanderDecks = "NonCommander".equalsIgnoreCase(value); + this.removedFromAIDecks |= "All".equalsIgnoreCase(value); + this.removedFromRandomDecks |= "Random".equalsIgnoreCase(value); + this.removedFromNonCommanderDecks |= "NonCommander".equalsIgnoreCase(value); } } else if ("AlternateMode".equals(key)) { this.altMode = CardSplitType.smartValueOf(value); diff --git a/forge-core/src/main/java/forge/card/CardType.java b/forge-core/src/main/java/forge/card/CardType.java index 3941b990124..257230a184a 100644 --- a/forge-core/src/main/java/forge/card/CardType.java +++ b/forge-core/src/main/java/forge/card/CardType.java @@ -58,7 +58,6 @@ public final class CardType implements Comparable, CardTypeView { Conspiracy(false, "conspiracies"), Creature(true, "creatures"), Dungeon(false, "dungeons"), - Emblem(false, "emblems"), Enchantment(true, "enchantments"), Instant(false, "instants"), Land(true, "lands"), @@ -437,11 +436,6 @@ public final class CardType implements Comparable, CardTypeView { return coreTypes.contains(CoreType.Phenomenon); } - @Override - public boolean isEmblem() { - return coreTypes.contains(CoreType.Emblem); - } - @Override public boolean isTribal() { return coreTypes.contains(CoreType.Tribal); @@ -547,7 +541,7 @@ public final class CardType implements Comparable, CardTypeView { if (!isInstant() && !isSorcery()) { Iterables.removeIf(subtypes, Predicates.IS_SPELL_TYPE); } - if (!isPlaneswalker() && !isEmblem()) { + if (!isPlaneswalker()) { Iterables.removeIf(subtypes, Predicates.IS_WALKER_TYPE); } } diff --git a/forge-core/src/main/java/forge/card/CardTypeView.java b/forge-core/src/main/java/forge/card/CardTypeView.java index cfecf57a752..f89452baac8 100644 --- a/forge-core/src/main/java/forge/card/CardTypeView.java +++ b/forge-core/src/main/java/forge/card/CardTypeView.java @@ -42,7 +42,6 @@ public interface CardTypeView extends Iterable, Serializable { boolean isBasicLand(); boolean isPlane(); boolean isPhenomenon(); - boolean isEmblem(); boolean isTribal(); boolean isDungeon(); CardTypeView getTypeWithChanges(Iterable changedCardTypes); diff --git a/forge-core/src/main/java/forge/deck/generation/DeckGeneratorMonoColor.java b/forge-core/src/main/java/forge/deck/generation/DeckGeneratorMonoColor.java index 551c36b8231..4abc1aa9dde 100644 --- a/forge-core/src/main/java/forge/deck/generation/DeckGeneratorMonoColor.java +++ b/forge-core/src/main/java/forge/deck/generation/DeckGeneratorMonoColor.java @@ -87,7 +87,6 @@ public class DeckGeneratorMonoColor extends DeckGeneratorBase { } } - @Override public final CardPool getDeck(final int size, final boolean forAi) { addCreaturesAndSpells(size, cmcLevels, forAi); diff --git a/forge-core/src/main/java/forge/item/generation/BoosterGenerator.java b/forge-core/src/main/java/forge/item/generation/BoosterGenerator.java index b917b0218ec..0570dc08ebe 100644 --- a/forge-core/src/main/java/forge/item/generation/BoosterGenerator.java +++ b/forge-core/src/main/java/forge/item/generation/BoosterGenerator.java @@ -61,7 +61,6 @@ import forge.util.TextUtil; */ public class BoosterGenerator { - private final static Map cachedSheets = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); private static synchronized PrintSheet getPrintSheet(String key) { if( !cachedSheets.containsKey(key) ) diff --git a/forge-core/src/main/java/forge/item/generation/UnOpenedProduct.java b/forge-core/src/main/java/forge/item/generation/UnOpenedProduct.java index 67c07beff5c..fc83c3254cd 100644 --- a/forge-core/src/main/java/forge/item/generation/UnOpenedProduct.java +++ b/forge-core/src/main/java/forge/item/generation/UnOpenedProduct.java @@ -31,7 +31,6 @@ public class UnOpenedProduct implements IUnOpenedProduct { this.poolLimited = considerNumbersInPool; // TODO: Add 0 to parameter's name. } - // Means to select from all unique cards (from base game, ie. no schemes or avatars) public UnOpenedProduct(SealedProduct.Template template) { tpl = template; diff --git a/forge-game/pom.xml b/forge-game/pom.xml index f3d98cf7c55..358894c0319 100644 --- a/forge-game/pom.xml +++ b/forge-game/pom.xml @@ -6,7 +6,7 @@ forge forge - 1.6.43-SNAPSHOT + 1.6.44-SNAPSHOT forge-game diff --git a/forge-game/src/main/java/forge/game/GameAction.java b/forge-game/src/main/java/forge/game/GameAction.java index 19a9f25ac72..b0a62990da8 100644 --- a/forge-game/src/main/java/forge/game/GameAction.java +++ b/forge-game/src/main/java/forge/game/GameAction.java @@ -705,17 +705,20 @@ public class GameAction { } } - if (zoneFrom == null) { - c.setCastFrom(null); - c.setCastSA(null); - } else if (zoneTo.is(ZoneType.Stack)) { - c.setCastFrom(zoneFrom.getZoneType()); + if (zoneTo.is(ZoneType.Stack)) { + // zoneFrom maybe null if the spell is cast from "Ouside the game", ex. ability of Garth One-Eye + if (zoneFrom == null) { + c.setCastFrom(null); + } else { + c.setCastFrom(zoneFrom.getZoneType()); + } if (cause != null && cause.isSpell() && c.equals(cause.getHostCard()) && !c.isCopiedSpell()) { c.setCastSA(cause); } else { c.setCastSA(null); } - } else if (!(zoneTo.is(ZoneType.Battlefield) && zoneFrom.is(ZoneType.Stack))) { + } else if (zoneFrom == null || !(zoneFrom.is(ZoneType.Stack) && + (zoneTo.is(ZoneType.Battlefield) || zoneTo.is(ZoneType.Merged)))) { c.setCastFrom(null); c.setCastSA(null); } diff --git a/forge-game/src/main/java/forge/game/GameActionUtil.java b/forge-game/src/main/java/forge/game/GameActionUtil.java index 95f447942bf..c78e34e62c7 100644 --- a/forge-game/src/main/java/forge/game/GameActionUtil.java +++ b/forge-game/src/main/java/forge/game/GameActionUtil.java @@ -153,8 +153,7 @@ public final class GameActionUtil { final StringBuilder sb = new StringBuilder(sa.getDescription()); if (!source.equals(host)) { sb.append(" by "); - if ((host.isEmblem() || host.getType().hasSubtype("Effect")) - && host.getEffectSource() != null) { + if ((host.isImmutable()) && host.getEffectSource() != null) { sb.append(host.getEffectSource()); } else { sb.append(host); @@ -542,7 +541,6 @@ public final class GameActionUtil { final Card eff = new Card(game.nextCardId(), game); eff.setTimestamp(game.getNextTimestamp()); eff.setName(sourceCard.getName() + "'s Effect"); - eff.addType("Effect"); eff.setOwner(controller); eff.setImageKey(sourceCard.getImageKey()); diff --git a/forge-game/src/main/java/forge/game/PlanarDice.java b/forge-game/src/main/java/forge/game/PlanarDice.java index d8705f3e889..6f46a28f604 100644 --- a/forge-game/src/main/java/forge/game/PlanarDice.java +++ b/forge-game/src/main/java/forge/game/PlanarDice.java @@ -1,5 +1,6 @@ package forge.game; +import java.util.Arrays; import java.util.Map; import com.google.common.collect.ImmutableList; @@ -8,7 +9,7 @@ import forge.game.ability.AbilityKey; import forge.game.player.Player; import forge.game.trigger.TriggerType; -/** +/** * Represents the planar dice for Planechase games. * */ @@ -16,7 +17,7 @@ public enum PlanarDice { Planeswalk, Chaos, Blank; - + public static PlanarDice roll(Player roller, PlanarDice riggedResult) { PlanarDice res = Blank; @@ -27,25 +28,37 @@ public enum PlanarDice { res = Planeswalk; else if (i == 1) res = Chaos; - - + + PlanarDice trigRes = res; - + if(roller.getGame().getStaticEffects().getGlobalRuleChange(GlobalRuleChange.blankIsChaos) && res == Blank) { trigRes = Chaos; } - final Map runParams = AbilityKey.newMap(); + Map runParams = AbilityKey.newMap(); runParams.put(AbilityKey.Player, roller); runParams.put(AbilityKey.Result, trigRes); roller.getGame().getTriggerHandler().runTrigger(TriggerType.PlanarDice, runParams,false); - - + + // Also run normal RolledDie and RolledDieOnce triggers + runParams = AbilityKey.newMap(); + runParams.put(AbilityKey.Player, roller); + runParams.put(AbilityKey.Sides, 6); + runParams.put(AbilityKey.Result, 0); + roller.getGame().getTriggerHandler().runTrigger(TriggerType.RolledDie, runParams, false); + + runParams = AbilityKey.newMap(); + runParams.put(AbilityKey.Player, roller); + runParams.put(AbilityKey.Sides, 6); + runParams.put(AbilityKey.Result, Arrays.asList(0)); + roller.getGame().getTriggerHandler().runTrigger(TriggerType.RolledDieOnce, runParams, false); + return res; } - + /** * Parses a string into an enum member. * @param string to parse diff --git a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java index 426a740137f..a423a15b6c3 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java @@ -31,6 +31,7 @@ import forge.card.mana.ManaCost; import forge.card.mana.ManaCostParser; import forge.card.mana.ManaCostShard; import forge.game.CardTraitBase; +import forge.game.Direction; import forge.game.Game; import forge.game.GameEntity; import forge.game.GameObject; @@ -111,9 +112,9 @@ public class AbilityUtils { // Probably will move to One function solution sometime in the future public static CardCollection getDefinedCards(final Card hostCard, final String def, final CardTraitBase sa) { CardCollection cards = new CardCollection(); - String defined = (def == null) ? "Self" : applyAbilityTextChangeEffects(def, sa); // default to Self - final String[] incR = defined.split("\\.", 2); - defined = incR[0]; + String changedDef = (def == null) ? "Self" : applyAbilityTextChangeEffects(def, sa); // default to Self + final String[] incR = changedDef.split("\\.", 2); + String defined = incR[0]; final Game game = hostCard.getGame(); Card c = null; @@ -131,7 +132,7 @@ public class AbilityUtils { } } else if (defined.equals("EffectSource")) { - if (hostCard.isEmblem() || hostCard.getType().hasSubtype("Effect")) { + if (hostCard.isImmutable()) { c = findEffectRoot(hostCard); } } @@ -313,6 +314,10 @@ public class AbilityUtils { for (final Card imprint : hostCard.getImprintedCards()) { cards.add(game.getCardState(imprint)); } + } else if (defined.equals("UntilLeavesBattlefield")) { + for (final Card ulb : hostCard.getUntilLeavesBattlefield()) { + cards.add(game.getCardState(ulb)); + } } else if (defined.startsWith("ThisTurnEntered")) { final String[] workingCopy = defined.split("_"); ZoneType destination, origin; @@ -345,6 +350,23 @@ public class AbilityUtils { cards.add(game.getCardState(cardByID)); } } + } else if (defined.startsWith("Valid")) { + Iterable candidates; + String validDefined; + if (defined.startsWith("Valid ")) { + candidates = game.getCardsIn(ZoneType.Battlefield); + validDefined = changedDef.substring("Valid ".length()); + } else if (defined.startsWith("ValidAll ")) { + candidates = game.getCardsInGame(); + validDefined = changedDef.substring("ValidAll ".length()); + } else { + String[] s = changedDef.split(" ", 2); + String zone = s[0].substring("Valid".length()); + candidates = game.getCardsIn(ZoneType.smartValueOf(zone)); + validDefined = s[1]; + } + cards.addAll(CardLists.getValidCards(candidates, validDefined.split(","), hostCard.getController(), hostCard, sa)); + return cards; } else { CardCollection list = null; if (sa instanceof SpellAbility) { @@ -376,19 +398,6 @@ public class AbilityUtils { } } - if (defined.startsWith("Valid ")) { - String validDefined = defined.substring("Valid ".length()); - list = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), validDefined.split(","), hostCard.getController(), hostCard, sa); - } else if (defined.startsWith("ValidAll ")) { - String validDefined = defined.substring("ValidAll ".length()); - list = CardLists.getValidCards(game.getCardsInGame(), validDefined.split(","), hostCard.getController(), hostCard, sa); - } else if (defined.startsWith("Valid")) { - String[] s = defined.split(" "); - String zone = s[0].substring("Valid".length()); - String validDefined = s[1]; - list = CardLists.getValidCards(game.getCardsIn(ZoneType.smartValueOf(zone)), validDefined.split(","), hostCard.getController(), hostCard, sa); - } - if (list != null) { cards.addAll(list); } @@ -420,7 +429,7 @@ public class AbilityUtils { private static Card findEffectRoot(Card startCard) { Card cc = startCard.getEffectSource(); if (cc != null) { - if (cc.isEmblem() || cc.getType().hasSubtype("Effect")) { + if (cc.isImmutable()) { return findEffectRoot(cc); } return cc; @@ -1268,6 +1277,9 @@ public class AbilityUtils { } else if (defined.equals("Opponent")) { players.addAll(player.getOpponents()); + } else if (defined.startsWith("NextPlayerToYour")) { + Direction dir = defined.substring(16).equals("Left") ? Direction.Left : Direction.Right; + players.add(game.getNextPlayerAfter(player, dir)); } else { for (Player p : game.getPlayersInTurnOrder()) { diff --git a/forge-game/src/main/java/forge/game/ability/ApiType.java b/forge-game/src/main/java/forge/game/ability/ApiType.java index 79589cf90d0..afbb4b7ab0f 100644 --- a/forge-game/src/main/java/forge/game/ability/ApiType.java +++ b/forge-game/src/main/java/forge/game/ability/ApiType.java @@ -142,6 +142,7 @@ public enum ApiType { ReplaceEffect (ReplaceEffect.class), ReplaceMana (ReplaceManaEffect.class), ReplaceDamage (ReplaceDamageEffect.class), + ReplaceToken (ReplaceTokenEffect.class), ReplaceSplitDamage (ReplaceSplitDamageEffect.class), RestartGame (RestartGameEffect.class), Reveal (RevealEffect.class), diff --git a/forge-game/src/main/java/forge/game/ability/SpellAbilityEffect.java b/forge-game/src/main/java/forge/game/ability/SpellAbilityEffect.java index 4c29e29dbb9..c84d0c0eb1a 100644 --- a/forge-game/src/main/java/forge/game/ability/SpellAbilityEffect.java +++ b/forge-game/src/main/java/forge/game/ability/SpellAbilityEffect.java @@ -13,7 +13,6 @@ import com.google.common.collect.Maps; import com.google.common.collect.Table; import forge.GameCommand; -import forge.card.CardType; import forge.card.MagicColor; import forge.game.Game; import forge.game.GameEntity; @@ -457,25 +456,19 @@ public abstract class SpellAbilityEffect { final Card eff = new Card(game.nextCardId(), game); eff.setTimestamp(game.getNextTimestamp()); eff.setName(name); + eff.setColor(hostCard.determineColor().getColor()); // if name includes emblem then it should be one - eff.addType(name.startsWith("Emblem") ? "Emblem" : "Effect"); - // add Planeswalker types into Emblem for fun - if (name.startsWith("Emblem") && hostCard.isPlaneswalker()) { - for (final String type : hostCard.getType().getSubtypes()) { - if (CardType.isAPlaneswalkerType(type)) { - eff.addType(type); - } - } + if (name.startsWith("Emblem")) { + eff.setEmblem(true); + // Emblem needs to be colorless + eff.setColor(MagicColor.COLORLESS); } + eff.setOwner(controller); eff.setSVars(sa.getSVars()); eff.setImageKey(image); - if (eff.getType().hasType(CardType.CoreType.Emblem)) { - eff.setColor(MagicColor.COLORLESS); - } else { - eff.setColor(hostCard.determineColor().getColor()); - } + eff.setImmutable(true); eff.setEffectSource(sa); diff --git a/forge-game/src/main/java/forge/game/ability/effects/AmassEffect.java b/forge-game/src/main/java/forge/game/ability/effects/AmassEffect.java index fe4bc675585..0bfe529c0a5 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/AmassEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/AmassEffect.java @@ -16,7 +16,6 @@ import forge.game.card.CardPredicates; import forge.game.card.CardZoneTable; import forge.game.card.CounterEnumType; import forge.game.card.CounterType; -import forge.game.card.token.TokenInfo; import forge.game.event.GameEventCombatChanged; import forge.game.event.GameEventTokenCreated; import forge.game.player.Player; @@ -53,37 +52,24 @@ public class AmassEffect extends TokenEffectBase { final int amount = AbilityUtils.calculateAmount(card, sa.getParamOrDefault("Num", "1"), sa); final boolean remember = sa.hasParam("RememberAmass"); - boolean useZoneTable = true; - CardZoneTable triggerList = sa.getChangeZoneTable(); - if (triggerList == null) { - triggerList = new CardZoneTable(); - useZoneTable = false; - } - if (sa.hasParam("ChangeZoneTable")) { - sa.setChangeZoneTable(triggerList); - useZoneTable = true; - } - - MutableBoolean combatChanged = new MutableBoolean(false); // create army token if needed if (CardLists.count(activator.getCardsIn(ZoneType.Battlefield), CardPredicates.isType("Army")) == 0) { - final String tokenScript = "b_0_0_zombie_army"; + CardZoneTable triggerList = new CardZoneTable(); + MutableBoolean combatChanged = new MutableBoolean(false); - final Card prototype = TokenInfo.getProtoType(tokenScript, sa, false); + makeTokenTable(makeTokenTableInternal(activator, "b_0_0_zombie_army", 1, sa), false, triggerList, combatChanged, sa); - makeTokens(prototype, activator, sa, 1, true, false, triggerList, combatChanged); + triggerList.triggerChangesZoneAll(game, sa); + triggerList.clear(); - if (!useZoneTable) { - triggerList.triggerChangesZoneAll(game, sa); - triggerList.clear(); - } game.fireEvent(new GameEventTokenCreated()); + + if (combatChanged.isTrue()) { + game.updateCombatForView(); + game.fireEvent(new GameEventCombatChanged()); + } } - if (combatChanged.isTrue()) { - game.updateCombatForView(); - game.fireEvent(new GameEventCombatChanged()); - } Map params = Maps.newHashMap(); params.put("CounterType", CounterType.get(CounterEnumType.P1P1)); params.put("Amount", 1); diff --git a/forge-game/src/main/java/forge/game/ability/effects/AnimateEffect.java b/forge-game/src/main/java/forge/game/ability/effects/AnimateEffect.java index 9b09ca23032..63f36f6a89e 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/AnimateEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/AnimateEffect.java @@ -190,11 +190,6 @@ public class AnimateEffect extends AnimateEffectBase { } } - // Restore immutable to effect - if (sa.hasParam("Immutable")) { - c.setImmutable(true); - } - game.fireEvent(new GameEventCardStatsChanged(c)); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/AnimateEffectBase.java b/forge-game/src/main/java/forge/game/ability/effects/AnimateEffectBase.java index bba087ecd8f..42d914afa41 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/AnimateEffectBase.java +++ b/forge-game/src/main/java/forge/game/ability/effects/AnimateEffectBase.java @@ -164,14 +164,6 @@ public abstract class AnimateEffectBase extends SpellAbilityEffect { final Trigger parsedTrigger = TriggerHandler.parseTrigger(AbilityUtils.getSVar(sa, s), c, false, sa); addedTriggers.add(parsedTrigger); } - if (sa.hasParam("GainsTriggeredAbilitiesOf")) { - final List cards = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("GainsTriggeredAbilitiesOf"), sa); - for (final Card card : cards) { - for (Trigger t : card.getTriggers()) { - addedTriggers.add(t.copy(c, false)); - } - } - } // give replacement effects final List addedReplacements = Lists.newArrayList(); diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChooseCardEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChooseCardEffect.java index ef97d4bf459..77b5a722913 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChooseCardEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChooseCardEffect.java @@ -119,6 +119,12 @@ public class ChooseCardEffect extends SpellAbilityEffect { Aggregates.random(choices, validAmount, chosen); } else { String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseaCard") + " "; + if (sa.hasParam ("ChoiceTitleAppendDefined")) { + String defined = AbilityUtils.getDefinedPlayers(sa.getHostCard(), sa.getParam("ChoiceTitleAppendDefined"), sa).toString(); + final StringBuilder sb = new StringBuilder(); + sb.append(title).append(" ").append(defined); + title = sb.toString(); + } chosen.addAll(p.getController().chooseCardsForEffect(choices, sa, title, minAmount, validAmount, !sa.hasParam("Mandatory"), null)); } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChooseTypeEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChooseTypeEffect.java index 2bfb5c1bbb0..6a601d7257b 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChooseTypeEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChooseTypeEffect.java @@ -72,8 +72,7 @@ public class ChooseTypeEffect extends SpellAbilityEffect { } } } - } - else { + } else { throw new InvalidParameterException(sa.getHostCard() + "'s ability resulted in no types to choose from"); } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/ControlGainEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ControlGainEffect.java index 691b149d6d6..dd9fa9b3bd9 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ControlGainEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ControlGainEffect.java @@ -67,7 +67,7 @@ public class ControlGainEffect extends SpellAbilityEffect { if (tapOnLose) { c.tap(); } - } // if + } host.removeGainControlTargets(c); } @@ -91,7 +91,12 @@ public class ControlGainEffect extends SpellAbilityEffect { if (sa.hasParam("ControlledByTarget")) { tgtCards = CardLists.filterControlledBy(tgtCards, getTargetPlayers(sa)); - } + } + + // in case source was LKI or still resolving + if (source.isLKI() || source.getZone().is(ZoneType.Stack)) { + source = game.getCardState(source); + } // check for lose control criteria right away if (lose != null && lose.contains("LeavesPlay") && !source.isInZone(ZoneType.Battlefield)) { @@ -103,7 +108,6 @@ public class ControlGainEffect extends SpellAbilityEffect { boolean combatChanged = false; for (Card tgtC : tgtCards) { - if (!tgtC.isInPlay() || !tgtC.canBeControlledBy(newController)) { continue; } diff --git a/forge-game/src/main/java/forge/game/ability/effects/CopyPermanentEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CopyPermanentEffect.java index 8061522ea74..f70bd56a975 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/CopyPermanentEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/CopyPermanentEffect.java @@ -20,6 +20,7 @@ import forge.game.card.CardFactory; import forge.game.card.CardLists; import forge.game.card.CardPredicates; import forge.game.card.CardZoneTable; +import forge.game.card.TokenCreateTable; import forge.game.event.GameEventCombatChanged; import forge.game.player.Player; import forge.game.player.PlayerActionConfirmMode; @@ -177,15 +178,18 @@ public class CopyPermanentEffect extends TokenEffectBase { } MutableBoolean combatChanged = new MutableBoolean(false); + TokenCreateTable tokenTable = new TokenCreateTable(); + for (final Card c : tgtCards) { // if it only targets player, it already got all needed cards from defined if (sa.usesTargeting() && !sa.getTargetRestrictions().canTgtPlayer() && !c.canBeTargetedBy(sa)) { continue; } - - makeTokens(getProtoType(sa, c), controller, sa, numCopies, true, true, triggerList, combatChanged); + tokenTable.put(controller, getProtoType(sa, c, controller), numCopies); } // end foreach Card + makeTokenTable(tokenTable, true, triggerList, combatChanged, sa); + if (!useZoneTable) { triggerList.triggerChangesZoneAll(game, sa); triggerList.clear(); @@ -196,9 +200,8 @@ public class CopyPermanentEffect extends TokenEffectBase { } } // end resolve - private Card getProtoType(final SpellAbility sa, final Card original) { + private Card getProtoType(final SpellAbility sa, final Card original, final Player newOwner) { final Card host = sa.getHostCard(); - final Player newOwner = sa.getActivatingPlayer(); int id = newOwner == null ? 0 : newOwner.getGame().nextCardId(); final Card copy = new Card(id, original.getPaperCard(), host.getGame()); copy.setOwner(newOwner); diff --git a/forge-game/src/main/java/forge/game/ability/effects/DetachedCardEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DetachedCardEffect.java index 0d62a05104b..56a1a46081d 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/DetachedCardEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/DetachedCardEffect.java @@ -12,7 +12,6 @@ public class DetachedCardEffect extends Card { card = card0; setName(name0); - addType("Effect"); setOwner(card0.getOwner()); setImmutable(true); diff --git a/forge-game/src/main/java/forge/game/ability/effects/EffectEffect.java b/forge-game/src/main/java/forge/game/ability/effects/EffectEffect.java index 04471bed67a..445d03088ed 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/EffectEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/EffectEffect.java @@ -140,10 +140,6 @@ public class EffectEffect extends SpellAbilityEffect { final Card eff = createEffect(sa, controller, name, image); eff.setSetCode(sa.getHostCard().getSetCode()); eff.setRarity(sa.getHostCard().getRarity()); - // For Raging River effect to add attacker "left" or "right" pile later - if (sa.hasParam("Mutable")) { - eff.setImmutable(false); - } // Abilities and triggers work the same as they do for Token // Grant abilities diff --git a/forge-game/src/main/java/forge/game/ability/effects/FightEffect.java b/forge-game/src/main/java/forge/game/ability/effects/FightEffect.java index 47c042d245a..e6f82bfb9f8 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/FightEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/FightEffect.java @@ -38,7 +38,6 @@ public class FightEffect extends DamageBaseEffect { return sb.toString(); } - /* (non-Javadoc) * @see forge.game.ability.SpellAbilityEffect#resolve(forge.game.spellability.SpellAbility) */ @@ -77,6 +76,7 @@ public class FightEffect extends DamageBaseEffect { final Map runParams = AbilityKey.newMap(); runParams.put(AbilityKey.Fighters, fighters); + game.getTriggerHandler().runTrigger(TriggerType.FightOnce, runParams, false); } private static List getFighters(SpellAbility sa) { diff --git a/forge-game/src/main/java/forge/game/ability/effects/InvestigateEffect.java b/forge-game/src/main/java/forge/game/ability/effects/InvestigateEffect.java index 2d8491757a4..30746f73093 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/InvestigateEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/InvestigateEffect.java @@ -6,7 +6,6 @@ import forge.game.Game; import forge.game.ability.AbilityUtils; import forge.game.card.Card; import forge.game.card.CardZoneTable; -import forge.game.card.token.TokenInfo; import forge.game.event.GameEventCombatChanged; import forge.game.event.GameEventTokenCreated; import forge.game.player.Player; @@ -36,14 +35,13 @@ public class InvestigateEffect extends TokenEffectBase { final int amount = AbilityUtils.calculateAmount(card, sa.getParamOrDefault("Num", "1"), sa); - final String tokenScript = "c_a_clue_draw"; - final Card prototype = TokenInfo.getProtoType(tokenScript, sa, false); - + // Investigate in Sequence for (final Player p : getTargetPlayers(sa)) { for (int i = 0; i < amount; i++) { CardZoneTable triggerList = new CardZoneTable(); MutableBoolean combatChanged = new MutableBoolean(false); - makeTokens(prototype, p, sa, 1, true, false, triggerList, combatChanged); + + makeTokenTable(makeTokenTableInternal(p, "c_a_clue_draw", 1, sa), false, triggerList, combatChanged, sa); triggerList.triggerChangesZoneAll(game, sa); p.addInvestigatedThisTurn(); diff --git a/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java b/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java index e69173083a6..6171e2dcde2 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java @@ -1,7 +1,10 @@ package forge.game.ability.effects; import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; import java.util.List; +import java.util.Map; import org.apache.commons.lang3.StringUtils; @@ -69,6 +72,8 @@ public class PlayEffect extends SpellAbilityEffect { final boolean optional = sa.hasParam("Optional"); boolean remember = sa.hasParam("RememberPlayed"); int amount = 1; + boolean hasTotalCMCLimit = sa.hasParam("WithTotalCMC"); + int totalCMCLimit = Integer.MAX_VALUE; if (sa.hasParam("Amount") && !sa.getParam("Amount").equals("All")) { amount = AbilityUtils.calculateAmount(source, sa.getParam("Amount"), sa); } @@ -163,13 +168,15 @@ public class PlayEffect extends SpellAbilityEffect { if (sa.hasParam("ValidSA")) { final String valid[] = {sa.getParam("ValidSA")}; - List toRemove = Lists.newArrayList(); - for (Card c : tgtCards) { + Iterator it = tgtCards.iterator(); + while (it.hasNext()) { + Card c = it.next(); if (!Iterables.any(AbilityUtils.getBasicSpellsFromPlayEffect(c, controller), SpellAbilityPredicates.isValid(valid, controller , c, sa))) { - toRemove.add(c); + // it.remove will only remove item from the list part of CardCollection + tgtCards.asSet().remove(c); + it.remove(); } } - tgtCards.removeAll(toRemove); if (tgtCards.isEmpty()) { return; } @@ -179,15 +186,37 @@ public class PlayEffect extends SpellAbilityEffect { amount = tgtCards.size(); } + if (hasTotalCMCLimit) { + totalCMCLimit = AbilityUtils.calculateAmount(source, sa.getParam("WithTotalCMC"), sa); + } + if (controlledByPlayer != null) { activator.addController(controlledByTimeStamp, controlledByPlayer); } boolean singleOption = tgtCards.size() == 1 && amount == 1 && optional; + Map params = hasTotalCMCLimit ? new HashMap<>() : null; + + while (!tgtCards.isEmpty() && amount > 0 && totalCMCLimit >= 0) { + if (hasTotalCMCLimit) { + // filter out cards with mana value greater than limit + Iterator it = tgtCards.iterator(); + final String [] valid = {"Spell.cmcLE"+totalCMCLimit}; + while (it.hasNext()) { + Card c = it.next(); + if (!Iterables.any(AbilityUtils.getBasicSpellsFromPlayEffect(c, controller), SpellAbilityPredicates.isValid(valid, controller , c, sa))) { + // it.remove will only remove item from the list part of CardCollection + tgtCards.asSet().remove(c); + it.remove(); + } + } + if (tgtCards.isEmpty()) + break; + params.put("CMCLimit", totalCMCLimit); + } - while (!tgtCards.isEmpty() && amount > 0) { activator.getController().tempShowCards(showCards); - Card tgtCard = controller.getController().chooseSingleEntityForEffect(tgtCards, sa, Localizer.getInstance().getMessage("lblSelectCardToPlay"), !singleOption && optional, null); + Card tgtCard = controller.getController().chooseSingleEntityForEffect(tgtCards, sa, Localizer.getInstance().getMessage("lblSelectCardToPlay"), !singleOption && optional, params); activator.getController().endTempShowCards(); if (tgtCard == null) { break; @@ -248,6 +277,14 @@ public class PlayEffect extends SpellAbilityEffect { final String valid[] = {sa.getParam("ValidSA")}; sas = Lists.newArrayList(Iterables.filter(sas, SpellAbilityPredicates.isValid(valid, controller , source, sa))); } + if (hasTotalCMCLimit) { + Iterator it = sas.iterator(); + while (it.hasNext()) { + SpellAbility s = it.next(); + if (s.getPayCosts().getTotalMana().getCMC() > totalCMCLimit) + it.remove(); + } + } if (sas.isEmpty()) { continue; @@ -276,6 +313,8 @@ public class PlayEffect extends SpellAbilityEffect { continue; } + final int tgtCMC = tgtSA.getPayCosts().getTotalMana().getCMC(); + if (sa.hasParam("WithoutManaCost")) { tgtSA = tgtSA.copyWithNoManaCost(); } else if (sa.hasParam("PlayCost")) { @@ -341,6 +380,7 @@ public class PlayEffect extends SpellAbilityEffect { } amount--; + totalCMCLimit -= tgtCMC; } // Remove controlled by player if any diff --git a/forge-game/src/main/java/forge/game/ability/effects/PumpEffect.java b/forge-game/src/main/java/forge/game/ability/effects/PumpEffect.java index 0a1042cc0ae..8ef9f106a3c 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/PumpEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/PumpEffect.java @@ -121,7 +121,7 @@ public class PumpEffect extends SpellAbilityEffect { final Card host = sa.getHostCard(); //if host is not on the battlefield don't apply // Suspend should does Affect the Stack - if ((sa.hasParam("UntilLoseControlOfHost") || sa.hasParam("UntilHostLeavesPlay")) + if (("UntilHostLeavesPlay".equals(sa.getParam("Duration")) || "UntilLoseControlOfHost".equals(sa.getParam("Duration"))) && !(host.isInPlay() || host.isInZone(ZoneType.Stack))) { return; } @@ -158,7 +158,6 @@ public class PumpEffect extends SpellAbilityEffect { } if (tgts.size() > 0) { - for (final GameEntity c : tgts) { sb.append(c).append(" "); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/RegenerationEffect.java b/forge-game/src/main/java/forge/game/ability/effects/RegenerationEffect.java index 7d42e9c5988..f96ad2a2ead 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/RegenerationEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/RegenerationEffect.java @@ -37,7 +37,7 @@ public class RegenerationEffect extends SpellAbilityEffect { // Play the Regen sound game.fireEvent(new GameEventCardRegenerated()); - if (host.getType().hasStringType("Effect")) { + if (host.isImmutable()) { c.subtractShield(host); host.removeRemembered(c); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/RepeatEffect.java b/forge-game/src/main/java/forge/game/ability/effects/RepeatEffect.java index 5c384cd1401..92652afa881 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/RepeatEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/RepeatEffect.java @@ -49,7 +49,7 @@ public class RepeatEffect extends SpellAbilityEffect { // TODO Replace Infinite Loop Break with a game draw. Here are the scenarios that can cause this: // Helm of Obedience vs Graveyard to Library replacement effect - if(source.getName().equals("Helm of Obedience")) { + if (source.getName().equals("Helm of Obedience")) { StringBuilder infLoop = new StringBuilder(sa.getHostCard().toString()); infLoop.append(" - To avoid an infinite loop, this repeat has been broken "); infLoop.append(" and the game will now continue in the current state, ending the loop early. "); diff --git a/forge-game/src/main/java/forge/game/ability/effects/ReplaceDamageEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ReplaceDamageEffect.java index cb59a12eb10..3a19bb05c42 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ReplaceDamageEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ReplaceDamageEffect.java @@ -47,7 +47,7 @@ public class ReplaceDamageEffect extends SpellAbilityEffect { prevent -= n; if (!StringUtils.isNumeric(varValue) && card.getSVar(varValue).startsWith("Number$")) { - if (card.getType().hasStringType("Effect") && prevent <= 0) { + if (card.isImmutable() && prevent <= 0) { game.getAction().exile(card, null); } else { card.setSVar(varValue, "Number$" + prevent); diff --git a/forge-game/src/main/java/forge/game/ability/effects/ReplaceEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ReplaceEffect.java index 08acad9616e..48689ab377a 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ReplaceEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ReplaceEffect.java @@ -3,12 +3,6 @@ package forge.game.ability.effects; import java.util.List; import java.util.Map; -import org.apache.commons.lang3.StringUtils; - -import com.google.common.collect.Maps; - -import forge.game.Game; -import forge.game.GameLogEntryType; import forge.game.GameObject; import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; @@ -17,25 +11,21 @@ import forge.game.card.Card; import forge.game.card.token.TokenInfo; import forge.game.player.Player; import forge.game.replacement.ReplacementResult; -import forge.game.replacement.ReplacementType; import forge.game.spellability.SpellAbility; -import forge.util.TextUtil; + public class ReplaceEffect extends SpellAbilityEffect { @Override public void resolve(SpellAbility sa) { final Card card = sa.getHostCard(); - final Game game = card.getGame(); final AbilityKey varName = AbilityKey.fromString(sa.getParam("VarName")); final String varValue = sa.getParam("VarValue"); final String type = sa.getParamOrDefault("VarType", "amount"); - final ReplacementType retype = sa.getReplacementEffect().getMode(); @SuppressWarnings("unchecked") - Map originalParams = (Map) sa.getReplacingObject(AbilityKey.OriginalParams); - Map params = Maps.newHashMap(originalParams); + Map params = (Map) sa.getReplacingObject(AbilityKey.OriginalParams); if ("Card".equals(type)) { List list = AbilityUtils.getDefinedCards(card, varValue, sa); @@ -53,7 +43,7 @@ public class ReplaceEffect extends SpellAbilityEffect { params.put(varName, list.get(0)); } } else if ("TokenScript".equals(type)) { - final Card protoType = TokenInfo.getProtoType(varValue, sa); + final Card protoType = TokenInfo.getProtoType(varValue, sa, sa.getActivatingPlayer()); if (protoType != null) { params.put(varName, protoType); } @@ -61,42 +51,7 @@ public class ReplaceEffect extends SpellAbilityEffect { params.put(varName, AbilityUtils.calculateAmount(card, varValue, sa)); } - if (params.containsKey(AbilityKey.EffectOnly)) { - params.put(AbilityKey.EffectOnly, true); - } - - if (retype == ReplacementType.DamageDone) { - for (Map.Entry e : params.entrySet()) { - originalParams.put(e.getKey(), e.getValue()); - } - originalParams.put(AbilityKey.ReplacementResult, ReplacementResult.Updated); - return; - } - - // need to log Updated events there, or the log is wrong order - String message = sa.getReplacementEffect().toString(); - if ( !StringUtils.isEmpty(message)) { - message = TextUtil.fastReplace(message, "CARDNAME", card.getName()); - game.getGameLog().add(GameLogEntryType.EFFECT_REPLACED, message); - } - - //try to call replacementHandler with new Params - ReplacementResult result = game.getReplacementHandler().run(retype, params); - switch (result) { - case NotReplaced: - case Updated: { - for (Map.Entry e : params.entrySet()) { - originalParams.put(e.getKey(), e.getValue()); - } - // effect was updated - originalParams.put(AbilityKey.ReplacementResult, ReplacementResult.Updated); - break; - } - default: - // effect was replaced with something else - originalParams.put(AbilityKey.ReplacementResult, result); - break; - } + params.put(AbilityKey.ReplacementResult, ReplacementResult.Updated); } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/ReplaceManaEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ReplaceManaEffect.java index bc8158111d8..aeb5ad22f3c 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ReplaceManaEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ReplaceManaEffect.java @@ -4,20 +4,15 @@ import java.util.Map; import org.apache.commons.lang3.StringUtils; -import com.google.common.collect.Maps; import forge.card.ColorSet; import forge.card.MagicColor; -import forge.game.Game; -import forge.game.GameLogEntryType; import forge.game.ability.AbilityKey; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; import forge.game.player.Player; import forge.game.replacement.ReplacementResult; -import forge.game.replacement.ReplacementType; import forge.game.spellability.SpellAbility; -import forge.util.TextUtil; public class ReplaceManaEffect extends SpellAbilityEffect { @@ -25,17 +20,14 @@ public class ReplaceManaEffect extends SpellAbilityEffect { public void resolve(SpellAbility sa) { final Card card = sa.getHostCard(); final Player player = sa.getActivatingPlayer(); - final Game game = card.getGame(); // outside of Replacement Effect, unwanted result if (!sa.isReplacementAbility()) { return; } - final ReplacementType event = sa.getReplacementEffect().getMode(); @SuppressWarnings("unchecked") - Map originalParams = (Map) sa.getReplacingObject(AbilityKey.OriginalParams); - Map params = Maps.newHashMap(originalParams); + Map params = (Map) sa.getReplacingObject(AbilityKey.OriginalParams); String replaced = (String)sa.getReplacingObject(AbilityKey.Mana); if (sa.hasParam("ReplaceMana")) { @@ -79,31 +71,8 @@ public class ReplaceManaEffect extends SpellAbilityEffect { replaced = StringUtils.repeat(replaced, " ", Integer.valueOf(sa.getParam("ReplaceAmount"))); } params.put(AbilityKey.Mana, replaced); - - // need to log Updated events there, or the log is wrong order - String message = sa.getReplacementEffect().toString(); - if (!StringUtils.isEmpty(message)) { - message = TextUtil.fastReplace(message, "CARDNAME", card.getName()); - game.getGameLog().add(GameLogEntryType.EFFECT_REPLACED, message); - } - - //try to call replacementHandler with new Params - ReplacementResult result = game.getReplacementHandler().run(event, params); - switch (result) { - case NotReplaced: - case Updated: { - for (Map.Entry e : params.entrySet()) { - originalParams.put(e.getKey(), e.getValue()); - } - // effect was updated - originalParams.put(AbilityKey.ReplacementResult, ReplacementResult.Updated); - break; - } - default: - // effect was replaced with something else - originalParams.put(AbilityKey.ReplacementResult, result); - break; - } + // effect was updated + params.put(AbilityKey.ReplacementResult, ReplacementResult.Updated); } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/ReplaceSplitDamageEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ReplaceSplitDamageEffect.java index 1f462099afe..65fce9f796d 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ReplaceSplitDamageEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ReplaceSplitDamageEffect.java @@ -45,7 +45,7 @@ public class ReplaceSplitDamageEffect extends SpellAbilityEffect { dmg -= n; prevent -= n; - if (card.getType().hasStringType("Effect") && prevent <= 0) { + if (card.isImmutable() && prevent <= 0) { game.getAction().exile(card, null); } else if (!StringUtils.isNumeric(varValue)) { sa.setSVar(varValue, "Number$" + prevent); diff --git a/forge-game/src/main/java/forge/game/ability/effects/ReplaceTokenEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ReplaceTokenEffect.java new file mode 100644 index 00000000000..a9dc9337ad1 --- /dev/null +++ b/forge-game/src/main/java/forge/game/ability/effects/ReplaceTokenEffect.java @@ -0,0 +1,131 @@ +package forge.game.ability.effects; + +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang3.ObjectUtils; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; + +import forge.game.Game; +import forge.game.ability.AbilityKey; +import forge.game.ability.AbilityUtils; +import forge.game.ability.SpellAbilityEffect; +import forge.game.card.Card; +import forge.game.card.TokenCreateTable; +import forge.game.card.token.TokenInfo; +import forge.game.player.Player; +import forge.game.replacement.ReplacementResult; +import forge.game.spellability.SpellAbility; + +public class ReplaceTokenEffect extends SpellAbilityEffect { + + @Override + public void resolve(SpellAbility sa) { + final Card card = sa.getHostCard(); + final Player p = sa.getActivatingPlayer(); + final Game game = card.getGame(); + + // ReplaceToken Effect only applies to one Player + Player affected = (Player) sa.getReplacingObject(AbilityKey.Player); + TokenCreateTable table = (TokenCreateTable) sa.getReplacingObject(AbilityKey.Token); + + @SuppressWarnings("unchecked") + Map originalParams = (Map) sa + .getReplacingObject(AbilityKey.OriginalParams); + + // currently the only ones that changes the amount does double it + if ("Amount".equals(sa.getParam("Type"))) { + for (Map.Entry e : table.row(affected).entrySet()) { + if (!sa.matchesValidParam("ValidCard", e.getKey())) { + continue; + } + // currently the amount is only doubled + table.put(affected, e.getKey(), e.getValue() * 2); + } + } else if ("AddToken".equals(sa.getParam("Type"))) { + long timestamp = game.getNextTimestamp(); + + Map byController = Maps.newHashMap(); + for (Map.Entry e : table.row(affected).entrySet()) { + if (!sa.matchesValidParam("ValidCard", e.getKey())) { + continue; + } + Player contoller = e.getKey().getController(); + int old = ObjectUtils.defaultIfNull(byController.get(contoller), 0); + byController.put(contoller, old + e.getValue()); + } + + if (!byController.isEmpty()) { + // for Xorn, might matter if you could somehow create Treasure under multiple players control + if (sa.hasParam("Amount")) { + int i = AbilityUtils.calculateAmount(card, sa.getParam("Amount"), sa); + for (Map.Entry e : byController.entrySet()) { + e.setValue(i); + } + } + for (Map.Entry e : byController.entrySet()) { + for (String script : sa.getParam("TokenScript").split(",")) { + final Card token = TokenInfo.getProtoType(script, sa, p); + + if (token == null) { + throw new RuntimeException("don't find Token for TokenScript: " + script); + } + token.setController(e.getKey(), timestamp); + table.put(p, token, e.getValue()); + } + } + } + } else if ("ReplaceToken".equals(sa.getParam("Type"))) { + long timestamp = game.getNextTimestamp(); + + Map toInsertMap = Maps.newHashMap(); + Set toRemoveSet = Sets.newHashSet(); + for (Map.Entry e : table.row(affected).entrySet()) { + if (!sa.matchesValidParam("ValidCard", e.getKey())) { + continue; + } + Player controller = e.getKey().getController(); + int old = ObjectUtils.defaultIfNull(toInsertMap.get(controller), 0); + toInsertMap.put(controller, old + e.getValue()); + toRemoveSet.add(e.getKey()); + } + // remove replaced tokens + table.row(affected).keySet().removeAll(toRemoveSet); + + // insert new tokens + for (Map.Entry pe : toInsertMap.entrySet()) { + if (pe.getValue() <= 0) { + continue; + } + for (String script : sa.getParam("TokenScript").split(",")) { + final Card token = TokenInfo.getProtoType(script, sa, pe.getKey()); + + if (token == null) { + throw new RuntimeException("don't find Token for TokenScript: " + script); + } + + token.setController(pe.getKey(), timestamp); + table.put(affected, token, pe.getValue()); + } + } + } else if ("ReplaceController".equals(sa.getParam("Type"))) { + long timestamp = game.getNextTimestamp(); + Player newController = sa.getActivatingPlayer(); + if (sa.hasParam("NewController")) { + newController = AbilityUtils.getDefinedPlayers(sa.getHostCard(), sa.getParam("NewController"), sa).get(0); + } + for (Map.Entry c : table.row(affected).entrySet()) { + if (!sa.matchesValidParam("ValidCard", c.getKey())) { + continue; + } + c.getKey().setController(newController, timestamp); + } + } + + // effect was updated + originalParams.put(AbilityKey.ReplacementResult, ReplacementResult.Updated); + } + +} diff --git a/forge-game/src/main/java/forge/game/ability/effects/TokenEffect.java b/forge-game/src/main/java/forge/game/ability/effects/TokenEffect.java index d902416c16e..e3f941eb852 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/TokenEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/TokenEffect.java @@ -23,10 +23,8 @@ import forge.game.Game; import forge.game.ability.AbilityUtils; import forge.game.card.Card; import forge.game.card.CardZoneTable; -import forge.game.card.token.TokenInfo; import forge.game.event.GameEventCombatChanged; import forge.game.event.GameEventTokenCreated; -import forge.game.player.Player; import forge.game.spellability.SpellAbility; public class TokenEffect extends TokenEffectBase { @@ -36,20 +34,6 @@ public class TokenEffect extends TokenEffectBase { return sa.getDescription(); } - public Card loadTokenPrototype(SpellAbility sa) { - if (!sa.hasParam("TokenScript")) { - return null; - } - - final Card result = TokenInfo.getProtoType(sa.getParam("TokenScript"), sa); - - if (result == null) { - throw new RuntimeException("don't find Token for TokenScript: " + sa.getParam("TokenScript")); - } - - return result; - } - @Override public void resolve(SpellAbility sa) { final Card host = sa.getHostCard(); @@ -67,9 +51,8 @@ public class TokenEffect extends TokenEffectBase { } } - Card prototype = loadTokenPrototype(sa); - final int finalAmount = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("TokenAmount", "1"), sa); + MutableBoolean combatChanged = new MutableBoolean(false); boolean useZoneTable = true; CardZoneTable triggerList = sa.getChangeZoneTable(); @@ -82,10 +65,8 @@ public class TokenEffect extends TokenEffectBase { useZoneTable = true; } - MutableBoolean combatChanged = new MutableBoolean(false); - for (final Player owner : AbilityUtils.getDefinedPlayers(host, sa.getParamOrDefault("TokenOwner", "You"), sa)) { - makeTokens(prototype, owner, sa, finalAmount, true, false, triggerList, combatChanged); - } + makeTokenTable(AbilityUtils.getDefinedPlayers(host, sa.getParamOrDefault("TokenOwner", "You"), sa), + sa.getParam("TokenScript").split(","), finalAmount, false, triggerList, combatChanged, sa); if (!useZoneTable) { triggerList.triggerChangesZoneAll(game, sa); diff --git a/forge-game/src/main/java/forge/game/ability/effects/TokenEffectBase.java b/forge-game/src/main/java/forge/game/ability/effects/TokenEffectBase.java index adc4a6bb571..743b5d89533 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/TokenEffectBase.java +++ b/forge-game/src/main/java/forge/game/ability/effects/TokenEffectBase.java @@ -2,123 +2,212 @@ package forge.game.ability.effects; import java.util.Arrays; import java.util.List; +import java.util.Map; +import java.util.Set; import org.apache.commons.lang3.mutable.MutableBoolean; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Sets; +import com.google.common.collect.Table; import forge.GameCommand; import forge.game.Game; import forge.game.GameEntity; import forge.game.GameObject; +import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; import forge.game.card.CardCollection; +import forge.game.card.CardFactory; import forge.game.card.CardUtil; import forge.game.card.CardZoneTable; import forge.game.card.CounterType; +import forge.game.card.TokenCreateTable; import forge.game.card.token.TokenInfo; import forge.game.event.GameEventCardStatsChanged; import forge.game.player.Player; +import forge.game.replacement.ReplacementType; import forge.game.spellability.SpellAbility; +import forge.game.trigger.Trigger; import forge.game.zone.ZoneType; public abstract class TokenEffectBase extends SpellAbilityEffect { - protected List makeTokens(final Card prototype, final Player creator, final SpellAbility sa, int finalAmount, - boolean applyMultiplier, boolean clone, CardZoneTable triggerList, MutableBoolean combatChanged) { + protected TokenCreateTable createTokenTable(Iterable players, String[] tokenScripts, final int finalAmount, final SpellAbility sa) { + + TokenCreateTable tokenTable = new TokenCreateTable(); + for (final Player owner : players) { + for (String script : tokenScripts) { + final Card result = TokenInfo.getProtoType(script, sa, owner); + + if (result == null) { + throw new RuntimeException("don't find Token for TokenScript: " + script); + } + // set owner + result.setOwner(owner); + tokenTable.put(owner, result, finalAmount); + } + } + return tokenTable; + } + + protected TokenCreateTable makeTokenTableInternal(Player owner, String script, final int finalAmount, final SpellAbility sa) { + TokenCreateTable tokenTable = new TokenCreateTable(); + final Card result = TokenInfo.getProtoType(script, sa, owner, false); + + if (result == null) { + throw new RuntimeException("don't find Token for TokenScript: " + script); + } + // set owner + result.setOwner(owner); + tokenTable.put(owner, result, finalAmount); + + return tokenTable; + } + + protected TokenCreateTable makeTokenTable(Iterable players, String[] tokenScripts, final int finalAmount, final boolean clone, + CardZoneTable triggerList, MutableBoolean combatChanged, final SpellAbility sa) { + return makeTokenTable(createTokenTable(players, tokenScripts, finalAmount, sa), clone, triggerList, combatChanged, sa); + } + + protected TokenCreateTable makeTokenTable(TokenCreateTable tokenTable, final boolean clone, CardZoneTable triggerList, MutableBoolean combatChanged, final SpellAbility sa) { final Card host = sa.getHostCard(); final Game game = host.getGame(); - final long timestamp = game.getNextTimestamp(); + long timestamp = game.getNextTimestamp(); + + // support PlayerCollection for affected + Set toRemove = Sets.newHashSet(); + for (Player p : tokenTable.rowKeySet()) { + + final Map repParams = AbilityKey.mapFromAffected(p); + repParams.put(AbilityKey.Token, tokenTable); + repParams.put(AbilityKey.EffectOnly, true); // currently only effects can create tokens? + + switch (game.getReplacementHandler().run(ReplacementType.CreateToken, repParams)) { + case NotReplaced: + break; + case Updated: { + tokenTable = (TokenCreateTable) repParams.get(AbilityKey.Token); + break; + } + default: + toRemove.add(p); + } + } + tokenTable.rowKeySet().removeAll(toRemove); final List pumpKeywords = Lists.newArrayList(); if (sa.hasParam("PumpKeywords")) { pumpKeywords.addAll(Arrays.asList(sa.getParam("PumpKeywords").split(" & "))); } - List allTokens = Lists.newArrayList(); - for (Card tok : TokenInfo.makeTokensFromPrototype(prototype, creator, finalAmount, applyMultiplier)) { - if (sa.hasParam("TokenTapped")) { - tok.setTapped(true); - } - - if (!sa.hasParam("AttachAfter") && sa.hasParam("AttachedTo") && !attachTokenTo(tok, sa)) { - continue; - } - - if (sa.hasParam("WithCounters")) { - String[] parse = sa.getParam("WithCounters").split("_"); - tok.addEtbCounter(CounterType.getType(parse[0]), Integer.parseInt(parse[1]), creator); - } - - if (sa.hasParam("WithCountersType")) { - CounterType cType = CounterType.getType(sa.getParam("WithCountersType")); - int cAmount = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("WithCountersAmount", "1"), sa); - tok.addEtbCounter(cType, cAmount, creator); - } - - if (clone) { - tok.setCopiedPermanent(prototype); - } - - // Should this be catching the Card that's returned? - Card c = game.getAction().moveToPlay(tok, sa); - if (c == null || c.getZone() == null) { - // in case token can't enter the battlefield, it isn't created - triggerList.put(ZoneType.None, ZoneType.None, c); - continue; - } - triggerList.put(ZoneType.None, c.getZone().getZoneType(), c); - - creator.addTokensCreatedThisTurn(); - - if (clone) { - c.setCloneOrigin(host); - } - if (!pumpKeywords.isEmpty()) { - c.addChangedCardKeywords(pumpKeywords, Lists.newArrayList(), false, false, timestamp); - addPumpUntil(sa, c, timestamp); - } - - if (sa.hasParam("AtEOTTrig")) { - addSelfTrigger(sa, sa.getParam("AtEOTTrig"), c); - } - - if (addToCombat(c, tok.getController(), sa, "TokenAttacking", "TokenBlocking")) { - combatChanged.setTrue(); - } - - if (sa.hasParam("AttachAfter") && sa.hasParam("AttachedTo")) { - attachTokenTo(tok, sa); - } - - c.updateStateForView(); - - if (sa.hasParam("RememberTokens")) { - host.addRemembered(c); - } - if (sa.hasParam("ImprintTokens")) { - host.addImprintedCard(c); - } - if (sa.hasParam("RememberSource")) { - c.addRemembered(host); - } - if (sa.hasParam("TokenRemembered")) { - final String remembered = sa.getParam("TokenRemembered"); - for (final Object o : AbilityUtils.getDefinedObjects(host, remembered, sa)) { - c.addRemembered(o); + for (final Table.Cell c : tokenTable.cellSet()) { + Card prototype = c.getColumnKey(); + Player creator = c.getRowKey(); + Player controller = prototype.getController(); + int cellAmount = c.getValue(); + for (int i = 0; i < cellAmount; i++) { + Card tok = CardFactory.copyCard(prototype, true); + // Crafty Cutpurse would change under which control it does enter, + // but it shouldn't change who creates the token + tok.setOwner(creator); + if (creator != controller) { + tok.setController(controller, timestamp); } + tok.setTimestamp(timestamp); + tok.setToken(true); + + // do effect stuff with the token + if (sa.hasParam("TokenTapped")) { + tok.setTapped(true); + } + + if (!sa.hasParam("AttachAfter") && sa.hasParam("AttachedTo") && !attachTokenTo(tok, sa)) { + continue; + } + if (sa.hasParam("WithCounters")) { + String[] parse = sa.getParam("WithCounters").split("_"); + tok.addEtbCounter(CounterType.getType(parse[0]), Integer.parseInt(parse[1]), creator); + } + + if (sa.hasParam("WithCountersType")) { + CounterType cType = CounterType.getType(sa.getParam("WithCountersType")); + int cAmount = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("WithCountersAmount", "1"), sa); + tok.addEtbCounter(cType, cAmount, creator); + } + + if (sa.hasParam("AddTriggersFrom")) { + final List cards = AbilityUtils.getDefinedCards(host, sa.getParam("AddTriggersFrom"), sa); + for (final Card card : cards) { + for (final Trigger trig : card.getTriggers()) { + tok.addTrigger(trig.copy(tok, false)); + } + } + } + + if (clone) { + tok.setCopiedPermanent(prototype); + } + + // Should this be catching the Card that's returned? + Card moved = game.getAction().moveToPlay(tok, sa); + if (moved == null || moved.getZone() == null) { + // in case token can't enter the battlefield, it isn't created + triggerList.put(ZoneType.None, ZoneType.None, moved); + continue; + } + triggerList.put(ZoneType.None, moved.getZone().getZoneType(), moved); + + creator.addTokensCreatedThisTurn(); + + if (clone) { + moved.setCloneOrigin(host); + } + if (!pumpKeywords.isEmpty()) { + moved.addChangedCardKeywords(pumpKeywords, Lists.newArrayList(), false, false, timestamp); + addPumpUntil(sa, moved, timestamp); + } + + if (sa.hasParam("AtEOTTrig")) { + addSelfTrigger(sa, sa.getParam("AtEOTTrig"), moved); + } + + if (addToCombat(moved, tok.getController(), sa, "TokenAttacking", "TokenBlocking")) { + combatChanged.setTrue(); + } + + if (sa.hasParam("AttachAfter") && sa.hasParam("AttachedTo")) { + attachTokenTo(tok, sa); + } + + moved.updateStateForView(); + + if (sa.hasParam("RememberTokens")) { + host.addRemembered(moved); + } + if (sa.hasParam("ImprintTokens")) { + host.addImprintedCard(moved); + } + if (sa.hasParam("RememberSource")) { + moved.addRemembered(host); + } + if (sa.hasParam("TokenRemembered")) { + final String remembered = sa.getParam("TokenRemembered"); + for (final Object o : AbilityUtils.getDefinedObjects(host, remembered, sa)) { + moved.addRemembered(o); + } + } + allTokens.add(moved); } - allTokens.add(c); } if (sa.hasParam("AtEOT")) { registerDelayedTrigger(sa, sa.getParam("AtEOT"), allTokens); } - return allTokens; + return tokenTable; } private boolean attachTokenTo(Card tok, SpellAbility sa) { diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java index 37e0a05eb53..10afad4b802 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -206,6 +206,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars { // for Vanguard / Manapool / Emblems etc. private boolean isImmutable = false; + private boolean isEmblem = false; private int exertThisTurn = 0; private PlayerCollection exertedByPlayer = new PlayerCollection(); @@ -1629,7 +1630,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars { return exiledWith; } public final void setExiledWith(final Card e) { - exiledWith = e; + exiledWith = view.setCard(exiledWith, e, TrackableProperty.ExiledWith); } public final void cleanupExiledWith() { @@ -1738,6 +1739,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars { public void setCurrentRoom(String room) { currentRoom = room; view.updateCurrentRoom(this); + view.getCurrentState().updateAbilityText(this, getCurrentState()); } public boolean isInLastRoom() { for (final Trigger t : getTriggers()) { @@ -2154,6 +2156,9 @@ public class Card extends GameEntity implements Comparable, IHasSVars { } public String getAbilityText(final CardState state) { + final String linebreak = "\r\n\r\n"; + final String grayTag = ""; + final String endTag = ""; final CardTypeView type = state.getType(); final StringBuilder sb = new StringBuilder(); @@ -2199,9 +2204,9 @@ public class Card extends GameEntity implements Comparable, IHasSVars { // Get original description since text might be translated if (replacementEffect.hasParam("Description") && replacementEffect.getParam("Description").contains("enters the battlefield")) { - sb.append(text).append("\r\n"); + sb.append(text).append(linebreak); } else { - replacementEffects.append(text).append("\r\n"); + replacementEffects.append(text).append(linebreak); } } } @@ -2213,7 +2218,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars { Cost cost = first.getPayCosts(); if (cost != null && !cost.isOnlyManaCost()) { sb.append(cost.toString()); - sb.append("\r\n"); + sb.append(linebreak); } } } @@ -2233,15 +2238,22 @@ public class Card extends GameEntity implements Comparable, IHasSVars { } // Give spellText line breaks for easier reading - sb.append("\r\n"); sb.append(text.replaceAll("\\\\r\\\\n", "\r\n")); - sb.append("\r\n"); + sb.append(linebreak); // Triggered abilities for (final Trigger trig : state.getTriggers()) { if (!trig.isSecondary() && !trig.isClassAbility()) { + boolean disabled = false; + // Disable text of other rooms + if (type.isDungeon() && !trig.getOverridingAbility().getParam("RoomName").equals(getCurrentRoom())) { + disabled = true; + } String trigStr = trig.replaceAbilityText(trig.toString(), state); - sb.append(trigStr.replaceAll("\\\\r\\\\n", "\r\n")).append("\r\n"); + if (disabled) sb.append(grayTag); + sb.append(trigStr.replaceAll("\\\\r\\\\n", "\r\n")); + if (disabled) sb.append(endTag); + sb.append(linebreak); } } @@ -2253,7 +2265,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars { if (!stAb.isSecondary() && !stAb.isClassAbility()) { final String stAbD = stAb.toString(); if (!stAbD.equals("")) { - sb.append(stAbD).append("\r\n"); + sb.append(stAbD).append(linebreak); } } } @@ -2326,7 +2338,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars { desc = TextUtil.fastReplace(desc, "EFFECTSOURCE", host.getEffectSource().getName()); } sb.append(desc); - sb.append("\r\n"); + sb.append(linebreak); } } } @@ -2334,13 +2346,10 @@ public class Card extends GameEntity implements Comparable, IHasSVars { // Class Abilities if (isClassCard()) { - String linebreak = "\r\n\r\n"; sb.append(linebreak); // Currently the maximum levels of all Class cards are all 3 for (int level = 1; level <= 3; ++level) { boolean disabled = level > getClassLevel() && isInZone(ZoneType.Battlefield); - final String grayTag = ""; - final String endTag = ""; for (final Trigger trig : state.getTriggers()) { if (trig.isClassLevelNAbility(level) && !trig.isSecondary()) { if (disabled) sb.append(grayTag); @@ -4532,15 +4541,13 @@ public class Card extends GameEntity implements Comparable, IHasSVars { } public final boolean isPermanent() { - return !isImmutable && (isInZone(ZoneType.Battlefield) || getType().isPermanent()); + return !isImmutable() && (isInZone(ZoneType.Battlefield) || getType().isPermanent()); } public final boolean isSpell() { return (isInstant() || isSorcery() || (isAura() && !isInZone((ZoneType.Battlefield)))); } - public final boolean isEmblem() { return getType().isEmblem(); } - public final boolean isLand() { return getType().isLand(); } public final boolean isBasicLand() { return getType().isBasicLand(); } public final boolean isSnow() { return getType().isSnow(); } @@ -4799,11 +4806,6 @@ public class Card extends GameEntity implements Comparable, IHasSVars { // Takes one argument like Permanent.Blue+withFlying @Override public final boolean isValid(final String restriction, final Player sourceController, final Card source, CardTraitBase spellAbility) { - if (isImmutable() && source != null && !source.isRemembered(this) && - !(restriction.startsWith("Emblem") || restriction.startsWith("Effect"))) { // special case exclusion - return false; - } - // Inclusive restrictions are Card types final String[] incR = restriction.split("\\.", 2); @@ -4813,14 +4815,27 @@ public class Card extends GameEntity implements Comparable, IHasSVars { incR[0] = incR[0].substring(1); // consume negation sign } - if (incR[0].equals("Spell") && !isSpell()) { - return testFailed; - } - if (incR[0].equals("Permanent") && !isPermanent()) { - return testFailed; - } - if (!incR[0].equals("card") && !incR[0].equals("Card") && !incR[0].equals("Spell") - && !incR[0].equals("Permanent") && !getType().hasStringType(incR[0])) { + if (incR[0].equals("Spell")) { + if (!isSpell()) { + return testFailed; + } + } else if (incR[0].equals("Permanent")) { + if (!isPermanent()) { + return testFailed; + } + } else if (incR[0].equals("Effect")) { + if (!isImmutable()) { + return testFailed; + } + } else if (incR[0].equals("Emblem")) { + if (!isEmblem()) { + return testFailed; + } + } else if (incR[0].equals("card") || incR[0].equals("Card")) { + if (isImmutable()) { + return testFailed; + } + } else if (!getType().hasStringType(incR[0])) { return testFailed; // Check for wrong type } @@ -4828,15 +4843,8 @@ public class Card extends GameEntity implements Comparable, IHasSVars { final String excR = incR[1]; final String[] exRs = excR.split("\\+"); // Exclusive Restrictions are ... for (String exR : exRs) { - if (exR.startsWith("!")) { - exR = exR.substring(1); - if (hasProperty(exR, sourceController, source, spellAbility)) { - return testFailed; - } - } else { - if (!hasProperty(exR, sourceController, source, spellAbility)) { - return testFailed; - } + if (!hasProperty(exR, sourceController, source, spellAbility)) { + return testFailed; } } } @@ -4846,6 +4854,9 @@ public class Card extends GameEntity implements Comparable, IHasSVars { // Takes arguments like Blue or withFlying @Override public boolean hasProperty(final String property, final Player sourceController, final Card source, CardTraitBase spellAbility) { + if (property.startsWith("!")) { + return !CardProperty.cardHasProperty(this, property.substring(1), sourceController, source, spellAbility); + } return CardProperty.cardHasProperty(this, property, sourceController, source, spellAbility); } @@ -4854,6 +4865,15 @@ public class Card extends GameEntity implements Comparable, IHasSVars { } public final void setImmutable(final boolean isImmutable0) { isImmutable = isImmutable0; + view.updateImmutable(this); + } + + public final boolean isEmblem() { + return isEmblem; + } + public final void setEmblem(final boolean isEmblem0) { + isEmblem = isEmblem0; + view.updateEmblem(this); } /* @@ -5969,6 +5989,19 @@ public class Card extends GameEntity implements Comparable, IHasSVars { public void setCastFrom(final ZoneType castFrom0) { castFrom = castFrom0; } + public boolean wasCast() { + if (hasMergedCard()) { + boolean wasCast = false; + for (Card c : getMergedCards()) { + if (null != c.getCastFrom()) { + wasCast = true; + break; + } + } + return wasCast; + } + return getCastFrom() != null; + } public SpellAbility getCastSA() { return castSA; diff --git a/forge-game/src/main/java/forge/game/card/CardProperty.java b/forge-game/src/main/java/forge/game/card/CardProperty.java index 9ba17f8b321..7942ebd9284 100644 --- a/forge-game/src/main/java/forge/game/card/CardProperty.java +++ b/forge-game/src/main/java/forge/game/card/CardProperty.java @@ -350,7 +350,7 @@ public class CardProperty { return false; } } else if (property.equals("EffectSource")) { - if (!source.isEmblem() && !source.getType().hasSubtype("Effect")) { + if (!source.isImmutable()) { return false; } @@ -446,6 +446,9 @@ public class CardProperty { } } else if (property.startsWith("CanEnchant")) { final String restriction = property.substring(10); + if (restriction.equals("EquippedBy")) { + if (!source.getEquipping().canBeAttached(card)) return false; + } if (restriction.equals("Remembered")) { for (final Object rem : source.getRemembered()) { if (!(rem instanceof Card) || !((Card) rem).canBeAttached(card)) @@ -1658,6 +1661,10 @@ public class CardProperty { if (source.hasImprintedCard(card)) { return false; } + } else if (property.equals("IsGoaded")) { + if (!card.isGoaded()) { + return false; + } } else if (property.equals("NoAbilities")) { if (!card.hasNoAbilities()) { return false; @@ -1680,16 +1687,15 @@ public class CardProperty { return false; } } else if (property.equals("wasCast")) { - if (null == card.getCastFrom()) { + if (!card.wasCast()) { return false; } } else if (property.equals("wasNotCast")) { - if (null != card.getCastFrom()) { + if (card.wasCast()) { return false; } } else if (property.startsWith("wasCastFrom")) { - // How are we getting in here with a comma? - final String strZone = property.split(",")[0].substring(11); + final String strZone = property.substring(11); final ZoneType realZone = ZoneType.smartValueOf(strZone); if (realZone != card.getCastFrom()) { return false; diff --git a/forge-game/src/main/java/forge/game/card/CardUtil.java b/forge-game/src/main/java/forge/game/card/CardUtil.java index 8aa688e4678..b5c8cf23516 100644 --- a/forge-game/src/main/java/forge/game/card/CardUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardUtil.java @@ -120,7 +120,7 @@ public final class CardUtil { List res = Lists.newArrayList(); final Game game = src.getGame(); if (to != ZoneType.Stack) { - for (Player p : game.getPlayers()) { + for (Player p : game.getRegisteredPlayers()) { res.addAll(p.getZone(to).getCardsAddedThisTurn(from)); } } @@ -242,6 +242,7 @@ public final class CardUtil { newCopy.setToken(in.isToken()); newCopy.setCopiedSpell(in.isCopiedSpell()); newCopy.setImmutable(in.isImmutable()); + newCopy.setEmblem(in.isEmblem()); // lock in the current P/T newCopy.setBasePower(in.getCurrentPower()); @@ -530,6 +531,7 @@ public final class CardUtil { // however, due to the changes necessary for SA_Requirements this is much // different than the original public static List getValidCardsToTarget(TargetRestrictions tgt, SpellAbility ability) { + Card activatingCard = ability.getHostCard(); final Game game = ability.getActivatingPlayer().getGame(); final List zone = tgt.getZone(); @@ -539,7 +541,6 @@ public final class CardUtil { if (canTgtStack) { // Since getTargetableCards doesn't have additional checks if one of the Zones is stack // Remove the activating card from targeting itself if its on the Stack - Card activatingCard = ability.getHostCard(); if (activatingCard.isInZone(ZoneType.Stack)) { choices.remove(ability.getHostCard()); } @@ -561,7 +562,7 @@ public final class CardUtil { final List choicesCopy = Lists.newArrayList(choices); for (final Card c : choicesCopy) { - if (c.getCMC() > tgt.getMaxTotalCMC(c, ability) - totalCMCTargeted) { + if (c.getCMC() > tgt.getMaxTotalCMC(activatingCard, ability) - totalCMCTargeted) { choices.remove(c); } } @@ -576,7 +577,7 @@ public final class CardUtil { final List choicesCopy = Lists.newArrayList(choices); for (final Card c : choicesCopy) { - if (c.getNetPower() > tgt.getMaxTotalPower(c, ability) - totalPowerTargeted) { + if (c.getNetPower() > tgt.getMaxTotalPower(activatingCard, ability) - totalPowerTargeted) { choices.remove(c); } } diff --git a/forge-game/src/main/java/forge/game/card/CardView.java b/forge-game/src/main/java/forge/game/card/CardView.java index 4edc56438e9..02e54357926 100644 --- a/forge-game/src/main/java/forge/game/card/CardView.java +++ b/forge-game/src/main/java/forge/game/card/CardView.java @@ -233,6 +233,20 @@ public class CardView extends GameEntityView { set(TrackableProperty.Token, c.isToken()); } + public boolean isImmutable() { + return get(TrackableProperty.IsImmutable); + } + public void updateImmutable(Card c) { + set(TrackableProperty.IsImmutable, c.isImmutable()); + } + + public boolean isEmblem() { + return get(TrackableProperty.IsEmblem); + } + public void updateEmblem(Card c) { + set(TrackableProperty.IsEmblem, c.isEmblem()); + } + public boolean isTokenCard() { return get(TrackableProperty.TokenCard); } void updateTokenCard(Card c) { set(TrackableProperty.TokenCard, c.isTokenCard()); } @@ -585,6 +599,10 @@ public class CardView extends GameEntityView { return get(TrackableProperty.CloneOrigin); } + public CardView getExiledWith() { + return get(TrackableProperty.ExiledWith); + } + public FCollectionView getImprintedCards() { return get(TrackableProperty.ImprintedCards); } diff --git a/forge-game/src/main/java/forge/game/card/CounterEnumType.java b/forge-game/src/main/java/forge/game/card/CounterEnumType.java index 8821fe46376..2a606219a63 100644 --- a/forge-game/src/main/java/forge/game/card/CounterEnumType.java +++ b/forge-game/src/main/java/forge/game/card/CounterEnumType.java @@ -65,6 +65,8 @@ public enum CounterEnumType { COIN("COIN",255,215,0), + COMPONENT("COMPN", 224, 160, 48), + CORPSE("CRPSE", 230, 186, 209), CORRUPTION("CRPTN", 210, 121, 210), diff --git a/forge-game/src/main/java/forge/game/card/TokenCreateTable.java b/forge-game/src/main/java/forge/game/card/TokenCreateTable.java new file mode 100644 index 00000000000..a61586898f0 --- /dev/null +++ b/forge-game/src/main/java/forge/game/card/TokenCreateTable.java @@ -0,0 +1,95 @@ +package forge.game.card; + +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.ObjectUtils; + +import com.google.common.collect.ForwardingTable; +import com.google.common.collect.HashBasedTable; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import com.google.common.collect.Table; + +import forge.game.CardTraitBase; +import forge.game.GameObjectPredicates; +import forge.game.player.Player; + +public class TokenCreateTable extends ForwardingTable { + + Table dataMap = HashBasedTable.create(); + + public TokenCreateTable() { + } + + @Override + protected Table delegate() { + return dataMap; + } + + public int add(Player p, Card c, int i) { + int old = ObjectUtils.defaultIfNull(this.get(p, c), 0); + int newValue = old + i; + this.put(p, c, newValue); + return newValue; + } + + public int getFilterAmount(String validOwner, String validToken, final CardTraitBase ctb) { + final Card host = ctb.getHostCard(); + int result = 0; + List filteredCards = null; + List filteredPlayer = null; + + if (validOwner == null && validToken == null) { + for (Integer i : values()) { + result += i; + } + return result; + } + + if (validOwner != null) { + filteredPlayer = Lists.newArrayList(Iterables.filter(rowKeySet(), + GameObjectPredicates.restriction(validOwner.split(","), host.getController(), host, ctb))); + if (filteredPlayer.isEmpty()) { + return 0; + } + } + if (validToken != null) { + filteredCards = CardLists.getValidCardsAsList(columnKeySet(), validToken, host.getController(), host, ctb); + if (filteredCards.isEmpty()) { + return 0; + } + } + + if (filteredPlayer == null) { + for (Map.Entry> e : columnMap().entrySet()) { + for (Integer i : e.getValue().values()) { + result += i; + } + } + return result; + } + + if (filteredCards == null) { + for (Map.Entry> e : rowMap().entrySet()) { + for (Integer i : e.getValue().values()) { + result += i; + } + } + return result; + } + + for (Table.Cell c : this.cellSet()) { + if (!filteredPlayer.contains(c.getRowKey())) { + continue; + } + if (!filteredCards.contains(c.getColumnKey())) { + continue; + } + result += c.getValue(); + } + + + return result; + } +} diff --git a/forge-game/src/main/java/forge/game/card/token/TokenInfo.java b/forge-game/src/main/java/forge/game/card/token/TokenInfo.java index 300efe36677..82cd621cc94 100644 --- a/forge-game/src/main/java/forge/game/card/token/TokenInfo.java +++ b/forge-game/src/main/java/forge/game/card/token/TokenInfo.java @@ -15,15 +15,12 @@ import forge.StaticData; import forge.card.CardType; import forge.card.MagicColor; import forge.game.Game; -import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.card.Card; -import forge.game.card.CardFactory; import forge.game.card.CardFactoryUtil; import forge.game.card.CardUtil; import forge.game.keyword.KeywordInterface; import forge.game.player.Player; -import forge.game.replacement.ReplacementType; import forge.game.spellability.SpellAbility; import forge.item.PaperToken; @@ -140,59 +137,6 @@ public class TokenInfo { return sb.toString(); } - public static List makeToken(final Card prototype, final Player owner, - final boolean applyMultiplier, final int num) { - final List list = Lists.newArrayList(); - - final Game game = owner.getGame(); - int multiplier = num; - Player player = owner; - Card proto = prototype; - - final Map repParams = AbilityKey.mapFromAffected(player); - repParams.put(AbilityKey.Token, prototype); - repParams.put(AbilityKey.TokenNum, multiplier); - repParams.put(AbilityKey.EffectOnly, applyMultiplier); - - switch (game.getReplacementHandler().run(ReplacementType.CreateToken, repParams)) { - case NotReplaced: - break; - case Updated: { - multiplier = (int) repParams.get(AbilityKey.TokenNum); - player = (Player) repParams.get(AbilityKey.Affected); - proto = (Card) repParams.get(AbilityKey.Token); - break; - } - default: - multiplier = 0; - break; - } - if (multiplier <= 0) { - return list; - } - - long timestamp = game.getNextTimestamp(); - - for (int i = 0; i < multiplier; i++) { - // need to set owner or copyCard will fail with assign new ID - proto.setOwner(owner); - Card copy = CardFactory.copyCard(proto, true); - // need to assign player after token is copied - if (player != owner) { - copy.setController(player, timestamp); - } - copy.setTimestamp(timestamp); - copy.setToken(true); - list.add(copy); - } - - return list; - } - - static public List makeTokensFromPrototype(Card prototype, final Player owner, int amount, final boolean applyMultiplier) { - return makeToken(prototype, owner, applyMultiplier, amount); - } - public Card makeOneToken(final Player controller) { final Game game = controller.getGame(); final Card c = toCard(game); @@ -321,10 +265,10 @@ public class TokenInfo { result.getCurrentState().changeTextIntrinsic(colorMap, typeMap); } - static public Card getProtoType(final String script, final SpellAbility sa) { - return getProtoType(script, sa, true); + static public Card getProtoType(final String script, final SpellAbility sa, final Player owner) { + return getProtoType(script, sa, owner, true); } - static public Card getProtoType(final String script, final SpellAbility sa, boolean applyTextChange) { + static public Card getProtoType(final String script, final SpellAbility sa, final Player owner, boolean applyTextChange) { // script might be null, or sa might be null if (script == null || sa == null) { return null; @@ -338,7 +282,7 @@ public class TokenInfo { if (token == null) { return null; } - final Card result = Card.fromPaperCard(token, null, game); + final Card result = Card.fromPaperCard(token, owner, game); if (sa.hasParam("TokenPower")) { String str = sa.getParam("TokenPower"); diff --git a/forge-game/src/main/java/forge/game/combat/CombatUtil.java b/forge-game/src/main/java/forge/game/combat/CombatUtil.java index 1f21fe3606c..61ca06ad748 100644 --- a/forge-game/src/main/java/forge/game/combat/CombatUtil.java +++ b/forge-game/src/main/java/forge/game/combat/CombatUtil.java @@ -1080,7 +1080,7 @@ public class CombatUtil { return canAttackerBeBlockedWithAmount(attacker, amount, combat != null ? combat.getDefenderPlayerByAttacker(attacker) : null); } public static boolean canAttackerBeBlockedWithAmount(Card attacker, int amount, Player defender) { - if(amount == 0 ) + if (amount == 0) return false; // no block List restrictions = Lists.newArrayList(); @@ -1093,7 +1093,7 @@ public class CombatUtil { restrictions.add("LT2"); } } - for ( String res : restrictions ) { + for (String res : restrictions) { int operand = Integer.parseInt(res.substring(2)); String operator = res.substring(0,2); if (Expressions.compare(amount, operator, operand) ) @@ -1118,7 +1118,7 @@ public class CombatUtil { } } int minBlockers = 1; - for ( String res : restrictions ) { + for (String res : restrictions) { int operand = Integer.parseInt(res.substring(2)); String operator = res.substring(0, 2); if (operator.equals("LT") || operator.equals("GE")) { diff --git a/forge-game/src/main/java/forge/game/cost/Cost.java b/forge-game/src/main/java/forge/game/cost/Cost.java index 80a0021c52f..fae4d70df52 100644 --- a/forge-game/src/main/java/forge/game/cost/Cost.java +++ b/forge-game/src/main/java/forge/game/cost/Cost.java @@ -363,6 +363,13 @@ public class Cost implements Serializable { return new CostFlipCoin(splitStr[0]); } + if (parse.startsWith("RollDice<")) { + // RollDice + final String[] splitStr = abCostParse(parse, 4); + final String description = splitStr.length > 3 ? splitStr[3] : null; + return new CostRollDice(splitStr[0], splitStr[1], splitStr[2], description); + } + if (parse.startsWith("Discard<")) { // Discard final String[] splitStr = abCostParse(parse, 3); diff --git a/forge-game/src/main/java/forge/game/cost/CostPayment.java b/forge-game/src/main/java/forge/game/cost/CostPayment.java index 18cf06f876f..34f1683168e 100644 --- a/forge-game/src/main/java/forge/game/cost/CostPayment.java +++ b/forge-game/src/main/java/forge/game/cost/CostPayment.java @@ -211,7 +211,7 @@ public class CostPayment extends ManaConversionMatrix { return false; } // abilities care what was used to pay for them - if( part instanceof CostPartWithList ) { + if (part instanceof CostPartWithList) { ((CostPartWithList) part).resetLists(); } diff --git a/forge-game/src/main/java/forge/game/cost/CostRollDice.java b/forge-game/src/main/java/forge/game/cost/CostRollDice.java new file mode 100644 index 00000000000..67355994a34 --- /dev/null +++ b/forge-game/src/main/java/forge/game/cost/CostRollDice.java @@ -0,0 +1,68 @@ +package forge.game.cost; + +import forge.game.ability.effects.RollDiceEffect; +import forge.game.player.Player; +import forge.game.spellability.SpellAbility; + +/** + * This is for the "RollDice" Cost + */ +public class CostRollDice extends CostPart { + + /** + * Serializables need a version ID. + */ + private static final long serialVersionUID = 1L; + + private final String resultSVar; + + /** + * Instantiates a new cost RollDice. + * + * @param amount + * the amount + */ + public CostRollDice(final String amount, final String sides, final String resultSVar, final String description) { + super(amount, sides, description); + this.resultSVar = resultSVar; + } + + /* + * (non-Javadoc) + * + * @see + * forge.card.cost.CostPart#canPay(forge.card.spellability.SpellAbility, + * forge.Card, forge.Player, forge.card.cost.Cost) + */ + @Override + public final boolean canPay(final SpellAbility ability, final Player payer) { + return true; + } + + @Override + public final String toString() { + final StringBuilder sb = new StringBuilder(); + + sb.append("Roll ").append(getAmount()); + + if (this.getTypeDescription() == null) { + sb.append("d").append(getType()); + } else { + sb.append(" ").append(this.getTypeDescription()); + } + + return sb.toString(); + } + + @Override + public boolean payAsDecided(Player payer, PaymentDecision pd, SpellAbility sa) { + int sides = Integer.parseInt(getType()); + int result = RollDiceEffect.rollDiceForPlayer(sa, payer, pd.c, sides); + sa.setSVar(resultSVar, Integer.toString(result)); + return true; + } + + public T accept(ICostVisitor visitor) { + return visitor.visit(this); + } +} diff --git a/forge-game/src/main/java/forge/game/cost/ICostVisitor.java b/forge-game/src/main/java/forge/game/cost/ICostVisitor.java index 1b46b741e7e..89b69c2c2e1 100644 --- a/forge-game/src/main/java/forge/game/cost/ICostVisitor.java +++ b/forge-game/src/main/java/forge/game/cost/ICostVisitor.java @@ -12,6 +12,7 @@ public interface ICostVisitor { T visit(CostExiledMoveToGrave cost); T visit(CostExert cost); T visit(CostFlipCoin cost); + T visit(CostRollDice cost); T visit(CostMill cost); T visit(CostAddMana cost); T visit(CostPayLife cost); @@ -84,6 +85,11 @@ public interface ICostVisitor { return null; } + @Override + public T visit(CostRollDice cost) { + return null; + } + @Override public T visit(CostMill cost) { return null; @@ -173,7 +179,7 @@ public interface ICostVisitor { public T visit(CostUnattach cost) { return null; } - + @Override public T visit(CostTapType cost) { return null; diff --git a/forge-game/src/main/java/forge/game/player/Player.java b/forge-game/src/main/java/forge/game/player/Player.java index a109941e95f..0e219e8ee56 100644 --- a/forge-game/src/main/java/forge/game/player/Player.java +++ b/forge-game/src/main/java/forge/game/player/Player.java @@ -2217,6 +2217,9 @@ public class Player extends GameEntity implements Comparable { @Override public final boolean hasProperty(final String property, final Player sourceController, final Card source, CardTraitBase spellAbility) { + if (property.startsWith("!")) { + return !PlayerProperty.playerHasProperty(this, property.substring(1), sourceController, source, spellAbility); + } return PlayerProperty.playerHasProperty(this, property, sourceController, source, spellAbility); } @@ -3173,6 +3176,7 @@ public class Player extends GameEntity implements Comparable { if (monarchEffect == null) { monarchEffect = new Card(game.nextCardId(), null, game); monarchEffect.setOwner(this); + monarchEffect.setImmutable(true); if (set != null) { monarchEffect.setImageKey("t:monarch_" + set.toLowerCase()); monarchEffect.setSetCode(set); @@ -3180,7 +3184,6 @@ public class Player extends GameEntity implements Comparable { monarchEffect.setImageKey("t:monarch"); } monarchEffect.setName("The Monarch"); - monarchEffect.addType("Effect"); { final String drawTrig = "Mode$ Phase | Phase$ End of Turn | TriggerZones$ Command | " + @@ -3277,8 +3280,7 @@ public class Player extends GameEntity implements Comparable { blessingEffect.setOwner(this); blessingEffect.setImageKey("t:blessing"); blessingEffect.setName("City's Blessing"); - blessingEffect.addType("Effect"); - + blessingEffect.setImmutable(true); blessingEffect.updateStateForView(); @@ -3350,7 +3352,6 @@ public class Player extends GameEntity implements Comparable { keywordEffect.setOwner(this); keywordEffect.setName("Keyword Effects"); keywordEffect.setImageKey(ImageKeys.HIDDEN_CARD); - keywordEffect.addType("Effect"); keywordEffect.updateStateForView(); diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceToken.java b/forge-game/src/main/java/forge/game/replacement/ReplaceToken.java index 933696fbd2e..73486000a6c 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplaceToken.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplaceToken.java @@ -4,6 +4,7 @@ import java.util.Map; import forge.game.ability.AbilityKey; import forge.game.card.Card; +import forge.game.card.TokenCreateTable; import forge.game.spellability.SpellAbility; /** @@ -27,9 +28,11 @@ public class ReplaceToken extends ReplacementEffect { */ @Override public boolean canReplace(Map runParams) { + /* if (((int) runParams.get(AbilityKey.TokenNum)) <= 0) { return false; } + //*/ if (hasParam("EffectOnly")) { final Boolean effectOnly = (Boolean) runParams.get(AbilityKey.EffectOnly); @@ -41,10 +44,16 @@ public class ReplaceToken extends ReplacementEffect { if (!matchesValidParam("ValidPlayer", runParams.get(AbilityKey.Affected))) { return false; } + + /*/ if (!matchesValidParam("ValidToken", runParams.get(AbilityKey.Token))) { return false; } + //*/ + if (filterAmount((TokenCreateTable) runParams.get(AbilityKey.Token)) <= 0) { + return false; + } return true; } @@ -54,8 +63,13 @@ public class ReplaceToken extends ReplacementEffect { */ @Override public void setReplacingObjects(Map runParams, SpellAbility sa) { - sa.setReplacingObject(AbilityKey.TokenNum, runParams.get(AbilityKey.TokenNum)); + sa.setReplacingObject(AbilityKey.TokenNum, filterAmount((TokenCreateTable) runParams.get(AbilityKey.Token))); + sa.setReplacingObject(AbilityKey.Token, runParams.get(AbilityKey.Token)); sa.setReplacingObject(AbilityKey.Player, runParams.get(AbilityKey.Affected)); } + + public int filterAmount(final TokenCreateTable table) { + return table.getFilterAmount(getParamOrDefault("ValidPlayer", null), getParamOrDefault("ValidToken", null), this); + } } diff --git a/forge-game/src/main/java/forge/game/replacement/ReplacementEffect.java b/forge-game/src/main/java/forge/game/replacement/ReplacementEffect.java index 115b8b0caa7..69a605e76e4 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplacementEffect.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplacementEffect.java @@ -220,7 +220,7 @@ public abstract class ReplacementEffect extends TriggerReplacementBase { if (hasParam("Description") && !this.isSuppressed()) { String desc = AbilityUtils.applyDescriptionTextChangeEffects(getParam("Description"), this); String currentName; - if (this.isIntrinsic() && !this.getHostCard().isMutated() && cardState != null) { + if (this.isIntrinsic() && cardState != null && cardState.getCard() == getHostCard()) { currentName = cardState.getName(); } else { diff --git a/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java b/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java index dd397fb70ca..e00dc6a0872 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java @@ -28,6 +28,7 @@ import java.util.Set; import org.apache.commons.lang3.StringUtils; import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import com.google.common.collect.Sets; import forge.game.CardTraitBase; @@ -274,20 +275,45 @@ public class ReplacementHandler { chosenRE.setOtherChoices(null); return res; } + + // Log there + String message = chosenRE.getDescription(); + if (!StringUtils.isEmpty(message)) { + if (chosenRE.getHostCard() != null) { + message = TextUtil.fastReplace(message, "CARDNAME", chosenRE.getHostCard().getName()); + } + game.getGameLog().add(GameLogEntryType.EFFECT_REPLACED, message); + } + + // if its updated, try to call event again + if (res == ReplacementResult.Updated) { + Map params = Maps.newHashMap(runParams); + + if (params.containsKey(AbilityKey.EffectOnly)) { + params.put(AbilityKey.EffectOnly, true); + } + ReplacementResult result = run(event, params); + switch (result) { + case NotReplaced: + case Updated: { + for (Map.Entry e : params.entrySet()) { + runParams.put(e.getKey(), e.getValue()); + } + // effect was updated + runParams.put(AbilityKey.ReplacementResult, ReplacementResult.Updated); + break; + } + default: + // effect was replaced with something else + runParams.put(AbilityKey.ReplacementResult, result); + break; + } + } + chosenRE.setHasRun(false); hasRun.remove(chosenRE); chosenRE.setOtherChoices(null); - // Updated Replacements need to be logged elsewhere because its otherwise in the wrong order - if (res != ReplacementResult.Updated) { - String message = chosenRE.getDescription(); - if (!StringUtils.isEmpty(message)) - if (chosenRE.getHostCard() != null) { - message = TextUtil.fastReplace(message, "CARDNAME", chosenRE.getHostCard().getName()); - } - game.getGameLog().add(GameLogEntryType.EFFECT_REPLACED, message); - } - return res; } @@ -300,7 +326,6 @@ public class ReplacementHandler { */ private ReplacementResult executeReplacement(final Map runParams, final ReplacementEffect replacementEffect, final Player decider, final Game game) { - final Map mapParams = replacementEffect.getMapParams(); SpellAbility effectSA = null; @@ -311,10 +336,9 @@ public class ReplacementHandler { host = game.getCardState(host); } - if (replacementEffect.getOverridingAbility() == null && mapParams.containsKey("ReplaceWith")) { - final String effectSVar = mapParams.get("ReplaceWith"); + if (replacementEffect.getOverridingAbility() == null && replacementEffect.hasParam("ReplaceWith")) { // TODO: the source of replacement effect should be the source of the original effect - effectSA = AbilityFactory.getAbility(host, effectSVar, replacementEffect); + effectSA = AbilityFactory.getAbility(host, replacementEffect.getParam("ReplaceWith"), replacementEffect); //replacementEffect.setOverridingAbility(effectSA); //effectSA.setTrigger(true); } else if (replacementEffect.getOverridingAbility() != null) { @@ -342,10 +366,10 @@ public class ReplacementHandler { // Decider gets to choose whether or not to apply the replacement. if (replacementEffect.hasParam("Optional")) { Player optDecider = decider; - if (mapParams.containsKey("OptionalDecider") && (effectSA != null)) { + if (replacementEffect.hasParam("OptionalDecider") && (effectSA != null)) { effectSA.setActivatingPlayer(host.getController()); optDecider = AbilityUtils.getDefinedPlayers(host, - mapParams.get("OptionalDecider"), effectSA).get(0); + replacementEffect.getParam("OptionalDecider"), effectSA).get(0); } Card cardForUi = host.getCardForUi(); @@ -360,12 +384,12 @@ public class ReplacementHandler { } } - boolean isPrevent = mapParams.containsKey("Prevent") && mapParams.get("Prevent").equals("True"); - if (isPrevent || mapParams.containsKey("PreventionEffect")) { + boolean isPrevent = "True".equals(replacementEffect.getParam("Prevent")); + if (isPrevent || replacementEffect.hasParam("PreventionEffect")) { if (Boolean.TRUE.equals(runParams.get(AbilityKey.NoPreventDamage))) { // If can't prevent damage, result is not replaced // But still put "prevented" amount for buffered SA - if (mapParams.containsKey("AlwaysReplace")) { + if (replacementEffect.hasParam("AlwaysReplace")) { runParams.put(AbilityKey.PreventedAmount, runParams.get(AbilityKey.DamageAmount)); } else { runParams.put(AbilityKey.PreventedAmount, 0); @@ -377,10 +401,8 @@ public class ReplacementHandler { } } - if (mapParams.containsKey("Skip")) { - if (mapParams.get("Skip").equals("True")) { - return ReplacementResult.Skipped; // Event is skipped. - } + if ("True".equals(replacementEffect.getParam("Skip"))) { + return ReplacementResult.Skipped; // Event is skipped. } Player player = host.getController(); @@ -394,6 +416,11 @@ public class ReplacementHandler { // The SA if buffered, but replacement result should be set to Replaced runParams.put(AbilityKey.ReplacementResult, ReplacementResult.Replaced); } + + // these ones are special for updating + if (apiType == ApiType.ReplaceToken || apiType == ApiType.ReplaceEffect || apiType == ApiType.ReplaceMana) { + runParams.put(AbilityKey.ReplacementResult, ReplacementResult.Updated); + } } // if the spellability is a replace effect then its some new logic diff --git a/forge-game/src/main/java/forge/game/spellability/LandAbility.java b/forge-game/src/main/java/forge/game/spellability/LandAbility.java index 0e2bcdde8f4..5def083a3b1 100644 --- a/forge-game/src/main/java/forge/game/spellability/LandAbility.java +++ b/forge-game/src/main/java/forge/game/spellability/LandAbility.java @@ -95,8 +95,7 @@ public class LandAbility extends Ability { Card source = sta.getHostCard(); if (!source.equals(getHostCard())) { sb.append(" by "); - if ((source.isEmblem() || source.getType().hasSubtype("Effect")) - && source.getEffectSource() != null) { + if (source.isImmutable() && source.getEffectSource() != null) { sb.append(source.getEffectSource()); } else { sb.append(source); diff --git a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java index cb1ed0c530b..6cdbd1b324d 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java @@ -854,7 +854,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit if (node.getHostCard() != null) { String currentName; // if alternate state is viewed while card uses original - if (node.isIntrinsic() && !node.getHostCard().isMutated() && node.cardState != null) { + if (node.isIntrinsic() && node.cardState != null && node.cardState.getCard() == node.getHostCard()) { currentName = node.cardState.getName(); } else { diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbility.java b/forge-game/src/main/java/forge/game/staticability/StaticAbility.java index 151f21622e9..ba2f804cedd 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbility.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbility.java @@ -209,7 +209,7 @@ public class StaticAbility extends CardTraitBase implements IIdentifiable, Clone public final String toString() { if (hasParam("Description") && !this.isSuppressed()) { String currentName; - if (this.isIntrinsic() && !this.getHostCard().isMutated() && cardState != null) { + if (this.isIntrinsic() && cardState != null && cardState.getCard() == getHostCard()) { currentName = cardState.getName(); } else { diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantAttackBlock.java b/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantAttackBlock.java index 343a88240e6..b5970550a0a 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantAttackBlock.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantAttackBlock.java @@ -92,7 +92,7 @@ public class StaticAbilityCantAttackBlock { } /** - * returns true if attacker can be blocked by blocker + * returns true if attacker can't be blocked by blocker * @param stAb * @param attacker * @param blocker @@ -104,9 +104,10 @@ public class StaticAbilityCantAttackBlock { return false; } if (stAb.hasParam("ValidBlocker")) { + boolean stillblock = true; for (final String v : stAb.getParam("ValidBlocker").split(",")) { if (blocker.isValid(v, host.getController(), host, stAb)) { - boolean stillblock = false; + stillblock = false; //Dragon Hunter check if (v.contains("withoutReach") && blocker.hasStartOfKeyword("IfReach")) { for (KeywordInterface inst : blocker.getKeywords()) { @@ -120,13 +121,14 @@ public class StaticAbilityCantAttackBlock { } } } - if (stillblock) { - return false; + if (!stillblock) { + break; } - } else { - return false; } } + if (stillblock) { + return false; + } } // relative valid relative to each other if (!stAb.matchesValidParam("ValidAttackerRelative", attacker, blocker)) { diff --git a/forge-game/src/main/java/forge/game/trigger/Trigger.java b/forge-game/src/main/java/forge/game/trigger/Trigger.java index 685fc21b54e..c1d71f61551 100644 --- a/forge-game/src/main/java/forge/game/trigger/Trigger.java +++ b/forge-game/src/main/java/forge/game/trigger/Trigger.java @@ -132,7 +132,7 @@ public abstract class Trigger extends TriggerReplacementBase { StringBuilder sb = new StringBuilder(); String currentName; - if (this.isIntrinsic() && !this.getHostCard().isMutated() && cardState != null) { + if (this.isIntrinsic() && cardState != null && cardState.getCard() == getHostCard()) { currentName = cardState.getName(); } else { diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerHandler.java b/forge-game/src/main/java/forge/game/trigger/TriggerHandler.java index e749f21f367..0ee95950379 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerHandler.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerHandler.java @@ -31,8 +31,6 @@ import forge.game.IHasSVars; import forge.game.ability.AbilityFactory; import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; -import forge.game.ability.ApiType; -import forge.game.ability.effects.CharmEffect; import forge.game.card.*; import forge.game.player.Player; import forge.game.spellability.AbilitySub; @@ -346,8 +344,7 @@ public class TriggerHandler { } } - private boolean runNonStaticTriggersForPlayer(final Player player, final TriggerWaiting wt, final List delayedTriggersWorkingCopy ) { - + private boolean runNonStaticTriggersForPlayer(final Player player, final TriggerWaiting wt, final List delayedTriggersWorkingCopy) { final TriggerType mode = wt.getMode(); final Map runParams = wt.getParams(); final List triggers = wt.getTriggers() != null ? wt.getTriggers() : activeTriggers; @@ -503,7 +500,6 @@ public class TriggerHandler { // runs it if so. // Return true if the trigger went off, false otherwise. private void runSingleTriggerInternal(final Trigger regtrig, final Map runParams) { - // All tests passed, execute ability. if (regtrig instanceof TriggerTapsForMana) { final SpellAbility abMana = (SpellAbility) runParams.get(AbilityKey.AbilityMana); @@ -519,8 +515,7 @@ public class TriggerHandler { if (sa == null) { if (!regtrig.hasParam("Execute")) { sa = new SpellAbility.EmptySa(host); - } - else { + } else { String name = regtrig.getParam("Execute"); if (!host.getCurrentState().hasSVar(name)) { System.err.println("Warning: tried to run a trigger for card " + host + " referencing a SVar " + name + " not present on the current state " + host.getCurrentState() + ". Aborting trigger execution to prevent a crash."); @@ -577,12 +572,6 @@ public class TriggerHandler { } sa.setStackDescription(sa.toString()); - if (sa.getApi() == ApiType.Charm && !sa.isWrapper()) { - if (!CharmEffect.makeChoices(sa)) { - // 603.3c If no mode is chosen, the ability is removed from the stack. - return; - } - } Player decider = null; boolean isMandatory = false; @@ -592,8 +581,7 @@ public class TriggerHandler { } else if (sa instanceof AbilitySub || !sa.hasParam("Cost") || sa.getParam("Cost").equals("0")) { isMandatory = true; - } - else { // triggers with a cost can't be mandatory + } else { // triggers with a cost can't be mandatory sa.setOptionalTrigger(true); decider = sa.getActivatingPlayer(); } @@ -605,8 +593,7 @@ public class TriggerHandler { wrapperAbility.setLastStateBattlefield(game.getLastStateBattlefield()); if (regtrig.isStatic()) { wrapperAbility.getActivatingPlayer().getController().playTrigger(host, wrapperAbility, isMandatory); - } - else { + } else { game.getStack().addSimultaneousStackEntry(wrapperAbility); } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerRolledDie.java b/forge-game/src/main/java/forge/game/trigger/TriggerRolledDie.java index e495f62c5bc..1adc634d3a2 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerRolledDie.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerRolledDie.java @@ -44,6 +44,11 @@ public class TriggerRolledDie extends Trigger { } return false; } + if (hasParam("ValidSides")) { + final int validSides = Integer.parseInt(getParam("ValidSides")); + final int sides = (int) runParams.get(AbilityKey.Sides); + if (sides == validSides) return true; + } return true; } diff --git a/forge-game/src/main/java/forge/game/trigger/WrappedAbility.java b/forge-game/src/main/java/forge/game/trigger/WrappedAbility.java index f46bd78e19f..ea8cafc7107 100644 --- a/forge-game/src/main/java/forge/game/trigger/WrappedAbility.java +++ b/forge-game/src/main/java/forge/game/trigger/WrappedAbility.java @@ -232,8 +232,8 @@ public class WrappedAbility extends Ability { if (regtrig == null) return ""; final StringBuilder sb = new StringBuilder(regtrig.replaceAbilityText(regtrig.toString(true), this)); List allTargets = sa.getAllTargetChoices(); - if (!allTargets.isEmpty()) { - sb.append(" (Targeting "); + if (!allTargets.isEmpty() && !ApiType.Charm.equals(sa.getApi())) { + sb.append(" (Targeting: "); sb.append(allTargets); sb.append(")"); } @@ -549,7 +549,6 @@ public class WrappedAbility extends Ability { sa.setXManaCostPaid(n); } - public CardState getCardState() { return sa.getCardState(); } diff --git a/forge-game/src/main/java/forge/game/zone/MagicStack.java b/forge-game/src/main/java/forge/game/zone/MagicStack.java index 1150bf071ff..f6a83e3bb93 100644 --- a/forge-game/src/main/java/forge/game/zone/MagicStack.java +++ b/forge-game/src/main/java/forge/game/zone/MagicStack.java @@ -40,6 +40,7 @@ import forge.game.GameObject; import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.ApiType; +import forge.game.ability.effects.CharmEffect; import forge.game.card.Card; import forge.game.card.CardCollection; import forge.game.card.CardUtil; @@ -224,8 +225,7 @@ public class MagicStack /* extends MyObservable */ implements Iterable activePlayerSAs = Lists.newArrayList(); + final List failedSAs = Lists.newArrayList(); for (int i = 0; i < simultaneousStackEntryList.size(); i++) { SpellAbility sa = simultaneousStackEntryList.get(i); Player activator = sa.getActivatingPlayer(); + + if (sa.getApi() == ApiType.Charm) { + if (!CharmEffect.makeChoices(sa)) { + // 603.3c If no mode is chosen, the ability is removed from the stack. + failedSAs.add(sa); + continue; + } + } + if (activator == null) { if (sa.getHostCard().getController().equals(activePlayer)) { activePlayerSAs.add(sa); @@ -823,6 +831,7 @@ public class MagicStack /* extends MyObservable */ implements Iterablejar -Xms1024m -Xmx1536m - 1.6.42.001 + 1.6.43.001 keystore alias storepass @@ -19,7 +19,7 @@ forge forge - 1.6.43-SNAPSHOT + 1.6.44-SNAPSHOT forge-gui-android diff --git a/forge-gui-desktop/pom.xml b/forge-gui-desktop/pom.xml index 5259da1cf67..5a28257e038 100644 --- a/forge-gui-desktop/pom.xml +++ b/forge-gui-desktop/pom.xml @@ -4,7 +4,7 @@ forge forge - 1.6.43-SNAPSHOT + 1.6.44-SNAPSHOT forge-gui-desktop diff --git a/forge-gui-desktop/src/main/java/forge/control/FControl.java b/forge-gui-desktop/src/main/java/forge/control/FControl.java index 169bd7c873e..2dcb1ebe1bd 100644 --- a/forge-gui-desktop/src/main/java/forge/control/FControl.java +++ b/forge-gui-desktop/src/main/java/forge/control/FControl.java @@ -414,4 +414,3 @@ public enum FControl implements KeyEventDispatcher { return GamePlayerUtil.getGuiPlayer(); } } - diff --git a/forge-gui-desktop/src/main/java/forge/itemmanager/DeckManager.java b/forge-gui-desktop/src/main/java/forge/itemmanager/DeckManager.java index 4a583e9fd2b..e70f92087ac 100644 --- a/forge-gui-desktop/src/main/java/forge/itemmanager/DeckManager.java +++ b/forge-gui-desktop/src/main/java/forge/itemmanager/DeckManager.java @@ -194,7 +194,6 @@ public final class DeckManager extends ItemManager implements IHasGam } @Override - protected void buildAddFilterMenu(final JMenu menu) { GuiUtils.addSeparator(menu); //separate from current search item @@ -228,7 +227,6 @@ public final class DeckManager extends ItemManager implements IHasGam } menu.add(fmt); - GuiUtils.addMenuItem(menu, localizer.getMessage("lblFormats") + "...", null, new Runnable() { @Override public void run() { final DeckFormatFilter existingFilter = getFilter(DeckFormatFilter.class); diff --git a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/CDeckEditorUI.java b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/CDeckEditorUI.java index f3a4118793b..ab8ef94132e 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/CDeckEditorUI.java +++ b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/CDeckEditorUI.java @@ -340,4 +340,3 @@ public enum CDeckEditorUI implements ICDoc { @Override public void update() { } } - diff --git a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/DeckController.java b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/DeckController.java index 42a8da8c752..7ef2bc6e79e 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/DeckController.java +++ b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/DeckController.java @@ -288,8 +288,7 @@ public class DeckController { final String name = getModelName(); if (name.isEmpty()) { newModel(); - } - else { + } else { load(name); } } @@ -297,8 +296,7 @@ public class DeckController { public void load(final String path, final String name) { if (StringUtils.isBlank(path)) { currentFolder = rootFolder; - } - else { + } else { currentFolder = rootFolder.tryGetFolder(path); } modelPath = path; @@ -380,8 +378,7 @@ public class DeckController { public void refreshModel() { if (model == null) { newModel(); - } - else { + } else { setModel(model, modelInStorage); } } diff --git a/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java b/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java index 07a91b0f00c..e9b82968393 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java +++ b/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java @@ -501,7 +501,7 @@ public final class CMatchUI @Override public void hideZones(final PlayerView controller, final Iterable zonesToUpdate) { - if ( zonesToUpdate != null ) { + if (zonesToUpdate != null) { for (final PlayerZoneUpdate update : zonesToUpdate) { final PlayerView player = update.getPlayer(); for (final ZoneType zone : update.getZones()) { @@ -532,7 +532,6 @@ public final class CMatchUI for (final PlayerView p : manaPoolUpdate) { getFieldViewFor(p).updateManaPool(); } - } // Player's lives and poison counters @@ -575,15 +574,15 @@ public final class CMatchUI @Override public void setSelectables(final Iterable cards) { - super.setSelectables(cards); - // update zones on tabletop and floating zones - non-selectable cards may be rendered differently - FThreads.invokeInEdtNowOrLater(new Runnable() { + super.setSelectables(cards); + // update zones on tabletop and floating zones - non-selectable cards may be rendered differently + FThreads.invokeInEdtNowOrLater(new Runnable() { @Override public final void run() { for (final PlayerView p : getGameView().getPlayers()) { - if ( p.getCards(ZoneType.Battlefield) != null ) { + if (p.getCards(ZoneType.Battlefield) != null) { updateCards(p.getCards(ZoneType.Battlefield)); } - if ( p.getCards(ZoneType.Hand) != null ) { + if (p.getCards(ZoneType.Hand) != null) { updateCards(p.getCards(ZoneType.Hand)); } } @@ -594,15 +593,15 @@ public final class CMatchUI @Override public void clearSelectables() { - super.clearSelectables(); - // update zones on tabletop and floating zones - non-selectable cards may be rendered differently - FThreads.invokeInEdtNowOrLater(new Runnable() { + super.clearSelectables(); + // update zones on tabletop and floating zones - non-selectable cards may be rendered differently + FThreads.invokeInEdtNowOrLater(new Runnable() { @Override public final void run() { for (final PlayerView p : getGameView().getPlayers()) { - if ( p.getCards(ZoneType.Battlefield) != null ) { + if (p.getCards(ZoneType.Battlefield) != null) { updateCards(p.getCards(ZoneType.Battlefield)); } - if ( p.getCards(ZoneType.Hand) != null ) { + if (p.getCards(ZoneType.Hand) != null) { updateCards(p.getCards(ZoneType.Hand)); } } @@ -617,7 +616,7 @@ public final class CMatchUI FThreads.invokeInEdtNowOrLater(new Runnable() { @Override public final void run() { for (final PlayerView p : getGameView().getPlayers()) { - if ( p.getCards(ZoneType.Battlefield) != null ) { + if (p.getCards(ZoneType.Battlefield) != null) { updateCards(p.getCards(ZoneType.Battlefield)); } } @@ -787,7 +786,7 @@ public final class CMatchUI final PhaseType ph = getGameView().getPhase(); // this should never happen, but I've seen it periodically... so, need to get to the bottom of it PhaseLabel lbl = null; - if (ph != null ) { + if (ph != null) { lbl = p == null ? null : getFieldViewFor(p).getPhaseIndicator().getLabelFor(ph); } else { // not sure what debugging information would help here, log for now @@ -1295,79 +1294,78 @@ public final class CMatchUI boolean isAi = sa.getActivatingPlayer().isAI(); boolean isTrigger = sa.isTrigger(); int stackIndex = event.stackIndex; - if(stackIndex == nextNotifiableStackIndex) { - if(ForgeConstants.STACK_EFFECT_NOTIFICATION_ALWAYS.equals(stackNotificationPolicy) || (ForgeConstants.STACK_EFFECT_NOTIFICATION_AI_AND_TRIGGERED.equals(stackNotificationPolicy) && (isAi || isTrigger))) { - // We can go and show the modal - SpellAbilityStackInstance si = event.si; + if (stackIndex == nextNotifiableStackIndex) { + if (ForgeConstants.STACK_EFFECT_NOTIFICATION_ALWAYS.equals(stackNotificationPolicy) || (ForgeConstants.STACK_EFFECT_NOTIFICATION_AI_AND_TRIGGERED.equals(stackNotificationPolicy) && (isAi || isTrigger))) { + // We can go and show the modal + SpellAbilityStackInstance si = event.si; - MigLayout migLayout = new MigLayout("insets 15, left, gap 30, fill"); - JPanel mainPanel = new JPanel(migLayout); - final Dimension parentSize = JOptionPane.getRootFrame().getSize(); - Dimension maxSize = new Dimension(1400, parentSize.height - 100); - mainPanel.setMaximumSize(maxSize); - mainPanel.setOpaque(false); + MigLayout migLayout = new MigLayout("insets 15, left, gap 30, fill"); + JPanel mainPanel = new JPanel(migLayout); + final Dimension parentSize = JOptionPane.getRootFrame().getSize(); + Dimension maxSize = new Dimension(1400, parentSize.height - 100); + mainPanel.setMaximumSize(maxSize); + mainPanel.setOpaque(false); - // Big Image - addBigImageToStackModalPanel(mainPanel, si); + // Big Image + addBigImageToStackModalPanel(mainPanel, si); - // Text - addTextToStackModalPanel(mainPanel,sa,si); + // Text + addTextToStackModalPanel(mainPanel,sa,si); - // Small images - int numSmallImages = 0; + // Small images + int numSmallImages = 0; - // If current effect is a triggered/activated ability of an enchantment card, I want to show the enchanted card - GameEntityView enchantedEntityView = null; - Card hostCard = sa.getHostCard(); - if(hostCard.isEnchantment()) { - GameEntity enchantedEntity = hostCard.getEntityAttachedTo(); - if(enchantedEntity != null) { - enchantedEntityView = enchantedEntity.getView(); - numSmallImages++; - } else if ((sa.getRootAbility() != null) - && (sa.getRootAbility().getPaidList("Sacrificed") != null) - && !sa.getRootAbility().getPaidList("Sacrificed").isEmpty()) { - // If the player activated its ability by sacrificing the enchantment, the enchantment has not anything attached anymore and the ex-enchanted card has to be searched in other ways.. for example, the green enchantment "Carapace" - enchantedEntity = sa.getRootAbility().getPaidList("Sacrificed").get(0).getEnchantingCard(); - if(enchantedEntity != null) { + // If current effect is a triggered/activated ability of an enchantment card, I want to show the enchanted card + GameEntityView enchantedEntityView = null; + Card hostCard = sa.getHostCard(); + if (hostCard.isEnchantment()) { + GameEntity enchantedEntity = hostCard.getEntityAttachedTo(); + if (enchantedEntity != null) { enchantedEntityView = enchantedEntity.getView(); numSmallImages++; + } else if ((sa.getRootAbility() != null) + && (sa.getRootAbility().getPaidList("Sacrificed") != null) + && !sa.getRootAbility().getPaidList("Sacrificed").isEmpty()) { + // If the player activated its ability by sacrificing the enchantment, the enchantment has not anything attached anymore and the ex-enchanted card has to be searched in other ways.. for example, the green enchantment "Carapace" + enchantedEntity = sa.getRootAbility().getPaidList("Sacrificed").get(0).getEnchantingCard(); + if (enchantedEntity != null) { + enchantedEntityView = enchantedEntity.getView(); + numSmallImages++; + } } } - } - // If current effect is a triggered ability, I want to show the triggering card if present - SpellAbility sourceSA = (SpellAbility) si.getTriggeringObject(AbilityKey.SourceSA); - CardView sourceCardView = null; - if(sourceSA != null) { - sourceCardView = sourceSA.getHostCard().getView(); - numSmallImages++; - } + // If current effect is a triggered ability, I want to show the triggering card if present + SpellAbility sourceSA = (SpellAbility) si.getTriggeringObject(AbilityKey.SourceSA); + CardView sourceCardView = null; + if (sourceSA != null) { + sourceCardView = sourceSA.getHostCard().getView(); + numSmallImages++; + } - // I also want to show each type of targets (both cards and players) - List targets = getTargets(si,new ArrayList()); - numSmallImages = numSmallImages + targets.size(); + // I also want to show each type of targets (both cards and players) + List targets = getTargets(si,new ArrayList()); + numSmallImages = numSmallImages + targets.size(); - // Now I know how many small images - on to render them - if(enchantedEntityView != null) { - addSmallImageToStackModalPanel(enchantedEntityView,mainPanel,numSmallImages); - } - if(sourceCardView != null) { - addSmallImageToStackModalPanel(sourceCardView,mainPanel,numSmallImages); - } - for(GameEntityView gev : targets) { - addSmallImageToStackModalPanel(gev, mainPanel, numSmallImages); - } + // Now I know how many small images - on to render them + if (enchantedEntityView != null) { + addSmallImageToStackModalPanel(enchantedEntityView,mainPanel,numSmallImages); + } + if (sourceCardView != null) { + addSmallImageToStackModalPanel(sourceCardView,mainPanel,numSmallImages); + } + for (GameEntityView gev : targets) { + addSmallImageToStackModalPanel(gev, mainPanel, numSmallImages); + } - FOptionPane.showOptionDialog(null, "Forge", null, mainPanel, ImmutableList.of(Localizer.getInstance().getMessage("lblOK"))); - // here the user closed the modal - time to update the next notifiable stack index + FOptionPane.showOptionDialog(null, "Forge", null, mainPanel, ImmutableList.of(Localizer.getInstance().getMessage("lblOK"))); + // here the user closed the modal - time to update the next notifiable stack index } // In any case, I have to increase the counter nextNotifiableStackIndex++; } else { - // Not yet time to show the modal - schedule the method again, and try again later Runnable tryAgainThread = new Runnable() { @Override @@ -1381,21 +1379,21 @@ public final class CMatchUI } private List getTargets(SpellAbilityStackInstance si, List result){ - if(si == null) { + if (si == null) { return result; } FCollectionView targetCards = CardView.getCollection(si.getTargetChoices().getTargetCards()); - for(CardView currCardView: targetCards) { + for (CardView currCardView: targetCards) { result.add(currCardView); } - for(SpellAbility currSA : si.getTargetChoices().getTargetSpells()) { + for (SpellAbility currSA : si.getTargetChoices().getTargetSpells()) { CardView currCardView = currSA.getCardView(); result.add(currCardView); } FCollectionView targetPlayers = PlayerView.getCollection(si.getTargetChoices().getTargetPlayers()); - for(PlayerView currPlayerView : targetPlayers) { + for (PlayerView currPlayerView : targetPlayers) { result.add(currPlayerView); } @@ -1443,7 +1441,7 @@ public final class CMatchUI } private void addSmallImageToStackModalPanel(GameEntityView gameEntityView, JPanel mainPanel, int numTarget) { - if(gameEntityView instanceof CardView) { + if (gameEntityView instanceof CardView) { CardView cardView = (CardView) gameEntityView; int currRotation = getRotation(cardView); FImagePanel targetPanel = new FImagePanel(); @@ -1454,7 +1452,7 @@ public final class CMatchUI Dimension targetPanelDimension = new Dimension(imageWidth,imageHeight); targetPanel.setMinimumSize(targetPanelDimension); mainPanel.add(targetPanel, "cell 1 1, split " + numTarget+ ", aligny bottom"); - } else if(gameEntityView instanceof PlayerView) { + } else if (gameEntityView instanceof PlayerView) { PlayerView playerView = (PlayerView) gameEntityView; SkinImage playerAvatar = getPlayerAvatar(playerView, 0); final FLabel lblIcon = new FLabel.Builder().icon(playerAvatar).build(); @@ -1499,11 +1497,10 @@ public final class CMatchUI } private void createLandPopupPanel(Card land) { - String landPlayedNotificationPolicy = FModel.getPreferences().getPref(FPref.UI_LAND_PLAYED_NOTIFICATION_POLICY); Player cardController = land.getController(); boolean isAi = cardController.isAI(); - if(ForgeConstants.LAND_PLAYED_NOTIFICATION_ALWAYS.equals(landPlayedNotificationPolicy) + if (ForgeConstants.LAND_PLAYED_NOTIFICATION_ALWAYS.equals(landPlayedNotificationPolicy) || (ForgeConstants.LAND_PLAYED_NOTIFICATION_AI.equals(landPlayedNotificationPolicy) && (isAi)) || (ForgeConstants.LAND_PLAYED_NOTIFICATION_ALWAYS_FOR_NONBASIC_LANDS.equals(landPlayedNotificationPolicy) && !land.isBasicLand()) || (ForgeConstants.LAND_PLAYED_NOTIFICATION_AI_FOR_NONBASIC_LANDS.equals(landPlayedNotificationPolicy) && !land.isBasicLand()) && (isAi)) { diff --git a/forge-gui-desktop/src/main/java/forge/screens/match/GameLogPanel.java b/forge-gui-desktop/src/main/java/forge/screens/match/GameLogPanel.java index 59175b47e08..1b05c61ed9d 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/match/GameLogPanel.java +++ b/forge-gui-desktop/src/main/java/forge/screens/match/GameLogPanel.java @@ -121,7 +121,6 @@ public class GameLogPanel extends JPanel { } public void addLogEntry(final String text) { - final boolean useAlternateBackColor = (scrollablePanel.getComponents().length % 2 == 0); final JTextArea tar = createNewLogEntryJTextArea(text, useAlternateBackColor); @@ -138,7 +137,6 @@ public class GameLogPanel extends JPanel { } forceVerticalScrollbarToMax(); - } public void setTextFont(final SkinFont newFont) { diff --git a/forge-gui-desktop/src/main/java/forge/screens/match/VAssignCombatDamage.java b/forge-gui-desktop/src/main/java/forge/screens/match/VAssignCombatDamage.java index cde47c463b2..bd844c2b8fc 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/match/VAssignCombatDamage.java +++ b/forge-gui-desktop/src/main/java/forge/screens/match/VAssignCombatDamage.java @@ -107,8 +107,8 @@ public class VAssignCombatDamage { private boolean canAssignTo(final CardView card) { for (DamageTarget dt : defenders) { - if (dt.card == card ) return true; - if (getDamageToKill(dt.card) > dt.damage ) + if (dt.card == card) return true; + if (getDamageToKill(dt.card) > dt.damage) return false; } throw new RuntimeException("Asking to assign damage to object which is not present in defenders list"); @@ -145,7 +145,7 @@ public class VAssignCombatDamage { boolean isLMB = SwingUtilities.isLeftMouseButton(evt); boolean isRMB = SwingUtilities.isRightMouseButton(evt); - if ( isLMB || isRMB) + if (isLMB || isRMB) assignDamageTo(source, meta, isLMB); } }; @@ -305,7 +305,7 @@ public class VAssignCombatDamage { int leftToAssign = getRemainingDamage(); // Left click adds damage, right click substracts damage. // Hold Ctrl to assign lethal damage, Ctrl-click again on a creature with lethal damage to assign all available damage to it - if ( meta ) { + if (meta) { if (isAdding) { damageToAdd = leftToKill > 0 ? leftToKill : leftToAssign; } else { @@ -313,7 +313,7 @@ public class VAssignCombatDamage { } } - if ( damageToAdd > leftToAssign ) + if (damageToAdd > leftToAssign) damageToAdd = leftToAssign; // cannot assign first blocker less than lethal damage except when overriding order @@ -321,7 +321,7 @@ public class VAssignCombatDamage { if (!overrideCombatantOrder && isFirstBlocker && damageToAdd + damageItHad < lethalDamage ) return; - if ( 0 == damageToAdd || damageToAdd + damageItHad < 0) + if (0 == damageToAdd || damageToAdd + damageItHad < 0) return; addDamage(source, damageToAdd); @@ -335,12 +335,12 @@ public class VAssignCombatDamage { } // Clear out any Damage that shouldn't be assigned to other combatants boolean hasAliveEnemy = false; - for(DamageTarget dt : defenders) { + for (DamageTarget dt : defenders) { int lethal = getDamageToKill(dt.card); int damage = dt.damage; // If overriding combatant order, make sure everything has lethal if defender has damage assigned to it // Otherwise, follow normal combatant order - if ( hasAliveEnemy && (!overrideCombatantOrder || dt.card == null || dt.card == defender)) + if (hasAliveEnemy && (!overrideCombatantOrder || dt.card == null || dt.card == defender)) dt.damage = 0; else hasAliveEnemy |= damage < lethal; @@ -357,15 +357,15 @@ public class VAssignCombatDamage { int dmgLeft = totalDamageToAssign; DamageTarget dtLast = null; - for(DamageTarget dt : defenders) { // MUST NOT RUN WITH EMPTY collection + for (DamageTarget dt : defenders) { // MUST NOT RUN WITH EMPTY collection int lethal = getDamageToKill(dt.card); int damage = Math.min(lethal, dmgLeft); addDamage(dt.card, damage); dmgLeft -= damage; dtLast = dt; - if ( dmgLeft <= 0 || !toAllBlockers ) break; + if (dmgLeft <= 0 || !toAllBlockers) break; } - if ( dmgLeft < 0 ) + if (dmgLeft < 0) throw new RuntimeException("initialAssignDamage managed to assign more damage than it could"); if (toAllBlockers && dmgLeft > 0) { // flush the remaining damage into last defender if assigning all damage @@ -376,7 +376,7 @@ public class VAssignCombatDamage { /** Reset Assign Damage back to how it was at the beginning. */ private void resetAssignedDamage() { - for(DamageTarget dt : defenders) + for (DamageTarget dt : defenders) dt.damage = 0; } @@ -398,7 +398,7 @@ public class VAssignCombatDamage { */ private int getRemainingDamage() { int spent = 0; - for(DamageTarget dt : defenders) { + for (DamageTarget dt : defenders) { spent += dt.damage; } return totalDamageToAssign - spent; @@ -407,11 +407,10 @@ public class VAssignCombatDamage { /** Updates labels and other UI elements. * @param index index of the last assigned damage*/ private void updateLabels() { - int damageLeft = totalDamageToAssign; boolean allHaveLethal = true; - for ( DamageTarget dt : defenders ) + for (DamageTarget dt : defenders) { int dmg = dt.damage; damageLeft -= dmg; @@ -438,7 +437,7 @@ public class VAssignCombatDamage { // assigned dynamically, the cards die off and further damage to them can't // be modified. private void finish() { - if ( getRemainingDamage() > 0 ) + if (getRemainingDamage() > 0) return; dlg.dispose(); @@ -456,8 +455,7 @@ public class VAssignCombatDamage { final CardView pw = (CardView)defender; lethalDamage = Integer.valueOf(pw.getCurrentState().getLoyalty()); } - } - else { + } else { lethalDamage = Math.max(0, card.getLethalDamage()); if (card.getCurrentState().getType().isPlaneswalker()) { lethalDamage = Integer.valueOf(card.getCurrentState().getLoyalty()); diff --git a/forge-gui-desktop/src/main/java/forge/screens/match/controllers/CCombat.java b/forge-gui-desktop/src/main/java/forge/screens/match/controllers/CCombat.java index 1d43b157052..442de8b3021 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/match/controllers/CCombat.java +++ b/forge-gui-desktop/src/main/java/forge/screens/match/controllers/CCombat.java @@ -156,7 +156,7 @@ public class CCombat implements ICDoc { sb.append("( ").append(state.getPower()).append(" / ").append(state.getToughness()).append(" ) ... "); if (c.isFaceDown()) { sb.append("Morph"); - } else { + } else { sb.append(name); } sb.append(" [").append(state.getDisplayId()).append("] "); diff --git a/forge-gui-desktop/src/main/java/forge/screens/match/controllers/CDetail.java b/forge-gui-desktop/src/main/java/forge/screens/match/controllers/CDetail.java index 4da1455e39c..d49e216def6 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/match/controllers/CDetail.java +++ b/forge-gui-desktop/src/main/java/forge/screens/match/controllers/CDetail.java @@ -78,7 +78,6 @@ public class CDetail implements ICDoc { @Override public void initialize() { - } @Override diff --git a/forge-gui-desktop/src/main/java/forge/view/arcane/CardPanel.java b/forge-gui-desktop/src/main/java/forge/view/arcane/CardPanel.java index e1839f48113..b0a1267e3db 100644 --- a/forge-gui-desktop/src/main/java/forge/view/arcane/CardPanel.java +++ b/forge-gui-desktop/src/main/java/forge/view/arcane/CardPanel.java @@ -269,7 +269,7 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl g2d.rotate(getTappedAngle(), cardXOffset + edgeOffset, (cardYOffset + cardHeight) - edgeOffset); } - super.paint(g2d); + super.paint(g2d); } @Override @@ -284,12 +284,12 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl final int cornerSize = noBorderPref && !cardImgHasAlpha ? 0 : Math.max(4, Math.round(cardWidth * CardPanel.ROUNDED_CORNER_SIZE)); final int offset = isTapped() && (!noBorderPref || cardImgHasAlpha) ? 1 : 0; - // Magenta outline for when card is chosen + // Magenta outline for when card is chosen if (matchUI.isUsedToPay(getCard())) { g2d.setColor(Color.magenta); final int n2 = Math.max(1, Math.round(2 * cardWidth * CardPanel.SELECTED_BORDER_SIZE)); g2d.fillRoundRect(cardXOffset - n2, (cardYOffset - n2) + offset, cardWidth + (n2 * 2), cardHeight + (n2 * 2), cornerSize + n2, cornerSize + n2); - } + } // Green outline for hover if (isSelected) { @@ -311,24 +311,24 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl final CardStateView state = getCard().getCurrentState(); final CardEdition ed = FModel.getMagicDb().getEditions().get(state.getSetCode()); boolean colorIsSet = false; - if (state.getType().isEmblem() || state.getType().hasStringType("Effect")) { + if (getCard().isImmutable()) { // Effects are drawn with orange border g2d.setColor(Color.ORANGE); colorIsSet = true; } else if (ed != null && state.getFoilIndex() == 0) { // Non-foil cards from white-bordered sets are drawn with white border switch (ed.getBorderColor()) { - case WHITE: - g2d.setColor(Color.WHITE); - colorIsSet = true; - break; - case GOLD: - g2d.setColor(Color.ORANGE); - colorIsSet = true; - break; - case SILVER: - g2d.setColor(Color.GRAY); - colorIsSet = true; + case WHITE: + g2d.setColor(Color.WHITE); + colorIsSet = true; + break; + case GOLD: + g2d.setColor(Color.ORANGE); + colorIsSet = true; + break; + case SILVER: + g2d.setColor(Color.GRAY); + colorIsSet = true; } } if (colorIsSet) { @@ -337,11 +337,11 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl } } - if (matchUI.isSelectable(getCard())) { // White border for selectable cards to further highlight them - g2d.setColor(Color.WHITE); - final int ins = 1; - g2d.fillRoundRect(cardXOffset+ins, cardYOffset+ins, cardWidth-ins*2, cardHeight-ins*2, cornerSize-ins, cornerSize-ins); - } + if (matchUI.isSelectable(getCard())) { // White border for selectable cards to further highlight them + g2d.setColor(Color.WHITE); + final int ins = 1; + g2d.fillRoundRect(cardXOffset+ins, cardYOffset+ins, cardWidth-ins*2, cardHeight-ins*2, cornerSize-ins, cornerSize-ins); + } } private void drawManaCost(final Graphics g, final ManaCost cost, final int deltaY) { @@ -366,16 +366,16 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl cardWidth, cardHeight, Math.round(cardWidth * BLACK_BORDER_SIZE)); } - boolean nonselectable = matchUI.isSelecting() && !matchUI.isSelectable(getCard()); - // if selecting, darken non-selectable cards - if ( nonselectable ) { - boolean noBorderPref = !isPreferenceEnabled(FPref.UI_RENDER_BLACK_BORDERS); - boolean cardImgHasAlpha = imagePanel != null && imagePanel.getSrcImage() != null && imagePanel.getSrcImage().getColorModel().hasAlpha(); - final int cornerSize = noBorderPref && !cardImgHasAlpha ? 0 : Math.max(4, Math.round(cardWidth * CardPanel.ROUNDED_CORNER_SIZE)); - final int offset = isTapped() && (!noBorderPref || cardImgHasAlpha) ? 1 : 0; - g.setColor(new Color(0.0f,0.0f,0.0f,0.6f)); - g.fillRoundRect(cardXOffset, cardYOffset + offset, cardWidth, cardHeight, cornerSize, cornerSize); - } + boolean nonselectable = matchUI.isSelecting() && !matchUI.isSelectable(getCard()); + // if selecting, darken non-selectable cards + if (nonselectable) { + boolean noBorderPref = !isPreferenceEnabled(FPref.UI_RENDER_BLACK_BORDERS); + boolean cardImgHasAlpha = imagePanel != null && imagePanel.getSrcImage() != null && imagePanel.getSrcImage().getColorModel().hasAlpha(); + final int cornerSize = noBorderPref && !cardImgHasAlpha ? 0 : Math.max(4, Math.round(cardWidth * CardPanel.ROUNDED_CORNER_SIZE)); + final int offset = isTapped() && (!noBorderPref || cardImgHasAlpha) ? 1 : 0; + g.setColor(new Color(0.0f,0.0f,0.0f,0.6f)); + g.fillRoundRect(cardXOffset, cardYOffset + offset, cardWidth, cardHeight, cornerSize, cornerSize); + } } public static void drawFoilEffect(final Graphics g, final CardView card2, final int x, final int y, final int width, final int height, final int borderSize) { @@ -390,7 +390,6 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl @Override public final void doLayout() { - int borderSize = calculateBorderSize(); final Point imgPos = new Point(cardXOffset + borderSize, cardYOffset + borderSize); @@ -408,7 +407,6 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl } private int calculateBorderSize() { - // Determine whether to render border from properties boolean noBorderPref = !isPreferenceEnabled(FPref.UI_RENDER_BLACK_BORDERS); @@ -426,7 +424,6 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl } return 0; - } private Dimension calculateImageSize() { @@ -491,7 +488,6 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl } } - if (card.getCounters() != null && !card.getCounters().isEmpty()) { switch (CounterDisplayType.from(FModel.getPreferences().getPref(FPref.UI_CARD_COUNTER_DISPLAY_TYPE))) { @@ -734,8 +730,7 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl abiY += abiSpace; } } - } - else { + } else { String keywordKey = card.getCurrentState().getKeywordKey(); String abilityText = card.getCurrentState().getAbilityText(); if (((keywordKey.indexOf("Flashback") == -1) @@ -752,7 +747,6 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl } private void drawCounterTabs(final Graphics g) { - final Dimension imgSize = calculateImageSize(); final int titleY = Math.round(imgSize.height * (54f / 640)) - 15; @@ -767,7 +761,6 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl FontMetrics largeFontMetrics = g.getFontMetrics(largeCounterFont); if (CounterDisplayType.from(FModel.getPreferences().getPref(FPref.UI_CARD_COUNTER_DISPLAY_TYPE)) == CounterDisplayType.OLD_WHEN_SMALL) { - int maxCounters = 0; for (Integer numberOfCounters : card.getCounters().values()) { maxCounters = Math.max(maxCounters, numberOfCounters); @@ -780,9 +773,7 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl } - for (Map.Entry counterEntry : card.getCounters().entrySet()) { - final CounterType counter = counterEntry.getKey(); final int numberOfCounters = counterEntry.getValue(); final int counterBoxRealWidth = counterBoxBaseWidth + largeFontMetrics.stringWidth(String.valueOf(numberOfCounters)); @@ -827,7 +818,6 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl } private void drawCounterImage(final Graphics g) { - int counters = 0; for (final Integer i : card.getCounters().values()) { counters += i; @@ -848,7 +838,6 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl } private void drawMarkersTabs(final Graphics g, List markers) { - final Dimension imgSize = calculateImageSize(); final int titleY = Math.round(imgSize.height * (54f / 640)) - 15; @@ -862,7 +851,6 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl FontMetrics smallFontMetrics = g.getFontMetrics(smallCounterFont); for (String marker : markers) { - final int markerBoxRealWidth = markerBoxBaseWidth + smallFontMetrics.stringWidth(marker); final int markerYOffset; @@ -907,7 +895,6 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl * @param font The font to use to draw the text. */ private void drawVerticallyCenteredString(Graphics g, String text, Rectangle area, Font font, final FontMetrics fontMetrics) { - Font oldFont = g.getFont(); int x = area.x; @@ -1114,8 +1101,7 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl } private boolean showCardManaCostOverlay() { - return isShowingOverlays() && - isPreferenceEnabled(FPref.UI_OVERLAY_CARD_MANA_COST); + return isShowingOverlays() && isPreferenceEnabled(FPref.UI_OVERLAY_CARD_MANA_COST); } private boolean showCardIdOverlay() { diff --git a/forge-gui-desktop/src/main/java/forge/view/arcane/CardPanelContainer.java b/forge-gui-desktop/src/main/java/forge/view/arcane/CardPanelContainer.java index 2eb4cb07258..7a7b739fcbd 100644 --- a/forge-gui-desktop/src/main/java/forge/view/arcane/CardPanelContainer.java +++ b/forge-gui-desktop/src/main/java/forge/view/arcane/CardPanelContainer.java @@ -183,7 +183,7 @@ public abstract class CardPanelContainer extends SkinnedPanel { } protected boolean cardPanelDraggable(final CardPanel panel) { - return true; + return true; } private MouseMotionListener setupMotionMouseListener() { @@ -212,22 +212,22 @@ public abstract class CardPanelContainer extends SkinnedPanel { return; } - if (cardPanelDraggable(panel)) { // allow for non-draggable cards - if (intialMouseDragX == -1) { - intialMouseDragX = x; - intialMouseDragY = y; - return; - } - if ((Math.abs(x - intialMouseDragX) < CardPanelContainer.DRAG_SMUDGE) - && (Math.abs(y - intialMouseDragY) < CardPanelContainer.DRAG_SMUDGE)) { - return; - } - mouseDownPanel = null; - setMouseDragPanel(panel); - mouseDragOffsetX = panel.getX() - intialMouseDragX; - mouseDragOffsetY = panel.getY() - intialMouseDragY; - mouseDragStart(getMouseDragPanel(), evt); - } + if (cardPanelDraggable(panel)) { // allow for non-draggable cards + if (intialMouseDragX == -1) { + intialMouseDragX = x; + intialMouseDragY = y; + return; + } + if ((Math.abs(x - intialMouseDragX) < CardPanelContainer.DRAG_SMUDGE) + && (Math.abs(y - intialMouseDragY) < CardPanelContainer.DRAG_SMUDGE)) { + return; + } + mouseDownPanel = null; + setMouseDragPanel(panel); + mouseDragOffsetX = panel.getX() - intialMouseDragX; + mouseDragOffsetY = panel.getY() - intialMouseDragY; + mouseDragStart(getMouseDragPanel(), evt); + } } @Override @@ -291,7 +291,7 @@ public abstract class CardPanelContainer extends SkinnedPanel { } public final void removeCardPanel(final CardPanel fromPanel) { - removeCardPanel(fromPanel,true); + removeCardPanel(fromPanel,true); } public final void removeCardPanel(final CardPanel fromPanel, final boolean repaint) { @@ -307,11 +307,11 @@ public abstract class CardPanelContainer extends SkinnedPanel { fromPanel.dispose(); getCardPanels().remove(fromPanel); remove(fromPanel); - if ( repaint ) { - invalidate(); - repaint(); - doingLayout(); - } + if (repaint) { + invalidate(); + repaint(); + doingLayout(); + } } public final void setCardPanels(final List cardPanels) { @@ -331,14 +331,14 @@ public abstract class CardPanelContainer extends SkinnedPanel { for (final CardPanel cardPanel : cardPanels) { this.add(cardPanel); } - //pfps the validate just below will do the layout, so don't do it here this.doLayout(); + //pfps the validate just below will do the layout, so don't do it here this.doLayout(); this.invalidate(); this.getParent().validate(); this.repaint(); } public final void clear() { - clear(true); + clear(true); } public final void clear(final boolean repaint) { FThreads.assertExecutedByEdt(true); @@ -347,12 +347,12 @@ public abstract class CardPanelContainer extends SkinnedPanel { } getCardPanels().clear(); removeAll(); - if ( repaint ) { - setPreferredSize(new Dimension(0, 0)); - invalidate(); - getParent().validate(); - repaint(); - } + if (repaint) { + setPreferredSize(new Dimension(0, 0)); + invalidate(); + getParent().validate(); + repaint(); + } } public final FScrollPane getScrollPane() { diff --git a/forge-gui-desktop/src/main/java/forge/view/arcane/FloatingCardArea.java b/forge-gui-desktop/src/main/java/forge/view/arcane/FloatingCardArea.java index e5bc7b7973f..9eb6167d86e 100644 --- a/forge-gui-desktop/src/main/java/forge/view/arcane/FloatingCardArea.java +++ b/forge-gui-desktop/src/main/java/forge/view/arcane/FloatingCardArea.java @@ -57,10 +57,10 @@ public abstract class FloatingCardArea extends CardArea { protected abstract Iterable getCards(); protected FloatingCardArea(final CMatchUI matchUI) { - this(matchUI, new FScrollPane(false, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER)); + this(matchUI, new FScrollPane(false, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER)); } protected FloatingCardArea(final CMatchUI matchUI, final FScrollPane scrollPane) { - super(matchUI, scrollPane); + super(matchUI, scrollPane); } protected void showWindow() { @@ -127,7 +127,7 @@ public abstract class FloatingCardArea extends CardArea { } protected FDialog getWindow() { - return window; + return window; } protected void loadLocation() { diff --git a/forge-gui-desktop/src/main/java/forge/view/arcane/PlayArea.java b/forge-gui-desktop/src/main/java/forge/view/arcane/PlayArea.java index dbb6fb7ef22..0ea0c3d023d 100644 --- a/forge-gui-desktop/src/main/java/forge/view/arcane/PlayArea.java +++ b/forge-gui-desktop/src/main/java/forge/view/arcane/PlayArea.java @@ -624,8 +624,7 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen if (toDelete.size() == getCardPanels().size()) { clear(false); - } - else { + } else { for (final CardView card : toDelete) { removeCardPanel(getCardPanel(card.getId()),false); } @@ -649,9 +648,9 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen needLayoutRefresh = true; } } - if (needLayoutRefresh) { - doLayout(); - } + if (needLayoutRefresh) { + doLayout(); + } invalidate(); //pfps do the extra invalidate before any scrolling if (!newPanels.isEmpty()) { @@ -681,8 +680,7 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen if (card.isTapped()) { toPanel.setTapped(true); toPanel.setTappedAngle(forge.view.arcane.CardPanel.TAPPED_ANGLE); - } - else { + } else { toPanel.setTapped(false); toPanel.setTappedAngle(0); } @@ -705,8 +703,7 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen CardPanel attachedToPanel; if (card.getAttachedTo() != null) { attachedToPanel = getCardPanel(card.getAttachedTo().getId()); - } - else { + } else { attachedToPanel = null; } if (toPanel.getAttachedToPanel() != attachedToPanel) { diff --git a/forge-gui-desktop/src/main/java/forge/view/arcane/ScaledImagePanel.java b/forge-gui-desktop/src/main/java/forge/view/arcane/ScaledImagePanel.java index b51a6baa82b..12efb37652b 100644 --- a/forge-gui-desktop/src/main/java/forge/view/arcane/ScaledImagePanel.java +++ b/forge-gui-desktop/src/main/java/forge/view/arcane/ScaledImagePanel.java @@ -103,8 +103,6 @@ public class ScaledImagePanel extends JPanel { if (src == null) { return; } - - //System.out.println(sz + " -- " + src); //ResampleOp resizer = new ResampleOp(DimensionConstrain.createMaxDimension(this.getWidth(), this.getHeight(), !scaleLarger)); //resizer.setUnsharpenMask(UnsharpenMask.Soft); @@ -112,10 +110,7 @@ public class ScaledImagePanel extends JPanel { boolean needsScale = img.getWidth() < sz.width; float scaleFactor = ((float)img.getWidth()) / sz.width; - if ( needsScale && ( scaleFactor < 0.95 || scaleFactor > 1.05 ) ) { // This should very low-quality scaling to draw during animation - - //System.out.println("Painting: " + img.getWidth() + " -> " + sz.width ); - + if (needsScale && ( scaleFactor < 0.95 || scaleFactor > 1.05 )) { // This should very low-quality scaling to draw during animation float maxZoomX = ((float)sz.width) / img.getWidth(); float maxZoomY = ((float)sz.height) / img.getHeight(); float zoom = Math.min(maxZoomX, maxZoomY); diff --git a/forge-gui-ios/pom.xml b/forge-gui-ios/pom.xml index 43d9d3fd363..6235c60b5a9 100644 --- a/forge-gui-ios/pom.xml +++ b/forge-gui-ios/pom.xml @@ -6,13 +6,13 @@ jar -Xms128m -Xmx2048m - 1.6.42.001 + 1.6.43.001 forge forge - 1.6.43-SNAPSHOT + 1.6.44-SNAPSHOT forge-gui-ios diff --git a/forge-gui-mobile-dev/pom.xml b/forge-gui-mobile-dev/pom.xml index f5484c19eb2..d9991f8e241 100644 --- a/forge-gui-mobile-dev/pom.xml +++ b/forge-gui-mobile-dev/pom.xml @@ -4,7 +4,7 @@ forge forge - 1.6.43-SNAPSHOT + 1.6.44-SNAPSHOT forge-gui-mobile-dev diff --git a/forge-gui-mobile/pom.xml b/forge-gui-mobile/pom.xml index 9f5c2eb5666..0848b4a9cd9 100644 --- a/forge-gui-mobile/pom.xml +++ b/forge-gui-mobile/pom.xml @@ -4,7 +4,7 @@ forge forge - 1.6.43-SNAPSHOT + 1.6.44-SNAPSHOT forge-gui-mobile diff --git a/forge-gui-mobile/src/forge/Forge.java b/forge-gui-mobile/src/forge/Forge.java index 9fda1592f3c..199a1500eeb 100644 --- a/forge-gui-mobile/src/forge/Forge.java +++ b/forge-gui-mobile/src/forge/Forge.java @@ -46,7 +46,7 @@ import forge.util.Localizer; import forge.util.Utils; public class Forge implements ApplicationListener { - public static final String CURRENT_VERSION = "1.6.42.001"; + public static final String CURRENT_VERSION = "1.6.43.001"; private static final ApplicationListener app = new Forge(); private static Clipboard clipboard; diff --git a/forge-gui-mobile/src/forge/assets/TextRenderer.java b/forge-gui-mobile/src/forge/assets/TextRenderer.java index ce7fdfb3006..84b693e439f 100644 --- a/forge-gui-mobile/src/forge/assets/TextRenderer.java +++ b/forge-gui-mobile/src/forge/assets/TextRenderer.java @@ -291,6 +291,19 @@ public class TextRenderer { case "clr": colorOverride = value != null ? new Color(Integer.parseInt(value)) : null; break; + case "span": + // + if (value != null && value.contains("color:")) { + int startIdx = value.indexOf(':') + 1; + int endIdx = value.indexOf(';'); + String colorName = value.substring(startIdx, endIdx); + if (colorName.equals("gray")) { + colorOverride = Color.GRAY; + } + } else { + colorOverride = null; + } + break; default: validKeyword = false; break; diff --git a/forge-gui-mobile/src/forge/card/CardImageRenderer.java b/forge-gui-mobile/src/forge/card/CardImageRenderer.java index 8076308b240..70ca2dbe0d2 100644 --- a/forge-gui-mobile/src/forge/card/CardImageRenderer.java +++ b/forge-gui-mobile/src/forge/card/CardImageRenderer.java @@ -362,8 +362,7 @@ public class CardImageRenderer { drawDetails(g, card, gameView, altState, x, y, w, h); return; } - if(card.isToken() && card.getCurrentState().getType().hasSubtype("Effect") - && FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_DISABLE_IMAGES_EFFECT_CARDS)){ + if(card.isImmutable() && FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_DISABLE_IMAGES_EFFECT_CARDS)){ drawDetails(g, card, gameView, altState, x, y, w, h); return; } diff --git a/forge-gui/pom.xml b/forge-gui/pom.xml index d99e365cda3..95c93831022 100644 --- a/forge-gui/pom.xml +++ b/forge-gui/pom.xml @@ -4,7 +4,7 @@ forge forge - 1.6.43-SNAPSHOT + 1.6.44-SNAPSHOT forge-gui diff --git a/forge-gui/release-files/ANNOUNCEMENTS.txt b/forge-gui/release-files/ANNOUNCEMENTS.txt index 6b5edde03e7..10aafc0664e 100644 --- a/forge-gui/release-files/ANNOUNCEMENTS.txt +++ b/forge-gui/release-files/ANNOUNCEMENTS.txt @@ -1,10 +1,7 @@ #Add one announcement per line -Get in the discord if you aren't yet. -Card support has been extended up to "Modern Horizons 2", including the available previews from the upcoming "Dungeons and Dragons: Adventures in the Forgotten Realms". -Collector Number has been added to all cards in the Catalog. -[Desktop] Card Catalog now adds the Cards' Collector Number as a sortable column. -[Desktop] Improved support for Custom Editions: now custom editions appear with their own names within other official editions, and can be selected in Set filters. -Net decks have been expanded and there are now tons of new decks in constructed, commander, brawl, oathbreaker and tiny leaders. -Complete support to game mechanics for all cards in Modern format. -Various other improvements to game mechanics and AI: please check the Git log for details if interested. -Improvements to Italian translation. +Get in the discord if you aren't yet. https://discord.gg/3v9JCVr +Pre-release build for "Dungeons and Dragons: Adventures in the Forgotten Realms", please report any bugs! +Commander cards for the D&D set are still being worked on. +Custom cards can now be loaded from your user profile. Enable it your preferences. +Add support for Collector Boosters (not implemented everywhere yet) +*** Android 7 & 8 support is now deprecated. Support will be dropped in an upcoming release. *** diff --git a/forge-gui/res/blockdata/blocks.txt b/forge-gui/res/blockdata/blocks.txt index cdbf25e1ccc..c70bab58191 100644 --- a/forge-gui/res/blockdata/blocks.txt +++ b/forge-gui/res/blockdata/blocks.txt @@ -97,3 +97,4 @@ Kaldheim, 3/6/KHM, KHM Time Spiral Remastered, 3/6/KHM, TSR Strixhaven: School of Mages, 3/6/STX, STX Modern Horizons 2, 3/6/MH2, MH2 +Adventures in the Forgotten Realms, 3/6/AFR, AFR diff --git a/forge-gui/res/cardsfolder/upcoming/aberrant_mind_sorceror.txt b/forge-gui/res/cardsfolder/a/aberrant_mind_sorceror.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/aberrant_mind_sorceror.txt rename to forge-gui/res/cardsfolder/a/aberrant_mind_sorceror.txt diff --git a/forge-gui/res/cardsfolder/a/academy_manufactor.txt b/forge-gui/res/cardsfolder/a/academy_manufactor.txt index b3d78de8191..e7fc486ac49 100644 --- a/forge-gui/res/cardsfolder/a/academy_manufactor.txt +++ b/forge-gui/res/cardsfolder/a/academy_manufactor.txt @@ -2,11 +2,8 @@ Name:Academy Manufactor ManaCost:3 Types:Artifact Creature Assembly-Worker PT:1/3 -R:Event$ CreateToken | ActiveZones$ Battlefield | ValidPlayer$ You | ValidToken$ Clue,Food,Treasure | ReplaceWith$ DBToken | Description$ If you would create a Clue, Food, or Treasure token, instead create one of each. -SVar:DBToken:DB$ Token | TokenScript$ c_a_clue_draw | TokenAmount$ X | SubAbility$ DBToken2 -SVar:DBToken2:DB$ Token | TokenScript$ c_a_food_sac | TokenAmount$ X | SubAbility$ DBToken3 -SVar:DBToken3:DB$ Token | TokenScript$ c_a_treasure_sac | TokenAmount$ X -SVar:X:ReplaceCount$TokenNum +R:Event$ CreateToken | ActiveZones$ Battlefield | ValidPlayer$ You | ValidToken$ Clue,Food,Treasure | ReplaceWith$ TokenReplace | Description$ If you would create a Clue, Food, or Treasure token, instead create one of each. +SVar:TokenReplace:DB$ ReplaceToken | Type$ ReplaceToken | ValidCard$ Clue,Food,Treasure | TokenScript$ c_a_clue_draw,c_a_food_sac,c_a_treasure_sac DeckHas:Ability$Sacrifice & Ability$Token & Ability$LifeGain DeckHints:Ability$Investigate Oracle:If you would create a Clue, Food, or Treasure token, instead create one of each. diff --git a/forge-gui/res/cardsfolder/upcoming/acererak_the_archlich.txt b/forge-gui/res/cardsfolder/a/acererak_the_archlich.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/acererak_the_archlich.txt rename to forge-gui/res/cardsfolder/a/acererak_the_archlich.txt diff --git a/forge-gui/res/cardsfolder/a/adrix_and_nev_twincasters.txt b/forge-gui/res/cardsfolder/a/adrix_and_nev_twincasters.txt index e563b29233e..7a2c6832306 100644 --- a/forge-gui/res/cardsfolder/a/adrix_and_nev_twincasters.txt +++ b/forge-gui/res/cardsfolder/a/adrix_and_nev_twincasters.txt @@ -3,8 +3,7 @@ ManaCost:2 G U Types:Legendary Creature Merfolk Wizard PT:2/2 K:Ward:2 -R:Event$ CreateToken | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ DoubleToken | Description$ If one or more tokens would be created under your control, twice that many of those tokens are created instead. -SVar:DoubleToken:DB$ ReplaceEffect | VarName$ TokenNum | VarValue$ X -SVar:X:ReplaceCount$TokenNum/Twice +R:Event$ CreateToken | ActiveZones$ Battlefield | ValidToken$ Card.YouCtrl | ReplaceWith$ DoubleToken | Description$ If one or more tokens would be created under your control, twice that many of those tokens are created instead. +SVar:DoubleToken:DB$ ReplaceToken | Type$ Amount | ValidCard$ Card.YouCtrl DeckHints:Ability$Token Oracle:Ward {2} (Whenever this creature becomes the target of a spell or ability an opponent controls, counter it unless that player pays {2}.)\nIf one or more tokens would be created under your control, twice that many of those tokens are created instead. diff --git a/forge-gui/res/cardsfolder/upcoming/adult_gold_dragon.txt b/forge-gui/res/cardsfolder/a/adult_gold_dragon.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/adult_gold_dragon.txt rename to forge-gui/res/cardsfolder/a/adult_gold_dragon.txt diff --git a/forge-gui/res/cardsfolder/upcoming/air_cult_elemental.txt b/forge-gui/res/cardsfolder/a/air_cult_elemental.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/air_cult_elemental.txt rename to forge-gui/res/cardsfolder/a/air_cult_elemental.txt diff --git a/forge-gui/res/cardsfolder/a/anointed_procession.txt b/forge-gui/res/cardsfolder/a/anointed_procession.txt index bb7a722e807..fb9a3a42067 100644 --- a/forge-gui/res/cardsfolder/a/anointed_procession.txt +++ b/forge-gui/res/cardsfolder/a/anointed_procession.txt @@ -1,9 +1,7 @@ Name:Anointed Procession ManaCost:3 W Types:Enchantment -R:Event$ CreateToken | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ DoubleToken | EffectOnly$ True | Description$ If an effect would create one or more tokens under your control, it creates twice that many of those tokens instead. -SVar:DoubleToken:DB$ ReplaceEffect | VarName$ TokenNum | VarValue$ X -SVar:X:ReplaceCount$TokenNum/Twice +R:Event$ CreateToken | ActiveZones$ Battlefield | ValidToken$ Card.YouCtrl | ReplaceWith$ DoubleToken | EffectOnly$ True | Description$ If an effect would create one or more tokens under your control, it creates twice that many of those tokens instead. +SVar:DoubleToken:DB$ ReplaceToken | Type$ Amount | ValidCard$ Card.YouCtrl DeckNeeds:Ability$Token -SVar:Picture:http://www.wizards.com/global/images/magic/general/anointed_procession.jpg Oracle:If an effect would create one or more tokens under your control, it creates twice that many of those tokens instead. diff --git a/forge-gui/res/cardsfolder/upcoming/arborea_pegasus.txt b/forge-gui/res/cardsfolder/a/arborea_pegasus.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/arborea_pegasus.txt rename to forge-gui/res/cardsfolder/a/arborea_pegasus.txt diff --git a/forge-gui/res/cardsfolder/a/arcane_endeavor.txt b/forge-gui/res/cardsfolder/a/arcane_endeavor.txt new file mode 100644 index 00000000000..f3878fdaa65 --- /dev/null +++ b/forge-gui/res/cardsfolder/a/arcane_endeavor.txt @@ -0,0 +1,7 @@ +Name:Arcane Endeavor +ManaCost:5 U U +Types:Sorcery +A:SP$ RollDice | Amount$ 2 | Sides$ 8 | ChosenSVar$ X | OtherSVar$ Y | SubAbility$ DBDraw | StackDescription$ SpellDescription | SpellDescription$ Roll two d8 and choose one result. Draw cards equal to that result. Then you may cast an instant or sorcery spell with mana value less than or equal to the other result from your hand without paying its mana cost. +SVar:DBDraw:DB$ Draw | NumCards$ X | SubAbility$ DBPlay | StackDescription$ None +SVar:DBPlay:DB$ Play | Valid$ Instant,Sorcery | ValidSA$ Spell.cmcLEY | ValidZone$ Hand | WithoutManaCost$ True | Amount$ 1 | Controller$ You | Optional$ True +Oracle:Roll two d8 and choose one result. Draw cards equal to that result. Then you may cast an instant or sorcery spell with mana value less than or equal to the other result from your hand without paying its mana cost. diff --git a/forge-gui/res/cardsfolder/upcoming/arcane_investigator.txt b/forge-gui/res/cardsfolder/a/arcane_investigator.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/arcane_investigator.txt rename to forge-gui/res/cardsfolder/a/arcane_investigator.txt diff --git a/forge-gui/res/cardsfolder/upcoming/armory_veteran.txt b/forge-gui/res/cardsfolder/a/armory_veteran.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/armory_veteran.txt rename to forge-gui/res/cardsfolder/a/armory_veteran.txt diff --git a/forge-gui/res/cardsfolder/upcoming/asmodeus_the_archfiend.txt b/forge-gui/res/cardsfolder/a/asmodeus_the_archfiend.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/asmodeus_the_archfiend.txt rename to forge-gui/res/cardsfolder/a/asmodeus_the_archfiend.txt diff --git a/forge-gui/res/cardsfolder/b/bag_of_devouring.txt b/forge-gui/res/cardsfolder/b/bag_of_devouring.txt new file mode 100644 index 00000000000..ec9cfc602a7 --- /dev/null +++ b/forge-gui/res/cardsfolder/b/bag_of_devouring.txt @@ -0,0 +1,16 @@ +Name:Bag of Devouring +ManaCost:B +Types:Artifact +T:Mode$ Sacrificed | ValidCard$ Artifact.nontoken+Other,Creature.nontoken+Other | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigExile | TriggerDescription$ Whenever you sacrifice another nontoken artifact or creature, exile it. +SVar:TrigExile:DB$ ChangeZone | Defined$ TriggeredCard | Origin$ Graveyard | Destination$ Exile | RememberChanged$ True +A:AB$ Draw | Cost$ 2 T Sac<1/Artifact.Other;Creature.Other/another artifact or creature> | NumCards$ 1 | SpellDescription$ Draw a card. +A:AB$ RollDice | Cost$ 3 T Sac<1/CARDNAME> | Sides$ 10 | ResultSVar$ X | SubAbility$ DBChoose | SpellDescription$ Roll a d10. Return up to X cards from among cards exiled with CARDNAME to their owners' hands, where X is the result. +SVar:DBChoose:DB$ ChooseCard | ChoiceZone$ Exile | Choices$ Card.IsRemembered+ExiledWithSource | Amount$ X | MinAmount$ 0 | SubAbility$ DBReturn | StackDescription$ None +SVar:DBReturn:DB$ ChangeZone | Defined$ ChosenCard | Origin$ Exile | Destination$ Hand | StackDescription$ Return up to X cards from among cards exiled with CARDNAME to their owners' hands, where X is the result. +T:Mode$ ChangesZone | Origin$ Exile | Destination$ Any | Static$ True | ValidCard$ Card.IsRemembered+ExiledWithSource | Execute$ DBForget +SVar:DBForget:DB$ Pump | ForgetObjects$ TriggeredCard +T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | Static$ True | ValidCard$ Card.Self | Execute$ DBCleanup +SVar:DBCleanup:DB$Cleanup | ClearRemembered$ True +SVar:NonStackingEffect:True +DeckHas:Ability$Sacrifice +Oracle:Whenever you sacrifice another nontoken artifact or creature, exile it.\n{2}, {T}, Sacrifice another artifact or creature: Draw a card.\n{3}, {T}, Sacrifice Bag of Devouring: Roll a d10. Return up to X cards from among cards exiled with Bag of Devouring to their owners' hands, where X is the result. diff --git a/forge-gui/res/cardsfolder/b/bag_of_tricks.txt b/forge-gui/res/cardsfolder/b/bag_of_tricks.txt new file mode 100644 index 00000000000..896545c4949 --- /dev/null +++ b/forge-gui/res/cardsfolder/b/bag_of_tricks.txt @@ -0,0 +1,6 @@ +Name:Bag of Tricks +ManaCost:1 G +Types:Artifact +A:AB$ RollDice | Cost$ 4 G T | Defined$ You | Sides$ 8 | ResultSVar$ X | SubAbility$ DBReveal | StackDescription$ SpellDescription | SpellDescription$ Roll a d8. Reveal cards from the top of your library until you reveal a creature card with mana value equal to the result. Put that card onto the battlefield and the rest on the bottom of your library in a random order. +SVar:DBReveal:DB$ DigUntil | Defined$ You | Valid$ Creature.cmcEQX | FoundDestination$ Battlefield | RevealedDestination$ Library | RevealedLibraryPosition$ -1 | RevealRandomOrder$ True | StackDescription$ None +Oracle:{4}{G}, {T}: Roll a d8. Reveal cards from the top of your library until you reveal a creature card with mana value equal to the result. Put that card onto the battlefield and the rest on the bottom of your library in a random order. diff --git a/forge-gui/res/cardsfolder/upcoming/baleful_beholder.txt b/forge-gui/res/cardsfolder/b/baleful_beholder.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/baleful_beholder.txt rename to forge-gui/res/cardsfolder/b/baleful_beholder.txt diff --git a/forge-gui/res/cardsfolder/upcoming/bar_the_gate.txt b/forge-gui/res/cardsfolder/b/bar_the_gate.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/bar_the_gate.txt rename to forge-gui/res/cardsfolder/b/bar_the_gate.txt diff --git a/forge-gui/res/cardsfolder/upcoming/barbarian_class.txt b/forge-gui/res/cardsfolder/b/barbarian_class.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/barbarian_class.txt rename to forge-gui/res/cardsfolder/b/barbarian_class.txt diff --git a/forge-gui/res/cardsfolder/upcoming/bard_class.txt b/forge-gui/res/cardsfolder/b/bard_class.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/bard_class.txt rename to forge-gui/res/cardsfolder/b/bard_class.txt diff --git a/forge-gui/res/cardsfolder/upcoming/barrowin_of_clan_undurr.txt b/forge-gui/res/cardsfolder/b/barrowin_of_clan_undurr.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/barrowin_of_clan_undurr.txt rename to forge-gui/res/cardsfolder/b/barrowin_of_clan_undurr.txt diff --git a/forge-gui/res/cardsfolder/upcoming/battle_cry_goblin.txt b/forge-gui/res/cardsfolder/b/battle_cry_goblin.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/battle_cry_goblin.txt rename to forge-gui/res/cardsfolder/b/battle_cry_goblin.txt diff --git a/forge-gui/res/cardsfolder/upcoming/belt_of_giant_strength.txt b/forge-gui/res/cardsfolder/b/belt_of_giant_strength.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/belt_of_giant_strength.txt rename to forge-gui/res/cardsfolder/b/belt_of_giant_strength.txt diff --git a/forge-gui/res/cardsfolder/upcoming/berserkers_frenzy.txt b/forge-gui/res/cardsfolder/b/berserkers_frenzy.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/berserkers_frenzy.txt rename to forge-gui/res/cardsfolder/b/berserkers_frenzy.txt diff --git a/forge-gui/res/cardsfolder/b/bestial_menace.txt b/forge-gui/res/cardsfolder/b/bestial_menace.txt index 4359c202906..e40bda6ae26 100644 --- a/forge-gui/res/cardsfolder/b/bestial_menace.txt +++ b/forge-gui/res/cardsfolder/b/bestial_menace.txt @@ -1,9 +1,5 @@ Name:Bestial Menace ManaCost:3 G G Types:Sorcery -A:SP$ Token | Cost$ 3 G G | TokenAmount$ 1 | TokenScript$ g_1_1_snake | TokenOwner$ You | LegacyImage$ | SubAbility$ DBWolfToken | ChangeZoneTable$ True | SpellDescription$ Create a 1/1 green Snake creature token, -SVar:DBWolfToken:DB$ Token | TokenAmount$ 1 | TokenScript$ g_2_2_wolf | TokenOwner$ You | LegacyImage$ g 2 2 wolf wwk | SubAbility$ DBElephantToken | SpellDescription$ a 2/2 green Wolf creature token, -SVar:DBElephantToken:DB$ Token | TokenAmount$ 1 | TokenScript$ g_3_3_elephant | TokenOwner$ You | LegacyImage$ g 3 3 elephant wwk | SubAbility$ DBResolve | SpellDescription$ and a 3/3 green Elephant creature token. -SVar:DBResolve:DB$ ChangeZoneResolve -SVar:Picture:http://www.wizards.com/global/images/magic/general/bestial_menace.jpg +A:SP$ Token | Cost$ 3 G G | TokenAmount$ 1 | TokenScript$ g_1_1_snake,g_2_2_wolf,g_3_3_elephant | TokenOwner$ You | SpellDescription$ Create a 1/1 green Snake creature token, a 2/2 green Wolf creature token, and a 3/3 green Elephant creature token. Oracle:Create a 1/1 green Snake creature token, a 2/2 green Wolf creature token, and a 3/3 green Elephant creature token. diff --git a/forge-gui/res/cardsfolder/upcoming/black_dragon.txt b/forge-gui/res/cardsfolder/b/black_dragon.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/black_dragon.txt rename to forge-gui/res/cardsfolder/b/black_dragon.txt diff --git a/forge-gui/res/cardsfolder/upcoming/blink_dog.txt b/forge-gui/res/cardsfolder/b/blink_dog.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/blink_dog.txt rename to forge-gui/res/cardsfolder/b/blink_dog.txt diff --git a/forge-gui/res/cardsfolder/upcoming/blue_dragon.txt b/forge-gui/res/cardsfolder/b/blue_dragon.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/blue_dragon.txt rename to forge-gui/res/cardsfolder/b/blue_dragon.txt diff --git a/forge-gui/res/cardsfolder/upcoming/boots_of_speed.txt b/forge-gui/res/cardsfolder/b/boots_of_speed.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/boots_of_speed.txt rename to forge-gui/res/cardsfolder/b/boots_of_speed.txt diff --git a/forge-gui/res/cardsfolder/upcoming/brazen_dwarf.txt b/forge-gui/res/cardsfolder/b/brazen_dwarf.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/brazen_dwarf.txt rename to forge-gui/res/cardsfolder/b/brazen_dwarf.txt diff --git a/forge-gui/res/cardsfolder/upcoming/bruenor_battlehammer.txt b/forge-gui/res/cardsfolder/b/bruenor_battlehammer.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/bruenor_battlehammer.txt rename to forge-gui/res/cardsfolder/b/bruenor_battlehammer.txt diff --git a/forge-gui/res/cardsfolder/b/bucknards_everfull_purse.txt b/forge-gui/res/cardsfolder/b/bucknards_everfull_purse.txt new file mode 100644 index 00000000000..7645bd353fb --- /dev/null +++ b/forge-gui/res/cardsfolder/b/bucknards_everfull_purse.txt @@ -0,0 +1,8 @@ +Name:Bucknard's Everfull Purse +ManaCost:2 +Types:Artifact +A:AB$ RollDice | Cost$ 1 T | Defined$ You | Sides$ 4 | ResultSVar$ X | SubAbility$ DBTreasure | StackDescription$ SpellDescription | SpellDescription$ Roll a d4 and create a number of Treasure tokens equal to the result. The player to your right gains control of CARDNAME. +SVar:DBTreasure:DB$ Token | TokenAmount$ X | TokenScript$ c_a_treasure_sac | TokenOwner$ You | SubAbility$ DBPass +SVar:DBPass:DB$ GainControl | Defined$ Self | NewController$ NextPlayerToYourRight +DeckHas:Ability$Token +Oracle:{1}, {T}: Roll a d4 and create a number of Treasure tokens equal to the result. The player to your right gains control of Bucknard's Everfull Purse. diff --git a/forge-gui/res/cardsfolder/upcoming/bulette.txt b/forge-gui/res/cardsfolder/b/bulette.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/bulette.txt rename to forge-gui/res/cardsfolder/b/bulette.txt diff --git a/forge-gui/res/cardsfolder/upcoming/bulls_strength.txt b/forge-gui/res/cardsfolder/b/bulls_strength.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/bulls_strength.txt rename to forge-gui/res/cardsfolder/b/bulls_strength.txt diff --git a/forge-gui/res/cardsfolder/upcoming/burning_hands.txt b/forge-gui/res/cardsfolder/b/burning_hands.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/burning_hands.txt rename to forge-gui/res/cardsfolder/b/burning_hands.txt diff --git a/forge-gui/res/cardsfolder/c/calix_destinys_hand.txt b/forge-gui/res/cardsfolder/c/calix_destinys_hand.txt index 7b471151a2b..42dea136dd6 100755 --- a/forge-gui/res/cardsfolder/c/calix_destinys_hand.txt +++ b/forge-gui/res/cardsfolder/c/calix_destinys_hand.txt @@ -4,7 +4,7 @@ Types:Legendary Planeswalker Calix Loyalty:4 A:AB$ Dig | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | DigNum$ 4 | ChangeNum$ 1 | Optional$ True | ForceRevealToController$ True | ChangeValid$ Enchantment | RestRandomOrder$ True | SpellDescription$ Look at the top four cards of your library. You may reveal an enchantment card from among them and put that card into your hand. Put the rest on the bottom of your library in a random order. A:AB$ ChangeZone | Cost$ SubCounter<3/LOYALTY> | Planeswalker$ True | ValidTgts$ Creature.YouDontCtrl,Enchantment.YouDontCtrl | TgtPrompt$ Select target creature or enchantment you don't control | Origin$ Battlefield | Destination$ Exile | RememberChanged$ True | SubAbility$ DBEffect | SpellDescription$ Exile target creature or enchantment you don't control until target enchantment you control leaves the battlefield. -SVar:DBEffect:DB$ Effect | ValidTgts$ Enchantment.YouCtrl | TgtPrompt$ Select target enchantment you control | Triggers$ ComeBack | RememberObjects$ Remembered | ImprintCards$ Targeted | ConditionPresent$ Card.Self | Duration$ Permanent | ForgetOnMoved$ Exile | SubAbility$ Cleanup +SVar:DBEffect:DB$ Effect | ValidTgts$ Enchantment.YouCtrl | TgtPrompt$ Select target enchantment you control | Triggers$ ComeBack | RememberObjects$ Remembered | ImprintCards$ ThisTargetedCard | ConditionPresent$ Card.Self | Duration$ Permanent | ForgetOnMoved$ Exile | SubAbility$ Cleanup SVar:Cleanup:DB$ Cleanup | ClearRemembered$ True SVar:ComeBack:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.IsImprinted | Execute$ TrigReturn | TriggerZones$ Command | TriggerController$ TriggeredCardController | Static$ True | TriggerDescription$ Target is exiled until target enchantment you control leaves the battlefield. SVar:TrigReturn:DB$ ChangeZone | Origin$ Exile | Destination$ Battlefield | Defined$ Remembered | SubAbility$ ExileSelf diff --git a/forge-gui/res/cardsfolder/c/catti_brie_of_mithral_hall.txt b/forge-gui/res/cardsfolder/c/catti_brie_of_mithral_hall.txt new file mode 100644 index 00000000000..29e931a36b2 --- /dev/null +++ b/forge-gui/res/cardsfolder/c/catti_brie_of_mithral_hall.txt @@ -0,0 +1,16 @@ +Name:Catti-brie of Mithral Hall +ManaCost:G W +Types:Legendary Creature Human Archer +PT:2/2 +K:First Strike +K:Reach +T:Mode$ Attacks | ValidCard$ Creature.Self | Execute$ TrigPutCounter | TriggerDescription$ Whenever CARDNAME attacks, put a +1/+1 counter on it for each Equipment attached to it. +SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ Y +SVar:Y:Count$Valid Equipment.Attached +A:AB$ DealDamage | Cost$ 1 SubCounter | NumDmg$ X | ValidTgts$ Creature.attacking+OppCtrl,Creature.blocking+OppCtrl | TgtPrompt$ Select target attacking or blocking creature an opponent controls | SpellDescription$ It deals X damage to target attacking or blocking creature an opponent controls, where X is the number of counters removed this way. +SVar:X:SVar$CostCountersRemoved +SVar:HasAttackEffect:TRUE +SVar:EquipMe:Multiple +DeckNeeds:Type$Equipment +DeckHas:Ability$Counters +Oracle:First strike, reach\nWhenever Catti-brie of Mithral Hall attacks, put a +1/+1 counter on it for each Equipment attached to it.\n{1}, Remove all +1/+1 counters from Catti-brie: It deals X damage to target attacking or blocking creature an opponent controls, where X is the number of counters removed this way. diff --git a/forge-gui/res/cardsfolder/upcoming/cave_of_the_frost_dragon.txt b/forge-gui/res/cardsfolder/c/cave_of_the_frost_dragon.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/cave_of_the_frost_dragon.txt rename to forge-gui/res/cardsfolder/c/cave_of_the_frost_dragon.txt diff --git a/forge-gui/res/cardsfolder/upcoming/celestial_unicorn.txt b/forge-gui/res/cardsfolder/c/celestial_unicorn.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/celestial_unicorn.txt rename to forge-gui/res/cardsfolder/c/celestial_unicorn.txt diff --git a/forge-gui/res/cardsfolder/upcoming/chaos_channeler.txt b/forge-gui/res/cardsfolder/c/chaos_channeler.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/chaos_channeler.txt rename to forge-gui/res/cardsfolder/c/chaos_channeler.txt diff --git a/forge-gui/res/cardsfolder/upcoming/chaos_dragon.txt b/forge-gui/res/cardsfolder/c/chaos_dragon.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/chaos_dragon.txt rename to forge-gui/res/cardsfolder/c/chaos_dragon.txt diff --git a/forge-gui/res/cardsfolder/c/chatterfang_squirrel_general.txt b/forge-gui/res/cardsfolder/c/chatterfang_squirrel_general.txt index 0fb16a15cd3..c8aae6bab23 100644 --- a/forge-gui/res/cardsfolder/c/chatterfang_squirrel_general.txt +++ b/forge-gui/res/cardsfolder/c/chatterfang_squirrel_general.txt @@ -3,12 +3,10 @@ ManaCost:2 G Types:Legendary Creature Squirrel Warrior PT:3/3 K:Forestwalk -R:Event$ CreateToken | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ DBReplace | Description$ If one or more tokens would be created under your control, those tokens plus that many 1/1 green Squirrel creature tokens are created instead. -SVar:DBReplace:DB$ ReplaceEffect | VarName$ TokenNum | VarValue$ Y | SubAbility$ DBToken -SVar:DBToken:DB$ Token | TokenAmount$ Y | TokenScript$ g_1_1_squirrel +R:Event$ CreateToken | ActiveZones$ Battlefield | ValidToken$ Card.YouCtrl | ReplaceWith$ DBReplace | Description$ If one or more tokens would be created under your control, those tokens plus that many 1/1 green Squirrel creature tokens are created instead. +SVar:DBReplace:DB$ ReplaceToken | Type$ AddToken | ValidCard$ Card.YouCtrl | TokenScript$ g_1_1_squirrel A:AB$ Pump | Cost$ B Sac | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ +X | NumDef$ -X | SpellDescription$ Target creature gets +X/-X until end of turn. SVar:X:Count$xPaid -SVar:Y:ReplaceCount$TokenNum DeckHas:Ability$Token DeckHints:Type$Squirrel Oracle:Forestwalk (This creature can't be blocked as long as defending player controls a Forest.)\nIf one or more tokens would be created under your control, those tokens plus that many 1/1 green Squirrel creature tokens are created instead.\n{B}, Sacrifice X Squirrels: Target creature gets +X/-X until end of turn. diff --git a/forge-gui/res/cardsfolder/upcoming/check_for_traps.txt b/forge-gui/res/cardsfolder/c/check_for_traps.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/check_for_traps.txt rename to forge-gui/res/cardsfolder/c/check_for_traps.txt diff --git a/forge-gui/res/cardsfolder/c/chicken_a_la_king.txt b/forge-gui/res/cardsfolder/c/chicken_a_la_king.txt index 53720fdfc14..0d12c573d40 100644 --- a/forge-gui/res/cardsfolder/c/chicken_a_la_king.txt +++ b/forge-gui/res/cardsfolder/c/chicken_a_la_king.txt @@ -2,7 +2,7 @@ Name:Chicken à la King ManaCost:1 U U Types:Creature Bird Noble PT:2/2 -T:Mode$ RolledDie | TriggerZones$ Battlefield | Execute$ TrigCounters | ValidResult$ 6 | TriggerDescription$ Whenever a 6 is rolled on a six-sided die, put a +1/+1 counter on each Bird. +T:Mode$ RolledDie | TriggerZones$ Battlefield | Execute$ TrigCounters | ValidResult$ 6 | ValidSides$ 6 | TriggerDescription$ Whenever a 6 is rolled on a six-sided die, put a +1/+1 counter on each Bird. SVar:TrigCounters:DB$ PutCounterAll | ValidCards$ Bird | CounterType$ P1P1 | CounterNum$ 1 A:AB$ RollDice | Cost$ tapXType<1/Bird> | AILogic$ AtOppEOT | SpellDescription$ Roll a six-sided die. DeckHas:Ability$Counters diff --git a/forge-gui/res/cardsfolder/upcoming/choose_your_weapon.txt b/forge-gui/res/cardsfolder/c/choose_your_weapon.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/choose_your_weapon.txt rename to forge-gui/res/cardsfolder/c/choose_your_weapon.txt diff --git a/forge-gui/res/cardsfolder/upcoming/circle_of_dreams_druid.txt b/forge-gui/res/cardsfolder/c/circle_of_dreams_druid.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/circle_of_dreams_druid.txt rename to forge-gui/res/cardsfolder/c/circle_of_dreams_druid.txt diff --git a/forge-gui/res/cardsfolder/upcoming/circle_of_the_moon_druid.txt b/forge-gui/res/cardsfolder/c/circle_of_the_moon_druid.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/circle_of_the_moon_druid.txt rename to forge-gui/res/cardsfolder/c/circle_of_the_moon_druid.txt diff --git a/forge-gui/res/cardsfolder/upcoming/clattering_skeletons.txt b/forge-gui/res/cardsfolder/c/clattering_skeletons.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/clattering_skeletons.txt rename to forge-gui/res/cardsfolder/c/clattering_skeletons.txt diff --git a/forge-gui/res/cardsfolder/c/clay_golem.txt b/forge-gui/res/cardsfolder/c/clay_golem.txt new file mode 100644 index 00000000000..d6e35596511 --- /dev/null +++ b/forge-gui/res/cardsfolder/c/clay_golem.txt @@ -0,0 +1,9 @@ +Name:Clay Golem +ManaCost:4 +Types:Artifact Creature Golem +PT:4/4 +A:AB$ PutCounter | Cost$ 6 RollDice<1/8/X> | ConditionPresent$ Card.Self+IsNotMonstrous | Monstrosity$ True | CounterNum$ X | CounterType$ P1P1 | StackDescription$ SpellDescription | SpellDescription$ Monstrosity X, where X is the result. (If this creature isn't monstrous, put X +1/+1 counters on it and it becomes monstrous.) +T:Mode$ BecomeMonstrous | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigDestroy | TriggerDescription$ Berserk — When CARDNAME becomes monstrous, destroy target permanent. +SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Permanent +DeckHas:Ability$Counters +Oracle:{6}, Roll a d8: Monstrosity X, where X is the result. (If this creature isn't monstrous, put X +1/+1 counters on it and it becomes monstrous.)\nBerserk — When Clay Golem becomes monstrous, destroy target permanent. diff --git a/forge-gui/res/cardsfolder/upcoming/cleric_class.txt b/forge-gui/res/cardsfolder/c/cleric_class.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/cleric_class.txt rename to forge-gui/res/cardsfolder/c/cleric_class.txt diff --git a/forge-gui/res/cardsfolder/upcoming/clever_conjurer.txt b/forge-gui/res/cardsfolder/c/clever_conjurer.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/clever_conjurer.txt rename to forge-gui/res/cardsfolder/c/clever_conjurer.txt diff --git a/forge-gui/res/cardsfolder/upcoming/cloister_gargoyle.txt b/forge-gui/res/cardsfolder/c/cloister_gargoyle.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/cloister_gargoyle.txt rename to forge-gui/res/cardsfolder/c/cloister_gargoyle.txt diff --git a/forge-gui/res/cardsfolder/upcoming/compelled_duel.txt b/forge-gui/res/cardsfolder/c/compelled_duel.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/compelled_duel.txt rename to forge-gui/res/cardsfolder/c/compelled_duel.txt diff --git a/forge-gui/res/cardsfolder/c/component_pouch.txt b/forge-gui/res/cardsfolder/c/component_pouch.txt new file mode 100644 index 00000000000..be7ad6622b2 --- /dev/null +++ b/forge-gui/res/cardsfolder/c/component_pouch.txt @@ -0,0 +1,9 @@ +Name:Component Pouch +ManaCost:3 +Types:Artifact +A:AB$ Mana | Cost$ T SubCounter<1/COMPONENT> | Amount$ 2 | Produced$ Combo AnyDifferent | SpellDescription$ Add two mana of different colors. +A:AB$ RollDice | Cost$ T | Sides$ 20 | ResultSubAbilities$ 1-9:PutOne,10-20:PutTwo | SpellDescription$ Roll a d20. +SVar:PutOne:DB$ PutCounter | Defined$ Self | CounterType$ COMPONENT | CounterNum$ 1 | SpellDescription$ 1-9 VERT Put a component counter on CARDNAME. +SVar:PutTwo:DB$ PutCounter | Defined$ Self | CounterType$ COMPONENT | CounterNum$ 2 | SpellDescription$ 10-20 VERT Put two component counters on CARDNAME. +DeckHas:Ability$Counters +Oracle:{T}, Remove a component counter from Component Pouch: Add two mana of different colors.\n{T}: Roll a d20.\n1-9 | Put a component counter on Component Pouch.\n10-20 | Put two component counters on Component Pouch. diff --git a/forge-gui/res/cardsfolder/upcoming/contact_other_plane.txt b/forge-gui/res/cardsfolder/c/contact_other_plane.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/contact_other_plane.txt rename to forge-gui/res/cardsfolder/c/contact_other_plane.txt diff --git a/forge-gui/res/cardsfolder/c/crafty_cutpurse.txt b/forge-gui/res/cardsfolder/c/crafty_cutpurse.txt index 911a8e65410..fab73f2e1e7 100644 --- a/forge-gui/res/cardsfolder/c/crafty_cutpurse.txt +++ b/forge-gui/res/cardsfolder/c/crafty_cutpurse.txt @@ -5,7 +5,6 @@ PT:2/2 K:Flash T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigEffect | TriggerDescription$ When CARDNAME enters the battlefield, each token that would be created under an opponent's control this turn is created under your control instead. SVar:TrigEffect:DB$ Effect | Name$ Crafty Cutpurse Effect | ReplacementEffects$ OppCreatEnters | SpellDescription$ Each token that would be created under an opponent's control this turn is created under your control instead. -SVar:OppCreatEnters:Event$ CreateToken | ActiveZones$ Command | ValidPlayer$ Player.Opponent | ReplaceWith$ ETBYourCtrl | Layer$ Control | Description$ Each token that would be created under an opponent's control this turn is created under your control instead. -SVar:ETBYourCtrl:DB$ ReplaceEffect | VarName$ Affected | VarValue$ You | VarType$ Player -SVar:Picture:http://www.wizards.com/global/images/magic/general/crafty_cutpurse.jpg +SVar:OppCreatEnters:Event$ CreateToken | ActiveZones$ Command | ValidToken$ Card.OppCtrl | ReplaceWith$ ETBYourCtrl | Layer$ Control | Description$ Each token that would be created under an opponent's control this turn is created under your control instead. +SVar:ETBYourCtrl:DB$ ReplaceToken | Type$ ReplaceController | ValidCard$ Card.OppCtrl | NewController$ You Oracle:Flash\nWhen Crafty Cutpurse enters the battlefield, each token that would be created under an opponent's control this turn is created under your control instead. diff --git a/forge-gui/res/cardsfolder/upcoming/critical_hit.txt b/forge-gui/res/cardsfolder/c/critical_hit.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/critical_hit.txt rename to forge-gui/res/cardsfolder/c/critical_hit.txt diff --git a/forge-gui/res/cardsfolder/upcoming/dancing_sword.txt b/forge-gui/res/cardsfolder/d/dancing_sword.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/dancing_sword.txt rename to forge-gui/res/cardsfolder/d/dancing_sword.txt diff --git a/forge-gui/res/cardsfolder/upcoming/dawnbringer_cleric.txt b/forge-gui/res/cardsfolder/d/dawnbringer_cleric.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/dawnbringer_cleric.txt rename to forge-gui/res/cardsfolder/d/dawnbringer_cleric.txt diff --git a/forge-gui/res/cardsfolder/upcoming/deadly_dispute.txt b/forge-gui/res/cardsfolder/d/deadly_dispute.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/deadly_dispute.txt rename to forge-gui/res/cardsfolder/d/deadly_dispute.txt diff --git a/forge-gui/res/cardsfolder/upcoming/death_priest_of_myrkul.txt b/forge-gui/res/cardsfolder/d/death_priest_of_myrkul.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/death_priest_of_myrkul.txt rename to forge-gui/res/cardsfolder/d/death_priest_of_myrkul.txt diff --git a/forge-gui/res/cardsfolder/upcoming/delina_wild_mage.txt b/forge-gui/res/cardsfolder/d/delina_wild_mage.txt similarity index 60% rename from forge-gui/res/cardsfolder/upcoming/delina_wild_mage.txt rename to forge-gui/res/cardsfolder/d/delina_wild_mage.txt index f4c665d2972..f77f4596778 100644 --- a/forge-gui/res/cardsfolder/upcoming/delina_wild_mage.txt +++ b/forge-gui/res/cardsfolder/d/delina_wild_mage.txt @@ -5,9 +5,11 @@ PT:3/2 T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ DBLoop | TriggerDescription$ Whenever CARDNAME attacks, choose target creature you control, then ABILITY SVar:DBLoop:DB$ Repeat | ValidTgts$ Creature.YouCtrl | RepeatCheckSVar$ RepeatCheck | RepeatSVarCompare$ GT0 | RepeatSubAbility$ DBRollDice | RepeatOptional$ True SVar:DBRollDice:DB$ RollDice | Sides$ 20 | ResultSubAbilities$ 1-14:DBCopy,15-20:DBCopyRepeat | SpellDescription$ roll a d20. -SVar:DBCopy:DB$ CopyPermanent | Defined$ Targeted | TokenTapped$ True | TokenAttacking$ True | NonLegendary$ True | AtEOT$ ExileCombat | SubAbility$ DBNotRepeat | SpellDescription$ 1-14 VERT Create a tapped and attacking token that's a copy of that creature, except it's not legendary and it has "Exile this creature at end of combat. +SVar:DBCopy:DB$ CopyPermanent | Defined$ Targeted | TokenTapped$ True | TokenAttacking$ True | NonLegendary$ True | AddSVars$ DelinaTrigExile | AddTriggers$ TrigPhase | SubAbility$ DBNotRepeat | SpellDescription$ 1-14 VERT Create a tapped and attacking token that's a copy of that creature, except it's not legendary and it has "Exile this creature at end of combat. SVar:DBNotRepeat:DB$ StoreSVar | SVar$ RepeatCheck | Type$ Number | Expression$ 0 -SVar:DBCopyRepeat:DB$ CopyPermanent | Defined$ Targeted | TokenTapped$ True | TokenAttacking$ True | NonLegendary$ True | AtEOT$ ExileCombat | SubAbility$ DBRepeat | SpellDescription$ 15-20 VERT Create one of those tokens. You may roll again. +SVar:DBCopyRepeat:DB$ CopyPermanent | Defined$ Targeted | TokenTapped$ True | TokenAttacking$ True | NonLegendary$ True | AddSVars$ DelinaTrigExile | AddTriggers$ TrigPhase | SubAbility$ DBRepeat | SpellDescription$ 15-20 VERT Create one of those tokens. You may roll again. +SVar:TrigPhase:Mode$ Phase | Phase$ EndCombat | TriggerZones$ Battlefield | Execute$ DelinaTrigExile | TriggerDescription$ Exile this creature at end of combat. +SVar:DelinaTrigExile:DB$ ChangeZone | Defined$ Self | Origin$ Battlefield | Destination$ Exile SVar:DBRepeat:DB$ StoreSVar | SVar$ RepeatCheck | Type$ Number | Expression$ 1 SVar:RepeatCheck:Number$1 SVar:HasAttackEffect:TRUE diff --git a/forge-gui/res/cardsfolder/upcoming/delvers_torch.txt b/forge-gui/res/cardsfolder/d/delvers_torch.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/delvers_torch.txt rename to forge-gui/res/cardsfolder/d/delvers_torch.txt diff --git a/forge-gui/res/cardsfolder/upcoming/demilich.txt b/forge-gui/res/cardsfolder/d/demilich.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/demilich.txt rename to forge-gui/res/cardsfolder/d/demilich.txt diff --git a/forge-gui/res/cardsfolder/upcoming/demogorgons_clutches.txt b/forge-gui/res/cardsfolder/d/demogorgons_clutches.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/demogorgons_clutches.txt rename to forge-gui/res/cardsfolder/d/demogorgons_clutches.txt diff --git a/forge-gui/res/cardsfolder/upcoming/den_of_the_bugbear.txt b/forge-gui/res/cardsfolder/d/den_of_the_bugbear.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/den_of_the_bugbear.txt rename to forge-gui/res/cardsfolder/d/den_of_the_bugbear.txt diff --git a/forge-gui/res/cardsfolder/upcoming/devoted_paladin.txt b/forge-gui/res/cardsfolder/d/devoted_paladin.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/devoted_paladin.txt rename to forge-gui/res/cardsfolder/d/devoted_paladin.txt diff --git a/forge-gui/res/cardsfolder/upcoming/devour_intellect.txt b/forge-gui/res/cardsfolder/d/devour_intellect.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/devour_intellect.txt rename to forge-gui/res/cardsfolder/d/devour_intellect.txt diff --git a/forge-gui/res/cardsfolder/upcoming/dire_wolf_prowler.txt b/forge-gui/res/cardsfolder/d/dire_wolf_prowler.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/dire_wolf_prowler.txt rename to forge-gui/res/cardsfolder/d/dire_wolf_prowler.txt diff --git a/forge-gui/res/cardsfolder/upcoming/displacer_beast.txt b/forge-gui/res/cardsfolder/d/displacer_beast.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/displacer_beast.txt rename to forge-gui/res/cardsfolder/d/displacer_beast.txt diff --git a/forge-gui/res/cardsfolder/upcoming/divine_smite.txt b/forge-gui/res/cardsfolder/d/divine_smite.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/divine_smite.txt rename to forge-gui/res/cardsfolder/d/divine_smite.txt diff --git a/forge-gui/res/cardsfolder/d/divine_visitation.txt b/forge-gui/res/cardsfolder/d/divine_visitation.txt index 44f1729f5d4..1316838efed 100644 --- a/forge-gui/res/cardsfolder/d/divine_visitation.txt +++ b/forge-gui/res/cardsfolder/d/divine_visitation.txt @@ -1,7 +1,7 @@ Name:Divine Visitation ManaCost:3 W W Types:Enchantment -R:Event$ CreateToken | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ TokenReplace | ValidToken$ Creature | Description$ If one or more creature tokens would be created under your control, that many 4/4 white Angel creature tokens with flying and vigilance are created instead. -SVar:TokenReplace:DB$ ReplaceEffect | VarName$ Token | VarValue$ w_4_4_angel_flying_vigilance | VarType$ TokenScript +R:Event$ CreateToken | ActiveZones$ Battlefield | ValidToken$ Creature.YouCtrl | ReplaceWith$ TokenReplace | Description$ If one or more creature tokens would be created under your control, that many 4/4 white Angel creature tokens with flying and vigilance are created instead. +SVar:TokenReplace:DB$ ReplaceToken | Type$ ReplaceToken | ValidCard$ Creature.YouCtrl | TokenScript$ w_4_4_angel_flying_vigilance DeckNeeds:Ability$Token Oracle:If one or more creature tokens would be created under your control, that many 4/4 white Angel creature tokens with flying and vigilance are created instead. diff --git a/forge-gui/res/cardsfolder/d/diviners_portent.txt b/forge-gui/res/cardsfolder/d/diviners_portent.txt new file mode 100644 index 00000000000..9f0dba31478 --- /dev/null +++ b/forge-gui/res/cardsfolder/d/diviners_portent.txt @@ -0,0 +1,10 @@ +Name:Diviner's Portent +ManaCost:X U U U +Types:Instant +A:SP$ RollDice | Sides$ 20 | Modifier$ Y | ResultSubAbilities$ 1-14:DBDraw,Else:DBScry | SpellDescription$ Roll a d20 and add the number of cards in your hand. +SVar:DBDraw:DB$ Draw | NumCards$ X | SpellDescription$ 1-14 VERT Draw X cards. +SVar:DBScry:DB$ Scry | ScryNum$ X | SubAbility$ DBDraw2 | SpellDescription$ 15+ VERT Scry X, then draw X cards. +SVar:DBDraw2:DB$ Draw | NumCards$ X +SVar:X:Count$xPaid +SVar:Y:Count$InYourHand +Oracle:Roll a d20 and add the number of cards in your hand.\n1-14 | Draw X cards.\n15+ | Scry X, then draw X cards. diff --git a/forge-gui/res/cardsfolder/upcoming/djinni_windseer.txt b/forge-gui/res/cardsfolder/d/djinni_windseer.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/djinni_windseer.txt rename to forge-gui/res/cardsfolder/d/djinni_windseer.txt diff --git a/forge-gui/res/cardsfolder/d/doubling_season.txt b/forge-gui/res/cardsfolder/d/doubling_season.txt index 8e2d5d2500b..7e3d1c5f1cc 100644 --- a/forge-gui/res/cardsfolder/d/doubling_season.txt +++ b/forge-gui/res/cardsfolder/d/doubling_season.txt @@ -1,11 +1,9 @@ Name:Doubling Season ManaCost:4 G Types:Enchantment -R:Event$ CreateToken | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ DoubleToken | EffectOnly$ True | Description$ If an effect would create one or more tokens under your control, it creates twice that many of those tokens instead. -SVar:DoubleToken:DB$ ReplaceEffect | VarName$ TokenNum | VarValue$ X +R:Event$ CreateToken | ActiveZones$ Battlefield | ValidToken$ Card.YouCtrl | ReplaceWith$ DoubleToken | EffectOnly$ True | Description$ If an effect would create one or more tokens under your control, it creates twice that many of those tokens instead. +SVar:DoubleToken:DB$ ReplaceToken | Type$ Amount | ValidCard$ Card.YouCtrl R:Event$ AddCounter | ActiveZones$ Battlefield | ValidCard$ Permanent.YouCtrl | EffectOnly$ True | ReplaceWith$ DoubleCounters | Description$ If an effect would put one or more counters on a permanent you control, it puts twice that many of those counters on that permanent instead. SVar:DoubleCounters:DB$ ReplaceEffect | VarName$ CounterNum | VarValue$ Y -SVar:X:ReplaceCount$TokenNum/Twice SVar:Y:ReplaceCount$CounterNum/Twice -SVar:Picture:http://www.wizards.com/global/images/magic/general/doubling_season.jpg Oracle:If an effect would create one or more tokens under your control, it creates twice that many of those tokens instead.\nIf an effect would put one or more counters on a permanent you control, it puts twice that many of those counters on that permanent instead. diff --git a/forge-gui/res/cardsfolder/upcoming/dragon_turtle.txt b/forge-gui/res/cardsfolder/d/dragon_turtle.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/dragon_turtle.txt rename to forge-gui/res/cardsfolder/d/dragon_turtle.txt diff --git a/forge-gui/res/cardsfolder/d/dragonborn_champion.txt b/forge-gui/res/cardsfolder/d/dragonborn_champion.txt new file mode 100644 index 00000000000..d9ab5d07aa1 --- /dev/null +++ b/forge-gui/res/cardsfolder/d/dragonborn_champion.txt @@ -0,0 +1,8 @@ +Name:Dragonborn Champion +ManaCost:2 R G +Types:Creature Dragon Warrior +PT:5/3 +K:Trample +T:Mode$ DamageDone | ValidSource$ Card.YouCtrl,Emblem.YouCtrl | ValidTarget$ Player | TriggerZones$ Battlefield | DamageAmount$ GE5 | Execute$ TrigDraw | TriggerDescription$ Whenever a source you control deals 5 or more damage to a player, draw a card. +SVar:TrigDraw:DB$ Draw | NumCards$ 1 | SpellDescription$ Draw a card. +Oracle:Trample\nWhenever a source you control deals 5 or more damage to a player, draw a card. diff --git a/forge-gui/res/cardsfolder/upcoming/dragons_disciple.txt b/forge-gui/res/cardsfolder/d/dragons_disciple.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/dragons_disciple.txt rename to forge-gui/res/cardsfolder/d/dragons_disciple.txt diff --git a/forge-gui/res/cardsfolder/upcoming/dragons_fire.txt b/forge-gui/res/cardsfolder/d/dragons_fire.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/dragons_fire.txt rename to forge-gui/res/cardsfolder/d/dragons_fire.txt diff --git a/forge-gui/res/cardsfolder/d/dread_wight.txt b/forge-gui/res/cardsfolder/d/dread_wight.txt index e2373ef98d3..aef6b05482e 100644 --- a/forge-gui/res/cardsfolder/d/dread_wight.txt +++ b/forge-gui/res/cardsfolder/d/dread_wight.txt @@ -5,7 +5,7 @@ PT:3/4 T:Mode$ Phase | Phase$ EndCombat | Execute$ TrigCounter | TriggerZones$ Battlefield | TriggerDescription$ At end of combat, put a paralyzation counter on each creature blocking or blocked by CARDNAME and tap those creatures. Each of those creatures doesn't untap during its controller's untap step for as long as it has a paralyzation counter on it. Each of those creatures gains "{4}: Remove a paralyzation counter from this creature." SVar:TrigCounter:DB$ PutCounterAll | CounterType$ PARALYZATION | CounterNum$ 1 | ValidCards$ Creature.blockedBySource,Creature.blockingSource | SubAbility$ DBTap SVar:DBTap:DB$ TapAll | ValidCards$ Creature.blockedBySource,Creature.blockingSource | SubAbility$ DBEffect -SVar:DBEffect:DB$ Effect | RememberObjects$ Valid Creature.blockedBySource,Valid Creature.blockingSource | StaticAbilities$ DontUntap | Duration$ Permanent | ConditionPresent$ Creature.blockedBySource,Creature.blockingSource | SubAbility$ DBAnimate | ForgetOnMoved$ Battlefield | ForgetCounter$ PARALYZATION +SVar:DBEffect:DB$ Effect | RememberObjects$ Valid Creature.blockedBySource,Creature.blockingSource | StaticAbilities$ DontUntap | Duration$ Permanent | ConditionPresent$ Creature.blockedBySource,Creature.blockingSource | SubAbility$ DBAnimate | ForgetOnMoved$ Battlefield | ForgetCounter$ PARALYZATION SVar:DBAnimate:DB$ AnimateAll | ValidCards$ Creature.blockedBySource,Creature.blockingSource | Abilities$ ABRemoveCounter | Duration$ Permanent SVar:ABRemoveCounter:AB$ RemoveCounter | Defined$ Self | Cost$ 4 | CounterType$ PARALYZATION | CounterNum$ 1 | SpellDescription$ Remove a paralyzation counter from this creature. SVar:DontUntap:Mode$ Continuous | EffectZone$ Command | AffectedZone$ Battlefield | Affected$ Card.IsRemembered | AddHiddenKeyword$ CARDNAME doesn't untap during your untap step. | Description$ Each of those creatures doesn't untap during its controller's untap step for as long as it has a paralyzation counter on it. diff --git a/forge-gui/res/cardsfolder/upcoming/drider.txt b/forge-gui/res/cardsfolder/d/drider.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/drider.txt rename to forge-gui/res/cardsfolder/d/drider.txt diff --git a/forge-gui/res/cardsfolder/upcoming/druid_class.txt b/forge-gui/res/cardsfolder/d/druid_class.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/druid_class.txt rename to forge-gui/res/cardsfolder/d/druid_class.txt diff --git a/forge-gui/res/cardsfolder/d/druid_of_purification.txt b/forge-gui/res/cardsfolder/d/druid_of_purification.txt new file mode 100644 index 00000000000..2a5a5447bf1 --- /dev/null +++ b/forge-gui/res/cardsfolder/d/druid_of_purification.txt @@ -0,0 +1,11 @@ +Name:Druid of Purification +ManaCost:3 G +Types:Creature Human Druid +PT:2/3 +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigChoice | TriggerDescription$ When CARDNAME enters the battlefield, starting with you, each player may choose an artifact or enchantment you don’t control. Destroy each permanent chosen this way. +SVar:TrigChoice:DB$ RepeatEach | RepeatPlayers$ Player | StartingWithActivator$ True | RepeatSubAbility$ DBChoosePermanent | SubAbility$ DBDestroy +SVar:DBChoosePermanent:DB$ ChooseCard | Defined$ Remembered | Choices$ Artifact.YouDontCtrl,Enchantment.YouDontCtrl | Optional$ True | ChoiceTitle$ Choose an artifact or enchantment | RememberChosen$ True +SVar:DBDestroy:DB$ Destroy | Defined$ Remembered | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +AI:RemoveDeck:Random +Oracle:When Druid of Purification enters the battlefield, starting with you, each player may choose an artifact or enchantment you don't control. Destroy each permanent chosen this way. diff --git a/forge-gui/res/cardsfolder/upcoming/dueling_rapier.txt b/forge-gui/res/cardsfolder/d/dueling_rapier.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/dueling_rapier.txt rename to forge-gui/res/cardsfolder/d/dueling_rapier.txt diff --git a/forge-gui/res/cardsfolder/upcoming/dungeon_crawler.txt b/forge-gui/res/cardsfolder/d/dungeon_crawler.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/dungeon_crawler.txt rename to forge-gui/res/cardsfolder/d/dungeon_crawler.txt diff --git a/forge-gui/res/cardsfolder/upcoming/dungeon_descent.txt b/forge-gui/res/cardsfolder/d/dungeon_descent.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/dungeon_descent.txt rename to forge-gui/res/cardsfolder/d/dungeon_descent.txt diff --git a/forge-gui/res/cardsfolder/upcoming/dungeon_map.txt b/forge-gui/res/cardsfolder/d/dungeon_map.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/dungeon_map.txt rename to forge-gui/res/cardsfolder/d/dungeon_map.txt diff --git a/forge-gui/res/cardsfolder/upcoming/dungeon_of_the_mad_mage.txt b/forge-gui/res/cardsfolder/d/dungeon_of_the_mad_mage.txt similarity index 85% rename from forge-gui/res/cardsfolder/upcoming/dungeon_of_the_mad_mage.txt rename to forge-gui/res/cardsfolder/d/dungeon_of_the_mad_mage.txt index 3e23e1d82bb..a12ad7f5047 100644 --- a/forge-gui/res/cardsfolder/upcoming/dungeon_of_the_mad_mage.txt +++ b/forge-gui/res/cardsfolder/d/dungeon_of_the_mad_mage.txt @@ -7,9 +7,8 @@ SVar:DBDungeon:DB$ Scry | ScryNum$ 1 | RoomName$ Dungeon Level | SpellDescriptio SVar:DBBazaar:DB$ Token | TokenScript$ c_a_treasure_sac | TokenOwner$ You | RoomName$ Goblin Bazaar | SpellDescription$ Create a Treasure token. | NextRoom$ DBLost SVar:DBCaverns:DB$ Pump | ValidTgts$ Creature | KW$ HIDDEN CARDNAME can't attack. | Duration$ UntilYourNextTurn | IsCurse$ True | RoomName$ Twisted Caverns | SpellDescription$ Target creature can't attack until your next turn. | NextRoom$ DBLost SVar:DBLost:DB$ Scry | ScryNum$ 2 | RoomName$ Lost Level | SpellDescription$ Scry 2. | NextRoom$ DBRunestone,DBGraveyard -SVar:DBRunestone:DB$ Dig | Defined$ You | DigNum$ 2 | ChangeNum$ All | DestinationZone$ Exile | RememberChanged$ True | SubAbility$ DBEffect | RoomName$ Runestone Caverns | SpellDescription$ Exile the top two cards of your library. You may play them. | NextRoom$ DBMines -SVar:DBEffect:DB$ Effect | StaticAbilities$ STPlay | RememberObjects$ RememberedCard | Duration$ Permanent | ForgetOnMoved$ Exile | SubAbility$ DBCleanup -SVar:STPlay:Mode$ Continuous | EffectZone$ Command | AffectedZone$ Exile | Affected$ Card.IsRemembered | MayPlay$ True | Description$ You may play them. +SVar:DBRunestone:DB$ Dig | Defined$ You | DigNum$ 2 | ChangeNum$ All | DestinationZone$ Exile | RememberChanged$ True | SubAbility$ DBPlayExiled | RoomName$ Runestone Caverns | SpellDescription$ Exile the top two cards of your library. You may play them. | NextRoom$ DBMines +SVar:DBPlayExiled:DB$ Play | Valid$ Card.IsRemembered | ValidZone$ Exile | Controller$ You | Optional$ True | Amount$ All | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:DBGraveyard:DB$ Token | TokenScript$ b_1_1_skeleton | TokenOwner$ You | TokenAmount$ 2 | RoomName$ Muiral's Graveyard | SpellDescription$ Create two 1/1 black Skeleton creature tokens. | NextRoom$ DBMines SVar:DBMines:DB$ Scry | ScryNum$ 3 | RoomName$ Deep Mines | SpellDescription$ Scry 3. | NextRoom$ DBLair diff --git a/forge-gui/res/cardsfolder/upcoming/dwarfhold_champion.txt b/forge-gui/res/cardsfolder/d/dwarfhold_champion.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/dwarfhold_champion.txt rename to forge-gui/res/cardsfolder/d/dwarfhold_champion.txt diff --git a/forge-gui/res/cardsfolder/upcoming/earth_cult_elemental.txt b/forge-gui/res/cardsfolder/e/earth_cult_elemental.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/earth_cult_elemental.txt rename to forge-gui/res/cardsfolder/e/earth_cult_elemental.txt diff --git a/forge-gui/res/cardsfolder/upcoming/ebondeath_dracolich.txt b/forge-gui/res/cardsfolder/e/ebondeath_dracolich.txt similarity index 72% rename from forge-gui/res/cardsfolder/upcoming/ebondeath_dracolich.txt rename to forge-gui/res/cardsfolder/e/ebondeath_dracolich.txt index 5e0723dac12..00c5cc2f9cc 100644 --- a/forge-gui/res/cardsfolder/upcoming/ebondeath_dracolich.txt +++ b/forge-gui/res/cardsfolder/e/ebondeath_dracolich.txt @@ -5,7 +5,7 @@ PT:5/2 K:Flash K:Flying K:CARDNAME enters the battlefield tapped. -S:Mode$ Continuous | Affected$ Card.Self | EffectZone$ Graveyard | MayPlay$ True | CheckSVar$ X | SVarCompare$ GE1 | Description$ You may cast CARDNAME from your graveyard if a creature not named Ebondeath, Dracolich died this turn. +S:Mode$ Continuous | Affected$ Card.Self | EffectZone$ Graveyard | AffectedZone$ Graveyard | MayPlay$ True | CheckSVar$ X | SVarCompare$ GE1 | Description$ You may cast CARDNAME from your graveyard if a creature not named Ebondeath, Dracolich died this turn. SVar:X:Count$ThisTurnEntered_Graveyard_from_Battlefield_Creature.notnamedEbondeath; Dracolich SVar:SacMe:3 SVar:DiscardMe:3 diff --git a/forge-gui/res/cardsfolder/e/ebony_fly.txt b/forge-gui/res/cardsfolder/e/ebony_fly.txt new file mode 100644 index 00000000000..2db7666fb07 --- /dev/null +++ b/forge-gui/res/cardsfolder/e/ebony_fly.txt @@ -0,0 +1,10 @@ +Name:Ebony Fly +ManaCost:2 +Types:Artifact +K:CARDNAME enters the battlefield tapped. +A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}. +A:AB$ RollDice | Cost$ 4 | Sides$ 6 | ResultSVar$ X | SubAbility$ DBAnimate | SpellDescription$ Roll a d6. +SVar:DBAnimate:DB$ Animate | Defined$ Self | Power$ X | Toughness$ X | Types$ Artifact,Creature,Insect | Keywords$ Flying | RemoveCardTypes$ True | Optional$ True | StackDescription$ SpellDescription | SpellDescription$ Until end of turn, you may have CARDNAME become an X/X Insect artifact creature with flying, where X is the result. +T:Mode$ Attacks | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigPump | TriggerDescription$ Whenever CARDNAME attacks, another target attacking creature gains flying until end of turn. +SVar:TrigPump:DB$ Pump | ValidTgts$ Creature.Other+attacking | TgtPrompt$ Select another target attacking creature | KW$ Flying +Oracle:Ebony Fly enters the battlefield tapped.\n{T}: Add {C}.\n{4}: Roll a d6. Until end of turn, you may have Ebony Fly become an X/X Insect artifact creature with flying, where X is the result.\nWhenever Ebony Fly attacks, another target attacking creature gains flying until end of turn. diff --git a/forge-gui/res/cardsfolder/upcoming/eccentric_apprentice.txt b/forge-gui/res/cardsfolder/e/eccentric_apprentice.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/eccentric_apprentice.txt rename to forge-gui/res/cardsfolder/e/eccentric_apprentice.txt diff --git a/forge-gui/res/cardsfolder/e/elephant_graveyard.txt b/forge-gui/res/cardsfolder/e/elephant_graveyard.txt index ec6c750710f..c4af3978e94 100644 --- a/forge-gui/res/cardsfolder/e/elephant_graveyard.txt +++ b/forge-gui/res/cardsfolder/e/elephant_graveyard.txt @@ -4,4 +4,6 @@ Types:Land A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}. A:AB$ Regenerate | ValidTgts$ Creature.Elephant | TgtPrompt$ Select target Elephant | Cost$ T | SpellDescription$ Regenerate target Elephant. SVar:Picture:http://www.wizards.com/global/images/magic/general/elephant_graveyard.jpg +AI:RemoveDeck:Random +DeckNeeds:Type$Elephant Oracle:{T}: Add {C}.\n{T}: Regenerate target Elephant. diff --git a/forge-gui/res/cardsfolder/upcoming/ellywick_tumblestrum.txt b/forge-gui/res/cardsfolder/e/ellywick_tumblestrum.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/ellywick_tumblestrum.txt rename to forge-gui/res/cardsfolder/e/ellywick_tumblestrum.txt diff --git a/forge-gui/res/cardsfolder/upcoming/elturgard_ranger.txt b/forge-gui/res/cardsfolder/e/elturgard_ranger.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/elturgard_ranger.txt rename to forge-gui/res/cardsfolder/e/elturgard_ranger.txt diff --git a/forge-gui/res/cardsfolder/e/emergency_powers.txt b/forge-gui/res/cardsfolder/e/emergency_powers.txt index bcf11be33b2..b10f3b2e8db 100644 --- a/forge-gui/res/cardsfolder/e/emergency_powers.txt +++ b/forge-gui/res/cardsfolder/e/emergency_powers.txt @@ -1,10 +1,8 @@ Name:Emergency Powers ManaCost:5 W U Types:Instant -A:SP$ ChangeZoneAll | Cost$ 5 W U | ChangeType$ Card | Origin$ Hand,Graveyard | Destination$ Library | Shuffle$ True | Random$ True | SubAbility$ DBDraw | UseAllOriginZones$ True | AILogic$ Timetwister | StackDescription$ SpellDescription | SpellDescription$ Each player shuffles their hand and hand into their library, then draws seven cards. Exile CARDNAME. +A:SP$ ChangeZoneAll | ChangeType$ Card | Origin$ Hand,Graveyard | Destination$ Library | Shuffle$ True | Random$ True | SubAbility$ DBDraw | UseAllOriginZones$ True | AILogic$ Timetwister | StackDescription$ SpellDescription | SpellDescription$ Each player shuffles their hand and hand into their library, then draws seven cards. Exile CARDNAME. SVar:DBDraw:DB$ Draw | NumCards$ 7 | Defined$ Player | SubAbility$ DBAddendum | StackDescription$ None -SVar:DBAddendum:DB$ ChooseCard | ChoiceZone$ Hand | Defined$ You | Amount$ 1 | Choices$ Permanent.cmcLE7+YouCtrl | AILogic$ BestCard | ConditionPlayerTurn$ True | ConditionPhases$ Main1,Main2 | ConditionDefined$ Self | ConditionPresent$ Card.wasCast | SubAbility$ DBChange | StackDescription$ SpellDescription | SpellDescription$ Addendum - If you cast this spell during your main phase, you may put a permanent card with mana value 7 or less from your hand onto the battlefield. -SVar:DBChange:DB$ ChangeZone | Origin$ Hand | Destination$ Battlefield | Defined$ ChosenCard | ConditionPlayerTurn$ True | ConditionPhases$ Main1,Main2 | ConditionDefined$ Self | ConditionPresent$ Card.wasCast | SubAbility$ DBCleanup | StackDescription$ None -SVar:DBCleanup:DB$ Cleanup | ClearChosen$ True | SubAbility$ DBExile +SVar:DBAddendum:DB$ ChangeZone | Origin$ Hand | Destination$ Battlefield | ChoiceZone$ Hand | Amount$ 1 | ChangeType$ Permanent.cmcLE7+YouCtrl | ChangeNum$ 1 | AILogic$ BestCard | ConditionPlayerTurn$ True | ConditionPhases$ Main1,Main2 | ConditionDefined$ Self | ConditionPresent$ Card.wasCast | SubAbility$ DBExile | StackDescription$ SpellDescription | SpellDescription$ Addendum - If you cast this spell during your main phase, you may put a permanent card with mana value 7 or less from your hand onto the battlefield. SVar:DBExile:DB$ ChangeZone | Origin$ Stack | Destination$ Exile | StackDescription$ None Oracle:Each player shuffles their hand and graveyard into their library, then draws seven cards. Exile Emergency Powers.\nAddendum — If you cast this spell during your main phase, you may put a permanent card with mana value 7 or less from your hand onto the battlefield. diff --git a/forge-gui/res/cardsfolder/e/extract_brain.txt b/forge-gui/res/cardsfolder/e/extract_brain.txt new file mode 100644 index 00000000000..a59b990cb28 --- /dev/null +++ b/forge-gui/res/cardsfolder/e/extract_brain.txt @@ -0,0 +1,9 @@ +Name:Extract Brain +ManaCost:X U B +Types:Sorcery +A:SP$ Reveal | Cost$ X U B | ValidTgts$ Opponent | IsCurse$ True | NumCards$ X | RememberRevealed$ True | SubAbility$ PickOne |StackDescription$ {p:Targeted} chooses X cards from their hand. Look at those cards. You may cast a spell from among them without paying its mana cost. | SpellDescription$ Target opponent chooses X cards from their hand. Look at those cards. You may cast a spell from among them without paying its mana cost. +SVar:PickOne:DB$ ChooseCard | Defined$ You | Amount$ 1 | ChoiceTitle$ Choose card to cast | Choices$ Card.IsRemembered | ChoiceZone$ Hand | SubAbility$ PlayChosen | StackDescription$ None +SVar:PlayChosen:DB$ Play | Defined$ ChosenCard | Controller$ You | WithoutManaCost$ True | Optional$ True | SubAbility$ DBCleanup | StackDescription$ None +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearChosenCard$ True +SVar:X:Count$xPaid +Oracle:Target opponent chooses X cards from their hand. Look at those cards. You may cast a spell from among them without paying its mana cost. diff --git a/forge-gui/res/cardsfolder/upcoming/eye_of_vecna.txt b/forge-gui/res/cardsfolder/e/eye_of_vecna.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/eye_of_vecna.txt rename to forge-gui/res/cardsfolder/e/eye_of_vecna.txt diff --git a/forge-gui/res/cardsfolder/upcoming/eyes_of_the_beholder.txt b/forge-gui/res/cardsfolder/e/eyes_of_the_beholder.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/eyes_of_the_beholder.txt rename to forge-gui/res/cardsfolder/e/eyes_of_the_beholder.txt diff --git a/forge-gui/res/cardsfolder/upcoming/farideh_devils_chosen.txt b/forge-gui/res/cardsfolder/f/farideh_devils_chosen.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/farideh_devils_chosen.txt rename to forge-gui/res/cardsfolder/f/farideh_devils_chosen.txt diff --git a/forge-gui/res/cardsfolder/upcoming/faridehs_fireball.txt b/forge-gui/res/cardsfolder/f/faridehs_fireball.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/faridehs_fireball.txt rename to forge-gui/res/cardsfolder/f/faridehs_fireball.txt diff --git a/forge-gui/res/cardsfolder/upcoming/fates_reversal.txt b/forge-gui/res/cardsfolder/f/fates_reversal.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/fates_reversal.txt rename to forge-gui/res/cardsfolder/f/fates_reversal.txt diff --git a/forge-gui/res/cardsfolder/upcoming/feign_death.txt b/forge-gui/res/cardsfolder/f/feign_death.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/feign_death.txt rename to forge-gui/res/cardsfolder/f/feign_death.txt diff --git a/forge-gui/res/cardsfolder/f/fevered_suspicion.txt b/forge-gui/res/cardsfolder/f/fevered_suspicion.txt new file mode 100644 index 00000000000..ef914643e8f --- /dev/null +++ b/forge-gui/res/cardsfolder/f/fevered_suspicion.txt @@ -0,0 +1,8 @@ +Name:Fevered Suspicion +ManaCost:6 B R +Types:Sorcery +K:Rebound +A:SP$ DigUntil | Cost$ 6 B R | Defined$ Player.Opponent | Valid$ Card.nonLand | FoundDestination$ Exile | RevealedDestination$ Exile | RememberFound$ True | SubAbility$ DBPlay | StackDescription$ SpellDescription | SpellDescription$ Each opponent exiles cards from the top of their library until they exile a nonland card. You may cast any number of spells from among those nonland cards without paying their mana costs. +SVar:DBPlay:DB$ Play | Controller$ You | OptionalDecider$ You | Defined$ Remembered | WithoutManaCost$ True | Optional$ True | SubAbility$ DBCleanup | StackDescription$ None +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +Oracle:Each opponent exiles cards from the top of their library until they exile a nonland card. You may cast any number of spells from among those nonland cards without paying their mana costs.\nRebound (If you cast this spell from your hand, exile it as it resolves. At the beginning of your next upkeep, you may cast this card from exile without paying its mana cost.) \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/f/fey_steed.txt b/forge-gui/res/cardsfolder/f/fey_steed.txt new file mode 100644 index 00000000000..b34f6ae2c75 --- /dev/null +++ b/forge-gui/res/cardsfolder/f/fey_steed.txt @@ -0,0 +1,10 @@ +Name:Fey Steed +ManaCost:2 W W +Types:Creature Elk +PT:4/4 +T:Mode$ Attacks | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigPump | TriggerDescription$ Whenever CARDNAME attacks, another target attacking creature you control gains indestructible until end of turn. +SVar:TrigPump:DB$ Pump | ValidTgts$ Creature.YouCtrl+Other+attacking | TgtPrompt$ Select another target attacking creature you control | KW$ Indestructible +T:Mode$ BecomesTarget | ValidSource$ Card.OppCtrl | ValidTarget$ Creature.YouCtrl+inZoneBattlefield,Planeswalker.YouCtrl+inZoneBattlefield | TriggerZones$ Battlefield | Execute$ TrigDraw | OptionalDecider$ You | TriggerDescription$ Whenever a creature or planeswalker you control becomes the target of a spell or ability an opponent controls, you may draw a card. +SVar:TrigDraw:DB$ Draw | NumCards$ 1 | Defined$ You +SVar:HasAttackEffect:TRUE +Oracle:Whenever Fey Steed attacks, another target attacking creature you control gains indestructible until end of turn.\nWhenever a creature or planeswalker you control becomes the target of a spell or ability an opponent controls, you may draw a card. diff --git a/forge-gui/res/cardsfolder/upcoming/feywild_trickster.txt b/forge-gui/res/cardsfolder/f/feywild_trickster.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/feywild_trickster.txt rename to forge-gui/res/cardsfolder/f/feywild_trickster.txt diff --git a/forge-gui/res/cardsfolder/upcoming/fifty_feet_of_rope.txt b/forge-gui/res/cardsfolder/f/fifty_feet_of_rope.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/fifty_feet_of_rope.txt rename to forge-gui/res/cardsfolder/f/fifty_feet_of_rope.txt diff --git a/forge-gui/res/cardsfolder/upcoming/fighter_class.txt b/forge-gui/res/cardsfolder/f/fighter_class.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/fighter_class.txt rename to forge-gui/res/cardsfolder/f/fighter_class.txt diff --git a/forge-gui/res/cardsfolder/upcoming/find_the_path.txt b/forge-gui/res/cardsfolder/f/find_the_path.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/find_the_path.txt rename to forge-gui/res/cardsfolder/f/find_the_path.txt diff --git a/forge-gui/res/cardsfolder/upcoming/flameskull.txt b/forge-gui/res/cardsfolder/f/flameskull.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/flameskull.txt rename to forge-gui/res/cardsfolder/f/flameskull.txt diff --git a/forge-gui/res/cardsfolder/upcoming/flumph.txt b/forge-gui/res/cardsfolder/f/flumph.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/flumph.txt rename to forge-gui/res/cardsfolder/f/flumph.txt diff --git a/forge-gui/res/cardsfolder/upcoming/fly.txt b/forge-gui/res/cardsfolder/f/fly.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/fly.txt rename to forge-gui/res/cardsfolder/f/fly.txt diff --git a/forge-gui/res/cardsfolder/f/forbidden_friendship.txt b/forge-gui/res/cardsfolder/f/forbidden_friendship.txt index fb71c9f4573..61a0d5d54c3 100755 --- a/forge-gui/res/cardsfolder/f/forbidden_friendship.txt +++ b/forge-gui/res/cardsfolder/f/forbidden_friendship.txt @@ -1,8 +1,6 @@ Name:Forbidden Friendship ManaCost:1 R Types:Sorcery -A:SP$ Token | Cost$ 1 R | TokenAmount$ 1 | TokenScript$ r_1_1_dinosaur_haste | TokenOwner$ You | LegacyImage$ r 1 1 dinosaur haste iko | ChangeZoneTable$ True | SubAbility$ DBToken | SpellDescription$ Create a 1/1 red Dinosaur creature token with haste and a 1/1 white Human Soldier creature token. -SVar:DBToken:DB$ Token | TokenAmount$ 1 | TokenScript$ w_1_1_human_soldier | TokenOwner$ You | LegacyImage$ w 1 1 human soldier iko | SubAbility$ DBResolve -SVar:DBResolve:DB$ ChangeZoneResolve +A:SP$ Token | Cost$ 1 R | TokenAmount$ 1 | TokenScript$ r_1_1_dinosaur_haste,w_1_1_human_soldier | TokenOwner$ You | SpellDescription$ Create a 1/1 red Dinosaur creature token with haste and a 1/1 white Human Soldier creature token. DeckHas:Ability$Token Oracle:Create a 1/1 red Dinosaur creature token with haste and a 1/1 white Human Soldier creature token. diff --git a/forge-gui/res/cardsfolder/upcoming/forsworn_paladin.txt b/forge-gui/res/cardsfolder/f/forsworn_paladin.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/forsworn_paladin.txt rename to forge-gui/res/cardsfolder/f/forsworn_paladin.txt diff --git a/forge-gui/res/cardsfolder/upcoming/froghemoth.txt b/forge-gui/res/cardsfolder/f/froghemoth.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/froghemoth.txt rename to forge-gui/res/cardsfolder/f/froghemoth.txt diff --git a/forge-gui/res/cardsfolder/g/galea_kindler_of_hope.txt b/forge-gui/res/cardsfolder/g/galea_kindler_of_hope.txt new file mode 100644 index 00000000000..e4c5f3d45df --- /dev/null +++ b/forge-gui/res/cardsfolder/g/galea_kindler_of_hope.txt @@ -0,0 +1,13 @@ +Name:Galea, Kindler of Hope +ManaCost:1 G U W +Types:Legendary Creature Elf Knight +PT:4/4 +K:Vigilance +S:Mode$ Continuous | Affected$ Card.TopLibrary+YouCtrl | AffectedZone$ Library | MayLookAt$ You | Description$ You may look at the top card of your library any time. +S:Mode$ Continuous | Affected$ Aura.TopLibrary+YouCtrl+nonLand,Equipment.TopLibrary+YouCtrl+nonLand | AffectedZone$ Library | MayPlay$ True | Description$ You may cast Aura and Equipment spells from the top of your library. When you cast an Equipment spell this way, it gains "When this Equipment enters the battlefield, attach it to target creature you control." +T:Mode$ SpellCast | ValidCard$ Equipment | ValidSA$ Spell.MayPlaySource | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigAnimate | Secondary$ True | TriggerDescription$ When you cast an Equipment spell this way, it gains "When this Equipment enters the battlefield, attach it to target creature you control." +SVar:TrigAnimate:DB$ Animate | Defined$ TriggeredCard | Triggers$ ETBAttach | Duration$ Permanent +SVar:ETBAttach:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigAttach | TriggerDescription$ When this Equipment enters the battlefield, attach it to target creature you control. +SVar:TrigAttach:DB$ Attach | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control +DeckHints:Type$Aura|Equipment +Oracle:Vigilance\nYou may look at the top card of your library any time./nYou may cast Aura and Equipment spells from the top of your library. When you cast an Equipment spell this way, it gains "When this Equipment enters the battlefield, attach it to target creature you control." diff --git a/forge-gui/res/cardsfolder/upcoming/gelatinous_cube.txt b/forge-gui/res/cardsfolder/g/gelatinous_cube.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/gelatinous_cube.txt rename to forge-gui/res/cardsfolder/g/gelatinous_cube.txt diff --git a/forge-gui/res/cardsfolder/g/gerrard_weatherlight_hero.txt b/forge-gui/res/cardsfolder/g/gerrard_weatherlight_hero.txt index 9f017a9d46d..c0aa968ae90 100644 --- a/forge-gui/res/cardsfolder/g/gerrard_weatherlight_hero.txt +++ b/forge-gui/res/cardsfolder/g/gerrard_weatherlight_hero.txt @@ -5,5 +5,5 @@ PT:3/3 K:First Strike T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigExile | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME dies, exile it and return to the battlefield all artifact and creature cards in your graveyard that were put there from the battlefield this turn. SVar:TrigExile:DB$ ChangeZone | Defined$ TriggeredNewCardLKICopy | Origin$ Graveyard | Destination$ Exile | SubAbility$ DBReturn -SVar:DBReturn:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | Defined$ ValidGraveyard Artifact,Creature.YouOwn+ThisTurnEnteredFrom_Battlefield +SVar:DBReturn:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | Defined$ ValidGraveyard Artifact.YouOwn+ThisTurnEnteredFrom_Battlefield,Creature.YouOwn+ThisTurnEnteredFrom_Battlefield Oracle:First strike\nWhen Gerrard, Weatherlight Hero dies, exile it and return to the battlefield all artifact and creature cards in your graveyard that were put there from the battlefield this turn. diff --git a/forge-gui/res/cardsfolder/upcoming/gloom_stalker.txt b/forge-gui/res/cardsfolder/g/gloom_stalker.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/gloom_stalker.txt rename to forge-gui/res/cardsfolder/g/gloom_stalker.txt diff --git a/forge-gui/res/cardsfolder/upcoming/gnoll_hunter.txt b/forge-gui/res/cardsfolder/g/gnoll_hunter.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/gnoll_hunter.txt rename to forge-gui/res/cardsfolder/g/gnoll_hunter.txt diff --git a/forge-gui/res/cardsfolder/upcoming/goblin_javelineer.txt b/forge-gui/res/cardsfolder/g/goblin_javelineer.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/goblin_javelineer.txt rename to forge-gui/res/cardsfolder/g/goblin_javelineer.txt diff --git a/forge-gui/res/cardsfolder/upcoming/goblin_morningstar.txt b/forge-gui/res/cardsfolder/g/goblin_morningstar.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/goblin_morningstar.txt rename to forge-gui/res/cardsfolder/g/goblin_morningstar.txt diff --git a/forge-gui/res/cardsfolder/upcoming/grand_master_of_flowers.txt b/forge-gui/res/cardsfolder/g/grand_master_of_flowers.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/grand_master_of_flowers.txt rename to forge-gui/res/cardsfolder/g/grand_master_of_flowers.txt diff --git a/forge-gui/res/cardsfolder/upcoming/grazilaxx_illithid_scholar.txt b/forge-gui/res/cardsfolder/g/grazilaxx_illithid_scholar.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/grazilaxx_illithid_scholar.txt rename to forge-gui/res/cardsfolder/g/grazilaxx_illithid_scholar.txt diff --git a/forge-gui/res/cardsfolder/upcoming/greataxe.txt b/forge-gui/res/cardsfolder/g/greataxe.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/greataxe.txt rename to forge-gui/res/cardsfolder/g/greataxe.txt diff --git a/forge-gui/res/cardsfolder/upcoming/green_dragon.txt b/forge-gui/res/cardsfolder/g/green_dragon.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/green_dragon.txt rename to forge-gui/res/cardsfolder/g/green_dragon.txt diff --git a/forge-gui/res/cardsfolder/upcoming/gretchen_titchwillow.txt b/forge-gui/res/cardsfolder/g/gretchen_titchwillow.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/gretchen_titchwillow.txt rename to forge-gui/res/cardsfolder/g/gretchen_titchwillow.txt diff --git a/forge-gui/res/cardsfolder/upcoming/grim_bounty.txt b/forge-gui/res/cardsfolder/g/grim_bounty.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/grim_bounty.txt rename to forge-gui/res/cardsfolder/g/grim_bounty.txt diff --git a/forge-gui/res/cardsfolder/upcoming/grim_wanderer.txt b/forge-gui/res/cardsfolder/g/grim_wanderer.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/grim_wanderer.txt rename to forge-gui/res/cardsfolder/g/grim_wanderer.txt diff --git a/forge-gui/res/cardsfolder/upcoming/guardian_of_faith.txt b/forge-gui/res/cardsfolder/g/guardian_of_faith.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/guardian_of_faith.txt rename to forge-gui/res/cardsfolder/g/guardian_of_faith.txt diff --git a/forge-gui/res/cardsfolder/upcoming/guild_thief.txt b/forge-gui/res/cardsfolder/g/guild_thief.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/guild_thief.txt rename to forge-gui/res/cardsfolder/g/guild_thief.txt diff --git a/forge-gui/res/cardsfolder/upcoming/half_elf_monk.txt b/forge-gui/res/cardsfolder/h/half_elf_monk.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/half_elf_monk.txt rename to forge-gui/res/cardsfolder/h/half_elf_monk.txt diff --git a/forge-gui/res/cardsfolder/upcoming/hall_of_storm_giants.txt b/forge-gui/res/cardsfolder/h/hall_of_storm_giants.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/hall_of_storm_giants.txt rename to forge-gui/res/cardsfolder/h/hall_of_storm_giants.txt diff --git a/forge-gui/res/cardsfolder/upcoming/hama_pashar_ruin_seeker.txt b/forge-gui/res/cardsfolder/h/hama_pashar_ruin_seeker.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/hama_pashar_ruin_seeker.txt rename to forge-gui/res/cardsfolder/h/hama_pashar_ruin_seeker.txt diff --git a/forge-gui/res/cardsfolder/upcoming/hand_of_vecna.txt b/forge-gui/res/cardsfolder/h/hand_of_vecna.txt similarity index 90% rename from forge-gui/res/cardsfolder/upcoming/hand_of_vecna.txt rename to forge-gui/res/cardsfolder/h/hand_of_vecna.txt index aa76cc3946b..5eb43f0675b 100644 --- a/forge-gui/res/cardsfolder/upcoming/hand_of_vecna.txt +++ b/forge-gui/res/cardsfolder/h/hand_of_vecna.txt @@ -2,8 +2,8 @@ Name:Hand of Vecna ManaCost:3 Types:Legendary Artifact Equipment T:Mode$Phase | Phase$ BeginCombat | ValidPlayer$ You | Execute$ TrigChoose | TriggerZones$ Battlefield | TriggerDescription$ At the beginning of combat on your turn, equipped creature or a creature you control named Vecna gets +X/+X until end of turn, where X is the number of cards in your hand. -SVar:TrigChoose:DB$ ChooseCard | Choices$ Creature.EquippedBy,Creature.YouCtrl+namedVecna | SubAbility$ DBPump -SVar:DBPump:DB$ Pump | Defined$ ChosenCard | NumAtt$ +X | NumDef$ +X | Mandatory$ True | SubAbility$ DBCleanup +SVar:TrigChoose:DB$ ChooseCard | Choices$ Creature.EquippedBy,Creature.YouCtrl+namedVecna | Mandatory$ True | SubAbility$ DBPump +SVar:DBPump:DB$ Pump | Defined$ ChosenCard | NumAtt$ +X | NumDef$ +X | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearChosenCard$ True K:Equip:PayLife K:Equip:2 diff --git a/forge-gui/res/cardsfolder/upcoming/herald_of_hadar.txt b/forge-gui/res/cardsfolder/h/herald_of_hadar.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/herald_of_hadar.txt rename to forge-gui/res/cardsfolder/h/herald_of_hadar.txt diff --git a/forge-gui/res/cardsfolder/upcoming/hill_giant_herdgorger.txt b/forge-gui/res/cardsfolder/h/hill_giant_herdgorger.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/hill_giant_herdgorger.txt rename to forge-gui/res/cardsfolder/h/hill_giant_herdgorger.txt diff --git a/forge-gui/res/cardsfolder/upcoming/hired_hexblade.txt b/forge-gui/res/cardsfolder/h/hired_hexblade.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/hired_hexblade.txt rename to forge-gui/res/cardsfolder/h/hired_hexblade.txt diff --git a/forge-gui/res/cardsfolder/upcoming/hive_of_the_eye_tyrant.txt b/forge-gui/res/cardsfolder/h/hive_of_the_eye_tyrant.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/hive_of_the_eye_tyrant.txt rename to forge-gui/res/cardsfolder/h/hive_of_the_eye_tyrant.txt diff --git a/forge-gui/res/cardsfolder/upcoming/hoard_robber.txt b/forge-gui/res/cardsfolder/h/hoard_robber.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/hoard_robber.txt rename to forge-gui/res/cardsfolder/h/hoard_robber.txt diff --git a/forge-gui/res/cardsfolder/upcoming/hoarding_ogre.txt b/forge-gui/res/cardsfolder/h/hoarding_ogre.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/hoarding_ogre.txt rename to forge-gui/res/cardsfolder/h/hoarding_ogre.txt diff --git a/forge-gui/res/cardsfolder/upcoming/hobgoblin_bandit_lord.txt b/forge-gui/res/cardsfolder/h/hobgoblin_bandit_lord.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/hobgoblin_bandit_lord.txt rename to forge-gui/res/cardsfolder/h/hobgoblin_bandit_lord.txt diff --git a/forge-gui/res/cardsfolder/upcoming/hobgoblin_captain.txt b/forge-gui/res/cardsfolder/h/hobgoblin_captain.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/hobgoblin_captain.txt rename to forge-gui/res/cardsfolder/h/hobgoblin_captain.txt diff --git a/forge-gui/res/cardsfolder/h/hofri_ghostforge.txt b/forge-gui/res/cardsfolder/h/hofri_ghostforge.txt index f942c3cde2f..7fa597e592a 100644 --- a/forge-gui/res/cardsfolder/h/hofri_ghostforge.txt +++ b/forge-gui/res/cardsfolder/h/hofri_ghostforge.txt @@ -5,11 +5,10 @@ PT:4/5 S:Mode$ Continuous | Affected$ Spirit.YouCtrl | AddPower$ 1 | AddToughness$ 1 | AddKeyword$ Trample & Haste | Description$ Spirits you control get +1/+1 and have trample and haste. T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.Other+nonToken+YouCtrl | Execute$ TrigChange | TriggerDescription$ Whenever another nontoken creature you control dies, exile it. If you do, create a token that's a copy of that creature, except it's a Spirit in addition to its other types and it has "When this creature leaves the battlefield, return the exiled card to its owner's graveyard." SVar:TrigChange:DB$ ChangeZone | Origin$ Graveyard | Destination$ Exile | Defined$ TriggeredNewCardLKICopy | RememberChanged$ True | SubAbility$ DBCopy -SVar:DBCopy:DB$ CopyPermanent | Defined$ TriggeredCardLKICopy | AddTypes$ Spirit | ConditionDefined$ TriggeredNewCardLKICopy | ConditionPresent$ Card | ConditionCompare$ EQExiledCount | ImprintTokens$ True | TokenRemembered$ Remembered | SubAbility$ DBAnimate -SVar:DBAnimate:DB$ Animate | Defined$ Imprinted | Duration$ Permanent | Triggers$ TrigLeavesBattlefield | sVars$ TrigReturn | SubAbility$ DBCleanup -SVar:TrigLeavesBattlefield:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.Self | Execute$ TrigReturn | TriggerDescription$ When this creature leaves the battlefield, return the exiled card to your graveyard. -SVar:TrigReturn:DB$ ChangeZone | Origin$ Exile | Destination$ Graveyard | Defined$ Remembered -SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearImprinted$ True +SVar:DBCopy:DB$ CopyPermanent | Defined$ TriggeredCardLKICopy | AddTypes$ Spirit | AddSVars$ HofriTrigReturn | AddTriggers$ TrigLeavesBattlefield | ConditionDefined$ TriggeredNewCardLKICopy | ConditionPresent$ Card | ConditionCompare$ EQExiledCount | TokenRemembered$ Remembered | SubAbility$ DBCleanup +SVar:TrigLeavesBattlefield:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.Self | Execute$ HofriTrigReturn | TriggerDescription$ When this creature leaves the battlefield, return the exiled card to your graveyard. +SVar:HofriTrigReturn:DB$ ChangeZone | Origin$ Exile | Destination$ Graveyard | Defined$ Remembered +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:ExiledCount:Count$RememberedSize DeckHas:Ability$Token DeckHints:Type$Spirit diff --git a/forge-gui/res/cardsfolder/h/holy_avenger.txt b/forge-gui/res/cardsfolder/h/holy_avenger.txt new file mode 100644 index 00000000000..38d8238625c --- /dev/null +++ b/forge-gui/res/cardsfolder/h/holy_avenger.txt @@ -0,0 +1,9 @@ +Name:Holy Avenger +ManaCost:2 W +Types:Artifact Equipment +S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddKeyword$ Double Strike | Description$ Equipped creature has double strike. +T:Mode$ DamageDealtOnce | CombatDamage$ True | ValidSource$ Creature.EquippedBy | Execute$ TrigChangeZone | TriggerZones$ Battlefield | OptionalDecider$ You | TriggerDescription$ Whenever equipped creature deals combat damage, you may put an Aura card from your hand onto the battlefield attached to it. +SVar:TrigChangeZone:DB$ ChangeZone | Origin$ Hand | Destination$ Battlefield | ChangeType$ Aura.CanEnchantEquippedBy | AttachedTo$ TriggeredSource +K:Equip:2 W +DeckHints:Type$Aura +Oracle:Equipped creature has double strike.\nWhenever equipped creature deals combat damage, you may put an Aura card from your hand onto the battlefield attached to it.\nEquip {2}{W} diff --git a/forge-gui/res/cardsfolder/upcoming/hulking_bugbear.txt b/forge-gui/res/cardsfolder/h/hulking_bugbear.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/hulking_bugbear.txt rename to forge-gui/res/cardsfolder/h/hulking_bugbear.txt diff --git a/forge-gui/res/cardsfolder/upcoming/hunters_mark.txt b/forge-gui/res/cardsfolder/h/hunters_mark.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/hunters_mark.txt rename to forge-gui/res/cardsfolder/h/hunters_mark.txt diff --git a/forge-gui/res/cardsfolder/h/hurl_through_hell.txt b/forge-gui/res/cardsfolder/h/hurl_through_hell.txt new file mode 100644 index 00000000000..de60ed330bb --- /dev/null +++ b/forge-gui/res/cardsfolder/h/hurl_through_hell.txt @@ -0,0 +1,8 @@ +Name:Hurl Through Hell +ManaCost:2 B R +Types:Instant +A:SP$ ChangeZone | Cost$ 2 B R | ValidTgts$ Creature | TgtPrompt$ Select target creature | Origin$ Battlefield | Destination$ Exile | RememberChanged$ True | SubAbility$ DBEffect | SpellDescription$ Exile target creature. Until the end of your next turn, you may cast that card and you may spend mana as though it were mana of any color to cast that spell. +SVar:DBEffect:DB$ Effect | StaticAbilities$ STPlay | RememberObjects$ Remembered | ForgetOnMoved$ Exile | Duration$ UntilTheEndOfYourNextTurn | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +SVar:STPlay:Mode$ Continuous | Affected$ Card.nonLand+IsRemembered | AffectedZone$ Exile | EffectZone$ Command | MayPlay$ True | MayPlayIgnoreColor$ True | Description$ You may cast the exiled card and you may spend mana as though it were mana of any color to cast that spell. +Oracle:Exile target creature. Until the end of your next turn, you may cast that card and you may spend mana as though it were mana of any color to cast that spell. diff --git a/forge-gui/res/cardsfolder/upcoming/icingdeath_frost_tyrant.txt b/forge-gui/res/cardsfolder/i/icingdeath_frost_tyrant.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/icingdeath_frost_tyrant.txt rename to forge-gui/res/cardsfolder/i/icingdeath_frost_tyrant.txt diff --git a/forge-gui/res/cardsfolder/i/idol_of_oblivion.txt b/forge-gui/res/cardsfolder/i/idol_of_oblivion.txt index eabaa262ef7..3f4bab2954a 100644 --- a/forge-gui/res/cardsfolder/i/idol_of_oblivion.txt +++ b/forge-gui/res/cardsfolder/i/idol_of_oblivion.txt @@ -1,7 +1,7 @@ Name:Idol of Oblivion ManaCost:2 Types:Artifact -A:AB$ Draw | Cost$ T | NumCards$ 1 | CheckSVar$ X | SpellDescription$ Draw a card. Activate only if you could a token this turn. +A:AB$ Draw | Cost$ T | NumCards$ 1 | CheckSVar$ X | SpellDescription$ Draw a card. Activate only if you created a token this turn. SVar:X:Count$ThisTurnEntered_Battlefield_Card.token+YouCtrl A:AB$ Token | Cost$ 8 T Sac<1/CARDNAME> | TokenAmount$ 1 | TokenScript$ c_10_10_eldrazi | TokenOwner$ You | LegacyImage$ c c 10 eldrazi c19 | SpellDescription$ Create a 10/10 colorless Eldrazi creature token. Oracle:{T}: Draw a card. Activate only if you created a token this turn.\n{8}, {T}, Sacrifice Idol of Oblivion: Create a 10/10 colorless Eldrazi creature token. diff --git a/forge-gui/res/cardsfolder/upcoming/improvised_weaponry.txt b/forge-gui/res/cardsfolder/i/improvised_weaponry.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/improvised_weaponry.txt rename to forge-gui/res/cardsfolder/i/improvised_weaponry.txt diff --git a/forge-gui/res/cardsfolder/i/inferno_of_the_star_mounts.txt b/forge-gui/res/cardsfolder/i/inferno_of_the_star_mounts.txt new file mode 100644 index 00000000000..e38ae662446 --- /dev/null +++ b/forge-gui/res/cardsfolder/i/inferno_of_the_star_mounts.txt @@ -0,0 +1,12 @@ +Name:Inferno of the Star Mounts +ManaCost:4 R R +Types:Legendary Creature Dragon +PT:6/6 +K:CARDNAME can't be countered. +K:Flying +K:Haste +A:AB$ Pump | Cost$ R | Defined$ Self | NumAtt$ +1 | SubAbility$ DBImmediateTrigger | SpellDescription$ CARDNAME gets +1/+0 until end of turn. When its power becomes 20 this way, it deals 20 damage to any target. +SVar:DBImmediateTrigger:DB$ ImmediateTrigger | Execute$ TrigDealDamage | ConditionCheckSVar$ X | ConditionSVarCompare$ EQ20 | TriggerDescription$ When its power becomes 20 this way, it deals 20 damage to any target. +SVar:TrigDealDamage:DB$ DealDamage | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target | NumDmg$ 20 +SVar:X:Count$CardPower +Oracle:This spell can’t be countered.\nFlying, haste\n{R}: Inferno of the Star Mounts gets +1/+0 until end of turn. When its power becomes 20 this way, it deals 20 damage to any target. diff --git a/forge-gui/res/cardsfolder/upcoming/ingenious_smith.txt b/forge-gui/res/cardsfolder/i/ingenious_smith.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/ingenious_smith.txt rename to forge-gui/res/cardsfolder/i/ingenious_smith.txt diff --git a/forge-gui/res/cardsfolder/upcoming/inspiring_bard.txt b/forge-gui/res/cardsfolder/i/inspiring_bard.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/inspiring_bard.txt rename to forge-gui/res/cardsfolder/i/inspiring_bard.txt diff --git a/forge-gui/res/cardsfolder/upcoming/instrument_of_the_bards.txt b/forge-gui/res/cardsfolder/i/instrument_of_the_bards.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/instrument_of_the_bards.txt rename to forge-gui/res/cardsfolder/i/instrument_of_the_bards.txt diff --git a/forge-gui/res/cardsfolder/upcoming/intrepid_outlander.txt b/forge-gui/res/cardsfolder/i/intrepid_outlander.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/intrepid_outlander.txt rename to forge-gui/res/cardsfolder/i/intrepid_outlander.txt diff --git a/forge-gui/res/cardsfolder/upcoming/iron_golem.txt b/forge-gui/res/cardsfolder/i/iron_golem.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/iron_golem.txt rename to forge-gui/res/cardsfolder/i/iron_golem.txt diff --git a/forge-gui/res/cardsfolder/upcoming/iymrith_desert_doom.txt b/forge-gui/res/cardsfolder/i/iymrith_desert_doom.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/iymrith_desert_doom.txt rename to forge-gui/res/cardsfolder/i/iymrith_desert_doom.txt diff --git a/forge-gui/res/cardsfolder/upcoming/jaded_sell_sword.txt b/forge-gui/res/cardsfolder/j/jaded_sell_sword.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/jaded_sell_sword.txt rename to forge-gui/res/cardsfolder/j/jaded_sell_sword.txt diff --git a/forge-gui/res/cardsfolder/upcoming/kalain_reclusive_painter.txt b/forge-gui/res/cardsfolder/k/kalain_reclusive_painter.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/kalain_reclusive_painter.txt rename to forge-gui/res/cardsfolder/k/kalain_reclusive_painter.txt diff --git a/forge-gui/res/cardsfolder/k/karazikar_the_eye_tyrant.txt b/forge-gui/res/cardsfolder/k/karazikar_the_eye_tyrant.txt new file mode 100644 index 00000000000..deb49c3e621 --- /dev/null +++ b/forge-gui/res/cardsfolder/k/karazikar_the_eye_tyrant.txt @@ -0,0 +1,11 @@ +Name:Karazikar, the Eye Tyrant +ManaCost:3 B R +Types:Legendary Creature Beholder +PT:5/5 +T:Mode$ AttackersDeclaredOneTarget | ValidAttackers$ Creature.YouCtrl | AttackedTarget$ Player | Execute$ TrigTap | TriggerZones$ Battlefield | TriggerDescription$ Whenever you attack a player, tap target creature that player controls and goad it. (Until your next turn, that creature attacks each combat if able and attacks a player other than you if able.) +SVar:TrigTap:DB$ Tap | ValidTgts$ Creature | TgtPrompt$ Select target creature that player controls | TargetsWithDefinedController$ TriggeredAttackedTarget | SubAbility$ DBGoad +SVar:DBGoad:DB$ Goad | Defined$ Targeted +T:Mode$ AttackersDeclaredOneTarget | AttackingPlayer$ Player.Opponent | AttackedTarget$ Opponent | Execute$ TrigDraw | TriggerZones$ Battlefield | TriggerDescription$ Whenever an opponent attacks another one of your opponents, you and the attacking player each draw a card and lose 1 life. +SVar:TrigDraw:DB$ Draw | NumCards$ 1 | Defined$ TriggeredAttackingPlayerAndYou | SubAbility$ DBLoseLife +SVar:DBLoseLife:DB$ LoseLife | Defined$ TriggeredAttackingPlayerAndYou | LifeAmount$ 1 +Oracle:Whenever you attack a player, tap target creature that player controls and goad it. (Until your next turn, that creature attacks each combat if able and attacks a player other than you if able.)\nWhenever an opponent attacks another one of your opponents, you and the attacking player each draw a card and lose 1 life. diff --git a/forge-gui/res/cardsfolder/upcoming/keen_eared_sentry.txt b/forge-gui/res/cardsfolder/k/keen_eared_sentry.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/keen_eared_sentry.txt rename to forge-gui/res/cardsfolder/k/keen_eared_sentry.txt diff --git a/forge-gui/res/cardsfolder/upcoming/kick_in_the_door.txt b/forge-gui/res/cardsfolder/k/kick_in_the_door.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/kick_in_the_door.txt rename to forge-gui/res/cardsfolder/k/kick_in_the_door.txt diff --git a/forge-gui/res/cardsfolder/k/klauth_unrivaled_ancient.txt b/forge-gui/res/cardsfolder/k/klauth_unrivaled_ancient.txt new file mode 100644 index 00000000000..2de586c77b0 --- /dev/null +++ b/forge-gui/res/cardsfolder/k/klauth_unrivaled_ancient.txt @@ -0,0 +1,11 @@ +Name:Klauth, Unrivaled Ancient +ManaCost:5 R G +Types:Legendary Creature Dragon +PT:4/4 +K:Flying +K:Haste +T:Mode$ Attacks | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigMana | TriggerDescription$ Whenever CARDNAME attacks, add X mana in any combination of colors, where X is the total power of attacking creatures. This mana can be used only to cast spells. Until end of turn, you don't lose this mana as steps and phases end. +SVar:TrigMana:DB$ Mana | Produced$ Combo Any | Amount$ X | PersistentMana$ True | RestrictValid$ Card +SVar:X:Count$SumPower_Creature.attacking +SVar:HasAttackEffect:TRUE +Oracle:Flying, haste\nWhenever Klauth, Unrivaled Ancient attacks, add X mana in any combination of colors, where X is the total power of attacking creatures. This mana can be used only to cast spells. Until end of turn, you don't lose this mana as steps and phases end. diff --git a/forge-gui/res/cardsfolder/k/klauths_will.txt b/forge-gui/res/cardsfolder/k/klauths_will.txt new file mode 100644 index 00000000000..b7e8bdf1cd4 --- /dev/null +++ b/forge-gui/res/cardsfolder/k/klauths_will.txt @@ -0,0 +1,10 @@ +Name:Klauth's Will +ManaCost:X R R G +Types:Instant +A:SP$ Charm | Cost$ X R R G | MinCharmNum$ 1 | CharmNum$ Y | Choices$ DBDamage,DBDestroy | AdditionalDescription$ If you control a commander as you cast this spell, you may choose both. +SVar:DBDamage:DB$ DamageAll | ValidCards$ Creature.withoutFlying | NumDmg$ X | SpellDescription$ Breathe Flame — CARDNAME deals X damage to each creature without flying. +SVar:DBDestroy:DB$ Destroy | TargetMin$ 0 | TargetMax$ X | ValidTgts$ Artifact,Enchantment | TgtPrompt$ Select up to X target artifacts and/or enchantments | SpellDescription$ Smash Relics — Destroy up to X target artifacts and/or enchantments. +SVar:X:Count$xPaid +SVar:Y:Count$Compare Z GE1.2.1 +SVar:Z:Count$Valid Card.IsCommander+YouCtrl +Oracle:Choose one. If you control a commander as you cast this spell, you may choose both.\n• Breathe Flame — Klauth's Will deals X damage to each creature without flying.\n• Smash Relics — Destroy up to X target artifacts and/or enchantments. diff --git a/forge-gui/res/cardsfolder/upcoming/krydle_of_baldurs_gate.txt b/forge-gui/res/cardsfolder/k/krydle_of_baldurs_gate.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/krydle_of_baldurs_gate.txt rename to forge-gui/res/cardsfolder/k/krydle_of_baldurs_gate.txt diff --git a/forge-gui/res/cardsfolder/upcoming/lair_of_the_hydra.txt b/forge-gui/res/cardsfolder/l/lair_of_the_hydra.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/lair_of_the_hydra.txt rename to forge-gui/res/cardsfolder/l/lair_of_the_hydra.txt diff --git a/forge-gui/res/cardsfolder/upcoming/leather_armor.txt b/forge-gui/res/cardsfolder/l/leather_armor.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/leather_armor.txt rename to forge-gui/res/cardsfolder/l/leather_armor.txt diff --git a/forge-gui/res/cardsfolder/upcoming/lightfoot_rogue.txt b/forge-gui/res/cardsfolder/l/lightfoot_rogue.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/lightfoot_rogue.txt rename to forge-gui/res/cardsfolder/l/lightfoot_rogue.txt diff --git a/forge-gui/res/cardsfolder/upcoming/loathsome_troll.txt b/forge-gui/res/cardsfolder/l/loathsome_troll.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/loathsome_troll.txt rename to forge-gui/res/cardsfolder/l/loathsome_troll.txt diff --git a/forge-gui/res/cardsfolder/upcoming/long_rest.txt b/forge-gui/res/cardsfolder/l/long_rest.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/long_rest.txt rename to forge-gui/res/cardsfolder/l/long_rest.txt diff --git a/forge-gui/res/cardsfolder/upcoming/lost_mine_of_phandelver.txt b/forge-gui/res/cardsfolder/l/lost_mine_of_phandelver.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/lost_mine_of_phandelver.txt rename to forge-gui/res/cardsfolder/l/lost_mine_of_phandelver.txt diff --git a/forge-gui/res/cardsfolder/upcoming/loyal_warhound.txt b/forge-gui/res/cardsfolder/l/loyal_warhound.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/loyal_warhound.txt rename to forge-gui/res/cardsfolder/l/loyal_warhound.txt diff --git a/forge-gui/res/cardsfolder/upcoming/lurking_roper.txt b/forge-gui/res/cardsfolder/l/lurking_roper.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/lurking_roper.txt rename to forge-gui/res/cardsfolder/l/lurking_roper.txt diff --git a/forge-gui/res/cardsfolder/m/maddening_hex.txt b/forge-gui/res/cardsfolder/m/maddening_hex.txt new file mode 100644 index 00000000000..a0d18f59040 --- /dev/null +++ b/forge-gui/res/cardsfolder/m/maddening_hex.txt @@ -0,0 +1,12 @@ +Name:Maddening Hex +ManaCost:1 R R +Types:Enchantment Aura Curse +K:Enchant player +A:SP$ Attach | Cost$ 1 R R | ValidTgts$ Player | AILogic$ Curse +T:Mode$ SpellCast | ValidCard$ Card.nonCreature | ValidActivatingPlayer$ Player.EnchantedBy | TriggerZones$ Battlefield | Execute$ TrigRollDice | TriggerDescription$ Whenever enchanted player casts a noncreature spell, roll a d6. CARDNAME deals damage to that player equal to the result. Then attach CARDNAME to another one of your opponents chosen at random. +SVar:TrigRollDice:DB$ RollDice | ResultSVar$ X | SubAbility$ DBDamage +SVar:DBDamage:DB$ DealDamage | Defined$ Player.EnchantedBy | NumDmg$ X | SubAbility$ DBChoose +SVar:DBChoose:DB$ ChoosePlayer | Defined$ You | Choices$ Player.Opponent+!EnchantedBy | Random$ True | SubAbility$ DBAttach +SVar:DBAttach:DB$ Attach | Defined$ ChosenPlayer | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearChosenPlayer$ True +Oracle:Enchant player\nWhenever enchanted player casts a noncreature spell, roll a d6. Maddening Hex deals damage to that player equal to the result. Then attach Maddening Hex to another one of your opponents chosen at random. diff --git a/forge-gui/res/cardsfolder/upcoming/magic_missile.txt b/forge-gui/res/cardsfolder/m/magic_missile.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/magic_missile.txt rename to forge-gui/res/cardsfolder/m/magic_missile.txt diff --git a/forge-gui/res/cardsfolder/upcoming/manticore.txt b/forge-gui/res/cardsfolder/m/manticore.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/manticore.txt rename to forge-gui/res/cardsfolder/m/manticore.txt diff --git a/forge-gui/res/cardsfolder/m/mascot_exhibition.txt b/forge-gui/res/cardsfolder/m/mascot_exhibition.txt index 020f50f2b4c..220c8dfe951 100644 --- a/forge-gui/res/cardsfolder/m/mascot_exhibition.txt +++ b/forge-gui/res/cardsfolder/m/mascot_exhibition.txt @@ -1,9 +1,6 @@ Name:Mascot Exhibition ManaCost:7 Types:Sorcery Lesson -A:SP$ Token | Cost$ 7 | TokenAmount$ 1 | TokenScript$ wb_2_1_inkling_flying | TokenOwner$ You | SubAbility$ DBSpiritToken | ChangeZoneTable$ True | SpellDescription$ Create a 2/1 white and black Inkling creature token with flying, -SVar:DBSpiritToken:DB$ Token | TokenAmount$ 1 | TokenScript$ rw_3_2_spirit | TokenOwner$ You | SubAbility$ DBElemToken | SpellDescription$ a 3/2 red and white Spirit creature token, -SVar:DBElemToken:DB$ Token | TokenAmount$ 1 | TokenScript$ ur_4_4_elemental | TokenOwner$ You | SubAbility$ DBResolve | SpellDescription$ and a 4/4 blue and red Elemental creature token. -SVar:DBResolve:DB$ ChangeZoneResolve +A:SP$ Token | Cost$ 7 | TokenAmount$ 1 | TokenScript$ wb_2_1_inkling_flying,rw_3_2_spirit,ur_4_4_elemental | TokenOwner$ You | SpellDescription$ Create a 2/1 white and black Inkling creature token with flying, a 3/2 red and white Spirit creature token, and a 4/4 blue and red Elemental creature token. DeckHas:Ability$Token Oracle:Create a 2/1 white and black Inkling creature token with flying, a 3/2 red and white Spirit creature token, and a 4/4 blue and red Elemental creature token. diff --git a/forge-gui/res/cardsfolder/upcoming/meteor_swarm.txt b/forge-gui/res/cardsfolder/m/meteor_swarm.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/meteor_swarm.txt rename to forge-gui/res/cardsfolder/m/meteor_swarm.txt diff --git a/forge-gui/res/cardsfolder/m/midnight_pathlighter.txt b/forge-gui/res/cardsfolder/m/midnight_pathlighter.txt new file mode 100644 index 00000000000..4c74fcc3b99 --- /dev/null +++ b/forge-gui/res/cardsfolder/m/midnight_pathlighter.txt @@ -0,0 +1,8 @@ +Name:Midnight Pathlighter +ManaCost:2 W U +Types:Creature Human Wizard +PT:2/3 +S:Mode$ CantBlockBy | ValidAttacker$ Creature.YouCtrl | ValidBlocker$ Creature.nonLegendary | Description$ Creatures you control can't be blocked except by legendary creatures. +T:Mode$ DamageDoneOnce | CombatDamage$ True | ValidSource$ Creature.YouCtrl | TriggerZones$ Battlefield | ValidTarget$ Player | Execute$ TrigVenture | TriggerDescription$ Whenever one or more creatures you control deal combat damage to a player, venture into the dungeon. +SVar:TrigVenture:DB$ Venture +Oracle:Creatures you control can't be blocked except by legendary creatures.\nWhenever one or more creatures you control deal combat damage to a player, venture into the dungeon. (Enter the first room or advance to the next room.) \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/upcoming/mimic.txt b/forge-gui/res/cardsfolder/m/mimic.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/mimic.txt rename to forge-gui/res/cardsfolder/m/mimic.txt diff --git a/forge-gui/res/cardsfolder/upcoming/mind_flayer.txt b/forge-gui/res/cardsfolder/m/mind_flayer.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/mind_flayer.txt rename to forge-gui/res/cardsfolder/m/mind_flayer.txt diff --git a/forge-gui/res/cardsfolder/m/minimus_containment.txt b/forge-gui/res/cardsfolder/m/minimus_containment.txt new file mode 100644 index 00000000000..63153821610 --- /dev/null +++ b/forge-gui/res/cardsfolder/m/minimus_containment.txt @@ -0,0 +1,8 @@ +Name:Minimus Containment +ManaCost:2 W +Types:Enchantment Aura +K:Enchant nonland permanent +A:SP$ Attach | ValidTgts$ Permanent.nonLand | TgtPrompt$ Select target nonland permanent | AILogic$ Curse +S:Mode$ Continuous | Affected$ Permanent.EnchantedBy | AddType$ Artifact & Treasure | RemoveCardTypes$ True | AddAbility$ TreasureSac | RemoveAllAbilities$ True | Description$ Enchanted permanent is a Treasure artifact with "{T}, Sacrifice this artifact: Add one mana of any color," and it loses all other abilities. (If it was a creature, it's no longer a creature.) +SVar:TreasureSac:AB$ Mana | Cost$ T Sac<1/CARDNAME> | Produced$ Any | SpellDescription$ Add one mana of any color. +Oracle:Enchant nonland permanent\nEnchanted permanent is a Treasure artifact with "{T}, Sacrifice this artifact: Add one mana of any color," and it loses all other abilities. (If it was a creature, it's no longer a creature.) diff --git a/forge-gui/res/cardsfolder/upcoming/minion_of_the_mighty.txt b/forge-gui/res/cardsfolder/m/minion_of_the_mighty.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/minion_of_the_mighty.txt rename to forge-gui/res/cardsfolder/m/minion_of_the_mighty.txt diff --git a/forge-gui/res/cardsfolder/m/minn_wily_illusionist.txt b/forge-gui/res/cardsfolder/m/minn_wily_illusionist.txt new file mode 100644 index 00000000000..c839a79c65b --- /dev/null +++ b/forge-gui/res/cardsfolder/m/minn_wily_illusionist.txt @@ -0,0 +1,12 @@ +Name:Minn, Wily Illusionist +ManaCost:1 U U +Types:Legendary Creature Gnome Wizard +PT:1/3 +T:Mode$ Drawn | ValidCard$ Card.YouCtrl | Number$ 2 | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ Whenever you draw your second card each turn, create a 1/1 blue Illusion creature token with "This creature gets +1/+0 for each other Illusion you control." +SVar:TrigToken:DB$ Token | TokenScript$ u_1_1_illusion_other_illusions +T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Illusion.YouCtrl | TriggerZones$ Battlefield | Execute$ TrigChangeZone | OptionalDecider$ You | TriggerDescription$ Whenever an Illusion you control dies, you may put a permanent card with mana value less than or equal to that creature's power from your hand onto the battlefield. +SVar:TrigChangeZone:DB$ ChangeZone | Origin$ Hand | Destination$ Battlefield | ChangeType$ Permanent.cmcLEX+YouOwn | ChangeNum$ 1 | StackDescription$ None +SVar:X:TriggeredCard$CardPower +DeckHas:Ability$Token +DeckHints:Type$Illusion +Oracle:Whenever you draw your second card each turn, create a 1/1 blue Illusion creature token with "This creature gets +1/+0 for each other Illusion you control."\nWhenever an Illusion you control dies, you may put a permanent card with mana value less than or equal to that creature's power from your hand onto the battlefield. diff --git a/forge-gui/res/cardsfolder/upcoming/minsc_beloved_ranger.txt b/forge-gui/res/cardsfolder/m/minsc_beloved_ranger.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/minsc_beloved_ranger.txt rename to forge-gui/res/cardsfolder/m/minsc_beloved_ranger.txt diff --git a/forge-gui/res/cardsfolder/upcoming/monk_class.txt b/forge-gui/res/cardsfolder/m/monk_class.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/monk_class.txt rename to forge-gui/res/cardsfolder/m/monk_class.txt diff --git a/forge-gui/res/cardsfolder/upcoming/monk_of_the_open_hand.txt b/forge-gui/res/cardsfolder/m/monk_of_the_open_hand.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/monk_of_the_open_hand.txt rename to forge-gui/res/cardsfolder/m/monk_of_the_open_hand.txt diff --git a/forge-gui/res/cardsfolder/upcoming/moon_blessed_cleric.txt b/forge-gui/res/cardsfolder/m/moon_blessed_cleric.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/moon_blessed_cleric.txt rename to forge-gui/res/cardsfolder/m/moon_blessed_cleric.txt diff --git a/forge-gui/res/cardsfolder/upcoming/mordenkainen.txt b/forge-gui/res/cardsfolder/m/mordenkainen.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/mordenkainen.txt rename to forge-gui/res/cardsfolder/m/mordenkainen.txt diff --git a/forge-gui/res/cardsfolder/upcoming/mordenkainens_polymorph.txt b/forge-gui/res/cardsfolder/m/mordenkainens_polymorph.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/mordenkainens_polymorph.txt rename to forge-gui/res/cardsfolder/m/mordenkainens_polymorph.txt diff --git a/forge-gui/res/cardsfolder/upcoming/nadaar_selfless_paladin.txt b/forge-gui/res/cardsfolder/n/nadaar_selfless_paladin.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/nadaar_selfless_paladin.txt rename to forge-gui/res/cardsfolder/n/nadaar_selfless_paladin.txt diff --git a/forge-gui/res/cardsfolder/upcoming/netherese_puzzle_ward.txt b/forge-gui/res/cardsfolder/n/netherese_puzzle_ward.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/netherese_puzzle_ward.txt rename to forge-gui/res/cardsfolder/n/netherese_puzzle_ward.txt diff --git a/forge-gui/res/cardsfolder/upcoming/neverwinter_dryad.txt b/forge-gui/res/cardsfolder/n/neverwinter_dryad.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/neverwinter_dryad.txt rename to forge-gui/res/cardsfolder/n/neverwinter_dryad.txt diff --git a/forge-gui/res/cardsfolder/n/neverwinter_hydra.txt b/forge-gui/res/cardsfolder/n/neverwinter_hydra.txt new file mode 100644 index 00000000000..713a5e7ee19 --- /dev/null +++ b/forge-gui/res/cardsfolder/n/neverwinter_hydra.txt @@ -0,0 +1,12 @@ +Name:Neverwinter Hydra +ManaCost:X X G G +Types:Creature Hydra +PT:0/0 +K:ETBReplacement:Other:RollCounters +SVar:RollCounters:DB$ RollDice | Amount$ X | ETB$ True | ResultSVar$ Result | SubAbility$ DBCounters | SpellDescription$ As CARDNAME enters the battlefield, roll X d6. It enters the battlefield with a number of +1/+1 counters on it equal to the total of those results. +SVar:DBCounters:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ Result | ETB$ True +K:Trample +K:Ward:4 +SVar:X:Count$xPaid +DeckHas:Ability$Counters +Oracle:As Neverwinter Hydra enters the battlefield, roll X d6. It enters with a number of +1/+1 counters on it equal to the total of those results.\nTrample\nWard {4} (Whenever this creature becomes the target of a spell or ability an opponent controls, counter it unless that player pays {4}.) diff --git a/forge-gui/res/cardsfolder/n/nightshade_assassin.txt b/forge-gui/res/cardsfolder/n/nightshade_assassin.txt index 934005aca29..b2f6c1d8e85 100644 --- a/forge-gui/res/cardsfolder/n/nightshade_assassin.txt +++ b/forge-gui/res/cardsfolder/n/nightshade_assassin.txt @@ -6,9 +6,9 @@ K:First Strike K:Madness:1 B T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Any | Destination$ Battlefield | Execute$ TrigReveal | OptionalDecider$ You | TriggerDescription$ When CARDNAME enters the battlefield, you may reveal X black cards in your hand. If you do, target creature gets -X/-X until end of turn. SVar:TrigReveal:DB$ Reveal | Defined$ You | RevealValid$ Card.Black | AnyNumber$ True | RememberRevealed$ True | SubAbility$ DBPump -SVar:DBPump:DB$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ X | NumDef$ X | IsCurse$ True | SubAbility$ DBNightshadeCleanup +SVar:DBPump:DB$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ -X | NumDef$ -X | IsCurse$ True | SubAbility$ DBNightshadeCleanup SVar:DBNightshadeCleanup:DB$ Cleanup | ClearRemembered$ True -SVar:X:Remembered$Amount.Negative +SVar:X:Remembered$Amount AI:RemoveDeck:All SVar:Picture:http://www.wizards.com/global/images/magic/general/nightshade_assassin.jpg Oracle:First strike\nWhen Nightshade Assassin enters the battlefield, you may reveal X black cards in your hand. If you do, target creature gets -X/-X until end of turn.\nMadness {1}{B} (If you discard this card, discard it into exile. When you do, cast it for its madness cost or put it into your graveyard.) diff --git a/forge-gui/res/cardsfolder/n/nightshade_seer.txt b/forge-gui/res/cardsfolder/n/nightshade_seer.txt index a9f72a880e3..fcec5895a31 100644 --- a/forge-gui/res/cardsfolder/n/nightshade_seer.txt +++ b/forge-gui/res/cardsfolder/n/nightshade_seer.txt @@ -3,9 +3,9 @@ ManaCost:3 B Types:Creature Human Wizard PT:1/1 A:AB$ Reveal | Cost$ 2 B T | Defined$ You | RevealValid$ Card.Black | AnyNumber$ True | RememberRevealed$ True | SubAbility$ DBNightshadePump | SpellDescription$ Reveal any number of black cards in your hand. Target creature gets -X/-X until end of turn, where X is the number of cards revealed this way. -SVar:DBNightshadePump:DB$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ NightshadeX | NumDef$ NightshadeX | IsCurse$ True | SubAbility$ DBNightshadeCleanup +SVar:DBNightshadePump:DB$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ -NightshadeX | NumDef$ -NightshadeX | IsCurse$ True | SubAbility$ DBNightshadeCleanup SVar:DBNightshadeCleanup:DB$ Cleanup | ClearRemembered$ True -SVar:NightshadeX:Remembered$Amount.Negative +SVar:NightshadeX:Remembered$Amount AI:RemoveDeck:All SVar:Picture:http://www.wizards.com/global/images/magic/general/nightshade_seer.jpg Oracle:{2}{B}, {T}: Reveal any number of black cards in your hand. Target creature gets -X/-X until end of turn, where X is the number of cards revealed this way. diff --git a/forge-gui/res/cardsfolder/upcoming/ochre_jelly.txt b/forge-gui/res/cardsfolder/o/ochre_jelly.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/ochre_jelly.txt rename to forge-gui/res/cardsfolder/o/ochre_jelly.txt diff --git a/forge-gui/res/cardsfolder/upcoming/old_gnawbone.txt b/forge-gui/res/cardsfolder/o/old_gnawbone.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/old_gnawbone.txt rename to forge-gui/res/cardsfolder/o/old_gnawbone.txt diff --git a/forge-gui/res/cardsfolder/upcoming/orb_of_dragonkind.txt b/forge-gui/res/cardsfolder/o/orb_of_dragonkind.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/orb_of_dragonkind.txt rename to forge-gui/res/cardsfolder/o/orb_of_dragonkind.txt diff --git a/forge-gui/res/cardsfolder/o/orcus_prince_of_undeath.txt b/forge-gui/res/cardsfolder/o/orcus_prince_of_undeath.txt new file mode 100644 index 00000000000..1465593da94 --- /dev/null +++ b/forge-gui/res/cardsfolder/o/orcus_prince_of_undeath.txt @@ -0,0 +1,16 @@ +Name:Orcus, Prince of Undeath +ManaCost:X 2 B R +Types:Legendary Creature Demon +PT:5/3 +K:Flying +K:Trample +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigCharm | TriggerDescription$ When CARDNAME enters the battlefield, ABILITY +SVar:TrigCharm:DB$ Charm | Choices$ DBPumpAll,DBReturn +SVar:DBPumpAll:DB$ PumpAll | NumAtt$ -X | NumDef$ -X | ValidCards$ Creature.Other | IsCurse$ True | SubAbility$ DBLoseLife | SpellDescription$ Each other creature gets -X/-X until end of turn. You lose X life. +SVar:DBLoseLife:DB$ LoseLife | LifeAmount$ X | StackDescription$ None +SVar:DBReturn:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | TargetMin$ 0 | TargetMax$ X | MaxTotalTargetCMC$ X | ValidTgts$ Creature.YouOwn | SubAbility$ DBPump | TgtPrompt$ Select up to X target creature cards with total mana value X or less | SpellDescription$ Return up to X target creature cards with total mana value X or less from your graveyard to the battlefield. They gain haste until end of turn. +SVar:DBPump:DB$ Pump | Defined$ Targeted | KW$ Haste | StackDescription$ None +SVar:X:Count$xPaid +SVar:PlayMain1:TRUE +DeckHas:Ability$Graveyard +Oracle:Flying, trample\nWhen Orcus, Prince of Undeath enters the battlefield, choose one —\n• Each other creature gets -X/-X until end of turn. You lose X life.\n• Return up to X target creature cards with total mana value X or less from your graveyard to the battlefield. They gain haste until end of turn. diff --git a/forge-gui/res/cardsfolder/upcoming/oswald_fiddlebender.txt b/forge-gui/res/cardsfolder/o/oswald_fiddlebender.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/oswald_fiddlebender.txt rename to forge-gui/res/cardsfolder/o/oswald_fiddlebender.txt diff --git a/forge-gui/res/cardsfolder/upcoming/owlbear.txt b/forge-gui/res/cardsfolder/o/owlbear.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/owlbear.txt rename to forge-gui/res/cardsfolder/o/owlbear.txt diff --git a/forge-gui/res/cardsfolder/upcoming/+2_mace.txt b/forge-gui/res/cardsfolder/p/+2_mace.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/+2_mace.txt rename to forge-gui/res/cardsfolder/p/+2_mace.txt diff --git a/forge-gui/res/cardsfolder/upcoming/paladin_class.txt b/forge-gui/res/cardsfolder/p/paladin_class.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/paladin_class.txt rename to forge-gui/res/cardsfolder/p/paladin_class.txt diff --git a/forge-gui/res/cardsfolder/upcoming/paladins_shield.txt b/forge-gui/res/cardsfolder/p/paladins_shield.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/paladins_shield.txt rename to forge-gui/res/cardsfolder/p/paladins_shield.txt diff --git a/forge-gui/res/cardsfolder/p/parallel_lives.txt b/forge-gui/res/cardsfolder/p/parallel_lives.txt index e134337e6e1..ed629c1e09c 100644 --- a/forge-gui/res/cardsfolder/p/parallel_lives.txt +++ b/forge-gui/res/cardsfolder/p/parallel_lives.txt @@ -1,8 +1,6 @@ Name:Parallel Lives ManaCost:3 G Types:Enchantment -R:Event$ CreateToken | ActiveZones$ Battlefield | ValidPlayer$ You | ReplaceWith$ DoubleToken | EffectOnly$ True | Description$ If an effect would create one or more tokens under your control, it creates twice that many of those tokens instead. -SVar:DoubleToken:DB$ ReplaceEffect | VarName$ TokenNum | VarValue$ X -SVar:X:ReplaceCount$TokenNum/Twice -SVar:Picture:http://www.wizards.com/global/images/magic/general/parallel_lives.jpg +R:Event$ CreateToken | ActiveZones$ Battlefield | ValidToken$ Card.YouCtrl | ReplaceWith$ DoubleToken | EffectOnly$ True | Description$ If an effect would create one or more tokens under your control, it creates twice that many of those tokens instead. +SVar:DoubleToken:DB$ ReplaceToken | Type$ Amount | ValidCard$ Card.YouCtrl Oracle:If an effect would create one or more tokens under your control, it creates twice that many of those tokens instead. diff --git a/forge-gui/res/cardsfolder/upcoming/pixie_guide.txt b/forge-gui/res/cardsfolder/p/pixie_guide.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/pixie_guide.txt rename to forge-gui/res/cardsfolder/p/pixie_guide.txt diff --git a/forge-gui/res/cardsfolder/p/plague_of_vermin.txt b/forge-gui/res/cardsfolder/p/plague_of_vermin.txt index c124f930313..4e8e3870c91 100644 --- a/forge-gui/res/cardsfolder/p/plague_of_vermin.txt +++ b/forge-gui/res/cardsfolder/p/plague_of_vermin.txt @@ -1,17 +1,16 @@ Name:Plague of Vermin ManaCost:6 B Types:Sorcery -A:SP$ Effect | Cost$ 6 B | Name$ Plague of Vermin Life Paid | EffectOwner$ Player | ImprintOnHost$ True | Mutable$ True | Duration$ Permanent | SubAbility$ DBRepeat | StackDescription$ SpellDescription | SpellDescription$ Starting with you, each player may pay any amount of life. Repeat this process until no one pays life. Each player creates a 1/1 black Rat creature token for each 1 life they paid this way. +A:SP$ Effect | Cost$ 6 B | Name$ Plague of Vermin Life Paid | EffectOwner$ Player | ImprintOnHost$ True | Duration$ Permanent | SubAbility$ DBRepeat | StackDescription$ SpellDescription | SpellDescription$ Starting with you, each player may pay any amount of life. Repeat this process until no one pays life. Each player creates a 1/1 black Rat creature token for each 1 life they paid this way. SVar:DBRepeat:DB$ Repeat | RepeatSubAbility$ DBResetCheck | RepeatCheckSVar$ NumPlayerGiveup | RepeatSVarCompare$ LTTotalPlayer | SubAbility$ DBRepeatToken SVar:DBResetCheck:DB$ StoreSVar | SVar$ NumPlayerGiveup | Type$ Number | Expression$ 0 | SubAbility$ DBRepeatChoice SVar:DBRepeatChoice:DB$ RepeatEach | StartingWithActivator$ True | RepeatSubAbility$ DBChoice | RepeatPlayers$ Player SVar:DBChoice:DB$ ChooseNumber | Defined$ Player.IsRemembered | Max$ LifeTotal | AILogic$ Vermin | ListTitle$ Pay Any Amount of Life | SubAbility$ DBCheckPaid SVar:DBCheckPaid:DB$ StoreSVar | SVar$ NumPlayerGiveup | Type$ CountSVar | Expression$ NumPlayerGiveup/Plus.1 | ConditionCheckSVar$ X | ConditionSVarCompare$ EQ0 | SubAbility$ DBStore -SVar:DBStore:DB$ PutCounter | Defined$ Imprinted.namedPlague of Vermin Life Paid+OwnedBy Player.IsRemembered | CounterNum$ X | Placer$ Player.IsRemembered | CounterType$ PLAGUE | ConditionCheckSVar$ X | ConditionSVarCompare$ GE1 | UnlessCost$ PayLife | UnlessPayer$ Player.IsRemembered | UnlessSwitched$ True | UnlessResolveSubs$ WhenNotPaid | SubAbility$ DBGiveUp | SpellDescription$ You may pay any amount of life. +SVar:DBStore:DB$ PutCounter | Defined$ ValidCommand Effect.namedPlague of Vermin Life Paid+OwnedBy Player.IsRemembered | CounterNum$ X | Placer$ Player.IsRemembered | CounterType$ PLAGUE | ConditionCheckSVar$ X | ConditionSVarCompare$ GE1 | UnlessCost$ PayLife | UnlessPayer$ Player.IsRemembered | UnlessSwitched$ True | UnlessResolveSubs$ WhenNotPaid | SubAbility$ DBGiveUp | SpellDescription$ You may pay any amount of life. SVar:DBGiveUp:DB$ StoreSVar | SVar$ NumPlayerGiveup | Type$ CountSVar | Expression$ NumPlayerGiveup/Plus.1 | ConditionCheckSVar$ X | ConditionSVarCompare$ GE1 SVar:DBRepeatToken:DB$ RepeatEach | StartingWithActivator$ True | RepeatSubAbility$ DBToken | RepeatPlayers$ Player | SubAbility$ DBFinalReset -SVar:DBToken:DB$ Token | TokenAmount$ LifePaidAmount | TokenScript$ b_1_1_rat | TokenOwner$ Player.IsRemembered | StackDescription$ None | SubAbility$ DBRestoreImmutable -SVar:DBRestoreImmutable:DB$ Animate | Defined$ Imprinted.namedPlague of Vermin Life Paid+OwnedBy Player.IsRemembered | Duration$ Permanent | Immutable$ True +SVar:DBToken:DB$ Token | TokenAmount$ LifePaidAmount | TokenScript$ b_1_1_rat | TokenOwner$ Player.IsRemembered | StackDescription$ None SVar:DBFinalReset:DB$ StoreSVar | SVar$ NumPlayerGiveup | Type$ Number | Expression$ 0 | SubAbility$ DBExileEffect SVar:DBExileEffect:DB$ ChangeZone | Defined$ Imprinted | Origin$ Command | Destination$ Exile | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearImprinted$ True diff --git a/forge-gui/res/cardsfolder/p/planar_ally.txt b/forge-gui/res/cardsfolder/p/planar_ally.txt new file mode 100644 index 00000000000..a03358efe76 --- /dev/null +++ b/forge-gui/res/cardsfolder/p/planar_ally.txt @@ -0,0 +1,8 @@ +Name:Planar Ally +ManaCost:3 W W +Types:Creature Angel +PT:3/3 +K:Flying +T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ DBVenture | TriggerDescription$ Whenever CARDNAME enters the battlefield or attacks, venture into the dungeon. (Enter the first room or advance to the next room.) +SVar:DBVenture:DB$ Venture | Defined$ You +Oracle:Flying\nWhenever Planar Ally attacks, venture into the dungeon. diff --git a/forge-gui/res/cardsfolder/upcoming/plate_armor.txt b/forge-gui/res/cardsfolder/p/plate_armor.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/plate_armor.txt rename to forge-gui/res/cardsfolder/p/plate_armor.txt diff --git a/forge-gui/res/cardsfolder/upcoming/plundering_barbarian.txt b/forge-gui/res/cardsfolder/p/plundering_barbarian.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/plundering_barbarian.txt rename to forge-gui/res/cardsfolder/p/plundering_barbarian.txt diff --git a/forge-gui/res/cardsfolder/upcoming/potion_of_healing.txt b/forge-gui/res/cardsfolder/p/potion_of_healing.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/potion_of_healing.txt rename to forge-gui/res/cardsfolder/p/potion_of_healing.txt diff --git a/forge-gui/res/cardsfolder/upcoming/power_of_persuasion.txt b/forge-gui/res/cardsfolder/p/power_of_persuasion.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/power_of_persuasion.txt rename to forge-gui/res/cardsfolder/p/power_of_persuasion.txt diff --git a/forge-gui/res/cardsfolder/upcoming/precipitous_drop.txt b/forge-gui/res/cardsfolder/p/precipitous_drop.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/precipitous_drop.txt rename to forge-gui/res/cardsfolder/p/precipitous_drop.txt diff --git a/forge-gui/res/cardsfolder/upcoming/price_of_loyalty.txt b/forge-gui/res/cardsfolder/p/price_of_loyalty.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/price_of_loyalty.txt rename to forge-gui/res/cardsfolder/p/price_of_loyalty.txt diff --git a/forge-gui/res/cardsfolder/upcoming/priest_of_ancient_lore.txt b/forge-gui/res/cardsfolder/p/priest_of_ancient_lore.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/priest_of_ancient_lore.txt rename to forge-gui/res/cardsfolder/p/priest_of_ancient_lore.txt diff --git a/forge-gui/res/cardsfolder/p/primal_vigor.txt b/forge-gui/res/cardsfolder/p/primal_vigor.txt index 3192f00044e..ff11199dd59 100644 --- a/forge-gui/res/cardsfolder/p/primal_vigor.txt +++ b/forge-gui/res/cardsfolder/p/primal_vigor.txt @@ -1,11 +1,9 @@ Name:Primal Vigor ManaCost:4 G Types:Enchantment -R:Event$ CreateToken | ActiveZones$ Battlefield | ValidPlayer$ Player | ReplaceWith$ DoubleToken | Description$ If one or more tokens would be created, twice that many of those tokens are created instead. -SVar:DoubleToken:DB$ ReplaceEffect | VarName$ TokenNum | VarValue$ X +R:Event$ CreateToken | ActiveZones$ Battlefield | ReplaceWith$ DoubleToken | Description$ If one or more tokens would be created, twice that many of those tokens are created instead. +SVar:DoubleToken:DB$ ReplaceToken | Type$ Amount R:Event$ AddCounter | ActiveZones$ Battlefield | ValidCard$ Creature | ValidCounterType$ P1P1 | ReplaceWith$ DoubleP1P1Counters | Description$ If one or more +1/+1 counters would be put on a creature, twice that many +1/+1 counters are put on that creature instead. SVar:DoubleP1P1Counters:DB$ ReplaceEffect | VarName$ CounterNum | VarValue$ Y -SVar:X:ReplaceCount$TokenNum/Twice SVar:Y:ReplaceCount$CounterNum/Twice -SVar:Picture:http://www.wizards.com/global/images/magic/general/primal_vigor.jpg Oracle:If one or more tokens would be created, twice that many of those tokens are created instead.\nIf one or more +1/+1 counters would be put on a creature, twice that many +1/+1 counters are put on that creature instead. diff --git a/forge-gui/res/cardsfolder/upcoming/prosper_tome_bound.txt b/forge-gui/res/cardsfolder/p/prosper_tome_bound.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/prosper_tome_bound.txt rename to forge-gui/res/cardsfolder/p/prosper_tome_bound.txt diff --git a/forge-gui/res/cardsfolder/p/purple_worm.txt b/forge-gui/res/cardsfolder/p/purple_worm.txt new file mode 100644 index 00000000000..c53e1c3fb90 --- /dev/null +++ b/forge-gui/res/cardsfolder/p/purple_worm.txt @@ -0,0 +1,8 @@ +Name:Purple Worm +ManaCost:5 G G +Types:Creature Worm +PT:8/7 +S:Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Amount$ 2 | EffectZone$ All | CheckSVar$ X | SVarCompare$ GE1 | Description$ CARDNAME costs {2} less to cast if a creature died this turn. +SVar:X:Count$Morbid.1.0 +K:Ward:2 +Oracle:This spell costs {2} less to cast if a creature died this turn.\nWard {2} (Whenever this creature becomes the target of a spell or ability an opponent controls, counter it unless that player pays {2}.) diff --git a/forge-gui/res/cardsfolder/r/radiant_solar.txt b/forge-gui/res/cardsfolder/r/radiant_solar.txt new file mode 100644 index 00000000000..4db6a13e8b3 --- /dev/null +++ b/forge-gui/res/cardsfolder/r/radiant_solar.txt @@ -0,0 +1,12 @@ +Name:Radiant Solar +ManaCost:5 W +Types:Creature Angel +PT:3/6 +K:Flying +K:Lifelink +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Creature.Other+nonToken+YouCtrl | Execute$ DBVenture | TriggerDescription$ Whenever CARDNAME or another nontoken creature enters the battlefield under your control, venture into the dungeon. (Enter the first room or advance to the next room.) +SVar:DBVenture:DB$ Venture +A:AB$ Venture | Cost$ W Discard<1/CARDNAME> | SubAbility$ DBGainLife | ActivationZone$ Hand | Defined$ You | SpellDescription$ Venture into the dungeon and you gain 3 life. +SVar:DBGainLife:DB$ GainLife | LifeAmount$ 3 | StackDescription$ None +DeckHas:Ability$LifeGain & Ability$Discard +Oracle:Flying, lifelink\nWhenever Radiant Solar or another nontoken creature enters the battlefield under your control, venture into the dungeon. (Enter the first room or advance to the next room.)\n{W}, Discard Radiant Solar: Venture into the dungeon and you gain 3 life. diff --git a/forge-gui/res/cardsfolder/r/raging_river.txt b/forge-gui/res/cardsfolder/r/raging_river.txt index 4091cb62b91..ad6e1dafcfb 100644 --- a/forge-gui/res/cardsfolder/r/raging_river.txt +++ b/forge-gui/res/cardsfolder/r/raging_river.txt @@ -3,16 +3,16 @@ ManaCost:R R Types:Enchantment T:Mode$ AttackersDeclared | AttackingPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigRepeatDefender | TriggerDescription$ Whenever one or more creatures you control attack, each defending player divides all creatures without flying they control into a "left" pile and a "right" pile. Then, for each attacking creature you control, choose "left" or "right." That creature can't be blocked this combat except by creatures with flying and creatures in a pile with the chosen label. SVar:TrigRepeatDefender:DB$ RepeatEach | RepeatPlayers$ TriggeredAttackedTarget | RepeatSubAbility$ DBDefLeftEffect | SubAbility$ DBAtkLeftRight -SVar:DBDefLeftEffect:DB$ Effect | EffectOwner$ Remembered | Name$ Raging River Left | StaticAbilities$ DBCantBlock | ImprintOnHost$ True | Mutable$ True | Duration$ UntilEndOfCombat | SubAbility$ DBDefRightEffect -SVar:DBDefRightEffect:DB$ Effect | EffectOwner$ Remembered | Name$ Raging River Right | StaticAbilities$ DBCantBlock | ImprintOnHost$ True | Mutable$ True | Duration$ UntilEndOfCombat | SubAbility$ DBDefLeftRight +SVar:DBDefLeftEffect:DB$ Effect | EffectOwner$ Remembered | Name$ Raging River Left | StaticAbilities$ DBCantBlock | ImprintOnHost$ True | Duration$ UntilEndOfCombat | SubAbility$ DBDefRightEffect +SVar:DBDefRightEffect:DB$ Effect | EffectOwner$ Remembered | Name$ Raging River Right | StaticAbilities$ DBCantBlock | ImprintOnHost$ True | Duration$ UntilEndOfCombat | SubAbility$ DBDefLeftRight SVar:DBCantBlock:Mode$ CantBlockBy | ValidAttacker$ Creature.IsRemembered | ValidBlocker$ Creature.withoutFlying+IsNotImprinted+YouCtrl | EffectZone$ Command SVar:DBDefLeftRight:DB$ TwoPiles | Defined$ Remembered | Separator$ Remembered | ValidCards$ Creature.withoutFlying+RememberedPlayerCtrl | Zone$ Battlefield | LeftRightPile$ True | ChosenPile$ DBDefLeftPile | UnchosenPile$ DBDefRightPile | AILogic$ Random | SubAbility$ DBClearImprinted -SVar:DBDefLeftPile:DB$ Animate | Defined$ Imprinted.namedRaging River Left | ImprintCards$ Remembered | Duration$ Permanent | SubAbility$ DBLeftPump -SVar:DBDefRightPile:DB$ Animate | Defined$ Imprinted.namedRaging River Right | ImprintCards$ Remembered | Duration$ Permanent | SubAbility$ DBRightPump +SVar:DBDefLeftPile:DB$ Animate | Defined$ ValidCommand Effect.namedRaging River Left+IsImprinted | ImprintCards$ Remembered | Duration$ Permanent | SubAbility$ DBLeftPump +SVar:DBDefRightPile:DB$ Animate | Defined$ ValidCommand Effect.namedRaging River Right+IsImprinted | ImprintCards$ Remembered | Duration$ Permanent | SubAbility$ DBRightPump SVar:DBClearImprinted:DB$ Cleanup | ClearImprinted$ True SVar:DBAtkLeftRight:DB$ TwoPiles | Defined$ You | Separator$ You | ValidCards$ Creature.attacking+YouCtrl | Zone$ Battlefield | LeftRightPile$ True | ChosenPile$ DBAtkLeftPile | UnchosenPile$ DBAtkRightPile | AILogic$ Random | SubAbility$ DBCleanup -SVar:DBAtkLeftPile:DB$ Animate | Defined$ ValidCommand Effect.namedRaging River Left | RememberObjects$ RememberedCard | Duration$ Permanent | Immutable$ True | SubAbility$ DBLeftPump -SVar:DBAtkRightPile:DB$ Animate | Defined$ ValidCommand Effect.namedRaging River Right | RememberObjects$ RememberedCard | Duration$ Permanent | Immutable$ True | SubAbility$ DBRightPump +SVar:DBAtkLeftPile:DB$ Animate | Defined$ ValidCommand Effect.namedRaging River Left | RememberObjects$ RememberedCard | Duration$ Permanent | SubAbility$ DBLeftPump +SVar:DBAtkRightPile:DB$ Animate | Defined$ ValidCommand Effect.namedRaging River Right | RememberObjects$ RememberedCard | Duration$ Permanent | SubAbility$ DBRightPump SVar:DBLeftPump:DB$ Pump | Defined$ Remembered | KW$ "Left" pile | Duration$ UntilEndOfCombat SVar:DBRightPump:DB$ Pump | Defined$ Remembered | KW$ "Right" pile | Duration$ UntilEndOfCombat SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True diff --git a/forge-gui/res/cardsfolder/upcoming/rally_maneuver.txt b/forge-gui/res/cardsfolder/r/rally_maneuver.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/rally_maneuver.txt rename to forge-gui/res/cardsfolder/r/rally_maneuver.txt diff --git a/forge-gui/res/cardsfolder/upcoming/ranger_class.txt b/forge-gui/res/cardsfolder/r/ranger_class.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/ranger_class.txt rename to forge-gui/res/cardsfolder/r/ranger_class.txt diff --git a/forge-gui/res/cardsfolder/upcoming/rangers_hawk.txt b/forge-gui/res/cardsfolder/r/rangers_hawk.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/rangers_hawk.txt rename to forge-gui/res/cardsfolder/r/rangers_hawk.txt diff --git a/forge-gui/res/cardsfolder/upcoming/rangers_longbow.txt b/forge-gui/res/cardsfolder/r/rangers_longbow.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/rangers_longbow.txt rename to forge-gui/res/cardsfolder/r/rangers_longbow.txt diff --git a/forge-gui/res/cardsfolder/upcoming/ray_of_enfeeblement.txt b/forge-gui/res/cardsfolder/r/ray_of_enfeeblement.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/ray_of_enfeeblement.txt rename to forge-gui/res/cardsfolder/r/ray_of_enfeeblement.txt diff --git a/forge-gui/res/cardsfolder/upcoming/ray_of_frost.txt b/forge-gui/res/cardsfolder/r/ray_of_frost.txt similarity index 93% rename from forge-gui/res/cardsfolder/upcoming/ray_of_frost.txt rename to forge-gui/res/cardsfolder/r/ray_of_frost.txt index 5603ee2b799..9669c1e7324 100644 --- a/forge-gui/res/cardsfolder/upcoming/ray_of_frost.txt +++ b/forge-gui/res/cardsfolder/r/ray_of_frost.txt @@ -3,7 +3,7 @@ ManaCost:1 U Types:Enchantment Aura K:Flash K:Enchant creature -A:SP$ Attach | Cost$ 1 U | ValidTgts$ Creature | AILogic$ Pump +A:SP$ Attach | Cost$ 1 U | ValidTgts$ Creature | AILogic$ KeepTapped T:Mode$ ChangesZone | ValidCard$ Card.Self | Destination$ Battlefield | IsPresent$ Creature.EnchantedBy+Red | Execute$ TrigTap | TriggerDescription$ When CARDNAME enters the battlefield, if enchanted creature is red, tap it. SVar:TrigTap:DB$ Tap | Defined$ Enchanted S:Mode$ Continuous | Affected$ Creature.EnchantedBy+Red | RemoveAllAbilities$ True | Description$ As long as enchanted creature is red, it loses all abilities. diff --git a/forge-gui/res/cardsfolder/upcoming/reapers_talisman.txt b/forge-gui/res/cardsfolder/r/reapers_talisman.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/reapers_talisman.txt rename to forge-gui/res/cardsfolder/r/reapers_talisman.txt diff --git a/forge-gui/res/cardsfolder/r/reckless_endeavor.txt b/forge-gui/res/cardsfolder/r/reckless_endeavor.txt new file mode 100644 index 00000000000..9c413b20f96 --- /dev/null +++ b/forge-gui/res/cardsfolder/r/reckless_endeavor.txt @@ -0,0 +1,8 @@ +Name:Reckless Endeavor +ManaCost:5 R R +Types:Sorcery +A:SP$ RollDice | Amount$ 2 | Sides$ 12 | ChosenSVar$ X | OtherSVar$ Y | SubAbility$ DBDamageAll | StackDescription$ SpellDescription | SpellDescription$ Roll two d12 and choose one result. CARDNAME deals damage equal to that result to each creature. Then create a number of Treasure tokens equal to the other result. +SVar:DBDamageAll:DB$ DamageAll | ValidCards$ Creature | NumDmg$ X | SubAbility$ DBToken | StackDescription$ None +SVar:DBToken:DB$ Token | TokenAmount$ Y | TokenScript$ c_a_treasure_sac +DeckHas:Ability$Token & Ability$Sacrifice +Oracle:Roll two d12 and choose one result. Reckless Endeavor deals damage equal to that result to each creature. Then create a number of Treasure tokens equal to the other result. diff --git a/forge-gui/res/cardsfolder/upcoming/red_dragon.txt b/forge-gui/res/cardsfolder/r/red_dragon.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/red_dragon.txt rename to forge-gui/res/cardsfolder/r/red_dragon.txt diff --git a/forge-gui/res/cardsfolder/r/reject.txt b/forge-gui/res/cardsfolder/r/reject.txt index ca23a04a91e..0b20ada00f6 100644 --- a/forge-gui/res/cardsfolder/r/reject.txt +++ b/forge-gui/res/cardsfolder/r/reject.txt @@ -1,5 +1,5 @@ Name:Reject ManaCost:1 U Types:Instant -A:SP$ Counter | Cost$ 1 U | TargetType$ Spell | TgtPrompt$ Select target creature or planeswalker spell | ValidTgts$ Creature,Planeswalker | UnlessCost$ 3 | Destination$ Exile | SpellDescription$ Counter target spell unless its controller pays {3}. +A:SP$ Counter | Cost$ 1 U | TargetType$ Spell | TgtPrompt$ Select target creature or planeswalker spell | ValidTgts$ Creature,Planeswalker | UnlessCost$ 3 | Destination$ Exile | SpellDescription$ Counter target spell unless its controller pays {3}. If that spell is countered this way, exile it instead of putting it into its owner's graveyard. Oracle:Counter target creature or planeswalker spell unless its controller pays {3}. If that spell is countered this way, exile it instead of putting it into its owner's graveyard. diff --git a/forge-gui/res/cardsfolder/r/revivify.txt b/forge-gui/res/cardsfolder/r/revivify.txt new file mode 100644 index 00000000000..080ff216d9d --- /dev/null +++ b/forge-gui/res/cardsfolder/r/revivify.txt @@ -0,0 +1,8 @@ +Name:Revivify +ManaCost:2 W +Types:Instant +A:SP$ RollDice | Sides$ 20 | Modifier$ X | ResultSubAbilities$ 1-14:DBToHand,Else:DBToField | SpellDescription$ Roll a d20 and add the number of creature cards in your graveyard that were put there from the battlefield this turn. +SVar:DBToHand:DB$ ChangeZone | Origin$ Graveyard | Destination$ Hand | Defined$ ValidGraveyard Creature.YouOwn+ThisTurnEnteredFrom_Battlefield | SpellDescription$ 1-14 VERT Return all creature cards in your graveyard that were put there from the battlefield this turn to your hand. +SVar:DBToField:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | Defined$ ValidGraveyard Creature.YouOwn+ThisTurnEnteredFrom_Battlefield | SpellDescription$ 15+ VERT Return those cards from your graveyard to the battlefield. +SVar:X:Count$ThisTurnEntered_Graveyard_from_Battlefield_Creature.YouCtrl +Oracle:Roll a d20 and add the number of creature cards in your graveyard that were put there from the battlefield this turn.\n1-14 | Return all creature cards in your graveyard that were put there from the battlefield this turn to your hand.\n15+ | Return those cards from your graveyard to the battlefield. diff --git a/forge-gui/res/cardsfolder/r/ride_the_avalanche.txt b/forge-gui/res/cardsfolder/r/ride_the_avalanche.txt new file mode 100644 index 00000000000..814f10df23a --- /dev/null +++ b/forge-gui/res/cardsfolder/r/ride_the_avalanche.txt @@ -0,0 +1,15 @@ +Name:Ride the Avalanche +ManaCost:G U +Types:Instant +A:SP$ Effect | Cost$ G U | StaticAbilities$ QuickenStA | Triggers$ SpellCastTrig,TrigCounters | SpellDescription$ The next spell you cast this turn can be cast as though it had flash. When you cast your next spell this turn, put X +1/+1 counters on up to one target creature, where X is +the mana value of that spell. +SVar:QuickenStA:Mode$ CastWithFlash | ValidCard$ Card | ValidSA$ Spell | EffectZone$ Command | Caster$ You +SVar:SpellCastTrig:Mode$ SpellCast | ValidCard$ Card | ValidActivatingPlayer$ You | Execute$ RemoveQuicken | Static$ True | TriggerDescription$ None +the mana value of that spell. +SVar:RemoveQuicken:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile +SVar:TrigCounters:Mode$ SpellCast | ValidCard$ Card | ValidActivatingPlayer$ You | Execute$ PutCounter | TriggerDescription$ When you cast your next spell this turn, put X +1/+1 counters on up to one target creature, where X is the mana value of that spell +SVar:PutCounter:DB$ PutCounter | CounterType$ P1P1 | CounterNum$ X | TargetMin$ 0 | TargetMax$ 1 | TgtPrompt$ Select target creature | ValidTgts$ Creature +SVar:X:TriggeredCard$CardManaCost +DeckHas:Ability$Counters +AI:RemoveDeck:All +Oracle:The next spell you cast this turn can be cast as though it had flash. When you cast your next spell this turn, put X +1/+1 counters on up to one target creature, where X is the mana value of that spell. diff --git a/forge-gui/res/cardsfolder/upcoming/rimeshield_frost_giant.txt b/forge-gui/res/cardsfolder/r/rimeshield_frost_giant.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/rimeshield_frost_giant.txt rename to forge-gui/res/cardsfolder/r/rimeshield_frost_giant.txt diff --git a/forge-gui/res/cardsfolder/r/robe_of_stars.txt b/forge-gui/res/cardsfolder/r/robe_of_stars.txt new file mode 100644 index 00000000000..e15c4341096 --- /dev/null +++ b/forge-gui/res/cardsfolder/r/robe_of_stars.txt @@ -0,0 +1,7 @@ +Name:Robe of Stars +ManaCost:1 W +Types:Artifact Equipment +K:Equip:1 +S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddToughness$ 3 | Description$ Equipped creature gets +0/+3. +A:AB$ Phases | Cost$ 1 W | Defined$ Equipped | PrecostDesc$ Astral Projection — | SpellDescription$ Equipped creature phases out. +Oracle:Equipped creature gets +0/+3.\nAstral Projection — {1}{W}: Equipped creature phases out. (Treat it and anything attached to it as though they don't exist until its controller's next turn.)\nEquip {1} ({1}: Attach to target creature you control. Equip only as a sorcery.) diff --git a/forge-gui/res/cardsfolder/upcoming/rogue_class.txt b/forge-gui/res/cardsfolder/r/rogue_class.txt similarity index 69% rename from forge-gui/res/cardsfolder/upcoming/rogue_class.txt rename to forge-gui/res/cardsfolder/r/rogue_class.txt index 75b21886009..ff72104a75f 100644 --- a/forge-gui/res/cardsfolder/upcoming/rogue_class.txt +++ b/forge-gui/res/cardsfolder/r/rogue_class.txt @@ -5,9 +5,14 @@ K:Class:3:1 U B,2 U B T:Mode$ ChangesZone | ValidCard$ Card.IsRemembered | Origin$ Exile | ExcludedDestinations$ Stack | Destination$ Any | TriggerZones$ Battlefield | Execute$ TrigForget | Static$ True T:Mode$ SpellCast | ValidCard$ Card.IsRemembered | TriggerZones$ Battlefield | Execute$ TrigForget | Static$ True SVar:TrigForget:DB$ Pump | ForgetObjects$ TriggeredCard +T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Battlefield | Destination$ Any | Execute$ TrigCleanup | Static$ True +SVar:TrigCleanup:DB$ Cleanup | ClearRemembered$ True | ClearImprinted$ True T:Mode$ DamageDone | ClassLevel$ 1 | ValidSource$ Creature.YouCtrl | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigDig | TriggerZones$ Battlefield | TriggerDescription$ Whenever a creature you control deals combat damage to a player, exile the top card of that player's library face down. You may look at it for as long as it remains exiled. -SVar:TrigDig:DB$ Dig | DigNum$ 1 | Defined$ TriggeredTarget | DestinationZone$ Exile | ExileFaceDown$ True | RememberChanged$ True | ChangeNum$ All -S:Mode$ Continuous | ClassLevel$ 1 | MayLookAt$ You | EffectZone$ Battlefield | Affected$ Card.IsRemembered | AffectedZone$ Exile +SVar:TrigDig:DB$ Dig | DigNum$ 1 | Defined$ TriggeredTarget | DestinationZone$ Exile | ExileFaceDown$ True | RememberChanged$ True | ChangeNum$ All | SubAbility$ DBExile +SVar:DBExile:DB$ ChangeZone | Defined$ Imprinted | Origin$ Command | Destination$ Exile | SubAbility$ DBUnimprint +SVar:DBUnimprint:DB$ Cleanup | ClearImprinted $True | SubAbility$ DBEffect +SVar:DBEffect:DB$ Effect | RememberObjects$ Remembered | ImprintOnHost$ True | StaticAbilities$ STMayLook | Duration$ Permanent | ForgetOnMoved$ Exile +SVar:STMayLook:Mode$ Continuous | MayLookAt$ You | EffectZone$ Command | Affected$ Card.IsRemembered | AffectedZone$ Exile | Description$ You may look at it for as long as it remains exiled. S:Mode$ Continuous | ClassLevel$ 2 | Affected$ Creature.YouCtrl | AddKeyword$ Menace | Description$ Creatures you control have menace. S:Mode$ Continuous | ClassLevel$ 3 | MayPlay$ True | MayPlayIgnoreType$ True | EffectZone$ Battlefield | Affected$ Card.IsRemembered | AffectedZone$ Exile | Description$ You may play cards exiled with CARDNAME, and you may spend mana as though it were mana of any color to cast those spells. SVar:PlayMain1:TRUE diff --git a/forge-gui/res/cardsfolder/upcoming/rust_monster.txt b/forge-gui/res/cardsfolder/r/rust_monster.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/rust_monster.txt rename to forge-gui/res/cardsfolder/r/rust_monster.txt diff --git a/forge-gui/res/cardsfolder/upcoming/scaled_herbalist.txt b/forge-gui/res/cardsfolder/s/scaled_herbalist.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/scaled_herbalist.txt rename to forge-gui/res/cardsfolder/s/scaled_herbalist.txt diff --git a/forge-gui/res/cardsfolder/s/scent_of_nightshade.txt b/forge-gui/res/cardsfolder/s/scent_of_nightshade.txt index ca917ebeca0..c7f015e5db7 100644 --- a/forge-gui/res/cardsfolder/s/scent_of_nightshade.txt +++ b/forge-gui/res/cardsfolder/s/scent_of_nightshade.txt @@ -2,9 +2,9 @@ Name:Scent of Nightshade ManaCost:1 B Types:Instant A:SP$ Reveal | Cost$ 1 B | Defined$ You | RevealValid$ Card.Black | AnyNumber$ True | RememberRevealed$ True | SubAbility$ DBScentOfNightshadePump | SpellDescription$ Reveal any number of black cards in your hand. Target creature gets -X/-X until end of turn, where X is the number of cards revealed this way. -SVar:DBScentOfNightshadePump:DB$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ ScentOfNightshadeX | NumDef$ ScentOfNightshadeX | SubAbility$ DBScentOfNightshadeCleanup +SVar:DBScentOfNightshadePump:DB$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ -ScentOfNightshadeX | NumDef$ -ScentOfNightshadeX | SubAbility$ DBScentOfNightshadeCleanup SVar:DBScentOfNightshadeCleanup:DB$ Cleanup | ClearRemembered$ True -SVar:ScentOfNightshadeX:Remembered$Amount.Negative +SVar:ScentOfNightshadeX:Remembered$Amount AI:RemoveDeck:All SVar:Picture:http://www.wizards.com/global/images/magic/general/scent_of_nightshade.jpg Oracle:Reveal any number of black cards in your hand. Target creature gets -X/-X until end of turn, where X is the number of cards revealed this way. diff --git a/forge-gui/res/cardsfolder/upcoming/scion_of_stygia.txt b/forge-gui/res/cardsfolder/s/scion_of_stygia.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/scion_of_stygia.txt rename to forge-gui/res/cardsfolder/s/scion_of_stygia.txt diff --git a/forge-gui/res/cardsfolder/s/second_sunrise.txt b/forge-gui/res/cardsfolder/s/second_sunrise.txt index 20a3a92b110..e05814dbb39 100644 --- a/forge-gui/res/cardsfolder/s/second_sunrise.txt +++ b/forge-gui/res/cardsfolder/s/second_sunrise.txt @@ -1,5 +1,5 @@ Name:Second Sunrise ManaCost:1 W W Types:Instant -A:SP$ChangeZone | Cost$ 1 W W | Origin$ Graveyard | Destination$ Battlefield | Defined$ ValidGraveyard Artifact,Creature,Enchantment,Land.ThisTurnEnteredFrom_Battlefield | SpellDescription$ Each player returns to the battlefield all artifact, creature, enchantment, and land cards in their graveyard that were put there from the battlefield this turn. +A:SP$ChangeZone | Cost$ 1 W W | Origin$ Graveyard | Destination$ Battlefield | Defined$ ValidGraveyard Artifact.ThisTurnEnteredFrom_Battlefield,Creature.ThisTurnEnteredFrom_Battlefield,Enchantment.ThisTurnEnteredFrom_Battlefield,Land.ThisTurnEnteredFrom_Battlefield | SpellDescription$ Each player returns to the battlefield all artifact, creature, enchantment, and land cards in their graveyard that were put there from the battlefield this turn. Oracle:Each player returns to the battlefield all artifact, creature, enchantment, and land cards in their graveyard that were put there from the battlefield this turn. diff --git a/forge-gui/res/cardsfolder/upcoming/secret_door.txt b/forge-gui/res/cardsfolder/s/secret_door.txt similarity index 92% rename from forge-gui/res/cardsfolder/upcoming/secret_door.txt rename to forge-gui/res/cardsfolder/s/secret_door.txt index 6f27ec663f1..23e0c13f210 100644 --- a/forge-gui/res/cardsfolder/upcoming/secret_door.txt +++ b/forge-gui/res/cardsfolder/s/secret_door.txt @@ -1,6 +1,6 @@ Name:Secret Door ManaCost:U -Types:Creature Wall +Types:Artifact Creature Wall PT:0/4 K:Defender A:AB$ Venture | Cost$ 4 U | SorcerySpeed$ True | SpellDescription$ Venture into the dungeon. Activate only as a sorcery. (Enter the first room or advance to the next room.) diff --git a/forge-gui/res/cardsfolder/s/sefris_of_the_hidden_ways.txt b/forge-gui/res/cardsfolder/s/sefris_of_the_hidden_ways.txt new file mode 100644 index 00000000000..030456bf2da --- /dev/null +++ b/forge-gui/res/cardsfolder/s/sefris_of_the_hidden_ways.txt @@ -0,0 +1,11 @@ +Name:Sefris of the Hidden Ways +ManaCost:W U B +Types:Legendary Creature Human Wizard +PT:2/3 +T:Mode$ ChangesZoneAll | ValidCards$ Creature.YouOwn+nonToken | Origin$ Any | Destination$ Graveyard | TriggerZones$ Battlefield | ActivationLimit$ 1 | Execute$ TrigVenture | TriggerDescription$ Whenever one or more creature cards are put into your graveyard from anywhere, venture into the dungeon. This ability triggers only once each turn. (To venture into the dungeon, enter the first room or advance to the next room.) +SVar:TrigVenture:DB$ Venture +T:Mode$ DungeonCompleted | ValidPlayer$ You | TriggerZones$ Battlefield | OptionalDecider$ You | Execute$ DBReturn | TriggerDescription$ Create Undead – Whenever you complete a dungeon, return target creature card from your graveyard to the battlefield. +SVar:DBReturn:DB$ ChangeZone | ValidTgts$ Creature.YouOwn | Origin$ Graveyard | Destination$ Battlefield +DeckHas:Ability$Graveyard +AI:RemoveDeck:Random +Oracle:Whenever one or more creature cards are put into your graveyard from anywhere, venture into the dungeon. This ability triggers only once each turn. (To venture into the dungeon, enter the first room or advance to the next room.)\nCreate Undead - Whenever you complete a dungeon, return target creature card from your graveyard to the battlefield. diff --git a/forge-gui/res/cardsfolder/s/selesnya_loft_gardens.txt b/forge-gui/res/cardsfolder/s/selesnya_loft_gardens.txt index e8bfafb6154..fae637b07de 100644 --- a/forge-gui/res/cardsfolder/s/selesnya_loft_gardens.txt +++ b/forge-gui/res/cardsfolder/s/selesnya_loft_gardens.txt @@ -2,14 +2,13 @@ Name:Selesnya Loft Gardens ManaCost:no cost Types:Plane Ravnica R:Event$ CreateToken | ActiveZones$ Command | ReplaceWith$ DoubleToken | EffectOnly$ True | Description$ If an effect would create one or more tokens, it creates twice that many of those tokens instead. -SVar:DoubleToken:DB$ ReplaceEffect | VarName$ TokenNum | VarValue$ Y +SVar:DoubleToken:DB$ ReplaceToken | Type$ Amount R:Event$ AddCounter | ActiveZones$ Command | ValidCard$ Permanent | EffectOnly$ True | ReplaceWith$ DoubleCounters | Description$ If an effect would put one or more counters on a permanent, it puts twice that many of those counters on that permanent instead. SVar:DoubleCounters:DB$ ReplaceEffect | VarName$ CounterNum | VarValue$ Z -SVar:Y:ReplaceCount$TokenNum/Twice SVar:Z:ReplaceCount$CounterNum/Twice T:Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Execute$ RolledChaos | TriggerDescription$ Whenever you roll {CHAOS}, until end of turn, whenever you tap a land for mana, add one mana of any type that land produced. SVar:RolledChaos:DB$ Effect | AILogic$ Always | Triggers$ TrigTapForMana SVar:TrigTapForMana:Mode$ TapsForMana | TriggerZones$ Command | ValidCard$ Land | Activator$ You | Execute$ TrigMana | Static$ True | TriggerDescription$ Whenever you tap a land for mana, add one mana of any type that land produced. SVar:TrigMana:DB$ ManaReflected | ColorOrType$ Type | ReflectProperty$ Produced | Defined$ You SVar:AIRollPlanarDieParams:Mode$ Always | MinTurn$ 1 | RollInMain1$ True -Oracle:If an effect would create one or more tokens, it creates twice that many of those tokens instead.\nIf an effect would put one or more counters on a permanent, it puts twice that many of those counters on that permanent instead.\nWhenever you roll {CHAOS}, until end of turn, whenever you tap a land for mana, add one mana of any type that land produced. +Oracle:If an effect would create one or more tokens, it creates twice that many of those tokens instead.\nIf an effect would put one or more counters on a permanent, it puts twice that many of those counters on that permanent instead.\nWhenever you roll {CHAOS}, until end of turn, whenever you tap a land for mana, add one mana of any type that land produced. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/upcoming/sepulcher_ghoul.txt b/forge-gui/res/cardsfolder/s/sepulcher_ghoul.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/sepulcher_ghoul.txt rename to forge-gui/res/cardsfolder/s/sepulcher_ghoul.txt diff --git a/forge-gui/res/cardsfolder/upcoming/shambling_ghast.txt b/forge-gui/res/cardsfolder/s/shambling_ghast.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/shambling_ghast.txt rename to forge-gui/res/cardsfolder/s/shambling_ghast.txt diff --git a/forge-gui/res/cardsfolder/upcoming/shessra_deaths_whisper.txt b/forge-gui/res/cardsfolder/s/shessra_deaths_whisper.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/shessra_deaths_whisper.txt rename to forge-gui/res/cardsfolder/s/shessra_deaths_whisper.txt diff --git a/forge-gui/res/cardsfolder/upcoming/shocking_grasp.txt b/forge-gui/res/cardsfolder/s/shocking_grasp.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/shocking_grasp.txt rename to forge-gui/res/cardsfolder/s/shocking_grasp.txt diff --git a/forge-gui/res/cardsfolder/upcoming/shortcut_seeker.txt b/forge-gui/res/cardsfolder/s/shortcut_seeker.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/shortcut_seeker.txt rename to forge-gui/res/cardsfolder/s/shortcut_seeker.txt diff --git a/forge-gui/res/cardsfolder/upcoming/silver_raven.txt b/forge-gui/res/cardsfolder/s/silver_raven.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/silver_raven.txt rename to forge-gui/res/cardsfolder/s/silver_raven.txt diff --git a/forge-gui/res/cardsfolder/upcoming/skeletal_swarming.txt b/forge-gui/res/cardsfolder/s/skeletal_swarming.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/skeletal_swarming.txt rename to forge-gui/res/cardsfolder/s/skeletal_swarming.txt diff --git a/forge-gui/res/cardsfolder/upcoming/skullport_merchant.txt b/forge-gui/res/cardsfolder/s/skullport_merchant.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/skullport_merchant.txt rename to forge-gui/res/cardsfolder/s/skullport_merchant.txt diff --git a/forge-gui/res/cardsfolder/s/song_of_inspiration.txt b/forge-gui/res/cardsfolder/s/song_of_inspiration.txt new file mode 100644 index 00000000000..f64c6bb597a --- /dev/null +++ b/forge-gui/res/cardsfolder/s/song_of_inspiration.txt @@ -0,0 +1,11 @@ +Name:Song of Inspiration +ManaCost:3 G G +Types:Instant +A:SP$ Pump | ValidTgts$ Permanent.YouCtrl | TgtZone$ Graveyard | TargetMin$ 0 | TargetMax$ 2 | SubAbility$ DBRollDice | StackDescription$ SpellDescription | SpellDescription$ Choose up to two target permanent cards in your graveyard. Roll a d20 and add the total mana value of those cards. +SVar:DBRollDice:DB$ RollDice | Defined$ You | Sides$ 20 | Modifier$ X | ResultSubAbilities$ 1-14:ToHand,Else:HandAndLife +SVar:ToHand:DB$ ChangeZone | Defined$ Targeted | Origin$ Graveyard | Destination$ Hand | SpellDescription$ 1-14 VERT Return those cards to your hand. +SVar:HandAndLife:DB$ ChangeZone | Defined$ Targeted | Origin$ Graveyard | Destination$ Hand | SubAbility$ DBGainLife | SpellDescription$ 15+ VERT Return those cards to your hand. You gain life equal to their total mana value. +SVar:DBGainLife:DB$ GainLife | Defined$ You | LifeAmount$ X +SVar:X:Targeted$CardManaCost +DeckHas:Ability$Graveyard & Ability$LifeGain +Oracle:Choose up to two target permanent cards in your graveyard. Roll a d20 and add the total mana value of those cards.\n1-14 | Return those cards to your hand.\n15+ | Return those cards to your hand. You gain life equal to their total mana value. diff --git a/forge-gui/res/cardsfolder/upcoming/sorcerer_class.txt b/forge-gui/res/cardsfolder/s/sorcerer_class.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/sorcerer_class.txt rename to forge-gui/res/cardsfolder/s/sorcerer_class.txt diff --git a/forge-gui/res/cardsfolder/upcoming/soulknife_spy.txt b/forge-gui/res/cardsfolder/s/soulknife_spy.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/soulknife_spy.txt rename to forge-gui/res/cardsfolder/s/soulknife_spy.txt diff --git a/forge-gui/res/cardsfolder/upcoming/spare_dagger.txt b/forge-gui/res/cardsfolder/s/spare_dagger.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/spare_dagger.txt rename to forge-gui/res/cardsfolder/s/spare_dagger.txt diff --git a/forge-gui/res/cardsfolder/s/specimen_collector.txt b/forge-gui/res/cardsfolder/s/specimen_collector.txt index 6cf90aee830..0750af15903 100644 --- a/forge-gui/res/cardsfolder/s/specimen_collector.txt +++ b/forge-gui/res/cardsfolder/s/specimen_collector.txt @@ -3,9 +3,7 @@ ManaCost:4 U Types:Creature Vedalken Wizard PT:2/1 T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ When CARDNAME enters the battlefield, create a 1/1 green Squirrel creature token and a 0/3 blue Crab creature token. -SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ g_1_1_squirrel | TokenOwner$ You | ChangeZoneTable$ True | SubAbility$ DBCrabToken -SVar:DBCrabToken:DB$ Token | TokenAmount$ 1 | TokenScript$ u_0_3_crab | TokenOwner$ You | SubAbility$ DBResolve -SVar:DBResolve:DB$ ChangeZoneResolve +SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ g_1_1_squirrel,u_0_3_crab | TokenOwner$ You T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigCopy | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME dies, create a token that's a copy of target token you control. SVar:TrigCopy:DB$ CopyPermanent | ValidTgts$ Permanent.token+YouCtrl | TgtPrompt$ Select target token you control DeckHas:Ability$Token diff --git a/forge-gui/res/cardsfolder/upcoming/sphere_of_annihilation.txt b/forge-gui/res/cardsfolder/s/sphere_of_annihilation.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/sphere_of_annihilation.txt rename to forge-gui/res/cardsfolder/s/sphere_of_annihilation.txt diff --git a/forge-gui/res/cardsfolder/upcoming/spiked_pit_trap.txt b/forge-gui/res/cardsfolder/s/spiked_pit_trap.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/spiked_pit_trap.txt rename to forge-gui/res/cardsfolder/s/spiked_pit_trap.txt diff --git a/forge-gui/res/cardsfolder/upcoming/split_the_party.txt b/forge-gui/res/cardsfolder/s/split_the_party.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/split_the_party.txt rename to forge-gui/res/cardsfolder/s/split_the_party.txt diff --git a/forge-gui/res/cardsfolder/upcoming/spoils_of_the_hunt.txt b/forge-gui/res/cardsfolder/s/spoils_of_the_hunt.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/spoils_of_the_hunt.txt rename to forge-gui/res/cardsfolder/s/spoils_of_the_hunt.txt diff --git a/forge-gui/res/cardsfolder/upcoming/steadfast_paladin.txt b/forge-gui/res/cardsfolder/s/steadfast_paladin.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/steadfast_paladin.txt rename to forge-gui/res/cardsfolder/s/steadfast_paladin.txt diff --git a/forge-gui/res/cardsfolder/s/storvald_frost_giant_jarl.txt b/forge-gui/res/cardsfolder/s/storvald_frost_giant_jarl.txt new file mode 100644 index 00000000000..0852382cae8 --- /dev/null +++ b/forge-gui/res/cardsfolder/s/storvald_frost_giant_jarl.txt @@ -0,0 +1,12 @@ +Name:Storvald, Frost Giant Jarl +ManaCost:4 G W U +Types:Legendary Creature Giant +PT:7/7 +K:Ward:3 +S:Mode$ Continuous | Affected$ Creature.Other+YouCtrl | AddKeyword$ Ward:3 | Description$ Other creatures you control have ward {3}. +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigCharm | TriggerDescription$ Whenever NICKNAME enters the battlefield or attacks, ABILITY +T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigCharm | Secondary$ True | TriggerDescription$ Whenever NICKNAME enters the battlefield or attacks, ABILITY +SVar:TrigCharm:DB$ Charm | MinCharmNum$ 1 | CharmNum$ 2 | Choices$ DBAnimate7,DBAnimate1 +SVar:DBAnimate7:DB$ Animate | ValidTgts$ Creature | TgtPrompt$ Select target creature | Power$ 7 | Toughness$ 7 | SpellDescription$ Target creature has base power and toughness 7/7 until end of turn. +SVar:DBAnimate1:DB$ Animate | ValidTgts$ Creature | TgtPrompt$ Select target creature | Power$ 1 | Toughness$ 1 | SpellDescription$ Target creature has base power and toughness 1/1 until end of turn. +Oracle:Ward {3}\nOther creatures you control have ward {3}.\nWhenever Storvald enters the battlefield or attacks, choose one or both —\n• Target creature has base power and toughness 7/7 until end of turn.\n• Target creature has base power and toughness 1/1 until end of turn. diff --git a/forge-gui/res/cardsfolder/s/sudden_insight.txt b/forge-gui/res/cardsfolder/s/sudden_insight.txt new file mode 100644 index 00000000000..efa48a65856 --- /dev/null +++ b/forge-gui/res/cardsfolder/s/sudden_insight.txt @@ -0,0 +1,8 @@ +Name:Sudden Insight +ManaCost:4 U U +Types:Instant +A:SP$ PumpAll | ValidCards$ Card.YouOwn+nonLand | PumpZone$ Graveyard | RememberAllPumped$ True | SubAbility$ DBDraw | StackDescription$ SpellDescription | SpellDescription$ Draw a card for each different mana value among nonland cards in your graveyard. +SVar:DBDraw:DB$ Draw | Defined$ You | NumCards$ X | SubAbility$ DBCleanup | StackDescription$ None +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +SVar:X:Remembered$DifferentCMC +Oracle:Draw a card for each different mana value among nonland cards in your graveyard. diff --git a/forge-gui/res/cardsfolder/s/sutured_ghoul.txt b/forge-gui/res/cardsfolder/s/sutured_ghoul.txt index c3d3926be6b..d59150085f8 100644 --- a/forge-gui/res/cardsfolder/s/sutured_ghoul.txt +++ b/forge-gui/res/cardsfolder/s/sutured_ghoul.txt @@ -3,14 +3,14 @@ ManaCost:4 B B B Types:Creature Zombie PT:*/* K:Trample -K:ETBReplacement:Copy:ChooseCreatures -SVar:ChooseCreatures:DB$ ChooseCard | Defined$ You | Amount$ X | Choices$ Creature.YouOwn | ChoiceTitle$ Exile any number of creature cards from your graveyard. | ChoiceZone$ Graveyard | RememberChosen$ True | SubAbility$ ExileCreatures | SpellDescription$ As CARDNAME enters the battlefield, exile any number of creature cards from your graveyard. CARDNAME's power is equal to the total power of the exiled cards and its toughness is equal to their total toughness. -SVar:ExileCreatures:DB$ ChangeZoneAll | ChangeType$ Remembered | Origin$ Graveyard | Destination$ Exile | SubAbility$ AnimateSuture -SVar:AnimateSuture:DB$ Animate | Defined$ Self | Power$ TotalPower | Toughness$ TotalToughness | Duration$ Permanent | SubAbility$ DBCleanup -SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +K:ETBReplacement:Other:ETBPrep +SVar:ETBPrep:DB$ Cleanup | ClearRemembered$ True | SubAbility$ DBChoose +SVar:DBChoose:DB$ ChooseCard | Defined$ You | MinAmount$ 0 | Amount$ X | Choices$ Creature.YouOwn+Other | ChoiceTitle$ Exile any number of creature cards from your graveyard | ChoiceZone$ Graveyard | RememberChosen$ True | SubAbility$ ExileCreatures | SpellDescription$ As CARDNAME enters the battlefield, exile any number of creature cards from your graveyard. CARDNAME's power is equal to the total power of the exiled cards and its toughness is equal to their total toughness. +SVar:ExileCreatures:DB$ ChangeZoneAll | ChangeType$ Card.IsRemembered | Origin$ Graveyard | Destination$ Exile | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearChosenCard$ True +S:Mode$ Continuous | EffectZone$ Battlefield | Affected$ Card.Self | SetPower$ TotalPower | SetToughness$ TotalToughness | Description$ CARDNAME's power is equal to the total power of the exiled cards and its toughness is equal to their total toughness. SVar:TotalPower:Remembered$CardPower SVar:TotalToughness:Remembered$CardToughness SVar:X:Count$TypeInYourYard.Creature AI:RemoveDeck:Random -SVar:Picture:http://www.wizards.com/global/images/magic/general/sutured_ghoul.jpg Oracle:Trample\nAs Sutured Ghoul enters the battlefield, exile any number of creature cards from your graveyard.\nSutured Ghoul's power is equal to the total power of the exiled cards and its toughness is equal to their total toughness. diff --git a/forge-gui/res/cardsfolder/upcoming/swarming_goblins.txt b/forge-gui/res/cardsfolder/s/swarming_goblins.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/swarming_goblins.txt rename to forge-gui/res/cardsfolder/s/swarming_goblins.txt diff --git a/forge-gui/res/cardsfolder/s/sword_of_hours.txt b/forge-gui/res/cardsfolder/s/sword_of_hours.txt new file mode 100644 index 00000000000..7624c7b9a43 --- /dev/null +++ b/forge-gui/res/cardsfolder/s/sword_of_hours.txt @@ -0,0 +1,12 @@ +Name:Sword of Hours +ManaCost:2 +Types:Artifact Equipment +K:Equip:2 +T:Mode$ Attacks | ValidCard$ Card.EquippedBy | Execute$ TrigPutCounter | TriggerDescription$ Whenever equipped creature attacks, put a +1/+1 counter on it. +SVar:TrigPutCounter:DB$ PutCounter | Defined$ Equipped | CounterType$ P1P1 | CounterNum$ 1 +T:Mode$ DamageDealtOnce | CombatDamage$ True | ValidSource$ Creature.EquippedBy | Execute$ TrigRollDice | TriggerZones$ Battlefield | TriggerDescription$ Whenever equipped creature deals combat damage, roll a d12. If the result is greater than the damage dealt or the result is 12, double the number of +1/+1 counters on that creature. +SVar:TrigRollDice:DB$ RollDice | Sides$ 12 | ResultSVar$ X | SubAbility$ DBDouble +SVar:DBDouble:DB$ MultiplyCounter | Defined$ Equipped | CounterType$ P1P1 | ConditionCheckSVar$ X | ConditionSVarCompare$ GTY +SVar:Y:TriggerCount$DamageAmount/LimitMax.11 +DeckHas:Ability$Counters +Oracle:Whenever equipped creature attacks, put a +1/+1 counter on it.\nWhenever equipped creature deals combat damage, roll a d12. If the result is greater than the damage dealt or the result is 12, double the number of +1/+1 counters on that creature.\nEquip {2} ({2}: Attach to target creature you control. Equip only as a sorcery.) diff --git a/forge-gui/res/cardsfolder/upcoming/sylvan_shepherd.txt b/forge-gui/res/cardsfolder/s/sylvan_shepherd.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/sylvan_shepherd.txt rename to forge-gui/res/cardsfolder/s/sylvan_shepherd.txt diff --git a/forge-gui/res/cardsfolder/upcoming/targ_nar_demon_fang_gnoll.txt b/forge-gui/res/cardsfolder/t/targ_nar_demon_fang_gnoll.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/targ_nar_demon_fang_gnoll.txt rename to forge-gui/res/cardsfolder/t/targ_nar_demon_fang_gnoll.txt diff --git a/forge-gui/res/cardsfolder/upcoming/tashas_hideous_laughter.txt b/forge-gui/res/cardsfolder/t/tashas_hideous_laughter.txt similarity index 84% rename from forge-gui/res/cardsfolder/upcoming/tashas_hideous_laughter.txt rename to forge-gui/res/cardsfolder/t/tashas_hideous_laughter.txt index adca1ec2a29..51c7622eceb 100644 --- a/forge-gui/res/cardsfolder/upcoming/tashas_hideous_laughter.txt +++ b/forge-gui/res/cardsfolder/t/tashas_hideous_laughter.txt @@ -2,8 +2,9 @@ Name:Tasha's Hideous Laughter ManaCost:1 U U Types:Sorcery A:SP$ RepeatEach | RepeatPlayers$ Opponent | RepeatSubAbility$ DBRepeat | SpellDescription$ Each opponent exiles cards from the top of their library until that player has exiled cards with total mana value 20 or more. -SVar:DBRepeat:DB$ Repeat | RepeatSubAbility$ DBExile | RepeatCheckSVar$ X | RepeatSVarCompare$ LT20 | SubAbility$ DBCleanup +SVar:DBRepeat:DB$ Repeat | RepeatSubAbility$ DBExile | RepeatCheckSVar$ X | RepeatSVarCompare$ LT20 | MaxRepeat$ Y | SubAbility$ DBCleanup SVar:DBExile:DB$ Dig | Defined$ Remembered | DigNum$ 1 | ChangeNum$ All | DestinationZone$ Exile | Imprint$ True SVar:DBCleanup:DB$ Cleanup | ClearImprinted$ True SVar:X:Imprinted$CardManaCost +SVar:Y:PlayerCountRemembered$CardsInLibrary Oracle:Each opponent exiles cards from the top of their library until that player has exiled cards with total mana value 20 or more. diff --git a/forge-gui/res/cardsfolder/upcoming/teleportation_circle.txt b/forge-gui/res/cardsfolder/t/teleportation_circle.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/teleportation_circle.txt rename to forge-gui/res/cardsfolder/t/teleportation_circle.txt diff --git a/forge-gui/res/cardsfolder/upcoming/temple_of_the_dragon_queen.txt b/forge-gui/res/cardsfolder/t/temple_of_the_dragon_queen.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/temple_of_the_dragon_queen.txt rename to forge-gui/res/cardsfolder/t/temple_of_the_dragon_queen.txt diff --git a/forge-gui/res/cardsfolder/upcoming/the_blackstaff_of_waterdeep.txt b/forge-gui/res/cardsfolder/t/the_blackstaff_of_waterdeep.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/the_blackstaff_of_waterdeep.txt rename to forge-gui/res/cardsfolder/t/the_blackstaff_of_waterdeep.txt diff --git a/forge-gui/res/cardsfolder/upcoming/the_book_of_exalted_deeds.txt b/forge-gui/res/cardsfolder/t/the_book_of_exalted_deeds.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/the_book_of_exalted_deeds.txt rename to forge-gui/res/cardsfolder/t/the_book_of_exalted_deeds.txt diff --git a/forge-gui/res/cardsfolder/upcoming/the_book_of_vile_darkness.txt b/forge-gui/res/cardsfolder/t/the_book_of_vile_darkness.txt similarity index 61% rename from forge-gui/res/cardsfolder/upcoming/the_book_of_vile_darkness.txt rename to forge-gui/res/cardsfolder/t/the_book_of_vile_darkness.txt index aa4327b7466..48a546bbca6 100644 --- a/forge-gui/res/cardsfolder/upcoming/the_book_of_vile_darkness.txt +++ b/forge-gui/res/cardsfolder/t/the_book_of_vile_darkness.txt @@ -4,9 +4,8 @@ Types:Legendary Artifact T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigToken | CheckSVar$ X | SVarCompare$ GE2 | TriggerDescription$ At the beginning of your end step, if you lost 2 or more life this turn, create a 2/2 black Zombie creature token. SVar:TrigToken:DB$ Token | TokenScript$ b_2_2_zombie SVar:X:PlayerCountPropertyYou$LifeLostThisTurn -A:AB$ Token | Cost$ T Exile<1/CARDNAME> Exile<1/Artifact.YouCtrl+namedEye of Vecna> Exile<1/Artifact.YouCtrl+namedHand of Vecna> | RememberCostCards$ True | ImprintTokens$ True | CostDesc$ {T}, Exile CARDNAME and artifacts you control named Eye of Vecna and Hand of Vecna: | TokenScript$ vecna | SubAbility$ DBAnimate | SpellDescription$ Create Vecna, a legendary 8/8 black Zombie God creature token with indestructible. It gains all triggered abilities of the exiled cards. -SVar:DBAnimate:DB$ Animate | Defined$ Imprinted | Duration$ Permanent | GainsTriggeredAbilitiesOf$ Remembered +A:AB$ Token | Cost$ T Exile<1/CARDNAME> Exile<1/Artifact.YouCtrl+namedEye of Vecna> Exile<1/Artifact.YouCtrl+namedHand of Vecna> | CostDesc$ {T}, Exile CARDNAME and artifacts you control named Eye of Vecna and Hand of Vecna: | TokenScript$ vecna | AddTriggersFrom$ ExiledCards | SpellDescription$ Create Vecna, a legendary 8/8 black Zombie God creature token with indestructible and all triggered abilities of the exiled cards. DeckHas:Ability$Token DeckHints:Type$Zombie DeckHints:Name$Eye of Vecna|Hand of Vecna -Oracle:At the beginning of your end step, if you lost 2 or more life this turn, create a 2/2 black Zombie creature token.\n{T}, Exile The Book of Vile Darkness and artifacts you control named Eye of Vecna and Hand of Vecna: Create Vecna, a legendary 8/8 black Zombie God creature token with indestructible. It gains all triggered abilities of the exiled cards. +Oracle:At the beginning of your end step, if you lost 2 or more life this turn, create a 2/2 black Zombie creature token.\n{T}, Exile The Book of Vile Darkness and artifacts you control named Eye of Vecna and Hand of Vecna: Create Vecna, a legendary 8/8 black Zombie God creature token with indestructible and all triggered abilities of the exiled cards. diff --git a/forge-gui/res/cardsfolder/upcoming/the_deck_of_many_things.txt b/forge-gui/res/cardsfolder/t/the_deck_of_many_things.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/the_deck_of_many_things.txt rename to forge-gui/res/cardsfolder/t/the_deck_of_many_things.txt diff --git a/forge-gui/res/cardsfolder/upcoming/the_tarrasque.txt b/forge-gui/res/cardsfolder/t/the_tarrasque.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/the_tarrasque.txt rename to forge-gui/res/cardsfolder/t/the_tarrasque.txt diff --git a/forge-gui/res/cardsfolder/upcoming/thieves_tools.txt b/forge-gui/res/cardsfolder/t/thieves_tools.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/thieves_tools.txt rename to forge-gui/res/cardsfolder/t/thieves_tools.txt diff --git a/forge-gui/res/cardsfolder/upcoming/tiger_tribe_hunter.txt b/forge-gui/res/cardsfolder/t/tiger_tribe_hunter.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/tiger_tribe_hunter.txt rename to forge-gui/res/cardsfolder/t/tiger_tribe_hunter.txt diff --git a/forge-gui/res/cardsfolder/upcoming/tomb_of_annihilation.txt b/forge-gui/res/cardsfolder/t/tomb_of_annihilation.txt similarity index 89% rename from forge-gui/res/cardsfolder/upcoming/tomb_of_annihilation.txt rename to forge-gui/res/cardsfolder/t/tomb_of_annihilation.txt index b081d2e0ac8..a06c2173752 100644 --- a/forge-gui/res/cardsfolder/upcoming/tomb_of_annihilation.txt +++ b/forge-gui/res/cardsfolder/t/tomb_of_annihilation.txt @@ -9,5 +9,5 @@ SVar:DBOubliette:DB$ Discard | Defined$ You | NumCards$ 1 | Mode$ TgtChoose | Su SVar:DBSacArtifact:DB$ Sacrifice | Defined$ You | SacValid$ Artifact & Creature & Land | SacEachValid$ True SVar:DBSandfallCell:DB$ RepeatEach | RepeatSubAbility$ DBLoseLife2 | RepeatPlayers$ Player | RoomName$ Sandfall Cell | SpellDescription$ Each player loses 2 life unless they sacrifice an artifact, a creature, or a land. | NextRoom$ DBCradleDeathGod SVar:DBLoseLife2:DB$ LoseLife | Defined$ Player.IsRemembered | LifeAmount$ 2 | UnlessCost$ Sac<1/Artifact;Creature;Land/an artifact, a creature, or a land> | UnlessPayer$ Remembered -SVar:DBCradleDeathGod:DB$ Token | TokenScript$ b_4_4_the_atropal_deathtouch | TokenOwner$ You | RoomName$ Cradle of the Death God | SpellDescription$ Create The Atropal, a legendary 4/4 black God Horror creature token with deathtouch. +SVar:DBCradleDeathGod:DB$ Token | TokenScript$ the_atropal | TokenOwner$ You | RoomName$ Cradle of the Death God | SpellDescription$ Create The Atropal, a legendary 4/4 black God Horror creature token with deathtouch. Oracle:Trapped Entry — Each player loses 1 life. (→ Veils of Fear or Oubliette)\nVeils of Fear — Each player loses 2 life unless they discard a card. (→ Sandfall Cell)\nSandfall Cell — Each player loses 2 life unless they sacrifice an artifact, a creature, or a land. (→ Cradle of the Death God)\nOubliette — Discard a card and sacrifice an artifact, a creature, and a land. (→ Cradle of the Death God)\nCradle of the Death God — Create The Atropal, a legendary 4/4 black God Horror creature token with deathtouch. diff --git a/forge-gui/res/cardsfolder/t/torrential_gearhulk.txt b/forge-gui/res/cardsfolder/t/torrential_gearhulk.txt index ddc73d6c508..8e57343f544 100644 --- a/forge-gui/res/cardsfolder/t/torrential_gearhulk.txt +++ b/forge-gui/res/cardsfolder/t/torrential_gearhulk.txt @@ -4,6 +4,6 @@ Types:Artifact Creature Construct PT:5/6 K:Flash T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigPlay | TriggerDescription$ When CARDNAME enters the battlefield, you may cast target instant card from your graveyard without paying its mana cost. If that spell would be put into your graveyard this turn, exile it instead. -SVar:TrigPlay:DB$ Play | TgtZone$ Graveyard | ValidTgts$ Instant.YouCtrl | TgtPrompt$ Choose target instant or sorcery card from your graveyard | WithoutManaCost$ True | Optional$ True | ReplaceGraveyard$ Exile | AILogic$ ReplaySpell +SVar:TrigPlay:DB$ Play | TgtZone$ Graveyard | ValidTgts$ Instant.YouCtrl | TgtPrompt$ Choose target instant card from your graveyard | WithoutManaCost$ True | Optional$ True | ReplaceGraveyard$ Exile | AILogic$ ReplaySpell SVar:Picture:http://www.wizards.com/global/images/magic/general/torrential_gearhulk.jpg Oracle:Flash\nWhen Torrential Gearhulk enters the battlefield, you may cast target instant card from your graveyard without paying its mana cost. If that spell would be put into your graveyard this turn, exile it instead. diff --git a/forge-gui/res/cardsfolder/upcoming/treasure_chest.txt b/forge-gui/res/cardsfolder/t/treasure_chest.txt similarity index 91% rename from forge-gui/res/cardsfolder/upcoming/treasure_chest.txt rename to forge-gui/res/cardsfolder/t/treasure_chest.txt index 96ef233d43d..17ff816dcb7 100644 --- a/forge-gui/res/cardsfolder/upcoming/treasure_chest.txt +++ b/forge-gui/res/cardsfolder/t/treasure_chest.txt @@ -1,7 +1,7 @@ Name:Treasure Chest ManaCost:3 Types:Artifact -A:AB$ RollDice | Cost$ Sac<1/CARDNAME> | Sides$ 20 | ResultSubAbilities$ 1:Trapped,2-9:DBToken,10-19:DBGainLife,20:DBChangeZone | SpellDescription$ Roll a d20. +A:AB$ RollDice | Cost$ 4 Sac<1/CARDNAME> | Sides$ 20 | ResultSubAbilities$ 1:Trapped,2-9:DBToken,10-19:DBGainLife,20:DBChangeZone | SpellDescription$ Roll a d20. SVar:Trapped:DB$ LoseLife | Defined$ You | LifeAmount$ 3 | SpellDescription$ 1 VERT Trapped! — You lose 3 life. SVar:DBToken:DB$ Token | TokenAmount$ 5 | TokenScript$ c_a_treasure_sac | SpellDescription$ 2-9 VERT Create five Treasure tokens. SVar:DBGainLife:DB$ GainLife | Defined$ You | LifeAmount$ 3 | SubAbility$ DBDraw | SpellDescription$ 10-19 VERT You gain 3 life and draw three cards. diff --git a/forge-gui/res/cardsfolder/upcoming/treasure_vault.txt b/forge-gui/res/cardsfolder/t/treasure_vault.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/treasure_vault.txt rename to forge-gui/res/cardsfolder/t/treasure_vault.txt diff --git a/forge-gui/res/cardsfolder/upcoming/trelasarra_moon_dancer.txt b/forge-gui/res/cardsfolder/t/trelasarra_moon_dancer.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/trelasarra_moon_dancer.txt rename to forge-gui/res/cardsfolder/t/trelasarra_moon_dancer.txt diff --git a/forge-gui/res/cardsfolder/upcoming/tricksters_talisman.txt b/forge-gui/res/cardsfolder/t/tricksters_talisman.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/tricksters_talisman.txt rename to forge-gui/res/cardsfolder/t/tricksters_talisman.txt diff --git a/forge-gui/res/cardsfolder/t/triplicate_titan.txt b/forge-gui/res/cardsfolder/t/triplicate_titan.txt index 4ae7b601aa2..a086b1ef3f6 100644 --- a/forge-gui/res/cardsfolder/t/triplicate_titan.txt +++ b/forge-gui/res/cardsfolder/t/triplicate_titan.txt @@ -5,10 +5,7 @@ PT:9/9 K:Flying K:Vigilance K:Trample -T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigTokenFly | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME dies, create a 3/3 colorless Golem artifact creature token with flying, a 3/3 colorless Golem artifact creature token with vigilance, and a 3/3 colorless Golem artifact creature token with trample. -SVar:TrigTokenFly:DB$Token | TokenAmount$ 1 | TokenScript$ c_3_3_a_golem_flying | ChangeZoneTable$ True | SubAbility$ DBTokenVig -SVar:DBTokenVig:DB$Token | TokenAmount$ 1 | TokenScript$ c_3_3_a_golem_vigilance | SubAbility$ DBTokenTra -SVar:DBTokenTra:DB$Token | TokenAmount$ 1 | TokenScript$ c_3_3_a_golem_trample | SubAbility$ DBResolve -SVar:DBResolve:DB$ ChangeZoneResolve +T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ When CARDNAME dies, create a 3/3 colorless Golem artifact creature token with flying, a 3/3 colorless Golem artifact creature token with vigilance, and a 3/3 colorless Golem artifact creature token with trample. +SVar:TrigToken:DB$Token | TokenAmount$ 1 | TokenScript$ c_3_3_a_golem_flying,c_3_3_a_golem_vigilance,c_3_3_a_golem_trample DeckHas:Ability$Token Oracle:Flying, vigilance, trample\nWhen Triplicate Titan dies, create a 3/3 colorless Golem artifact creature token with flying, a 3/3 colorless Golem artifact creature token with vigilance, and a 3/3 colorless Golem artifact creature token with trample. diff --git a/forge-gui/res/cardsfolder/upcoming/triumphant_adventurer.txt b/forge-gui/res/cardsfolder/t/triumphant_adventurer.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/triumphant_adventurer.txt rename to forge-gui/res/cardsfolder/t/triumphant_adventurer.txt diff --git a/forge-gui/res/cardsfolder/upcoming/true_polymorph.txt b/forge-gui/res/cardsfolder/t/true_polymorph.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/true_polymorph.txt rename to forge-gui/res/cardsfolder/t/true_polymorph.txt diff --git a/forge-gui/res/cardsfolder/upcoming/underdark_basilisk.txt b/forge-gui/res/cardsfolder/u/underdark_basilisk.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/underdark_basilisk.txt rename to forge-gui/res/cardsfolder/u/underdark_basilisk.txt diff --git a/forge-gui/res/cardsfolder/u/underdark_rift.txt b/forge-gui/res/cardsfolder/u/underdark_rift.txt new file mode 100644 index 00000000000..52f987f5d53 --- /dev/null +++ b/forge-gui/res/cardsfolder/u/underdark_rift.txt @@ -0,0 +1,8 @@ +Name:Underdark Rift +ManaCost:no cost +Types:Land +A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}. +A:AB$ Pump | Cost$ 5 T Exile<1/CARDNAME> | ValidTgts$ Artifact,Creature,Planeswalker | TgtPrompt$ Select target artifact, creature, or planeswalker | SorcerySpeed$ True | IsCurse$ True | SubAbility$ DBRollDice | StackDescription$ None | SpellDescription$ Roll a d10. Put target artifact, creature, or planeswalker into its owner's library just beneath the top X cards of that library, where X is the result. Activate only as a sorcery. +SVar:DBRollDice:DB$ RollDice | Sides$ 10 | ResultSVar$ X | SubAbility$ DBReturn +SVar:DBReturn:DB$ ChangeZone | Defined$ Targeted | Destination$ Library | LibraryPosition$ X | StackDescription$ Put {c:Targeted} into its owner's library just beneath the top X cards of that library, where X is the result. +Oracle:{T}: Add {C}.\n{5}, {T}, Exile Underdark Rift: Roll a d10. Put target artifact, creature, or planeswalker into its owner's library just beneath the top X cards of that library, where X is the result. Activate only as a sorcery. diff --git a/forge-gui/res/cardsfolder/upcoming/unexpected_windfall.txt b/forge-gui/res/cardsfolder/u/unexpected_windfall.txt similarity index 55% rename from forge-gui/res/cardsfolder/upcoming/unexpected_windfall.txt rename to forge-gui/res/cardsfolder/u/unexpected_windfall.txt index 52a86873baf..581b4aba91d 100644 --- a/forge-gui/res/cardsfolder/upcoming/unexpected_windfall.txt +++ b/forge-gui/res/cardsfolder/u/unexpected_windfall.txt @@ -1,7 +1,7 @@ Name:Unexpected Windfall ManaCost:2 R R -Types:Sorcery -A:SP$ Draw | Cost$ 3 R Discard<1/Card/card> | CostDesc$ As an additional cost to cast this spell, discard a card. | NumCards$ 2 | Defined$ You | SubAbility$ DBToken | SpellDescription$ Draw two cards and create two Treasure tokens. (They're artifacts with "{T}, Sacrifice this artifact: Add one mana of any color.") +Types:Instant +A:SP$ Draw | Cost$ 2 R R Discard<1/Card/card> | CostDesc$ As an additional cost to cast this spell, discard a card. | NumCards$ 2 | Defined$ You | SubAbility$ DBToken | SpellDescription$ Draw two cards and create two Treasure tokens. | StackDescription$ SpellDescription SVar:DBToken:DB$ Token | TokenAmount$ 2 | TokenScript$ c_a_treasure_sac | TokenOwner$ You DeckHas:Ability$Discard DeckHints:Keyword$Madness & Ability$Delirium diff --git a/forge-gui/res/cardsfolder/upcoming/danse_macabre.txt b/forge-gui/res/cardsfolder/upcoming/danse_macabre.txt new file mode 100644 index 00000000000..e3c531858fb --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/danse_macabre.txt @@ -0,0 +1,10 @@ +Name:Danse Macabre +ManaCost:3 B B +Types:Sorcery +A:SP$ Sacrifice | Cost$ 3 B B | SacValid$ Creature.nonToken | Defined$ Player | RememberSacrificed$ True | SubAbility$ RollD20 | SacMessage$ nontoken creature | StackDescription$ SpellDescription | SpellDescription$ Each player sacrifices a nontoken creature. +SVar:RollD20:DB$ RollDice | Sides$ 20 | Modifier$ Y | ResultSubAbilities$ 1-14:ChooseOne,Else:ChooseTwo | StackDescription$ SpellDescription | SpellDescription$ Roll a d20 and add the toughness of the creature you sacrificed this way. +SVar:ChooseOne:DB$ ChangeZone | ChangeType$ Creature.IsRemembered | ChangeNum$ 1 | Hidden$ True | Origin$ Graveyard | Destination$ Battlefield | GainControl$ True | SubAbility$ DBCleanup | Mandatory$ True | StackDescription$ SpellDescription | SpellDescription$ 1-14 VERT Return a creature card put into a graveyard this way to the battlefield under your control. +SVar:ChooseTwo:DB$ ChangeZone | ChangeType$ Creature.IsRemembered | ChangeNum$ 2 | Hidden$ True | Origin$ Graveyard | Destination$ Battlefield | GainControl$ True | SubAbility$ DBCleanup | StackDescription$ SpellDescription | SpellDescription$ 15+ VERT Return up to two creature cards put into a graveyard this way to the battlefield under your control +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +SVar:Y:RememberedLKI$FilterControlledBySourceController_CardToughness +Oracle:Each player sacrifices a nontoken creature. Roll a d20 and add the toughness of the creature you sacrificed this way.\n1-14 | Return a creature card put into a graveyard this way to the battlefield under your control.\n15+ | Return up to two creature cards put into a graveyard this way to the battlefield under your control \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/upcoming/death_tyrant.txt b/forge-gui/res/cardsfolder/upcoming/death_tyrant.txt new file mode 100644 index 00000000000..217710626c6 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/death_tyrant.txt @@ -0,0 +1,10 @@ +Name:Death Tyrant +ManaCost:4 B +Types:Creature Beholder Skeleton +PT:4/6 +K:Menace +T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.attackingLKI+YouCtrl,Creature.blocking+OppCtrl | Execute$ TrigToken | TriggerZones$ Battlefield | TriggerDescription$ Negative Energy Cone — Whenever an attacking creature you control or a blocking creature an opponent controls dies, create a 2/2 black Zombie creature token. +SVar:TrigToken:DB$ Token | TokenScript$ b_2_2_zombie | TokenOwner$ You | TokenAmount$ 1 +A:AB$ ChangeZone | Cost$ 5 B | Origin$ Graveyard | Destination$ Battlefield | ActivationZone$ Graveyard | Tapped$ True | SpellDescription$ Return CARDNAME from your graveyard to the battlefield tapped. +DeckHas:Ability$Token +Oracle:Menace\nNegative Energy Cone — Whenever an attacking creature you control or a blocking creature an opponent controls dies, create a 2/2 black Zombie creature token.\n{5}{B}: Return Death Tyrant from your graveyard to the battlefield tapped. diff --git a/forge-gui/res/cardsfolder/upcoming/grave_endeavor.txt b/forge-gui/res/cardsfolder/upcoming/grave_endeavor.txt new file mode 100644 index 00000000000..9f3d3c34cc6 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/grave_endeavor.txt @@ -0,0 +1,11 @@ +Name:Grave Endeavor +ManaCost:5 B B +Types:Instant +A:SP$ RollDice | Cost$ 5 B B | Amount$ 2 | Sides$ 10 | ChosenSVar$ X | OtherSVar$ Y | SubAbility$ DBChangeZone | StackDescription$ SpellDescription | SpellDescription$ Roll two d10 and choose one result. Return a creature card from your graveyard to the battlefield with a number of +1/+1 counters on it equal to that result. Then each opponent loses X life and you gain X life, where X is the other result. +SVar:DBChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Creature.YouOwn | ChangeNum$ 1 | Mandatory$ True | SelectPrompt$ Choose a creature card to return to the battlefield | Hidden$ True | RememberChanged$ True | SubAbility$ DBCounter +SVar:DBCounter:DB$ PutCounter | Defined$ Remembered | CounterType$ P1P1 | CounterNum$ X | Static$ True | SubAbility$ DBLoseLife +SVar:DBLoseLife:DB$ LoseLife | Defined$ Player.Opponent | LifeAmount$ Y | SubAbility$ DBGainLife +SVar:DBGainLife:DB$ GainLife | LifeAmount$ Y | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +DeckHas:Ability$Graveyard & Ability$LifeGain & Ability$Counters +Oracle:Roll two d10 and choose one result. Return a creature card from your graveyard to the battlefield with a number of +1/+1 counters on it equal to that result. Then each opponent loses X life and you gain X life, where X is the other result. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/upcoming/grim_hireling.txt b/forge-gui/res/cardsfolder/upcoming/grim_hireling.txt new file mode 100644 index 00000000000..6508236e75d --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/grim_hireling.txt @@ -0,0 +1,10 @@ +Name:Grim Hireling +ManaCost:3 B +Types:Creature Tiefling Rogue +PT:3/2 +T:Mode$ DamageDoneOnce | CombatDamage$ True | ValidSource$ Creature.YouCtrl | TriggerZones$ Battlefield | ValidTarget$ Player | Execute$ DBToken | TriggerDescription$ Whenever one or more creatures you control deal combat damage to a player, create two Treasure tokens. +SVar:DBToken:DB$ Token | TokenAmount$ 2 | TokenScript$ c_a_treasure_sac | TokenOwner$ You +A:AB$ Pump | Cost$ 4 B Sac | SorcerySpeed$ True | ValidTgts$ Creature | TgtPrompt$ Select target creature | IsCurse$ True | NumAtt$ -X | NumDef$ -X | SpellDescription$ Target creature gets -X/-X until end of turn. Activate only as a sorcery. +SVar:X:Count$xPaid +DeckHas:Ability$Token & Ability$Sacrifice +Oracle:Whenever one or more creatures you control deal combat damage to a player, create two Treasure tokens.\n{B}, Sacrifice X Treasures: Target creature gets -X/-X until end of turn. Activate only as a sorcery. diff --git a/forge-gui/res/cardsfolder/upcoming/immovable_rod.txt b/forge-gui/res/cardsfolder/upcoming/immovable_rod.txt new file mode 100644 index 00000000000..6f81a9d270c --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/immovable_rod.txt @@ -0,0 +1,12 @@ +Name:Immovable Rod +ManaCost:W +Types:Artifact +K:You may choose not to untap CARDNAME during your untap step. +T:Mode$ Untaps | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigVenture | TriggerDescription$ Whenever CARDNAME becomes untapped, venture into the dungeon. +SVar:TrigVenture:DB$ Venture +A:AB$ Pump | Cost$ 3 W T | ValidTgts$ Permanent | TgtPrompt$ Select target permanent | RememberObjects$ Targeted | SpellDescription$ For as long as CARDNAME remains tapped, another target permanent loses all abilities and can't attack or block. +S:Mode$ Continuous | Affected$ Card.IsRemembered | AddHiddenKeyword$ CARDNAME can't attack or block. | RemoveAllAbilities$ True +T:Mode$ Untaps | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ ClearRemembered | Static$ True +SVar:ClearRemembered:DB$ Cleanup | ClearRemembered$ True +AI:RemoveDeck:All +Oracle:You may choose not to untap Immovable Rod during your untap step.\nWhenever Immovable Rod becomes untapped, venture into the dungeon.\n{3}{W}, {T}: For as long as Immovable Rod remains tapped, another target permanent loses all abilities and can't attack or block. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/upcoming/indomitable_might.txt b/forge-gui/res/cardsfolder/upcoming/indomitable_might.txt new file mode 100644 index 00000000000..c277777647f --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/indomitable_might.txt @@ -0,0 +1,8 @@ +Name:Indomitable Might +ManaCost:3 G +Types:Enchantment Aura +K:Flash +K:Enchant creature +A:SP$ Attach | Cost$ 3 G | ValidTgts$ Creature | TgtPrompt$ Select creature | AILogic$ Pump +S:Mode$ Continuous | Affected$ Creature.EnchantedBy | AddPower$ 3 | AddToughness$ 3 | AddHiddenKeyword$ You may have CARDNAME assign its combat damage as though it weren't blocked. | Description$ Enchanted creature gets +3/+3. Enchanted creature's controller may have it assign combat damage as though it weren't blocked. +Oracle:Flash\nEnchant creature\nEnchanted creature gets +3/+3.\nEnchanted creature's controller may have it assign combat damage as though it weren't blocked. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/upcoming/mantle_of_the_ancients.txt b/forge-gui/res/cardsfolder/upcoming/mantle_of_the_ancients.txt new file mode 100644 index 00000000000..db684ce1568 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/mantle_of_the_ancients.txt @@ -0,0 +1,12 @@ +Name:Mantle of the Ancients +ManaCost:3 W W +Types:Enchantment Aura +K:Enchant creature you control +A:SP$ Attach | Cost$ 3 W W | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select creature you control | AILogic$ Pump +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigMove | TriggerDescription$ When CARDNAME enters the battlefield, return any number of target Aura and/or Equipment cards that could be attached to enchanted creature from your graveyard to the battlefield attached to enchanted creature. +SVar:TrigMove:DB$ ChangeZone | ValidTgts$ Aura.CanEnchantEquippedBy,Equipment.CanEnchantEquippedBy | TargetMin$ 0 | TargetMax$ X | TgtZone$ Graveyard | TargetUnique$ True| TgtPrompt$ Select any number of Aura and/or Equipment cards in your graveyard. | Origin$ Graveyard | Destination$ Battlefield | AttachedTo$ Valid Creature.EnchantedBy +SVar:X:Count$ValidGraveyard Aura.CanEnchantEquippedBy,Equipment.CanEnchantEquippedBy +S:Mode$ Continuous | Affected$ Creature.EnchantedBy | AddPower$ Y | AddToughness$ Y | AddSVar$ EnchantMe | Description$ Enchanted creature gets +1/+1 for each Aura and Equipment attached to it. +SVar:Y:Count$Valid Aura.AttachedTo Creature.EnchantedBy,Equipment.AttachedTo Creature.EnchantedBy +SVar:EnchantMe:Multiple +Oracle:Enchant creature you control\nWhen Mantle of the Ancients enters the battlefield, return any number of target Aura and/or Equipment cards that could be attached to enchanted creature from your graveyard to the battlefield attached to enchanted creature.\nEnchanted creature gets +1/+1 for each Aura and Equipment attached to it. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/upcoming/minimus_containment.txt b/forge-gui/res/cardsfolder/upcoming/minimus_containment.txt deleted file mode 100644 index 768e8556ad3..00000000000 --- a/forge-gui/res/cardsfolder/upcoming/minimus_containment.txt +++ /dev/null @@ -1,8 +0,0 @@ -Name:Minimus Containment -ManaCost:2 W -Types:Enchantment Aura -K:Enchant nonland permanent -A:SP$ Attach | Cost$ 2 W | ValidTgts$ Permanent.nonLand | TgtPrompt$ Select target nonland permanent | AILogic$ Curse -S:Mode$ Continuous | Affected$ Creature.EnchantedBy | AddType$ Artifact & Treasure | RemoveCardTypes$ True | AddAbility$ TreasureSac | RemoveAllAbilities$ True | Description$ Enchanted permanent is a Treasure artifact with "{T}, Sacrifice this artifact: Add one mana of any color," and it loses all other abilities. (If it was a creature, it's no longer a creature.) -SVar:TreasureSac:AB$ Mana | Cost$ T Sac<1/CARDNAME> | Produced$ Any | SpellDescription$ Add one mana of any color. -Oracle:Enchant nonland permanent\nEnchanted permanent is a Treasure artifact with "{T}, Sacrifice this artifact: Add one mana of any color," and it loses all other abilities. (If it was a creature, it's no longer a creature.) diff --git a/forge-gui/res/cardsfolder/upcoming/nihiloor.txt b/forge-gui/res/cardsfolder/upcoming/nihiloor.txt new file mode 100644 index 00000000000..bb40e973d35 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/nihiloor.txt @@ -0,0 +1,17 @@ +Name:Nihiloor +ManaCost:2 W U B +Types:Legendary Creature Horror +PT:3/5 +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ DBRepeat | TriggerDescription$ When CARDNAME enters the battlefield, for each opponent, tap up to one untapped creature you control. When you do, gain control of target creature that player controls with power less than or equal to the tapped creature's power for as long as you control CARDNAME. +SVar:DBRepeat:DB$ RepeatEach | RepeatPlayers$ Player.Opponent | RepeatSubAbility$ DBChoose | SubAbility$ DBCleanup +SVar:DBChoose:DB$ ChooseCard | Defined$ You | MinAmount$ 0 | Amount$ 1 | Choices$ Creature.untapped+YouCtrl | ChoiceTitle$ Choose up to one untapped creature you control to tap | ChoiceTitleAppendDefined$ Player.IsRemembered | ChoiceZone$ Battlefield | SubAbility$ DBTap +SVar:DBTap:DB$ Tap | Defined$ ChosenCard | SubAbility$ DBImmediateTrigger +SVar:DBImmediateTrigger:DB$ ImmediateTrigger | RememberObjects$ ChosenCard,Player.IsRemembered | ConditionDefined$ ChosenCard | ConditionPresent$ Card | ConditionCompare$ GE1 | Execute$ TrigGainControl | TrigDescReminderDefined$ Player.IsRemembered | TriggerDescription$ When you do, gain control of target creature that player controls with power less than or equal to the tapped creature's power for as long as you control CARDNAME. +SVar:TrigGainControl:DB$ GainControl | ValidTgts$ Creature.RememberedPlayerCtrl+powerLEX | LoseControl$ LeavesPlay,LoseControl | TgtPrompt$ Select target creature that opponent controls +SVar:X:TriggerRemembered$CardPower +SVar:DBCleanup:DB$ Cleanup | ClearChosenCard$ True +T:Mode$ Attacks | ValidCard$ Creature.YouCtrl+OppOwn | TriggerZones$ Battlefield | Execute$ TrigGain | TriggerDescription$ Whenever you attack with a creature an opponent owns, you gain 2 life and that player loses 2 life. +SVar:TrigGain:DB$ GainLife | LifeAmount$ 2 | SubAbility$ DBLoseLife +SVar:DBLoseLife:DB$ LoseLife | LifeAmount$ 2 | Defined$ TriggeredAttackerOwner +DeckHas:Ability$LifeGain +Oracle:When Nihiloor enters the battlefield, for each opponent, tap up to one untapped creature you control. When you do, gain control of target creature that player controls with power less than or equal to the tapped creature's power for as long as you control Nihiloor.\nWhenever you attack with a creature an opponent owns, you gain 2 life and that player loses 2 life. diff --git a/forge-gui/res/cardsfolder/upcoming/phantom_steed.txt b/forge-gui/res/cardsfolder/upcoming/phantom_steed.txt new file mode 100644 index 00000000000..2a76962dbd1 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/phantom_steed.txt @@ -0,0 +1,13 @@ +Name:Phantom Steed +ManaCost:3 U +Types:Creature Horse Illusion +PT:4/3 +K:Flash +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExile | TriggerDescription$ When CARDNAME enters the battlefield, exile another target creature you control until CARDNAME leaves the battlefield. +SVar:TrigExile:DB$ ChangeZone | Origin$ Battlefield | Destination$ Exile | ValidTgts$ Creature.YouCtrl+Other | TgtPrompt$ Select another target creature you control | RememberChanged$ True | Duration$ UntilHostLeavesPlay +SVar:PlayMain1:TRUE +T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigCopy | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME attacks, create a tapped and attacking token that's a copy of the exiled card, except it's an Illusion in addition to its other types. Sacrifice that token at end of combat. +SVar:TrigCopy:DB$ CopyPermanent | Defined$ UntilLeavesBattlefield | TokenTapped$ True | TokenAttacking$ True | AddTypes$ Illusion | AtEOT$ SacrificeCombat +SVar:HasAttackEffect:TRUE +DeckHas:Ability$Sacrifice +Oracle:Flash\nWhen Phantom Steed enters the battlefield, exile another target creature you control until Phantom Steed leaves the battlefield.\nWhenever Phantom Steed attacks, create a tapped and attacking token that's a copy of the exiled card, except it's an Illusion in addition to its other types. Sacrifice that token at end of combat. diff --git a/forge-gui/res/cardsfolder/upcoming/planar_ally.txt b/forge-gui/res/cardsfolder/upcoming/planar_ally.txt deleted file mode 100644 index d7d98d5b5b5..00000000000 --- a/forge-gui/res/cardsfolder/upcoming/planar_ally.txt +++ /dev/null @@ -1,8 +0,0 @@ -Name:Planar Ally -ManaCost:3 W W -Types:Creature Angel -PT:3/3 -K:Flying -T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ DBVenture | Secondary$ True | TriggerDescription$ Whenever CARDNAME enters the battlefield or attacks, venture into the dungeon. (Enter the first room or advance to the next room.) -SVar:DBVenture:DB$ Venture | Defined$ You -Oracle:Flying\nWhenever Planar Ally attacks, venture into the dungeon. diff --git a/forge-gui/res/cardsfolder/upcoming/rod_of_absorption.txt b/forge-gui/res/cardsfolder/upcoming/rod_of_absorption.txt new file mode 100644 index 00000000000..9a929ce02ce --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/rod_of_absorption.txt @@ -0,0 +1,16 @@ +Name:Rod of Absorption +ManaCost:2 U +Types:Artifact +T:Mode$ ChangesZone | ValidCard$ Card.IsRemembered | Origin$ Exile | Destination$ Any | TriggerZones$ Battlefield | Execute$ TrigForget | Static$ True +SVar:TrigForget:DB$ Pump | ForgetObjects$ TriggeredCard +T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Battlefield | Destination$ Any | Execute$ DBCleanup | Static$ True +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +T:Mode$ SpellCast | ValidCard$ Instant,Sorcery | Execute$ TrigEffect | TriggerZones$ Battlefield | TriggerDescription$ Whenever a player casts an instant or sorcery spell, exile it instead of putting it into a graveyard as it resolves. +SVar:TrigEffect:DB$ Effect | ReplacementEffects$ ReMoved | RememberObjects$ TriggeredCard +SVar:ReMoved:Event$ Moved | ValidCard$ Card.IsRemembered | Origin$ Stack | Destination$ Graveyard | Fizzle$ False | ReplaceWith$ DBExile | Description$ Exile it instead of putting it into a graveyard as it resolves. +SVar:DBExile:DB$ ChangeZone | Defined$ ReplacedCard | Origin$ Stack | Destination$ Exile | SubAbility$ DBRemember +SVar:DBRemember:DB$ Animate | Defined$ EffectSource | RememberObjects$ ReplacedCard | Duration$ Permanent | SubAbility$ ExileSelf +SVar:ExileSelf:DB$ ChangeZone | Origin$ Command | Destination$ Exile | Defined$ Self +A:AB$ Play | Cost$ X T Sac<1/CARDNAME> | Defined$ ValidExile Card.IsRemembered | ValidSA$ Spell | Amount$ All | WithTotalCMC$ X | WithoutManaCost$ True | Optional$ True | AILogic$ WithTotalCMC | SpellDescription$ You may cast any number of spells from among cards exiled with CARDNAME with total mana value X or less without paying their mana costs. +SVar:X:Count$xPaid +Oracle:Whenever a player casts an instant or sorcery spell, exile it instead of putting it into a graveyard as it resolves.\n{X}, {T}, Sacrifice Rod of Absorption: You may cast any number of spells from among cards exiled with Rod of Absorption with total mana value X or less without paying their mana costs. diff --git a/forge-gui/res/cardsfolder/upcoming/thorough_investigation.txt b/forge-gui/res/cardsfolder/upcoming/thorough_investigation.txt new file mode 100644 index 00000000000..b4cb9e5f75b --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/thorough_investigation.txt @@ -0,0 +1,9 @@ +Name:Thorough Investigation +ManaCost:2 W +Types:Enchantment +T:Mode$ AttackersDeclared | AttackingPlayer$ You | Execute$ TrigInvestigate | TriggerZones$ Battlefield | TriggerDescription$ Whenever you attack, investigate. +SVar:TrigInvestigate:DB$ Investigate +T:Mode$ Sacrificed | ValidCard$ Clue.YouCtrl | Execute$ TrigVenture | TriggerZones$ Battlefield | TriggerDescription$ Whenever you sacrifice a Clue, venture into the dungeon. +SVar:TrigVenture:DB$ Venture +DeckHas:Ability$Investigate & Ability$Token +Oracle:Whenever you attack, investigate. (Create a colorless Clue artifact token with "{2}, Sacrifice this artifact: Draw a card.")\nWhenever you sacrifice a Clue, venture into the dungeon. (Enter the first room or advance to the next room.) \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/upcoming/vengeful_ancestor.txt b/forge-gui/res/cardsfolder/upcoming/vengeful_ancestor.txt new file mode 100644 index 00000000000..c369c76ee9d --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/vengeful_ancestor.txt @@ -0,0 +1,11 @@ +Name:Vengeful Ancestor +ManaCost:2 R R +Types:Creature Spirit Dragon +PT:3/4 +K:Flying +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigGoad | TriggerDescription$ When CARDNAME enters the battlefield or attacks, goad target creature. +T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigGoad | Secondary$ True | TriggerDescription$ When CARDNAME enters the battlefield or attacks, goad target creature. +SVar:TrigGoad:DB$ Goad | ValidTgts$ Creature | TgtPrompt$ Select target creature +T:Mode$ Attacks | ValidCard$ Creature.IsGoaded | Execute$ TrigDamage | Secondary$ True | TriggerDescription$ Whenever a goaded creature attacks, it deals 1 damage to its controller. +SVar:TrigDamage:DB$ DealDamage | Defined$ TriggeredAttackerController | DamageSource$ TriggeredAttackerLKICopy | NumDmg$ 1 +Oracle:Flying\nWhen Vengeful Ancestor enters the battlefield or attacks, goad target creature. (Until your next turn, that creature attacks each combat if able and attacks a player other than you if able.)\nWhenever a goaded creature attacks, it deals 1 damage to its controller. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/upcoming/wand_of_orcus.txt b/forge-gui/res/cardsfolder/upcoming/wand_of_orcus.txt new file mode 100644 index 00000000000..11345464cb6 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/wand_of_orcus.txt @@ -0,0 +1,15 @@ +Name:Wand of Orcus +ManaCost:2 B +Types:Legendary Artifact Equipment +T:Mode$ Attacks | ValidCard$ Card.EquippedBy | TriggerZones$ Battlefield | Execute$ TrigPumpA | TriggerDescription$ Whenever enchanted creature attacks or blocks, it and Zombies you control gain deathtouch until end of turn. +T:Mode$ Blocks | ValidCard$ Card.EquippedBy | TriggerZones$ Battlefield | Execute$ TrigPumpB | Secondary$ True | TriggerDescription$ Whenever enchanted creature attacks or blocks, it and Zombies you control gain deathtouch until end of turn. +SVar:TrigPumpA:DB$ Pump | Defined$ TriggeredAttacker | KW$ Deathtouch | SubAbility$ DBPumpZ +SVar:TrigPumpB:DB$ Pump | Defined$ TriggeredBlocker | KW$ Deathtouch | SubAbility$ DBPumpZ +SVar:DBPumpZ:DB$ PumpAll | ValidCards$ Zombie.YouCtrl | KW$ Deathtouch +T:Mode$ DamageDone | ValidSource$ Card.EquippedBy | Execute$ TrigToken | CombatDamage$ True | ValidTarget$ Player | TriggerZones$ Battlefield | TriggerDescription$ Whenever equipped creature deals combat damage to a player, create that many 2/2 black Zombie creature tokens. +SVar:TrigToken:DB$ Token | TokenAmount$ X | TokenScript$ b_2_2_zombie +SVar:X:TriggerCount$DamageAmount +K:Equip:3 +DeckHas:Ability$Token & Type$Zombie +DeckHints:Type$Zombie +Oracle:Whenever equipped creature attacks or blocks, it and Zombies you control gain deathtouch until end of turn.\nWhenever equipped creature deals combat damage to a player, create that many 2/2 black Zombie creature tokens.\nEquip {3} diff --git a/forge-gui/res/cardsfolder/upcoming/winged_boots.txt b/forge-gui/res/cardsfolder/upcoming/winged_boots.txt new file mode 100644 index 00000000000..e6e8fe0b024 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/winged_boots.txt @@ -0,0 +1,6 @@ +Name:Winged Boots +ManaCost:1 U +Types:Artifact Equipment +S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddKeyword$ Flying & Ward:4 | Description$ Equipped creature has flying and ward {4}. +K:Equip:1 +Oracle:Equipped creature has flying and ward {4}. (Whenever equipped creature becomes the target of a spell or ability an opponent controls, counter it unless that player pays {4}.)\nEquip {1} \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/upcoming/xorn.txt b/forge-gui/res/cardsfolder/upcoming/xorn.txt deleted file mode 100644 index 799b0cf4f09..00000000000 --- a/forge-gui/res/cardsfolder/upcoming/xorn.txt +++ /dev/null @@ -1,10 +0,0 @@ -Name:Xorn -ManaCost:2 R -Types:Creature Elemental -PT:3/2 -R:Event$ CreateToken | ActiveZones$ Battlefield | ValidPlayer$ You | ValidToken$ Treasure | ReplaceWith$ AdditionalToken | Description$ If you would create one or more Treasure tokens, instead create those tokens plus an additional Treasure token. -SVar:AdditionalToken:DB$ ReplaceEffect | VarName$ TokenNum | VarValue$ X -SVar:X:ReplaceCount$TokenNum/Plus.1 -DeckNeeds:Type$Token -AI:RemoveDeck:Random -Oracle:If you would create one or more Treasure tokens, instead create those tokens plus an additional Treasure token. diff --git a/forge-gui/res/cardsfolder/upcoming/valiant_endeavor.txt b/forge-gui/res/cardsfolder/v/valiant_endeavor.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/valiant_endeavor.txt rename to forge-gui/res/cardsfolder/v/valiant_endeavor.txt diff --git a/forge-gui/res/cardsfolder/upcoming/valor_singer.txt b/forge-gui/res/cardsfolder/v/valor_singer.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/valor_singer.txt rename to forge-gui/res/cardsfolder/v/valor_singer.txt diff --git a/forge-gui/res/cardsfolder/upcoming/vampire_spawn.txt b/forge-gui/res/cardsfolder/v/vampire_spawn.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/vampire_spawn.txt rename to forge-gui/res/cardsfolder/v/vampire_spawn.txt diff --git a/forge-gui/res/cardsfolder/upcoming/varis_silverymoon_ranger.txt b/forge-gui/res/cardsfolder/v/varis_silverymoon_ranger.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/varis_silverymoon_ranger.txt rename to forge-gui/res/cardsfolder/v/varis_silverymoon_ranger.txt diff --git a/forge-gui/res/cardsfolder/upcoming/veteran_dungeoneer.txt b/forge-gui/res/cardsfolder/v/veteran_dungeoneer.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/veteran_dungeoneer.txt rename to forge-gui/res/cardsfolder/v/veteran_dungeoneer.txt diff --git a/forge-gui/res/cardsfolder/v/vish_kal_blood_arbiter.txt b/forge-gui/res/cardsfolder/v/vish_kal_blood_arbiter.txt index 3c939feaac5..035af83c72e 100644 --- a/forge-gui/res/cardsfolder/v/vish_kal_blood_arbiter.txt +++ b/forge-gui/res/cardsfolder/v/vish_kal_blood_arbiter.txt @@ -4,10 +4,9 @@ Types:Legendary Creature Vampire PT:5/5 K:Flying K:Lifelink -A:AB$PutCounter | Cost$ Sac<1/Creature> | Defined$ Self | CounterType$ P1P1 | CounterNum$ Y | SpellDescription$ Put X +1/+1 counters on CARDNAME, where X is the sacrificed creature's power. -A:AB$ Pump | Cost$ SubCounter | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ -X | NumDef$ -X | SpellDescription$ Target creature gets -1/-1 until end of turn for each +1/+1 counter removed this way. +A:AB$ PutCounter | Cost$ Sac<1/Creature> | Defined$ Self | CounterType$ P1P1 | CounterNum$ Y | SpellDescription$ Put X +1/+1 counters on CARDNAME, where X is the sacrificed creature's power. +A:AB$ Pump | Cost$ SubCounter | CostDesc$ Remove all +1/+1 counters from NICKNAME: | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ -X | NumDef$ -X | SpellDescription$ Target creature gets -1/-1 until end of turn for each +1/+1 counter removed this way. SVar:Y:Sacrificed$CardPower SVar:X:SVar$CostCountersRemoved AI:RemoveDeck:All -SVar:Picture:http://www.wizards.com/global/images/magic/general/vish_kal_blood_arbiter.jpg Oracle:Flying, lifelink\nSacrifice a creature: Put X +1/+1 counters on Vish Kal, Blood Arbiter, where X is the sacrificed creature's power.\nRemove all +1/+1 counters from Vish Kal: Target creature gets -1/-1 until end of turn for each +1/+1 counter removed this way. diff --git a/forge-gui/res/cardsfolder/upcoming/volo_guide_to_monsters.txt b/forge-gui/res/cardsfolder/v/volo_guide_to_monsters.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/volo_guide_to_monsters.txt rename to forge-gui/res/cardsfolder/v/volo_guide_to_monsters.txt diff --git a/forge-gui/res/cardsfolder/v/vrondiss_rage_of_ancients.txt b/forge-gui/res/cardsfolder/v/vrondiss_rage_of_ancients.txt new file mode 100644 index 00000000000..b11e0b39d95 --- /dev/null +++ b/forge-gui/res/cardsfolder/v/vrondiss_rage_of_ancients.txt @@ -0,0 +1,11 @@ +Name:Vrondiss, Rage of Ancients +ManaCost:3 R G +Types:Legendary Creature Dragon Barbarian +PT:5/4 +T:Mode$ DamageDoneOnce | Execute$ TrigToken | ValidTarget$ Card.Self | TriggerZones$ Battlefield | OptionalDecider$ You | TriggerDescription$ Enrage — Whenever CARDNAME is dealt damage, you may create a 5/4 red and green Dragon Spirit creature token with "When this creature deals damage, sacrifice it." +SVar:TrigToken:DB$ Token | TokenScript$ rg_5_4_dragon_spirit_damagesac +T:Mode$ RolledDieOnce | TriggerZones$ Battlefield | ValidPlayer$ You | OptionalDecider$ You | Execute$ TrigDamageSelf | TriggerDescription$ Whenever you roll one or more dice, you may have NICKNAME deal 1 damage to itself. +SVar:TrigDamageSelf:DB$ DealDamage | Defined$ Self | NumDmg$ 1 +SVar:HasCombatEffect:TRUE +DeckHas:Ability$Token & Ability$Sacrifice +Oracle:Enrage — Whenever Vrondiss, Rage of Ancients is dealt damage, you may create a 5/4 red and green Dragon Spirit creature token with "When this creature deals damage, sacrifice it."\nWhenever you roll one or more dice, you may have Vrondiss deal 1 damage to itself. diff --git a/forge-gui/res/cardsfolder/upcoming/wandering_troubadour.txt b/forge-gui/res/cardsfolder/w/wandering_troubadour.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/wandering_troubadour.txt rename to forge-gui/res/cardsfolder/w/wandering_troubadour.txt diff --git a/forge-gui/res/cardsfolder/w/war_elephant.txt b/forge-gui/res/cardsfolder/w/war_elephant.txt index 7fb2b81793b..35eaedcabc1 100644 --- a/forge-gui/res/cardsfolder/w/war_elephant.txt +++ b/forge-gui/res/cardsfolder/w/war_elephant.txt @@ -4,6 +4,5 @@ Types:Creature Elephant PT:2/2 K:Trample K:Banding -AI:RemoveDeck:All SVar:Picture:http://www.wizards.com/global/images/magic/general/war_elephant.jpg Oracle:Trample; banding (Any creatures with banding, and up to one without, can attack in a band. Bands are blocked as a group. If any creatures with banding you control are blocking or being blocked by a creature, you divide that creature's combat damage, not its controller, among any of the creatures it's being blocked by or is blocking.) diff --git a/forge-gui/res/cardsfolder/upcoming/warlock_class.txt b/forge-gui/res/cardsfolder/w/warlock_class.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/warlock_class.txt rename to forge-gui/res/cardsfolder/w/warlock_class.txt diff --git a/forge-gui/res/cardsfolder/upcoming/werewolf_pack_leader.txt b/forge-gui/res/cardsfolder/w/werewolf_pack_leader.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/werewolf_pack_leader.txt rename to forge-gui/res/cardsfolder/w/werewolf_pack_leader.txt diff --git a/forge-gui/res/cardsfolder/upcoming/westgate_regent.txt b/forge-gui/res/cardsfolder/w/westgate_regent.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/westgate_regent.txt rename to forge-gui/res/cardsfolder/w/westgate_regent.txt diff --git a/forge-gui/res/cardsfolder/upcoming/white_dragon.txt b/forge-gui/res/cardsfolder/w/white_dragon.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/white_dragon.txt rename to forge-gui/res/cardsfolder/w/white_dragon.txt diff --git a/forge-gui/res/cardsfolder/upcoming/wight.txt b/forge-gui/res/cardsfolder/w/wight.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/wight.txt rename to forge-gui/res/cardsfolder/w/wight.txt diff --git a/forge-gui/res/cardsfolder/w/wild_endeavor.txt b/forge-gui/res/cardsfolder/w/wild_endeavor.txt new file mode 100644 index 00000000000..c777509bae9 --- /dev/null +++ b/forge-gui/res/cardsfolder/w/wild_endeavor.txt @@ -0,0 +1,8 @@ +Name:Wild Endeavor +ManaCost:4 G G +Types:Sorcery +A:SP$ RollDice | Amount$ 2 | Sides$ 4 | ChosenSVar$ X | OtherSVar$ Y | SubAbility$ DBToken | StackDescription$ SpellDescription | SpellDescription$ Roll two d4 and choose one result. Create a number of 3/3 green Beast creature tokens equal to that result. Then search your library for a number of basic land cards equal to the other result, put them onto the battlefield tapped, then shuffle. +SVar:DBToken:DB$ Token | TokenAmount$ X | TokenScript$ g_3_3_beast | SubAbility$ DBChangeZone +SVar:DBChangeZone:DB$ ChangeZone | Origin$ Library | ChangeNum$ Y | ChangeType$ Land.Basic | Destination$ Battlefield | Tapped$ True | StackDescription$ None +DeckHas:Ability$Token +Oracle:Roll two d4 and choose one result. Create a number of 3/3 green Beast creature tokens equal to that result. Then search your library for a number of basic land cards equal to the other result, put them onto the battlefield tapped, then shuffle. diff --git a/forge-gui/res/cardsfolder/w/wild_magic_sorceror.txt b/forge-gui/res/cardsfolder/w/wild_magic_sorceror.txt new file mode 100644 index 00000000000..232d1f2b76b --- /dev/null +++ b/forge-gui/res/cardsfolder/w/wild_magic_sorceror.txt @@ -0,0 +1,9 @@ +Name:Wild-Magic Sorcerer +ManaCost:3 R +Types:Creature Orc Shaman +PT:4/3 +S:Mode$ Continuous | Affected$ Card.YouCtrl+wasCastFromExile | AffectedZone$ Stack | AddKeyword$ Cascade | CheckSVar$ Y | SVarCompare$ EQ0 | Description$ The first spell you cast from exile each turn has cascade. +SVar:Y:Count$ThisTurnCast_Card.YouCtrl+wasCastFromExile +DeckNeeds:Keyword$Cascade +AI:RemoveDeck:Random +Oracle:The first spell you cast from exile each turn has cascade. (When you cast your first spell from exile, exile cards from the top of your library until you exile a card that costs less. You may cast it without paying its mana cost. Put the exiled cards on the bottom of your library in a random order.) diff --git a/forge-gui/res/cardsfolder/upcoming/wild_shape.txt b/forge-gui/res/cardsfolder/w/wild_shape.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/wild_shape.txt rename to forge-gui/res/cardsfolder/w/wild_shape.txt diff --git a/forge-gui/res/cardsfolder/upcoming/wish.txt b/forge-gui/res/cardsfolder/w/wish.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/wish.txt rename to forge-gui/res/cardsfolder/w/wish.txt diff --git a/forge-gui/res/cardsfolder/upcoming/wizard_class.txt b/forge-gui/res/cardsfolder/w/wizard_class.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/wizard_class.txt rename to forge-gui/res/cardsfolder/w/wizard_class.txt diff --git a/forge-gui/res/cardsfolder/upcoming/wizards_spellbook.txt b/forge-gui/res/cardsfolder/w/wizards_spellbook.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/wizards_spellbook.txt rename to forge-gui/res/cardsfolder/w/wizards_spellbook.txt diff --git a/forge-gui/res/cardsfolder/w/wulfgar_of_icewind_dale.txt b/forge-gui/res/cardsfolder/w/wulfgar_of_icewind_dale.txt new file mode 100644 index 00000000000..217b878bbc4 --- /dev/null +++ b/forge-gui/res/cardsfolder/w/wulfgar_of_icewind_dale.txt @@ -0,0 +1,7 @@ +Name:Wulfgar of Icewind Dale +ManaCost:3 R G +Types:Legendary Creature Human Barbarian +PT:4/4 +K:Melee +S:Mode$ Panharmonicon | ValidMode$ Attacks,AttackersDeclared,AttackersDeclaredOneTarget | ValidCard$ Permanent.YouCtrl | ValidCause$ Creature.YouCtrl | Description$ If a creature you control attacking would cause a triggered ability of a permanent you control to trigger, that ability triggers an additional time. +Oracle:Melee (Whenever this creature attacks, it gets +1/+1 until end of turn for each opponent you attacked this combat.)\nIf a creature you control attacking would cause a triggered ability of a permanent you control to trigger, that ability triggers an additional time. diff --git a/forge-gui/res/cardsfolder/upcoming/xanathar_guild_kingpin.txt b/forge-gui/res/cardsfolder/x/xanathar_guild_kingpin.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/xanathar_guild_kingpin.txt rename to forge-gui/res/cardsfolder/x/xanathar_guild_kingpin.txt diff --git a/forge-gui/res/cardsfolder/x/xorn.txt b/forge-gui/res/cardsfolder/x/xorn.txt new file mode 100644 index 00000000000..1b82cc5ee5c --- /dev/null +++ b/forge-gui/res/cardsfolder/x/xorn.txt @@ -0,0 +1,9 @@ +Name:Xorn +ManaCost:2 R +Types:Creature Elemental +PT:3/2 +R:Event$ CreateToken | ActiveZones$ Battlefield | ValidPlayer$ You | ValidToken$ Treasure | ReplaceWith$ DBReplace | Description$ If you would create one or more Treasure tokens, instead create those tokens plus an additional Treasure token. +SVar:DBReplace:DB$ ReplaceToken | Type$ AddToken | Amount$ 1 | ValidCard$ Treasure | TokenScript$ c_a_treasure_sac +DeckNeeds:Type$Token +AI:RemoveDeck:Random +Oracle:If you would create one or more Treasure tokens, instead create those tokens plus an additional Treasure token. diff --git a/forge-gui/res/cardsfolder/upcoming/you_come_to_a_gnoll_camp.txt b/forge-gui/res/cardsfolder/y/you_come_to_a_gnoll_camp.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/you_come_to_a_gnoll_camp.txt rename to forge-gui/res/cardsfolder/y/you_come_to_a_gnoll_camp.txt diff --git a/forge-gui/res/cardsfolder/upcoming/you_come_to_a_river.txt b/forge-gui/res/cardsfolder/y/you_come_to_a_river.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/you_come_to_a_river.txt rename to forge-gui/res/cardsfolder/y/you_come_to_a_river.txt diff --git a/forge-gui/res/cardsfolder/upcoming/you_find_a_cursed_idol.txt b/forge-gui/res/cardsfolder/y/you_find_a_cursed_idol.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/you_find_a_cursed_idol.txt rename to forge-gui/res/cardsfolder/y/you_find_a_cursed_idol.txt diff --git a/forge-gui/res/cardsfolder/upcoming/you_find_some_prisoners.txt b/forge-gui/res/cardsfolder/y/you_find_some_prisoners.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/you_find_some_prisoners.txt rename to forge-gui/res/cardsfolder/y/you_find_some_prisoners.txt diff --git a/forge-gui/res/cardsfolder/upcoming/you_find_the_villains_lair.txt b/forge-gui/res/cardsfolder/y/you_find_the_villains_lair.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/you_find_the_villains_lair.txt rename to forge-gui/res/cardsfolder/y/you_find_the_villains_lair.txt diff --git a/forge-gui/res/cardsfolder/upcoming/you_happen_on_a_glade.txt b/forge-gui/res/cardsfolder/y/you_happen_on_a_glade.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/you_happen_on_a_glade.txt rename to forge-gui/res/cardsfolder/y/you_happen_on_a_glade.txt diff --git a/forge-gui/res/cardsfolder/upcoming/you_hear_something_on_watch.txt b/forge-gui/res/cardsfolder/y/you_hear_something_on_watch.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/you_hear_something_on_watch.txt rename to forge-gui/res/cardsfolder/y/you_hear_something_on_watch.txt diff --git a/forge-gui/res/cardsfolder/upcoming/you_meet_in_a_tavern.txt b/forge-gui/res/cardsfolder/y/you_meet_in_a_tavern.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/you_meet_in_a_tavern.txt rename to forge-gui/res/cardsfolder/y/you_meet_in_a_tavern.txt diff --git a/forge-gui/res/cardsfolder/upcoming/you_see_a_guard_approach.txt b/forge-gui/res/cardsfolder/y/you_see_a_guard_approach.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/you_see_a_guard_approach.txt rename to forge-gui/res/cardsfolder/y/you_see_a_guard_approach.txt diff --git a/forge-gui/res/cardsfolder/upcoming/you_see_a_pair_of_goblins.txt b/forge-gui/res/cardsfolder/y/you_see_a_pair_of_goblins.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/you_see_a_pair_of_goblins.txt rename to forge-gui/res/cardsfolder/y/you_see_a_pair_of_goblins.txt diff --git a/forge-gui/res/cardsfolder/upcoming/youre_ambushed_on_the_road.txt b/forge-gui/res/cardsfolder/y/youre_ambushed_on_the_road.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/youre_ambushed_on_the_road.txt rename to forge-gui/res/cardsfolder/y/youre_ambushed_on_the_road.txt diff --git a/forge-gui/res/cardsfolder/upcoming/yuan_ti_fang_blade.txt b/forge-gui/res/cardsfolder/y/yuan_ti_fang_blade.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/yuan_ti_fang_blade.txt rename to forge-gui/res/cardsfolder/y/yuan_ti_fang_blade.txt diff --git a/forge-gui/res/cardsfolder/upcoming/yuan_ti_malison.txt b/forge-gui/res/cardsfolder/y/yuan_ti_malison.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/yuan_ti_malison.txt rename to forge-gui/res/cardsfolder/y/yuan_ti_malison.txt diff --git a/forge-gui/res/cardsfolder/upcoming/zalto_fire_giant_duke.txt b/forge-gui/res/cardsfolder/z/zalto_fire_giant_duke.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/zalto_fire_giant_duke.txt rename to forge-gui/res/cardsfolder/z/zalto_fire_giant_duke.txt diff --git a/forge-gui/res/cardsfolder/upcoming/zariel_archduke_of_avernus.txt b/forge-gui/res/cardsfolder/z/zariel_archduke_of_avernus.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/zariel_archduke_of_avernus.txt rename to forge-gui/res/cardsfolder/z/zariel_archduke_of_avernus.txt diff --git a/forge-gui/res/cardsfolder/upcoming/zombie_ogre.txt b/forge-gui/res/cardsfolder/z/zombie_ogre.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/zombie_ogre.txt rename to forge-gui/res/cardsfolder/z/zombie_ogre.txt diff --git a/forge-gui/res/draft/rankings.txt b/forge-gui/res/draft/rankings.txt index 9ce21b6f44c..c419e06d371 100644 --- a/forge-gui/res/draft/rankings.txt +++ b/forge-gui/res/draft/rankings.txt @@ -1,4 +1,266 @@ //Rank|Name|Rarity|Set +#1|Iymrith, Desert Doom|M|AFR +#2|Lolth, Spider Queen|M|AFR +#3|Mordenkainen|M|AFR +#4|Icingdeath, Frost Tyrant|M|AFR +#5|Inferno of the Star Mounts|M|AFR +#6|Varis, Silverymoon Ranger|R|AFR +#7|Ebondeath, Dracolich|M|AFR +#8|Adult Gold Dragon|R|AFR +#9|Drizzt Do'Urden|R|AFR +#10|Westgate Regent|R|AFR +#11|Xanathar, Guild Kingpin|M|AFR +#12|Gelatinous Cube|R|AFR +#13|Orcus, Prince of Undeath|R|AFR +#14|Zariel, Archduke of Avernus|M|AFR +#15|Mind Flayer|R|AFR +#16|Froghemoth|R|AFR +#17|The Book of Exalted Deeds|M|AFR +#18|Grand Master of Flowers|M|AFR +#19|Old Gnawbone|M|AFR +#20|Ranger Class|R|AFR +#21|Nadaar, Selfless Paladin|R|AFR +#22|Skeletal Swarming|R|AFR +#23|Meteor Swarm|R|AFR +#24|Flameskull|M|AFR +#25|Dancing Sword|R|AFR +#26|Werewolf Pack Leader|R|AFR +#27|Vorpal Sword|R|AFR +#28|Ellywick Tumblestrum|M|AFR +#29|Minsc, Beloved Ranger|M|AFR +#30|Paladin Class|R|AFR +#31|Lair of the Hydra|R|AFR +#32|Hobgoblin Bandit Lord|R|AFR +#33|Teleportation Circle|R|AFR +#34|Grazilaxx, Illithid Scholar|R|AFR +#35|Ochre Jelly|R|AFR +#36|Hall of Storm Giants|R|AFR +#37|Den of the Bugbear|R|AFR +#38|Cave of the Frost Dragon|R|AFR +#39|Forsworn Paladin|R|AFR +#40|Monk Class|R|AFR +#41|Yuan-Ti Malison|R|AFR +#42|Triumphant Adventurer|R|AFR +#43|Wight|R|AFR +#44|Hive of the Eye Tyrant|R|AFR +#45|Grim Bounty|C|AFR +#46|Hand of Vecna|R|AFR +#47|Acererak the Archlich|M|AFR +#48|Volo, Guide to Monsters|R|AFR +#49|Demilich|M|AFR +#50|Tiamat|M|AFR +#51|Dragon's Fire|C|AFR +#52|Fighter Class|R|AFR +#53|Gretchen Titchwillow|U|AFR +#54|Zalto, Fire Giant Duke|R|AFR +#55|Dragon Turtle|R|AFR +#56|Sphere of Annihilation|R|AFR +#57|Priest of Ancient Lore|C|AFR +#58|Loyal Warhound|R|AFR +#59|Burning Hands|U|AFR +#60|Sorcerer Class|R|AFR +#61|Ingenious Smith|U|AFR +#62|Wandering Troubadour|U|AFR +#63|Wizard's Spellbook|R|AFR +#64|Targ Nar, Demon-Fang Gnoll|U|AFR +#65|Krydle of Baldur's Gate|U|AFR +#66|Trelasarra, Moon Dancer|U|AFR +#67|Bruenor Battlehammer|U|AFR +#68|Magic Missile|U|AFR +#69|Asmodeus the Archfiend|R|AFR +#70|Ray of Enfeeblement|U|AFR +#71|Cleric Class|U|AFR +#72|Precipitous Drop|C|AFR +#73|Eccentric Apprentice|U|AFR +#74|Bag of Holding|U|AFR +#75|Hama Pashar, Ruin Seeker|U|AFR +#76|Barrowin of Clan Undurr|U|AFR +#77|Farideh, Devil's Chosen|U|AFR +#78|Intrepid Outlander|U|AFR +#79|Power Word Kill|U|AFR +#80|Rust Monster|U|AFR +#81|Spoils of the Hunt|C|AFR +#82|Rogue Class|R|AFR +#83|Instrument of the Bards|R|AFR +#84|Kalain, Reclusive Painter|U|AFR +#85|Minimus Containment|C|AFR +#86|Guardian of Faith|R|AFR +#87|Skullport Merchant|U|AFR +#88|Ray of Frost|U|AFR +#89|Shessra, Death's Whisper|U|AFR +#90|The Blackstaff of Waterdeep|R|AFR +#91|Circle of Dreams Druid|R|AFR +#92|Battle Cry Goblin|U|AFR +#93|Devoted Paladin|C|AFR +#94|The Tarrasque|M|AFR +#95|Prosperous Innkeeper|U|AFR +#96|Aberrant Mind Sorcerer|U|AFR +#97|White Dragon|U|AFR +#98|Divine Smite|U|AFR +#99|Barbarian Class|U|AFR +#100|Warlock Class|U|AFR +#101|Wizard Class|U|AFR +#102|The Deck of Many Things|M|AFR +#103|Death-Priest of Myrkul|U|AFR +#104|Djinni Windseer|C|AFR +#105|Delina, Wild Mage|R|AFR +#106|Hunter's Mark|U|AFR +#107|Displacer Beast|U|AFR +#108|Charmed Sleep|C|AFR +#109|The Book of Vile Darkness|M|AFR +#110|Celestial Unicorn|C|AFR +#111|Tiger-Tribe Hunter|U|AFR +#112|Owlbear|C|AFR +#113|Cloister Gargoyle|U|AFR +#114|Farideh's Fireball|C|AFR +#115|Eye of Vecna|R|AFR +#116|Monk of the Open Hand|C|AFR +#117|Long Rest|R|AFR +#118|Xorn|R|AFR +#119|Bard Class|R|AFR +#120|Split the Party|U|AFR +#121|Goblin Morningstar|U|AFR +#122|Feywild Trickster|U|AFR +#123|Hulking Bugbear|U|AFR +#124|Red Dragon|U|AFR +#125|Grim Wanderer|U|AFR +#126|Chaos Channeler|U|AFR +#127|Drider|U|AFR +#128|Green Dragon|U|AFR +#129|Blue Dragon|U|AFR +#130|Check for Traps|U|AFR +#131|Eyes of the Beholder|C|AFR +#132|True Polymorph|R|AFR +#133|Sudden Insight|U|AFR +#134|Druid Class|U|AFR +#135|Reaper's Talisman|U|AFR +#136|Veteran Dungeoneer|C|AFR +#137|Lightfoot Rogue|U|AFR +#138|Treasure Chest|R|AFR +#139|Swarming Goblins|C|AFR +#140|Air-Cult Elemental|C|AFR +#141|Dungeon Map|U|AFR +#142|Elturgard Ranger|C|AFR +#143|You See a Pair of Goblins|U|AFR +#144|Black Dragon|U|AFR +#145|Purple Worm|U|AFR +#146|You Come to a River|C|AFR +#147|Iron Golem|U|AFR +#148|Steadfast Paladin|C|AFR +#149|Temple of the Dragon Queen|U|AFR +#150|Circle of the Moon Druid|C|AFR +#151|Plate Armor|U|AFR +#152|Wild Shape|U|AFR +#153|Rally Maneuver|U|AFR +#154|Sepulcher Ghoul|C|AFR +#155|Trickster's Talisman|U|AFR +#156|Soulknife Spy|C|AFR +#157|Clattering Skeletons|C|AFR +#158|Planar Ally|C|AFR +#159|Hill Giant Herdgorger|C|AFR +#160|Power of Persuasion|U|AFR +#161|Loathsome Troll|U|AFR +#162|Bulette|C|AFR +#163|Guild Thief|U|AFR +#164|Manticore|C|AFR +#165|Fifty Feet of Rope|U|AFR +#166|Moon-Blessed Cleric|U|AFR +#167|Inspiring Bard|C|AFR +#168|Hobgoblin Captain|C|AFR +#169|Wish|R|AFR +#170|Valor Singer|U|AFR +#171|Portable Hole|C|AFR +#172|Dungeon Crawler|C|AFR +#173|Vampire Spawn|C|AFR +#174|Hoard Robber|C|AFR +#175|Armory Veteran|C|AFR +#176|Boots of Speed|C|AFR +#177|Underdark Basilisk|C|AFR +#178|Arborea Pegasus|C|AFR +#179|Blink Dog|U|AFR +#180|Neverwinter Dryad|C|AFR +#181|Unexpected Windfall|C|AFR +#182|Arcane Investigator|C|AFR +#183|You Meet in a Tavern|U|AFR +#184|Dire Wolf Prowler|C|AFR +#185|Secret Door|C|AFR +#186|Dragon's Disciple|U|AFR +#187|Sylvan Shepherd|C|AFR +#188|Pixie Guide|C|AFR +#189|Scion of Stygia|C|AFR +#190|Contact Other Plane|C|AFR +#191|Jaded Sell-Sword|C|AFR +#192|Hoarding Ogre|C|AFR +#193|Lurking Roper|U|AFR +#194|Rimeshield Frost Giant|C|AFR +#195|Fly|U|AFR +#196|Find the Path|C|AFR +#197|Zombie Ogre|C|AFR +#198|Keen-Eared Sentry|U|AFR +#199|Dwarfhold Champion|C|AFR +#200|Yuan-Ti Fang-Blade|C|AFR +#201|Half-Elf Monk|C|AFR +#202|Clever Conjurer|C|AFR +#203|You Happen On a Glade|C|AFR +#204|Gnoll Hunter|C|AFR +#205|Dungeon Descent|R|AFR +#206|Improvised Weaponry|C|AFR +#207|Spiked Pit Trap|C|AFR +#208|You Hear Something on Watch|C|AFR +#209|Choose Your Weapon|U|AFR +#210|Orb of Dragonkind|R|AFR +#211|You Find the Villains' Lair|C|AFR +#212|Baleful Beholder|C|AFR +#213|Ranger's Hawk|C|AFR +#214|Oswald Fiddlebender|R|AFR +#215|Mimic|C|AFR +#216|Flumph|R|AFR +#217|Tasha's Hideous Laughter|R|AFR +#218|Shortcut Seeker|C|AFR +#219|Evolving Wilds|C|AFR +#220|Deadly Dispute|C|AFR +#221|Thieves' Tools|C|AFR +#222|Ranger's Longbow|C|AFR +#223|Paladin's Shield|C|AFR +#224|Demogorgon's Clutches|U|AFR +#225|Delver's Torch|C|AFR +#226|Hired Hexblade|C|AFR +#227|Herald of Hadar|C|AFR +#228|Bar the Gate|C|AFR +#229|Feign Death|C|AFR +#230|You Find a Cursed Idol|C|AFR +#231|You Come to the Gnoll Camp|C|AFR +#232|You Find Some Prisoners|C|AFR +#233|Earth-Cult Elemental|C|AFR +#234|Kick in the Door|C|AFR +#235|Fates' Reversal|C|AFR +#236|+2 Mace|C|AFR +#237|Plundering Barbarian|C|AFR +#238|Dawnbringer Cleric|C|AFR +#239|Bull's Strength|C|AFR +#240|Dueling Rapier|C|AFR +#241|Minion of the Mighty|R|AFR +#242|Greataxe|C|AFR +#243|Spare Dagger|C|AFR +#244|Potion of Healing|C|AFR +#245|Critical Hit|U|AFR +#246|Brazen Dwarf|C|AFR +#247|Shocking Grasp|C|AFR +#248|You're Ambushed on the Road|C|AFR +#249|Shambling Ghast|C|AFR +#250|Gloom Stalker|C|AFR +#251|Silver Raven|C|AFR +#252|Compelled Duel|C|AFR +#253|Leather Armor|C|AFR +#254|Scaled Herbalist|C|AFR +#255|Goblin Javelineer|C|AFR +#256|You See a Guard Approach|C|AFR +#257|Devour Intellect|C|AFR +#258|Plummet|C|AFR +#259|Price of Loyalty|C|AFR +#260|Treasure Vault|R|AFR +#261|Mordenkainen's Polymorph|C|AFR +//Rank|Name|Rarity|Set #1|Fury|M|MH2 #2|Grist, the Hunger Tide|M|MH2 #3|Kaldra Compleat|M|MH2 @@ -33391,4 +33653,4 @@ #257|Dust to Dust|U|ME4 #258|Gate to Phyrexia|U|ME4 #259|Tablet of Epityr|C|ME4 -#260|Leeches|R|ME4 +#260|Leeches|R|ME4 \ No newline at end of file diff --git a/forge-gui/res/editions/2021 Lunar New Year.txt b/forge-gui/res/editions/2021 Lunar New Year.txt index 2569019bc78..78af5d1ea3c 100644 --- a/forge-gui/res/editions/2021 Lunar New Year.txt +++ b/forge-gui/res/editions/2021 Lunar New Year.txt @@ -6,9 +6,9 @@ Type=Promo ScryfallCode=PL21 [cards] -1 R Sethron, Hurloon General -2 M Moraug, Fury of Akoum -3 M Ox of Agonas +1 M Moraug, Fury of Akoum +1★ R Sethron, Hurloon General +2 M Ox of Agonas [tokens] r_2_3_minotaur diff --git a/forge-gui/res/editions/Dungeons & Dragons Adventures in the Forgotten Realms Commander.txt b/forge-gui/res/editions/Dungeons & Dragons Adventures in the Forgotten Realms Commander.txt index 1a58da53b6b..6415779a8cb 100644 --- a/forge-gui/res/editions/Dungeons & Dragons Adventures in the Forgotten Realms Commander.txt +++ b/forge-gui/res/editions/Dungeons & Dragons Adventures in the Forgotten Realms Commander.txt @@ -10,7 +10,346 @@ ScryfallCode=AFC 2 M Prosper, Tome-Bound 3 M Sefris of the Hidden Ways 4 M Vrondiss, Rage of Ancients +5 R Fey Steed +6 R Holy Avenger +7 R Immovable Rod +8 R Mantle of the Ancients +9 R Radiant Solar +10 R Revivify +11 R Robe of Stars +12 R Thorough Investigation +13 R Valiant Endeavor +14 R Arcane Endeavor +15 R Diviner's Portent +16 R Minn, Wily Illusionist +17 R Netherese Puzzle-Ward +18 R Phantom Steed +19 R Rod of Absorption +20 R Winged Boots +21 R Bag of Devouring +22 R Danse Macabre +23 R Death Tyrant +24 R Grave Endeavor +25 R Grim Hireling +26 R Hellish Rebuke +27 R Lorcan, Warlock Collector +28 R Wand of Orcus +29 R Berserker's Frenzy +30 R Chaos Dragon +31 R Fiendlash +32 R Maddening Hex +33 R Reckless Endeavor +34 R Share the Spoils +35 R Vengeful Ancestor +36 R Wild-Magic Sorcerer +37 R Bag of Tricks +38 R Belt of Giant Strength +39 R Druid of Purification +40 R Indomitable Might +41 R Neverwinter Hydra +42 R Song of Inspiration +43 R Wild Endeavor +44 R Catti-brie of Mithral Hall +45 R Dragonborn Champion +46 R Extract Brain +47 R Fevered Suspicion +48 R Hurl Through Hell +49 M Karazikar, the Eye Tyrant +50 M Klauth, Unrivaled Ancient +51 R Klauth's Will +52 R Midnight Pathlighter +53 M Nihiloor +54 R Ride the Avalanche +55 M Storvald, Frost Giant Jarl +56 R Wulfgar of Icewind Dale +57 U Bucknard's Everfull Purse +58 U Clay Golem +59 U Component Pouch +60 U Ebony Fly +61 U Sword of Hours +62 U Underdark Rift +63 R Angel of Finality +64 C Angelic Gift +65 M Cataclysmic Gearhulk +66 R Eternal Dragon +67 U Gryff's Boon +68 R Karmic Guide +69 R Puresteel Paladin +70 M Realm-Cloaked Giant +71 C Ronom Unicorn +72 R Sram, Senior Edificer +73 M Sun Titan +74 R Sunblast Angel +75 U Swords to Plowshares +76 U Valorous Stance +77 U Wall of Omens +78 R Winds of Rath +79 C Brainstorm +80 R Champion of Wits +81 R Curator of Mysteries +82 U Curse of Verbosity +83 C Eel Umbra +84 U Forbidden Alchemy +85 R Imprisoned in the Moon +86 U Merfolk Looter +87 U Mulldrifter +88 U Murder of Crows +89 R Phantasmal Image +90 R Prognostic Sphinx +91 U Propaganda +92 U Psychic Impetus +93 U Riverwise Augur +94 U Serum Visions +95 R Chittering Witch +96 R Consuming Vapors +97 R Dead Man's Chest +98 R Doomed Necromancer +99 R Fiend of the Shadows +100 R Gonti, Lord of Luxury +101 R Hex +102 R Marionette Master +103 R Necromantic Selection +104 R Ogre Slumlord +105 U Phthisis +106 R Piper of the Swarm +107 U Plaguecrafter +108 R Pontiff of Blight +109 U Reassembling Skeleton +110 U Shriekmaw +111 U Unburial Rites +112 U Victimize +113 U Anger +114 M Apex of Power +115 M Bogardan Hellkite +116 R Chain Reaction +117 R Chaos Warp +118 R Commune with Lava +119 R Dark-Dweller Oracle +120 R Demanding Dragon +121 R Dire Fleet Daredevil +122 R Disrupt Decorum +123 U Dragonlord's Servant +124 M Dragonmaster Outcast +125 R Dream Pillager +126 R Etali, Primal Storm +127 R Gratuitous Violence +128 R Hoard-Smelter Dragon +129 R Ignite the Future +130 R Izzet Chemister +131 U Light Up the Stage +132 U Loyal Apprentice +133 R Magmaquake +134 R Opportunistic Dragon +135 R Outpost Siege +136 C Rile +137 R Scourge of Valkas +138 U Shiny Impetus +139 R Shivan Hellkite +140 R Skyline Despot +141 R Skyship Stalker +142 R Spit Flame +143 R Taurean Mauler +144 R Tectonic Giant +145 R Terror of Mount Velus +146 U Throes of Chaos +147 R Thunderbreak Regent +148 U Vandalblast +149 R Warstorm Surge +150 C Abundant Growth +151 U Acidic Slime +152 U Beast Within +153 R Chameleon Colossus +154 U Colossal Majesty +155 U Cultivate +156 R Decree of Savagery +157 C Explore +158 C Fertile Ground +159 U Garruk's Uprising +160 R Greater Good +161 R Heroic Intervention +162 U Kenrith's Transformation +163 R Kindred Summons +164 C Nature's Lore +165 U Paradise Druid +166 C Rampant Growth +167 U Rancor +168 R Return of the Wildspeaker +169 C Return to Nature +170 R Rishkar's Expertise +171 R Shamanic Revelation +172 U Utopia Sprawl +173 R Verdant Embrace +174 C Wild Growth +175 M Ashen Rider +176 R Atarka, World Render +177 R Baleful Strix +178 U Bant Charm +179 R Bedevil +180 U Behemoth Sledge +181 U Bituminous Blast +182 U Cloudblazer +183 R Cold-Eyed Selkie +184 U Despark +185 R Fleecemane Lion +186 R Hostage Taker +187 R Knight of Autumn +188 U Necrotic Sliver +189 U Obsessive Stitcher +190 U Rakdos Charm +191 U Savage Ventmaw +192 C Shielding Plax +193 U Terminate +194 R Theater of Horrors +195 R Utter End +196 U Vanish into Memory +197 C Arcane Signet +198 R Argentum Armor +199 R Basilisk Collar +200 U Burnished Hart +201 R Chaos Wand +202 U Colossus Hammer +203 C Commander's Sphere +204 R Dragon's Hoard +205 C Explorer's Scope +206 U Fellwar Stone +207 U Gruul Signet +208 U Heirloom Blade +209 R Masterwork of Ingenuity +210 U Meteor Golem +211 U Mind Stone +212 R Moonsilver Spear +213 C Orazca Relic +214 U Rakdos Signet +215 U Sol Ring +216 R Solemn Simulacrum +217 U Swiftfoot Boots +218 R Sword of the Animist +219 U Talisman of Indulgence +220 U Unstable Obelisk +221 C Viridian Longbow +222 C Wayfarer's Bauble +223 U Arcane Sanctum +224 U Azorius Chancery +225 C Bant Panorama +226 C Bojuka Bog +227 R Canopy Vista +228 R Choked Estuary +229 R Cinder Glade +230 C Command Tower +231 R Crucible of the Spirit Dragon +232 R Darkwater Catacombs +233 U Desert +234 U Dimir Aqueduct +235 C Esper Panorama +236 R Exotic Orchard +237 U Flood Plain +238 R Foreboding Ruins +239 R Fortified Village +240 R Game Trail +241 R Geier Reach Sanitarium +242 U Grasslands +243 U Gruul Turf +244 C Halimar Depths +245 R Haven of the Spirit Dragon +246 R High Market +247 R Lumbering Falls +248 U Mishra's Factory +249 C Mortuary Mire +250 R Mossfire Valley +251 R Mosswort Bridge +252 R Nimbus Maze +253 U Orzhov Basilica +254 C Path of Ancestry +255 R Port Town +256 R Prairie Stream +257 U Rakdos Carnarium +258 U Seaside Citadel +259 R Shadowblood Ridge +260 U Simic Growth Chamber +261 R Skycloud Expanse +262 R Smoldering Marsh +263 R Spinerock Knoll +264 R Sungrass Prairie +265 R Sunken Hollow +266 U Tainted Peak +267 C Terramorphic Expanse +268 C Thriving Grove +269 C Thriving Heath +270 C Thriving Isle +271 C Thriving Moor +272 U Vitu-Ghazi, the City-Tree +273 U Zhalfirin Void +274 R Fey Steed +275 R Holy Avenger +276 R Immovable Rod +277 R Mantle of the Ancients +278 R Radiant Solar +279 R Revivify +280 R Robe of Stars +281 R Thorough Investigation +282 R Valiant Endeavor +283 R Arcane Endeavor +284 R Diviner's Portent +285 R Minn, Wily Illusionist +286 R Netherese Puzzle-Ward +287 R Phantom Steed +288 R Rod of Absorption +289 R Winged Boots +290 R Bag of Devouring +291 R Danse Macabre +292 R Death Tyrant +293 R Grave Endeavor +294 R Grim Hireling +295 R Hellish Rebuke +296 R Lorcan, Warlock Collector +297 R Wand of Orcus +298 R Berserker's Frenzy +299 R Chaos Dragon +300 R Fiendlash +301 R Maddening Hex +302 R Reckless Endeavor +303 R Share the Spoils +304 R Vengeful Ancestor +305 R Wild-Magic Sorcerer +306 R Bag of Tricks +307 R Belt of Giant Strength +308 R Druid of Purification +309 R Indomitable Might +310 R Neverwinter Hydra +311 R Song of Inspiration +312 R Wild Endeavor +313 R Catti-brie of Mithral Hall +314 R Dragonborn Champion +315 R Extract Brain +316 R Fevered Suspicion 317 M Galea, Kindler of Hope +318 R Hurl Through Hell +319 M Karazikar, the Eye Tyrant +320 M Klauth, Unrivaled Ancient +321 C Klauth's Will +322 R Midnight Pathlighter +323 M Nihiloor 324 M Prosper, Tome-Bound +325 R Ride the Avalanche 326 M Sefris of the Hidden Ways +327 M Storvald, Frost Giant Jarl 328 M Vrondiss, Rage of Ancients +329 R Wulfgar of Icewind Dale +330 U Dragonspeaker Shaman +331 U Lightning Greaves + +[tokens] +b_1_1_rat +c_1_1_a_servo +c_1_1_a_thopter_flying +c_a_clue_draw +g_1_1_saproling +g_3_3_beast +r_5_5_dragon_flying +rg_5_4_dragon_spirit_damagesac +u_1_1_illusion_other_illusions +w_2_2_knight_vigilance +w_4_4_angel_flying + +[other] +eternalize_champion_of_wits diff --git a/forge-gui/res/editions/Dungeons & Dragons Adventures in the Forgotten Realms.txt b/forge-gui/res/editions/Dungeons & Dragons Adventures in the Forgotten Realms.txt index a8c9555bb06..1ab73206e1e 100644 --- a/forge-gui/res/editions/Dungeons & Dragons Adventures in the Forgotten Realms.txt +++ b/forge-gui/res/editions/Dungeons & Dragons Adventures in the Forgotten Realms.txt @@ -6,6 +6,9 @@ Code2=AFR MciCode=afr Type=Expansion ScryfallCode=AFR +BoosterCovers=5 +Booster=10 Common, 3 Uncommon, 1 RareMythic, 1 BasicLand +Prerelease=6 Boosters, 1 RareMythic+ [cards] 1 C +2 Mace @@ -425,3 +428,20 @@ ScryfallCode=AFR S Dungeon of the Mad Mage S Lost Mine of Phandelver S Tomb of Annihilation + +[tokens] +b_1_1_skeleton +b_2_1_spider_menace_reach +b_2_2_zombie +the_atropal +boo +c_a_treasure_sac +g_2_2_wolf +guenhwyvar +icingdeath_frost_tongue +r_1_1_devil_burn +r_1_1_goblin +u_1_1_faerie_dragon_flying +u_x_x_dog_illusion_cardsinhand +vecna +w_3_3_angel_flying diff --git a/forge-gui/res/editions/Love Your LGS 2021.txt b/forge-gui/res/editions/Love Your LGS 2021.txt index 7df61471eea..0e4be5a0da4 100644 --- a/forge-gui/res/editions/Love Your LGS 2021.txt +++ b/forge-gui/res/editions/Love Your LGS 2021.txt @@ -7,7 +7,10 @@ ScryfallCode=PLG21 [cards] 1 R Aven Mindcensor +J1 R Orb of Dragonkind 2 R Dig Through Time +J2 R Orb of Dragonkind 3 R Bolas's Citadel +J3 R Orb of Dragonkind 4 R Goblin Guide 5 R Scavenging Ooze diff --git a/forge-gui/res/editions/The List.txt b/forge-gui/res/editions/The List.txt index 76cc9910b11..c1b240c5fec 100644 --- a/forge-gui/res/editions/The List.txt +++ b/forge-gui/res/editions/The List.txt @@ -459,3 +459,52 @@ ScryfallCode=PLIST 451 R Petrified Field 452 R Urborg, Tomb of Yawgmoth 453 L Mountain +454 U Quest for the Holy Relic +455 C Resurrection +456 S Silence +457 U Twinblade Paladin +458 U Undead Slayer +459 U Air Elemental +460 C Invisibility +461 U Invisible Stalker +462 C Jump +463 R Polymorph +464 U Raven Familiar +465 U Sleep +466 C Sleeping Potion +467 R Tempest Djinn +468 R Trade Routes +469 U Treasure Trove +470 U Assassin's Blade +471 R Captivating Vampire +472 R Demonic Tutor +473 C Dungeon Shade +474 R Nightmare +475 U Noxious Ghoul +476 U Tymaret, Chosen from Death +477 U Will-o'-the-Wisp +478 M Balefire Dragon +479 U Fireball +480 C Orcish Lumberjack +481 R Sneak Attack +482 U Stone Giant +483 R Hermit Druid +484 R Traverse the Outlands +485 R Yisan, the Wanderer Bard +486 M Arcades, the Strategist +487 M Daxos the Returned +488 M Dragonlord Dromoka +489 R Grenzo, Dungeon Warden +490 M Hellkite Overlord +491 R Cloud Key +492 R Coveted Jewel +493 R Doubling Cube +494 C Expedition Map +495 R Gauntlet of Power +496 U Golem's Heart +497 R Haunted Plate Mail +498 U Sorcerer's Wand +499 R Staff of Domination +500 R Transmogrifying Wand +501 R Eiganjo Castle +502 R Gemstone Caverns diff --git a/forge-gui/res/formats/Casual/Brawl.txt b/forge-gui/res/formats/Casual/Brawl.txt index 5f574bc5b7b..60a7bdf65ea 100644 --- a/forge-gui/res/formats/Casual/Brawl.txt +++ b/forge-gui/res/formats/Casual/Brawl.txt @@ -3,5 +3,5 @@ Name:Brawl Order:101 Type:Casual Subtype:Commander -Sets:ELD, THB, IKO, M21, ZNR, KHM, STX +Sets:ELD, THB, IKO, M21, ZNR, KHM, STX, AFR Banned:Drannith Magistrate; Lutri, the Spellchaser; Oko, Thief of Crowns; Omnath, Locus of Creation; Runed Halo; Sorcerous Spyglass; Winota, Joiner of Forces; diff --git a/forge-gui/res/formats/Casual/Commander.txt b/forge-gui/res/formats/Casual/Commander.txt index 9c1b8870001..d1bc20d8226 100644 --- a/forge-gui/res/formats/Casual/Commander.txt +++ b/forge-gui/res/formats/Casual/Commander.txt @@ -3,4 +3,4 @@ Name:Commander Type:Casual Subtype:Commander Order:137 -Banned:Adriana's Valor; Advantageous Proclamation; Ashnod's Coupon; Assemble the Rank and Vile; Backup Plan; Brago's Favor; Double Cross; Double Deal; Double Dip; Double Play; Double Stroke; Double Take; Echoing Boon; Emissary's Ploy; Enter the Dungeon; Flash; Hired Heist; Hold the Perimeter; Hymn of the Wilds; Immediate Action; Incendiary Dissent; Iterative Analysis; Lutri, the Spellchaser; Magical Hacker; Mox Lotus; Muzzio's Preparations; Natural Unity; Once More with Feeling; Power Play; R&D's Secret Lair; Richard Garfield, Ph.D.; Secret Summoning; Secrets of Paradise; Sentinel Dispatch; Sovereign's Realm; Staying Power; Summoner's Bond; Time Machine; Unexpected Potential; Weight Advantage; Worldknit; Amulet of Quoz; Bronze Tablet; Contract from Below; Darkpact; Demonic Attorney; Jeweled Bird; Rebirth; Tempest Efreet; Timmerian Fiends; Ancestral Recall; Balance; Biorhythm; Black Lotus; Braids, Cabal Minion; Chaos Orb; Coalition Victory; Channel; Emrakul, the Aeons Torn; Erayo, Soratami Ascendant; Falling Star; Fastbond; Gifts Ungiven; Griselbrand; Iona, Shield of Emeria; Karakas; Leovold, Emissary of Trest; Library of Alexandria; Limited Resources; Mox Emerald; Mox Jet; Mox Pearl; Mox Ruby; Mox Sapphire; Panoptic Mirror; Paradox Engine; Primeval Titan; Prophet of Kruphix; Recurring Nightmare; Rofellos, Llanowar Emissary; Shahrazad; Sundering Titan; Sway of the Stars; Sylvan Primordial; Time Vault; Time Walk; Tinker; Tolarian Academy; Trace Secrets; Upheaval; Worldfire; Yawgmoth's Bargain +Banned:Adriana's Valor; Advantageous Proclamation; Ashnod's Coupon; Assemble the Rank and Vile; Backup Plan; Brago's Favor; Double Cross; Double Deal; Double Dip; Double Play; Double Stroke; Double Take; Echoing Boon; Emissary's Ploy; Enter the Dungeon; Flash; Hired Heist; Hold the Perimeter; Hullbreacher; Hymn of the Wilds; Immediate Action; Incendiary Dissent; Iterative Analysis; Lutri, the Spellchaser; Magical Hacker; Mox Lotus; Muzzio's Preparations; Natural Unity; Once More with Feeling; Power Play; R&D's Secret Lair; Richard Garfield, Ph.D.; Secret Summoning; Secrets of Paradise; Sentinel Dispatch; Sovereign's Realm; Staying Power; Summoner's Bond; Time Machine; Unexpected Potential; Weight Advantage; Worldknit; Amulet of Quoz; Bronze Tablet; Contract from Below; Darkpact; Demonic Attorney; Jeweled Bird; Rebirth; Tempest Efreet; Timmerian Fiends; Ancestral Recall; Balance; Biorhythm; Black Lotus; Braids, Cabal Minion; Chaos Orb; Coalition Victory; Channel; Emrakul, the Aeons Torn; Erayo, Soratami Ascendant; Falling Star; Fastbond; Gifts Ungiven; Griselbrand; Iona, Shield of Emeria; Karakas; Leovold, Emissary of Trest; Library of Alexandria; Limited Resources; Mox Emerald; Mox Jet; Mox Pearl; Mox Ruby; Mox Sapphire; Panoptic Mirror; Paradox Engine; Primeval Titan; Prophet of Kruphix; Recurring Nightmare; Rofellos, Llanowar Emissary; Shahrazad; Sundering Titan; Sway of the Stars; Sylvan Primordial; Time Vault; Time Walk; Tinker; Tolarian Academy; Trace Secrets; Upheaval; Worldfire; Yawgmoth's Bargain diff --git a/forge-gui/res/formats/Sanctioned/Historic.txt b/forge-gui/res/formats/Sanctioned/Historic.txt index d7f9cc86434..c8c6dbb7895 100644 --- a/forge-gui/res/formats/Sanctioned/Historic.txt +++ b/forge-gui/res/formats/Sanctioned/Historic.txt @@ -4,5 +4,5 @@ Type:Digital Subtype:Arena Effective:2019-11-21 Order:142 -Sets:XLN, RIX, DOM, M19, GRN, G18, RNA, WAR, M20, ELD, HA1, THB, HA2, IKO, HA3, M21, JMP, AKR, ZNR, KLR, KHM, HA4, STX, STA, HA5 -Banned:Agent of Treachery; Channel; Counterspell; Dark Ritual; Demonic Tutor; Field of the Dead; Fires of Invention; Lightning Bolt; Oko, Thief of Crowns; Omnath, Locus of Creation; Natural Order; Nexus of Fate; Once Upon a Time; Swords to Plowshares; Teferi, Time Raveler; Veil of Summer; Uro, Titan of Nature's Wrath; Wilderness Reclamation; Winota, Joiner of Forces +Sets:XLN, RIX, DOM, M19, GRN, G18, RNA, WAR, M20, ELD, HA1, THB, HA2, IKO, HA3, M21, JMP, AKR, ZNR, KLR, KHM, HA4, STX, STA, HA5, AFR +Banned:Agent of Treachery; Channel; Counterspell; Dark Ritual; Demonic Tutor; Field of the Dead; Fires of Invention; Lightning Bolt; Oko, Thief of Crowns; Omnath, Locus of Creation; Natural Order; Nexus of Fate; Once Upon a Time; Swords to Plowshares; Teferi, Time Raveler; Thassa's Oracle; Time Warp; Veil of Summer; Uro, Titan of Nature's Wrath; Wilderness Reclamation; Winota, Joiner of Forces diff --git a/forge-gui/res/formats/Sanctioned/Legacy.txt b/forge-gui/res/formats/Sanctioned/Legacy.txt index c6a8f66d607..548a684f4b0 100644 --- a/forge-gui/res/formats/Sanctioned/Legacy.txt +++ b/forge-gui/res/formats/Sanctioned/Legacy.txt @@ -3,5 +3,5 @@ Name:Legacy Order:105 Subtype:Legacy Type:Sanctioned -Sets:7ED, 9ED, ORI, M14, M15, 6ED, 8ED, M11, 3ED, M10, M12, 10E, M13, G18, M21, M20, M19, 5ED, 2ED, 4ED, LEB, LEA, 5DN, SOM, KTK, THS, DIS, JOU, MOR, TMP, SOI, FEM, USG, ALL, ROE, EXO, TSP, LRW, TOR, ALA, RIX, DGM, DKA, MBS, AER, RNA, GTC, CSP, HML, NPH, OGW, ZNR, EMN, UDS, SHM, BNG, SOK, EVE, INV, THB, DOM, NMS, VIS, WAR, GRN, PCY, SCG, MRD, XLN, ONS, IKO, MMQ, CHK, ULG, AKH, MIR, ISD, AVR, KLD, APC, RTR, WWK, PLC, HOU, LEG, AFR, ARN, ICE, STX, LGN, ARB, KHM, CFX, TSB, ZEN, ELD, JUD, GPT, BFZ, BOK, DTK, FRF, FUT, WTH, ODY, RAV, ATQ, DRK, PLS, STH, DST, TD2, HA1, ME4, HA3, HA2, HA5, HA4, MED, ANB, ME3, KLR, PZ2, ANA, PRM, PZ1, AJMP, ME2, TD1, TD0, TPR, VMA, AKR, MBP, PZEN, PGTW, PL21, PFUT, PWAR, PAL01, PJUD, PAL00, PTKDF, PWOR, PWP12, PSTH, POGW, PFRF, PG07, PSUS, PUST, J18, PWP10, PAL02, PAL03, PWP11, J19, PGRN, PM10, PDP14, PRTR, PMPS06, PBNG, J21, G09, PNPH, PM15, PAL06, G08, PDST, J20, PMBS, PMPS07, PEXO, PDOM, PONS, PRW2, PMPS11, PMPS, PM19, PWWK, PCEL, PAL04, PAL05, PMPS10, PDTK, PALP, F10, F04, PMOR, PAL99, PEMN, PCNS, PPLC, PRAV, PPP1, PI14, PXLN, PF20, PTSP, F05, F11, PSCG, PBOOK, F07, F13, PODY, PM12, P08, PSS1, P2HG, P09, PTOR, PDP13, F12, F06, PALA, PXTC, F02, F16, PHOU, PSOM, PI13, PCON, PDGM, PIDW, PMRD, PRNA, P9ED, PHEL, F17, F03, PURL, F15, F01, PWOS, PPC1, PBOK, PTMP, PS19, PS18, PF19, PGPT, PCHK, FNM, F14, PISD, PAKH, PDP15, PRIX, PS15, PPCY, OLGC, OVNT, PLGN, PS14, P03, PDTP, PM14, FS, PPLS, MPR, PKTK, PS16, PRWK, PS17, PBFZ, PSS2, PINV, G03, P8ED, PARL, P04, P10, PSDC, JGP, G99, WW, P11, P05, PDIS, PROE, PDP10, F08, P10E, PELP, PMH1, P07, P5DN, PGRU, SHC, PM11, P06, PUSG, PCMP, PULG, F09, PUDS, PARB, DRC94, PMPS09, PORI, J12, G06, PMMQ, G07, J13, PMPS08, PM20, PSOI, PJSE, G05, G11, PNAT, PSOK, PEVE, PRED, G10, G04, PSHM, PPRO, PAPC, PJJT, ARENA, PKLD, G00, J14, PLGM, P15A, PCSP, PWPN, PJAS, PWP21, PWP09, PDKA, PNEM, PPTK, J15, G01, PG08, PLRW, PMEI, PM13, PHJ, PGTC, J17, PRES, PWCQ, PJOU, PDP12, PAER, PAVR, PTHS, G02, J16, PSUM, PGPX, UGF, PSS3, MM2, MM3, MB1, FMB1, A25, 2XM, MMA, PLIST, CHR, EMA, IMA, TSR, UMA, PUMA, E02, DPA, ATH, MD1, GK1, GK2, CST, BRB, BTD, DKM, FVE, V17, V13, STA, MPS_RNA, V16, SLD, V12, CC1, MPS_GRN, DRB, FVR, SS3, SS1, MPS_AKH, FVL, V15, MPS_KLD, ZNE, PDS, SS2, PD3, SLU, V14, PD2, EXP, MPS_WAR, DDQ, DDE, GS1, DDS, DDU, DD1, DDL, DDF, DDP, DD2, DDR, DDH, DDT, DDK, DDG, DDC, DDM, DDJ, DDO, GVL, JVC, DDI, DVD, DDN, EVG, DDD, C18, C19, C21, C20, C13, CMA, C14, C15, KHC, ZNC, C17, C16, COM, CM1, CM2, PO2, S99, W16, W17, S00, PTK, CP3, POR, CP1, CP2, CMR, MH2, H1R, CNS, BBD, MH1, CN2, JMP, PCA, GNT, ARC, GN2, PC2, E01, HOP, PLG20, PLG21 +Sets:7ED, 9ED, ORI, M14, M15, 6ED, 8ED, M11, 3ED, M10, M12, 10E, M13, G18, M21, M20, M19, 5ED, 2ED, 4ED, LEB, LEA, 5DN, SOM, KTK, THS, DIS, JOU, MOR, TMP, SOI, FEM, USG, ALL, ROE, EXO, TSP, LRW, TOR, ALA, RIX, DGM, DKA, MBS, AER, RNA, GTC, CSP, HML, NPH, OGW, ZNR, EMN, UDS, SHM, BNG, SOK, EVE, INV, THB, DOM, NMS, VIS, WAR, GRN, PCY, SCG, MRD, XLN, ONS, IKO, MMQ, CHK, ULG, AKH, MIR, ISD, AVR, KLD, APC, RTR, WWK, PLC, HOU, LEG, AFR, ARN, ICE, STX, LGN, ARB, KHM, CFX, TSB, ZEN, ELD, JUD, GPT, BFZ, BOK, DTK, FRF, FUT, WTH, ODY, RAV, ATQ, DRK, PLS, STH, DST, TD2, HA1, ME4, HA3, HA2, HA5, HA4, MED, ANB, ME3, KLR, PZ2, ANA, PRM, PZ1, AJMP, ME2, TD1, TD0, TPR, VMA, AKR, MBP, PZEN, PGTW, PL21, PFUT, PWAR, PAL01, PJUD, PAL00, PTKDF, PWOR, PWP12, PSTH, POGW, PFRF, PG07, PSUS, PUST, J18, PWP10, PAL02, PAL03, PWP11, J19, PGRN, PM10, PDP14, PRTR, PMPS06, PBNG, J21, G09, PNPH, PM15, PAL06, G08, PDST, J20, PMBS, PMPS07, PEXO, PDOM, PONS, PRW2, PMPS11, PMPS, PM19, PWWK, PCEL, PAL04, PAL05, PMPS10, PDTK, PALP, F10, F04, PMOR, PAL99, PEMN, PCNS, PPLC, PRAV, PPP1, PI14, PXLN, PF20, PTSP, F05, F11, PSCG, PBOOK, F07, F13, PODY, PM12, P08, PSS1, P2HG, P09, PTOR, PDP13, F12, F06, PALA, PXTC, F02, F16, PHOU, PSOM, PI13, PCON, PDGM, PIDW, PMRD, PRNA, P9ED, PHEL, F17, F03, PURL, F15, F01, PWOS, PPC1, PBOK, PTMP, PS19, PS18, PF19, PGPT, PCHK, FNM, F14, PISD, PAKH, PDP15, PRIX, PS15, PPCY, OLGC, OVNT, PLGN, PS14, P03, PDTP, PM14, FS, PPLS, MPR, PKTK, PS16, PRWK, PS17, PBFZ, PSS2, PINV, G03, P8ED, PARL, P04, P10, PSDC, JGP, G99, WW, P11, P05, PDIS, PROE, PDP10, F08, P10E, PELP, PMH1, P07, P5DN, PGRU, SHC, PM11, P06, PUSG, PCMP, PULG, F09, PUDS, PARB, DRC94, PMPS09, PORI, J12, G06, PMMQ, G07, J13, PMPS08, PM20, PSOI, PJSE, G05, G11, PNAT, PSOK, PEVE, PRED, G10, G04, PSHM, PPRO, PAPC, PJJT, ARENA, PKLD, G00, J14, PLGM, P15A, PCSP, PWPN, PJAS, PWP21, PWP09, PDKA, PNEM, PPTK, J15, G01, PG08, PLRW, PMEI, PM13, PHJ, PGTC, J17, PRES, PWCQ, PJOU, PDP12, PAER, PAVR, PTHS, G02, J16, PSUM, PGPX, UGF, PSS3, MM2, MM3, MB1, FMB1, A25, 2XM, MMA, PLIST, CHR, EMA, IMA, TSR, UMA, PUMA, E02, DPA, ATH, MD1, GK1, GK2, CST, BRB, BTD, DKM, FVE, V17, V13, STA, MPS_RNA, V16, SLD, V12, CC1, MPS_GRN, DRB, FVR, SS3, SS1, MPS_AKH, FVL, V15, MPS_KLD, ZNE, PDS, SS2, PD3, SLU, V14, PD2, EXP, MPS_WAR, DDQ, DDE, GS1, DDS, DDU, DD1, DDL, DDF, DDP, DD2, DDR, DDH, DDT, DDK, DDG, DDC, DDM, DDJ, DDO, GVL, JVC, DDI, DVD, DDN, EVG, DDD, C18, C19, C21, C20, C13, CMA, C14, C15, KHC, ZNC, AFC, C17, C16, COM, CM1, CM2, PO2, S99, W16, W17, S00, PTK, CP3, POR, CP1, CP2, CMR, MH2, H1R, CNS, BBD, MH1, CN2, JMP, PCA, GNT, ARC, GN2, PC2, E01, HOP, PLG20, PLG21 Banned:Adriana's Valor; Advantageous Proclamation; Arcum's Astrolabe; Assemble the Rank and Vile; Backup Plan; Brago's Favor; Deathrite Shaman; Double Stroke; Dreadhorde Arcanist; Echoing Boon; Emissary's Ploy; Gitaxian Probe; Hired Heist; Hold the Perimeter; Hymn of the Wilds; Immediate Action; Incendiary Dissent; Iterative Analysis; Lurrus of the Dream-Den; Muzzio's Preparations; Natural Unity; Oko, Thief of Crowns; Power Play; Secret Summoning; Secrets of Paradise; Sentinel Dispatch; Sovereign's Realm; Summoner's Bond; Underworld Breach; Unexpected Potential; Weight Advantage; Worldknit; Amulet of Quoz; Bronze Tablet; Contract from Below; Darkpact; Demonic Attorney; Jeweled Bird; Rebirth; Tempest Efreet; Timmerian Fiends; Ancestral Recall; Balance; Bazaar of Baghdad; Black Lotus; Channel; Chaos Orb; Demonic Consultation; Demonic Tutor; Dig Through Time; Earthcraft; Falling Star; Fastbond; Flash; Frantic Search; Goblin Recruiter; Gush; Hermit Druid; Imperial Seal; Library of Alexandria; Mana Crypt; Mana Drain; Mana Vault; Memory Jar; Mental Misstep; Mind Twist; Mind's Desire; Mishra's Workshop; Mox Emerald; Mox Jet; Mox Pearl; Mox Ruby; Mox Sapphire; Mystical Tutor; Necropotence; Oath of Druids; Sensei's Divining Top; Shahrazad; Skullclamp; Sol Ring; Strip Mine; Survival of the Fittest; Time Vault; Time Walk; Timetwister; Tinker; Tolarian Academy; Treasure Cruise; Vampiric Tutor; Wheel of Fortune; Windfall; Wrenn and Six; Yawgmoth's Bargain; Yawgmoth's Will; Zirda, the Dawnwaker diff --git a/forge-gui/res/formats/Sanctioned/Modern.txt b/forge-gui/res/formats/Sanctioned/Modern.txt index 2365b4c6edd..5b6f32d0c47 100644 --- a/forge-gui/res/formats/Sanctioned/Modern.txt +++ b/forge-gui/res/formats/Sanctioned/Modern.txt @@ -3,5 +3,5 @@ Name:Modern Order:103 Subtype:Modern Type:Sanctioned -Sets:8ED, MRD, DST, 5DN, CHK, BOK, SOK, 9ED, RAV, GPT, DIS, CSP, TSP, TSB, TSR, PLC, FUT, 10E, LRW, EVE, SHM, MOR, ALA, CFX, ARB, M10, ZEN, WWK, ROE, M11, SOM, MBS, NPH, M12, ISD, DKA, AVR, M13, RTR, GTC, DGM, M14, THS, BNG, JOU, M15, KTK, FRF, DTK, MMA, MM2, MM3, ORI, BFZ, OGW, SOI, EMN, KLD, AER, AKH, W16, W17, HOU, XLN, RIX, DOM, M19, G18, GRN, RNA, WAR, MH1, M20, ELD, THB, IKO, M21, ZNR, KHM, STX, MH2 +Sets:8ED, MRD, DST, 5DN, CHK, BOK, SOK, 9ED, RAV, GPT, DIS, CSP, TSP, TSB, TSR, PLC, FUT, 10E, LRW, EVE, SHM, MOR, ALA, CFX, ARB, M10, ZEN, WWK, ROE, M11, SOM, MBS, NPH, M12, ISD, DKA, AVR, M13, RTR, GTC, DGM, M14, THS, BNG, JOU, M15, KTK, FRF, DTK, MMA, MM2, MM3, ORI, BFZ, OGW, SOI, EMN, KLD, AER, AKH, W16, W17, HOU, XLN, RIX, DOM, M19, G18, GRN, RNA, WAR, MH1, M20, ELD, THB, IKO, M21, ZNR, KHM, STX, MH2, AFR Banned:Ancient Den; Arcum's Astrolabe; Birthing Pod; Blazing Shoal; Bridge from Below; Chrome Mox; Cloudpost; Dark Depths; Deathrite Shaman; Dig Through Time; Dread Return; Eye of Ugin; Faithless Looting; Field of the Dead; Gitaxian Probe; Glimpse of Nature; Golgari Grave-Troll; Great Furnace; Green Sun's Zenith; Hogaak, Arisen Necropolis; Hypergenesis; Krark-Clan Ironworks; Mental Misstep; Mox Opal; Mycosynth Lattice; Mystic Sanctuary; Oko, Thief of Crowns; Once Upon A Time; Ponder; Preordain; Punishing Fire; Rite of Flame; Seat of the Synod; Second Sunrise; Seething Song; Sensei's Divining Top; Simian Spirit Guide; Skullclamp; Splinter Twin; Summer Bloom; Tibalt's Trickery; Treasure Cruise; Tree of Tales; Umezawa's Jitte; Uro, Titan of Nature's Wrath; Vault of Whispers diff --git a/forge-gui/res/formats/Sanctioned/Pioneer.txt b/forge-gui/res/formats/Sanctioned/Pioneer.txt index c4b473332c5..ba13692baaa 100644 --- a/forge-gui/res/formats/Sanctioned/Pioneer.txt +++ b/forge-gui/res/formats/Sanctioned/Pioneer.txt @@ -3,5 +3,5 @@ Name:Pioneer Order:102 Subtype:Pioneer Type:Sanctioned -Sets:RTR, GTC, DGM, M14, THS, BNG, JOU, M15, KTK, FRF, DTK, ORI, BFZ, OGW, SOI, EMN, KLD, AER, AKH, HOU, XLN, RIX, DOM, M19, G18, GRN, RNA, WAR, M20, ELD, THB, IKO, M21, ZNR, KHM, STX +Sets:RTR, GTC, DGM, M14, THS, BNG, JOU, M15, KTK, FRF, DTK, ORI, BFZ, OGW, SOI, EMN, KLD, AER, AKH, HOU, XLN, RIX, DOM, M19, G18, GRN, RNA, WAR, M20, ELD, THB, IKO, M21, ZNR, KHM, STX, AFR Banned:Balustrade Spy; Bloodstained Mire; Felidar Guardian; Field of the Dead; Flooded Strand; Inverter of Truth; Kethis, the Hidden Hand; Leyline of Abundance; Nexus of Fate; Oko, Thief of Crowns; Once Upon a Time; Polluted Delta; Smuggler's Copter; Teferi, Time Raveler; Undercity Informer; Underworld Breach; Uro, Titan of Nature's Wrath; Veil of Summer; Walking Ballista; Wilderness Reclamation; Windswept Heath; Wooded Foothills diff --git a/forge-gui/res/formats/Sanctioned/Standard.txt b/forge-gui/res/formats/Sanctioned/Standard.txt index 779ec92c6ed..c44e7dcce6c 100644 --- a/forge-gui/res/formats/Sanctioned/Standard.txt +++ b/forge-gui/res/formats/Sanctioned/Standard.txt @@ -3,5 +3,5 @@ Name:Standard Order:101 Subtype:Standard Type:Sanctioned -Sets:ELD, THB, IKO, M21, ZNR, KHM, STX +Sets:ELD, THB, IKO, M21, ZNR, KHM, STX, AFR Banned:Cauldron Familiar; Escape to the Wilds; Fires of Invention; Lucky Clover; Oko, Thief of Crowns; Omnath, Locus of Creation; Once Upon a Time; Uro, Titan of Nature's Wrath; Veil of Summer diff --git a/forge-gui/res/formats/Sanctioned/Vintage.txt b/forge-gui/res/formats/Sanctioned/Vintage.txt index 5a68eb7c073..bacd0569ad6 100644 --- a/forge-gui/res/formats/Sanctioned/Vintage.txt +++ b/forge-gui/res/formats/Sanctioned/Vintage.txt @@ -3,6 +3,6 @@ Name:Vintage Order:104 Subtype:Vintage Type:Sanctioned -Sets:7ED, 9ED, ORI, M14, M15, 6ED, 8ED, M11, 3ED, M10, M12, 10E, M13, G18, M21, M20, M19, 5ED, 2ED, 4ED, LEB, LEA, 5DN, SOM, KTK, THS, DIS, JOU, MOR, TMP, SOI, FEM, USG, ALL, ROE, EXO, TSP, LRW, TOR, ALA, RIX, DGM, DKA, MBS, AER, RNA, GTC, CSP, HML, NPH, OGW, ZNR, EMN, UDS, SHM, BNG, SOK, EVE, INV, THB, DOM, NMS, VIS, WAR, GRN, PCY, SCG, MRD, XLN, ONS, IKO, MMQ, CHK, ULG, AKH, MIR, ISD, AVR, KLD, APC, RTR, WWK, PLC, HOU, LEG, AFR, ARN, ICE, STX, LGN, ARB, KHM, CFX, TSB, ZEN, ELD, JUD, GPT, BFZ, BOK, DTK, FRF, FUT, WTH, ODY, RAV, ATQ, DRK, PLS, STH, DST, TD2, HA1, ME4, HA3, HA2, HA5, HA4, MED, ANB, ME3, KLR, PZ2, ANA, PRM, PZ1, AJMP, ME2, TD1, TD0, TPR, VMA, AKR, MBP, PZEN, PGTW, PL21, PFUT, PWAR, PAL01, PJUD, PAL00, PTKDF, PWOR, PWP12, PSTH, POGW, PFRF, PG07, PSUS, PUST, J18, PWP10, PAL02, PAL03, PWP11, J19, PGRN, PM10, PDP14, PRTR, PMPS06, PBNG, J21, G09, PNPH, PM15, PAL06, G08, PDST, J20, PMBS, PMPS07, PEXO, PDOM, PONS, PRW2, PMPS11, PMPS, PM19, PWWK, PCEL, PAL04, PAL05, PMPS10, PDTK, PALP, F10, F04, PMOR, PAL99, PEMN, PCNS, PPLC, PRAV, PPP1, PI14, PXLN, PF20, PTSP, F05, F11, PSCG, PBOOK, F07, F13, PODY, PM12, P08, PSS1, P2HG, P09, PTOR, PDP13, F12, F06, PALA, PXTC, F02, F16, PHOU, PSOM, PI13, PCON, PDGM, PIDW, PMRD, PRNA, P9ED, PHEL, F17, F03, PURL, F15, F01, PWOS, PPC1, PBOK, PTMP, PS19, PS18, PF19, PGPT, PCHK, FNM, F14, PISD, PAKH, PDP15, PRIX, PS15, PPCY, OLGC, OVNT, PLGN, PS14, P03, PDTP, PM14, FS, PPLS, MPR, PKTK, PS16, PRWK, PS17, PBFZ, PSS2, PINV, G03, P8ED, PARL, P04, P10, PSDC, JGP, G99, WW, P11, P05, PDIS, PROE, PDP10, F08, P10E, PELP, PMH1, P07, P5DN, PGRU, SHC, PM11, P06, PUSG, PCMP, PULG, F09, PUDS, PARB, DRC94, PMPS09, PORI, J12, G06, PMMQ, G07, J13, PMPS08, PM20, PSOI, PJSE, G05, G11, PNAT, PSOK, PEVE, PRED, G10, G04, PSHM, PPRO, PAPC, PJJT, ARENA, PKLD, G00, J14, PLGM, P15A, PCSP, PWPN, PJAS, PWP21, PWP09, PDKA, PNEM, PPTK, J15, G01, PG08, PLRW, PMEI, PM13, PHJ, PGTC, J17, PRES, PWCQ, PJOU, PDP12, PAER, PAVR, PTHS, G02, J16, PSUM, PGPX, UGF, PSS3, MM2, MM3, MB1, FMB1, A25, 2XM, MMA, PLIST, CHR, EMA, IMA, TSR, UMA, PUMA, E02, DPA, ATH, MD1, GK1, GK2, CST, BRB, BTD, DKM, FVE, V17, V13, STA, MPS_RNA, V16, SLD, V12, CC1, MPS_GRN, DRB, FVR, SS3, SS1, MPS_AKH, FVL, V15, MPS_KLD, ZNE, PDS, SS2, PD3, SLU, V14, PD2, EXP, MPS_WAR, DDQ, DDE, GS1, DDS, DDU, DD1, DDL, DDF, DDP, DD2, DDR, DDH, DDT, DDK, DDG, DDC, DDM, DDJ, DDO, GVL, JVC, DDI, DVD, DDN, EVG, DDD, C18, C19, C21, C20, C13, CMA, C14, C15, KHC, ZNC, C17, C16, COM, CM1, CM2, PO2, S99, W16, W17, S00, PTK, CP3, POR, CP1, CP2, CMR, MH2, H1R, CNS, BBD, MH1, CN2, JMP, PCA, GNT, ARC, GN2, PC2, E01, HOP, PLG20, PLG21 +Sets:7ED, 9ED, ORI, M14, M15, 6ED, 8ED, M11, 3ED, M10, M12, 10E, M13, G18, M21, M20, M19, 5ED, 2ED, 4ED, LEB, LEA, 5DN, SOM, KTK, THS, DIS, JOU, MOR, TMP, SOI, FEM, USG, ALL, ROE, EXO, TSP, LRW, TOR, ALA, RIX, DGM, DKA, MBS, AER, RNA, GTC, CSP, HML, NPH, OGW, ZNR, EMN, UDS, SHM, BNG, SOK, EVE, INV, THB, DOM, NMS, VIS, WAR, GRN, PCY, SCG, MRD, XLN, ONS, IKO, MMQ, CHK, ULG, AKH, MIR, ISD, AVR, KLD, APC, RTR, WWK, PLC, HOU, LEG, AFR, ARN, ICE, STX, LGN, ARB, KHM, CFX, TSB, ZEN, ELD, JUD, GPT, BFZ, BOK, DTK, FRF, FUT, WTH, ODY, RAV, ATQ, DRK, PLS, STH, DST, TD2, HA1, ME4, HA3, HA2, HA5, HA4, MED, ANB, ME3, KLR, PZ2, ANA, PRM, PZ1, AJMP, ME2, TD1, TD0, TPR, VMA, AKR, MBP, PZEN, PGTW, PL21, PFUT, PWAR, PAL01, PJUD, PAL00, PTKDF, PWOR, PWP12, PSTH, POGW, PFRF, PG07, PSUS, PUST, J18, PWP10, PAL02, PAL03, PWP11, J19, PGRN, PM10, PDP14, PRTR, PMPS06, PBNG, J21, G09, PNPH, PM15, PAL06, G08, PDST, J20, PMBS, PMPS07, PEXO, PDOM, PONS, PRW2, PMPS11, PMPS, PM19, PWWK, PCEL, PAL04, PAL05, PMPS10, PDTK, PALP, F10, F04, PMOR, PAL99, PEMN, PCNS, PPLC, PRAV, PPP1, PI14, PXLN, PF20, PTSP, F05, F11, PSCG, PBOOK, F07, F13, PODY, PM12, P08, PSS1, P2HG, P09, PTOR, PDP13, F12, F06, PALA, PXTC, F02, F16, PHOU, PSOM, PI13, PCON, PDGM, PIDW, PMRD, PRNA, P9ED, PHEL, F17, F03, PURL, F15, F01, PWOS, PPC1, PBOK, PTMP, PS19, PS18, PF19, PGPT, PCHK, FNM, F14, PISD, PAKH, PDP15, PRIX, PS15, PPCY, OLGC, OVNT, PLGN, PS14, P03, PDTP, PM14, FS, PPLS, MPR, PKTK, PS16, PRWK, PS17, PBFZ, PSS2, PINV, G03, P8ED, PARL, P04, P10, PSDC, JGP, G99, WW, P11, P05, PDIS, PROE, PDP10, F08, P10E, PELP, PMH1, P07, P5DN, PGRU, SHC, PM11, P06, PUSG, PCMP, PULG, F09, PUDS, PARB, DRC94, PMPS09, PORI, J12, G06, PMMQ, G07, J13, PMPS08, PM20, PSOI, PJSE, G05, G11, PNAT, PSOK, PEVE, PRED, G10, G04, PSHM, PPRO, PAPC, PJJT, ARENA, PKLD, G00, J14, PLGM, P15A, PCSP, PWPN, PJAS, PWP21, PWP09, PDKA, PNEM, PPTK, J15, G01, PG08, PLRW, PMEI, PM13, PHJ, PGTC, J17, PRES, PWCQ, PJOU, PDP12, PAER, PAVR, PTHS, G02, J16, PSUM, PGPX, UGF, PSS3, MM2, MM3, MB1, FMB1, A25, 2XM, MMA, PLIST, CHR, EMA, IMA, TSR, UMA, PUMA, E02, DPA, ATH, MD1, GK1, GK2, CST, BRB, BTD, DKM, FVE, V17, V13, STA, MPS_RNA, V16, SLD, V12, CC1, MPS_GRN, DRB, FVR, SS3, SS1, MPS_AKH, FVL, V15, MPS_KLD, ZNE, PDS, SS2, PD3, SLU, V14, PD2, EXP, MPS_WAR, DDQ, DDE, GS1, DDS, DDU, DD1, DDL, DDF, DDP, DD2, DDR, DDH, DDT, DDK, DDG, DDC, DDM, DDJ, DDO, GVL, JVC, DDI, DVD, DDN, EVG, DDD, C18, C19, C21, C20, C13, CMA, C14, C15, KHC, ZNC, AFC, C17, C16, COM, CM1, CM2, PO2, S99, W16, W17, S00, PTK, CP3, POR, CP1, CP2, CMR, MH2, H1R, CNS, BBD, MH1, CN2, JMP, PCA, GNT, ARC, GN2, PC2, E01, HOP, PLG20, PLG21 Banned:Adriana's Valor; Advantageous Proclamation; Assemble the Rank and Vile; Backup Plan; Brago's Favor; Double Stroke; Echoing Boon; Emissary's Ploy; Hired Heist; Hold the Perimeter; Hymn of the Wilds; Immediate Action; Incendiary Dissent; Iterative Analysis; Muzzio's Preparations; Natural Unity; Power Play; Secret Summoning; Secrets of Paradise; Sentinel Dispatch; Sovereign's Realm; Summoner's Bond; Unexpected Potential; Weight Advantage; Worldknit; Amulet of Quoz; Bronze Tablet; Contract from Below; Darkpact; Demonic Attorney; Jeweled Bird; Rebirth; Tempest Efreet; Timmerian Fiends; Chaos Orb; Falling Star; Shahrazad Restricted:Ancestral Recall; Balance; Black Lotus; Brainstorm; Chalice of the Void; Channel; Demonic Consultation; Demonic Tutor; Dig Through Time; Flash; Gitaxian Probe; Golgari Grave-Troll; Gush; Imperial Seal; Karn, the Great Creator; Library of Alexandria; Lion's Eye Diamond; Lodestone Golem; Lotus Petal; Mana Crypt; Mana Vault; Memory Jar; Mental Misstep; Merchant Scroll; Mind's Desire; Monastery Mentor; Mox Emerald; Mox Jet; Mox Pearl; Mox Ruby; Mox Sapphire; Mystic Forge; Mystical Tutor; Narset, Parter of Veils; Necropotence; Ponder; Sol Ring; Strip Mine; Thorn of Amethyst; Time Vault; Time Walk; Timetwister; Tinker; Tolarian Academy; Treasure Cruise; Trinisphere; Vampiric Tutor; Wheel of Fortune; Windfall; Yawgmoth's Will diff --git a/forge-gui/res/languages/de-DE.properties b/forge-gui/res/languages/de-DE.properties index 470ae4aa85f..d4c8e95c0f7 100644 --- a/forge-gui/res/languages/de-DE.properties +++ b/forge-gui/res/languages/de-DE.properties @@ -1034,7 +1034,7 @@ lblEnableUnknownCards=Erlaube unbekannte Karten nlEnableUnknownCards=Erlaube unbekannte Karten von unbekannten Sets. (Erfordert Neustart) lblEnableNonLegalCards=Erlaube nicht-legale Karten nlEnableNonLegalCards=Erlaube nicht-legale Karten, wie Un-Sets and PlayTest-Karten. (Erfordert Neustart) -lblEnableCustomCards=Erlaube benutzerdefinierten Karten +lblEnableCustomCards=Erlaube benutzerdefinierte Karten nlEnableCustomCards=Aktivieren Sie die Verwendung von benutzerdefinierten Karten für das Spielen. (Erfordert Neustart) lblDisableCardImages=Kartenbilder abschalten nlDisableCardImages=Wenn aktiviert, zeigt Forge keine Kartenbilder mehr. @@ -1725,6 +1725,7 @@ lblDoYouWantPayNLife=Möchtest du {0} Leben bezahlen? lblDoyouWantTo=Möchtest du lblDoYouWantMillNCardsOrDoAction=Möchtest du {0} Karte(n) von der Bibliothek auf den Friedhof legen? {1} lblDoYouWantFlipNCoinAction=Möchtest du {0} Münze(n) werfen? +lblDoYouWantRollNDiceAction=Möchtest du mit {0}{1} würfeln? lblDoYouWantRemoveNTargetTypeCounterFromCard=Möchtest du {0} {1}-Marken von {2} entfernen? lblDoYouWantRemoveCountersFromCard=Möchtest du Marken von {0} entfernen? lblDoYouWantExileNCardsFromYourLibrary=Möchtest du {0} Karte(n) von deiner Bibliothek ins Exil schicken? diff --git a/forge-gui/res/languages/en-US.properties b/forge-gui/res/languages/en-US.properties index 8281fac578b..9bca8751700 100644 --- a/forge-gui/res/languages/en-US.properties +++ b/forge-gui/res/languages/en-US.properties @@ -1725,6 +1725,7 @@ lblDoYouWantPayNLife=Do you want to pay {0} life? lblDoyouWantTo=Do you want to lblDoYouWantMillNCardsOrDoAction=Do you want to mill {0} card(s)? {1} lblDoYouWantFlipNCoinAction=Do you want to flip {0} coin(s)? +lblDoYouWantRollNDiceAction=Do you want to roll {0}{1}? lblDoYouWantRemoveNTargetTypeCounterFromCard=Do you want to remove {0} {1} counter from {2}? lblDoYouWantRemoveCountersFromCard=Do you want to remove counters from {0}? lblDoYouWantExileNCardsFromYourLibrary=Do you want to exile {0} card(s) from your library? diff --git a/forge-gui/res/languages/es-ES.properties b/forge-gui/res/languages/es-ES.properties index 670c71b1f39..fbc8c2ee7bd 100644 --- a/forge-gui/res/languages/es-ES.properties +++ b/forge-gui/res/languages/es-ES.properties @@ -1724,6 +1724,7 @@ lblDoYouWantPayNLife=¿Quieres pagar {0} de vida? lblDoyouWantTo=¿Quieres lblDoYouWantMillNCardsOrDoAction=¿Quieres moler {0} carta(s)? {1} lblDoYouWantFlipNCoinAction=¿Quieres lanzar {0} moneda(s)? +lblDoYouWantRollNDiceAction=Do you want to roll {0}{1}? lblDoYouWantRemoveNTargetTypeCounterFromCard=¿Quieres quitar el contador {0} {1} de {2}? lblDoYouWantRemoveCountersFromCard=¿Quieres quitar los contadores de {0}? lblDoYouWantExileNCardsFromYourLibrary=¿Quieres exiliar {0} carta(s) de tu biblioteca? diff --git a/forge-gui/res/languages/it-IT.properties b/forge-gui/res/languages/it-IT.properties index 8c488fb82f9..705c55d8a55 100644 --- a/forge-gui/res/languages/it-IT.properties +++ b/forge-gui/res/languages/it-IT.properties @@ -1724,6 +1724,7 @@ lblDoYouWantPayNLife=Vuoi pagare {0} punti vita? lblDoyouWantTo=Vuoi lblDoYouWantMillNCardsOrDoAction=Vuoi macinare {0} carta/e? {1} lblDoYouWantFlipNCoinAction=Vuoi lanciare {0} moneta/e? +lblDoYouWantRollNDiceAction=Do you want to roll {0}{1}? lblDoYouWantRemoveNTargetTypeCounterFromCard=Vuoi rimuovere {0} segnalino {1} da {2}? lblDoYouWantRemoveCountersFromCard=Vuoi rimuovere i segnalini da {0}? lblDoYouWantExileNCardsFromYourLibrary=Vuoi esiliare {0} carta/e dal tuo grimorio? diff --git a/forge-gui/res/languages/ja-JP.properties b/forge-gui/res/languages/ja-JP.properties index dd183bd0b6b..5792fd342ac 100644 --- a/forge-gui/res/languages/ja-JP.properties +++ b/forge-gui/res/languages/ja-JP.properties @@ -1724,7 +1724,8 @@ lblDoYouWantPay=プレイしますか? lblDoYouWantPayNLife={0}点のライフを支払いますか? lblDoyouWantTo=この行動をしてもいい? lblDoYouWantMillNCardsOrDoAction={0}枚のカードを切削しますか? {1} -lblDoYouWantFlipNCoinOrDoAction={0}枚のコイントスをしますか? {1} +lblDoYouWantFlipNCoinAction={0}枚のコイントスをしますか? +lblDoYouWantRollNDiceAction={0}{1}を投げますか? lblDoYouWantRemoveNTargetTypeCounterFromCard={2}から {1}個の {0}カウンターを取り除きますか? lblDoYouWantRemoveCountersFromCard={0}からカウンターを取り除きますか? lblDoYouWantExileNCardsFromYourLibrary=ライブラリーから {0}枚のカードを追放しますか? diff --git a/forge-gui/res/languages/zh-CN.properties b/forge-gui/res/languages/zh-CN.properties index 533f8a7552d..1f0cc199f83 100644 --- a/forge-gui/res/languages/zh-CN.properties +++ b/forge-gui/res/languages/zh-CN.properties @@ -1725,6 +1725,7 @@ lblDoYouWantPayNLife=你想要支付{0}点生命吗? lblDoyouWantTo=你想要 lblDoYouWantMillNCardsOrDoAction=你想要磨{0}张牌吗? {1} lblDoYouWantFlipNCoinAction=你想要抛{0}个硬币吗? +lblDoYouWantRollNDiceAction=Do you want to roll {0}{1}? lblDoYouWantRemoveNTargetTypeCounterFromCard=你想要从{2}移除{0}个{1}指示物吗? lblDoYouWantRemoveCountersFromCard=你想要从{0}删除指示物吗? lblDoYouWantExileNCardsFromYourLibrary=你想要从你的牌库放逐{0}张牌吗? diff --git a/forge-gui/res/lists/altwin-achievements.txt b/forge-gui/res/lists/altwin-achievements.txt index 2a574c9d2b3..eb5160eb27d 100644 --- a/forge-gui/res/lists/altwin-achievements.txt +++ b/forge-gui/res/lists/altwin-achievements.txt @@ -32,6 +32,7 @@ Strixhaven Stadium|The Mage Tower|And that's game, set, and match! Test of Endurance|The Test|So... did I pass? Thassa's Oracle|The Prophecy of Victory|I see... nothing. We must've won. The Cheese Stands Alone|The Cheese|It's cheesy, but hey, it works! +The Deck of Many Things|Down on the Deck|Lucky draw! Triskaidekaphobia|The Fear of 13|It's just a silly ancient superstition... right? -Vorpal Sword|Snicker-Snack!|"And hast thou slain the Jabberwock? Come to my arms, my beamish boy!" +Vorpal Sword|Snicker-Snack!|He left it dead, and with its head / He went galumphing back. Emblem - Vraska, Golgari Queen|The Flurry of Assassins|How good is your dodging? diff --git a/forge-gui/res/lists/planeswalker-achievements.txt b/forge-gui/res/lists/planeswalker-achievements.txt index aaffb48e65f..3d76a12de2e 100644 --- a/forge-gui/res/lists/planeswalker-achievements.txt +++ b/forge-gui/res/lists/planeswalker-achievements.txt @@ -44,6 +44,7 @@ Dovin Baan|Dovin's Static|Have you tried to turn it off and on again? Dovin, Architect of Law|Dovin's Freeze|With one gear out of place, the whole machine grinds to halt. Dovin, Grand Arbiter|Dovin's Modern Recall|The best solutions for the worst problems. Dungeon Master|Dungeons and Dragons|A fighter, a wizard, a rogue, and a cleric walk into a dungeon... +Ellywick Tumblestrum|Ellywick's Song|Hear the tale of dungeons... and dragons! Elspeth Tirel|Elspeth's Solitude|Tokens are my only friends... Elspeth, Knight-Errant|Elspeth's Endurance|Bant will prevail! Elspeth, Sun's Champion|Elspeth's Crusade|With Heliod on my side, I'm invincible! @@ -106,8 +107,10 @@ Liliana, the Necromancer|Liliana's Recycling|Old foes to new servants, and it's Liliana, Untouched by Death|Liliana's Graveyard Party|What? I'm not touching you! Liliana, Waker of the Dead|Liliana's Rotten Reserves|They awaken, feeling well-rested. Lord Windgrace|Windgrace's Hunting Party|Let me show you a true cat-astrophe. +Lolth, Spider Queen|Lolth's Eight-legged Strike|I eight all my opponents alive. Lukka, Coppercoat Outcast|Lukka's Ultimatum|Get them. Lukka, Wayward Bonder|Lukka's Pandemonium|At them, girl! +Mordenkainen|Mordenkainen's Library|All the manuals you could ever need. Nahiri, Heir of the Ancients|Swiss-Army Nahiri|It pays to be well-equipped. Nahiri, the Harbinger|Nahiri's Mystery Guest|This should be your cue to run. Nahiri, the Lithomancer|Nahiri's Gift|I pulled it out! Now I'm a king! @@ -191,3 +194,4 @@ Jiang Yanggu|Yanggu's Giant Growth|Now, Mowu! Fetch that tree! Mu Yanling|Yanling's Time Manipulation|Sleep now, for three days and three nights. Mu Yanling, Celestial Wind|Yanling's Wind of Heavens|Let's clear the skies. Mu Yanling, Sky Dancer|Yanling's Secrets of the Deep|The water knows. Read in it. +Zariel, Archduke of Avernus|Zariel's Relentless Assault|Attack! For victory and/or death! \ No newline at end of file diff --git a/forge-gui/res/lists/skinsList.txt b/forge-gui/res/lists/skinsList.txt index 7c613692684..677069c1ba9 100644 --- a/forge-gui/res/lists/skinsList.txt +++ b/forge-gui/res/lists/skinsList.txt @@ -131,3 +131,17 @@ https://downloads.cardforge.org/skins/magic/sprite_manaicons.png https://downloads.cardforge.org/skins/magic/sprite_planar_conquest.png https://downloads.cardforge.org/skins/magic/sprite_start.png https://downloads.cardforge.org/skins/magic/sprite_trophies.png +https://downloads.cardforge.org/skins/magic_blue/bg_chaos_wheel.png +https://downloads.cardforge.org/skins/magic_blue/bg_match.jpg +https://downloads.cardforge.org/skins/magic_blue/bg_splash.png +https://downloads.cardforge.org/skins/magic_blue/bg_splash_hd.png +https://downloads.cardforge.org/skins/magic_blue/bg_texture.jpg +https://downloads.cardforge.org/skins/magic_blue/font1.ttf +https://downloads.cardforge.org/skins/magic_blue/hd_logo.png +https://downloads.cardforge.org/skins/magic_blue/sprite_avatars.png +https://downloads.cardforge.org/skins/magic_blue/sprite_buttons.png +https://downloads.cardforge.org/skins/magic_blue/sprite_icons.png +https://downloads.cardforge.org/skins/magic_blue/sprite_manaicons.png +https://downloads.cardforge.org/skins/magic_blue/sprite_planar_conquest.png +https://downloads.cardforge.org/skins/magic_blue/sprite_start.png +https://downloads.cardforge.org/skins/magic_blue/sprite_trophies.png diff --git a/forge-gui/res/puzzle/PS_MH21.pzl b/forge-gui/res/puzzle/PS_MH21.pzl new file mode 100644 index 00000000000..bb84bb5db3a --- /dev/null +++ b/forge-gui/res/puzzle/PS_MH21.pzl @@ -0,0 +1,19 @@ +[metadata] +Name:Possibility Storm - Modern Horizons 2 #01 +URL:https://i2.wp.com/www.possibilitystorm.com/wp-content/uploads/2021/07/178.-MH2_1-1-scaled.jpg +Goal:Win +Turns:1 +Difficulty:Rare +Description:Win this turn. Both graveyards start empty. Assume you have one additional Power Depot and Rustvale Bridge in your deck. +[state] +humanlife=20 +ailife=14 +turn=1 +activeplayer=human +activephase=MAIN1 +humanhand=Mogg Salvage|Set:MH2;Kaleidoscorch|Set:MH2;Fury|Set:MH2;Zuran Orb|Set:MH2;Sojourner's Companion|Set:MH2 +humanlibrary=Rustvale Bridge|Set:MH2;Power Depot|Set:MH2 +humanbattlefield=Arcbound Tracker|Counters:P1P1=2|Set:MH2;Arcbound Whelp|Counters:P1P1=2|Set:MH2;Viashino Lashclaw|Set:MH2;Altar of the Goyf|Set:MH2;Sol Talisman|Set:MH2;Sol Talisman|Set:MH2;Power Depot|Counters:P1P1=1|NoETBTrigs|Set:MH2;Rustvale Bridge|Set:MH2;Rustvale Bridge|Set:MH2;Rustvale Bridge|Set:MH2 +aibattlefield=Glimmer Bairn|Counters:P1P1=1;Glimmer Bairn|Counters:P1P1=1;Void Mirror +aiprecast=Fairgrounds Patrol:CustomScript:DB$ Token | TokenScript$ c_1_1_a_thopter_flying +removesummoningsickness=true diff --git a/forge-gui/res/tokenscripts/rg_5_4_dragon_spirit_damagesac.txt b/forge-gui/res/tokenscripts/rg_5_4_dragon_spirit_damagesac.txt new file mode 100644 index 00000000000..d2d1867d5f0 --- /dev/null +++ b/forge-gui/res/tokenscripts/rg_5_4_dragon_spirit_damagesac.txt @@ -0,0 +1,8 @@ +Name:Dragon Spirit +ManaCost:no cost +Types:Creature Dragon Spirit +Colors:red,green +PT:5/4 +T:Mode$ DamageDealtOnce | ValidSource$ Card.Self | Execute$ TrigSac | TriggerZones$ Battlefield | TriggerDescription$ When this creature deals damage, sacrifice it. +SVar:TrigSac:DB$ Sacrifice | Defined$ Self +Oracle:When this creature deals damage, sacrifice it. diff --git a/forge-gui/res/tokenscripts/b_4_4_the_atropal_deathtouch.txt b/forge-gui/res/tokenscripts/the_atropal.txt similarity index 100% rename from forge-gui/res/tokenscripts/b_4_4_the_atropal_deathtouch.txt rename to forge-gui/res/tokenscripts/the_atropal.txt diff --git a/forge-gui/res/tokenscripts/u_1_1_illusion_other_illusions.txt b/forge-gui/res/tokenscripts/u_1_1_illusion_other_illusions.txt new file mode 100644 index 00000000000..058300289ea --- /dev/null +++ b/forge-gui/res/tokenscripts/u_1_1_illusion_other_illusions.txt @@ -0,0 +1,8 @@ +Name:Illusion +ManaCost:no cost +Types:Creature Illusion +Colors:blue +PT:1/1 +S:Mode$ Continuous | Affected$ Card.Self | AddPower$ X | Description$ This creature gets +1/+0 for each other Illusion you control. +SVar:X:Count$Valid Illusion.Other+YouCtrl +Oracle:This creature gets +1/+0 for each other Illusion you control. diff --git a/forge-gui/src/main/java/forge/deck/CardThemedDeckGenerator.java b/forge-gui/src/main/java/forge/deck/CardThemedDeckGenerator.java index dfd5686b69a..938aca44192 100644 --- a/forge-gui/src/main/java/forge/deck/CardThemedDeckGenerator.java +++ b/forge-gui/src/main/java/forge/deck/CardThemedDeckGenerator.java @@ -14,9 +14,9 @@ import forge.model.FModel; public class CardThemedDeckGenerator extends DeckProxy implements Comparable { public static List getMatrixDecks(GameFormat format, boolean isForAi){ final List decks = new ArrayList<>(); - for(String card: CardArchetypeLDAGenerator.ldaPools.get(format.getName()).keySet()) { + for (String card: CardArchetypeLDAGenerator.ldaPools.get(format.getName()).keySet()) { //exclude non AI playables as keycards for AI decks - if(isForAi&&FModel.getMagicDb().getCommonCards().getUniqueByName(card).getRules().getAiHints().getRemAIDecks()){ + if (isForAi&&FModel.getMagicDb().getCommonCards().getUniqueByName(card).getRules().getAiHints().getRemAIDecks()) { continue; } decks.add(new CardThemedDeckGenerator(card, format, isForAi)); @@ -42,7 +42,6 @@ public class CardThemedDeckGenerator extends DeckProxy implements Comparable 0) { addLands(clrCnts, landSetCode); @@ -352,33 +348,40 @@ public class LimitedDeckBuilder extends DeckGeneratorBase { // total of all ClrCnts int totalColor = 0; - int numColors = 0; for (int i = 0; i < 5; i++) { totalColor += clrCnts[i]; - if (clrCnts[i] > 0) { - numColors++; - } } if (totalColor == 0) { + // TODO: Technically this can happen in a colorless deck. throw new RuntimeException("Add Lands to empty deck list!"); } - - // do not update landsNeeded until after the loop, because the - // calculation involves landsNeeded + + // First, add 2 land of each required color. This prevents the AI from including + // a splash card with no viable way to cast it. for (int i = 0; i < 5; i++) { if (clrCnts[i] > 0) { - // calculate number of lands for each color - float p = (float) clrCnts[i] / (float) totalColor; - if (numColors == 2) { - // In the normal two-color case, constrain to within 40% and 60% so that the AI - // doesn't put too few lands of the lesser color, risking getting screwed on that color. - // Don't do this for the odd case where a third color had to be added to the deck. - p = Math.min(Math.max(p, 0.4f), 0.6f); + int nLand = 2; + System.out.printf("Basics[%s]: %d cards%n", MagicColor.Constant.BASIC_LANDS.get(i), nLand); + for (int j = 0; j < nLand; j++) { + deckList.add(getBasicLand(i, landSetCode)); } - int nLand = Math.round(landsNeeded * p); // desired truncation to int + } + } + + for (int i = 0; i < 5; i++) { + int slotsRemaining = 40-deckList.size(); // How many to still distribute + if (clrCnts[i] > 0) { + // calculate proportion of mana symbols for each remaining color + float p = (float) clrCnts[i] / (float) totalColor; + + // Rounding prefers WUBRG order, as a side effect. + int nLand = Math.round(slotsRemaining * p); // Round up/down + if (logToConsole) { System.out.printf("Basics[%s]: %d/%d = %f%% = %d cards%n", MagicColor.Constant.BASIC_LANDS.get(i), clrCnts[i], totalColor, 100*p, nLand); } + + totalColor -= clrCnts[i]; // if appropriate snow-covered lands are available, add them for (final PaperCard cp : basicLands) { @@ -394,14 +397,6 @@ public class LimitedDeckBuilder extends DeckGeneratorBase { } } - // A common problem at this point is that p in the above loop was exactly 1/2, - // and nLand rounded up for both colors, so that one too many lands was added. - // So if the deck size is > 40, remove the last land added. - // Otherwise, the fixDeckSize() method would remove random cards. - while (deckList.size() > 40) { - deckList.remove(deckList.size() - 1); - } - deckList.addAll(snowLands); aiPlayables.removeAll(snowLands); } @@ -505,7 +500,7 @@ public class LimitedDeckBuilder extends DeckGeneratorBase { hasColor = Predicates.or(new DeckGeneratorBase.MatchColorIdentity(colors), DeckGeneratorBase.COLORLESS_CARDS); - final Iterable threeColorList = Iterables.filter(aiPlayables, + final Iterable threeColorList = Iterables.filter(rankedOthers, Predicates.compose(hasColor, PaperCard.FN_GET_RULES)); for (final PaperCard card : threeColorList) { if (num > 0) { @@ -611,6 +606,8 @@ public class LimitedDeckBuilder extends DeckGeneratorBase { availableList.add(card); if (card.getRules().getType().isCreature()) { numCreatures++; + } else if (card.getRules().getType().isLand()) { + // Do nothing, it will be replaced with basics later. } else { numOthers++; } diff --git a/forge-gui/src/main/java/forge/gamemodes/match/AbstractGuiGame.java b/forge-gui/src/main/java/forge/gamemodes/match/AbstractGuiGame.java index 5c2fb7f8f38..674158ad0c2 100644 --- a/forge-gui/src/main/java/forge/gamemodes/match/AbstractGuiGame.java +++ b/forge-gui/src/main/java/forge/gamemodes/match/AbstractGuiGame.java @@ -153,8 +153,7 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards { setCurrentPlayer(Iterables.getFirst(gameControllers.keySet(), null)); } } - } - else { + } else { gameControllers.put(player, gameController); } } @@ -270,7 +269,7 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards { private final Set selectableCards = Sets.newHashSet(); public void setSelectables(final Iterable cards) { - for ( CardView cv : cards ) { selectableCards.add(cv); } + for (CardView cv : cards) { selectableCards.add(cv); } } public void clearSelectables() { selectableCards.clear(); @@ -285,12 +284,12 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards { public void setgamePause(boolean pause) { gamePause = pause; } public void pauseMatch() { IGameController controller = spectator; - if(controller != null && !isGamePaused()) + if (controller != null && !isGamePaused()) controller.selectButtonOk(); } public void resumeMatch() { IGameController controller = spectator; - if(controller != null && isGamePaused()) + if (controller != null && isGamePaused()) controller.selectButtonOk(); } @@ -315,12 +314,10 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards { // Concede each player on this Gui (except mind-controlled players) c.concede(); } - } - else { + } else { return false; } - } - else { + } else { return !ignoreConcedeChain; } if (gameView.isGameOver()) { diff --git a/forge-gui/src/main/java/forge/gamemodes/match/input/InputSelectTargets.java b/forge-gui/src/main/java/forge/gamemodes/match/input/InputSelectTargets.java index 0453e296a91..3a5d36d9c5f 100644 --- a/forge-gui/src/main/java/forge/gamemodes/match/input/InputSelectTargets.java +++ b/forge-gui/src/main/java/forge/gamemodes/match/input/InputSelectTargets.java @@ -392,8 +392,8 @@ public final class InputSelectTargets extends InputSyncronizedBase { @Override protected void onStop() { - getController().getGui().clearSelectables(); - super.onStop(); + getController().getGui().clearSelectables(); + super.onStop(); } } diff --git a/forge-gui/src/main/java/forge/gamemodes/puzzle/Puzzle.java b/forge-gui/src/main/java/forge/gamemodes/puzzle/Puzzle.java index 82c6ee6dc32..d4b34e04c56 100644 --- a/forge-gui/src/main/java/forge/gamemodes/puzzle/Puzzle.java +++ b/forge-gui/src/main/java/forge/gamemodes/puzzle/Puzzle.java @@ -121,7 +121,7 @@ public class Puzzle extends GameState implements InventoryItem, Comparable 0) { ptText.insert(0, "P/T: "); ptText.append(" - ").append("Loy: "); - } - else { + } else { ptText.append("Loyalty: "); } @@ -221,7 +220,7 @@ public class CardDetailUtil { String curColors = ""; // do not show current colors for temp effect cards, emblems and the like - if (state.getType().isEmblem() || state.getType().hasSubtype("Effect")) { + if (state.getCard().isImmutable()) { return ""; } @@ -275,16 +274,14 @@ public class CardDetailUtil { // Token if (card.isToken()) { - if(card.getCurrentState().getType().hasSubtype("Effect")) - area.append("Effect"); - else if(card.getCurrentState().getType().isEmblem()) - area.append("Emblem"); - else - area.append("Token"); + area.append("Token"); } else if (card.isTokenCard()) { area.append("Token card"); + } else if (card.isEmblem()) { + area.append("Emblem"); + } else if (card.isImmutable()) { + area.append("Effect"); } - // card text if (area.length() != 0) { area.append("\n"); @@ -299,7 +296,6 @@ public class CardDetailUtil { card.getText(state, needTranslation ? CardTranslation.getTranslationTexts(state.getName(), "") : null) : card.getText(state, needTranslation ? CardTranslation.getTranslationTexts(card.getLeftSplitState().getName(), card.getRightSplitState().getName()) : null ); - // LEVEL [0-9]+-[0-9]+ // LEVEL [0-9]+\+ @@ -575,7 +571,7 @@ public class CardDetailUtil { if (area.length() != 0) { area.append("\n"); } - area.append("Until leaves the Battlefield: ").append(card.getUntilLeavesBattlefield()); + area.append("Exiled until this leaves the battlefield: ").append(card.getUntilLeavesBattlefield()); } // must block diff --git a/forge-gui/src/main/java/forge/gui/card/CardScriptInfo.java b/forge-gui/src/main/java/forge/gui/card/CardScriptInfo.java index 73700303006..65443c79773 100644 --- a/forge-gui/src/main/java/forge/gui/card/CardScriptInfo.java +++ b/forge-gui/src/main/java/forge/gui/card/CardScriptInfo.java @@ -72,7 +72,7 @@ public final class CardScriptInfo { final String filename = name.toLowerCase().replaceAll("[^-a-z0-9\\s]","").replaceAll("[-\\s]","_").replaceAll("__","_") + ".txt"; String[] folders = { String.valueOf(filename.charAt(0)), "upcoming"}; - for(String folder : folders){ + for (String folder : folders) { final File file = new File(ForgeConstants.CARD_DATA_DIR + folder + File.separator + filename); if (file.exists()) { script = new CardScriptInfo(FileUtil.readFileToString(file), file); diff --git a/forge-gui/src/main/java/forge/player/GamePlayerUtil.java b/forge-gui/src/main/java/forge/player/GamePlayerUtil.java index e2200460db4..21a0c400e07 100644 --- a/forge-gui/src/main/java/forge/player/GamePlayerUtil.java +++ b/forge-gui/src/main/java/forge/player/GamePlayerUtil.java @@ -104,7 +104,7 @@ public final class GamePlayerUtil { final String oldPlayerName = FModel.getPreferences().getPref(FPref.PLAYER_NAME); String newPlayerName; - try{ + try { if (StringUtils.isBlank(oldPlayerName)) { newPlayerName = getVerifiedPlayerName(getPlayerNameUsingFirstTimePrompt(), oldPlayerName); } else { diff --git a/forge-gui/src/main/java/forge/player/HumanCostDecision.java b/forge-gui/src/main/java/forge/player/HumanCostDecision.java index 6e3920266d5..ed69cdd0fd2 100644 --- a/forge-gui/src/main/java/forge/player/HumanCostDecision.java +++ b/forge-gui/src/main/java/forge/player/HumanCostDecision.java @@ -277,8 +277,6 @@ public class HumanCostDecision extends CostDecisionMakerBase { return exileFromSame(cost, list, c, payableZone); } - - // Inputs // Exile @@ -482,6 +480,22 @@ public class HumanCostDecision extends CostDecisionMakerBase { return PaymentDecision.number(c); } + @Override + public PaymentDecision visit(final CostRollDice cost) { + final String amount = cost.getAmount(); + Integer c = cost.convertAmount(); + + if (c == null) { + c = AbilityUtils.calculateAmount(source, amount, ability); + } + + if (!player.getController().confirmPayment(cost, Localizer.getInstance().getMessage("lblDoYouWantRollNDiceAction", String.valueOf(c), "d" + cost.getType()), ability)) { + return null; + } + + return PaymentDecision.number(c); + } + @Override public PaymentDecision visit(final CostGainControl cost) { final String amount = cost.getAmount(); diff --git a/forge-gui/src/main/java/forge/player/HumanPlay.java b/forge-gui/src/main/java/forge/player/HumanPlay.java index f7e120b8e51..a410e3e3006 100644 --- a/forge-gui/src/main/java/forge/player/HumanPlay.java +++ b/forge-gui/src/main/java/forge/player/HumanPlay.java @@ -349,6 +349,18 @@ public class HumanPlay { else part.payAsDecided(p, pd, sourceAbility); } + else if (part instanceof CostRollDice) { + if (!part.canPay(sourceAbility, p)) { + return false; + } + + PaymentDecision pd = part.accept(hcd); + + if (pd == null) + return false; + else + part.payAsDecided(p, pd, sourceAbility); + } else if (part instanceof CostDamage) { if (!part.canPay(sourceAbility, p)) { return false; diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java index 7a7e894c172..1823ef56935 100644 --- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java @@ -334,7 +334,6 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont String errMsg; if (newMain.size() < deckMinSize) { errMsg = TextUtil.concatNoSpace(localizer.getMessage("lblTooFewCardsMainDeck", String.valueOf(deckMinSize))); - } else { errMsg = TextUtil.concatNoSpace(localizer.getMessage("lblTooManyCardsSideboard", String.valueOf(sbMax))); } @@ -1324,7 +1323,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont } if (sa.hasParam("TokenScript")) { sa.setActivatingPlayer(player); - Card protoType = TokenInfo.getProtoType(sa.getParam("TokenScript"), sa); + Card protoType = TokenInfo.getProtoType(sa.getParam("TokenScript"), sa, null); for (String type : protoType.getType().getCreatureTypes()) { Integer count = typesInDeck.get(type); if (count == null) { @@ -1340,7 +1339,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont if (sa != null) { if (sa.hasParam("TokenScript")) { sa.setActivatingPlayer(player); - Card protoType = TokenInfo.getProtoType(sa.getParam("TokenScript"), sa); + Card protoType = TokenInfo.getProtoType(sa.getParam("TokenScript"), sa, null); for (String type : protoType.getType().getCreatureTypes()) { Integer count = typesInDeck.get(type); if (count == null) { diff --git a/forge-lda/pom.xml b/forge-lda/pom.xml index 67bd74cac17..71b50b57465 100644 --- a/forge-lda/pom.xml +++ b/forge-lda/pom.xml @@ -4,7 +4,7 @@ forge forge - 1.6.43-SNAPSHOT + 1.6.44-SNAPSHOT forge-lda diff --git a/pom.xml b/pom.xml index 8fc54be15bc..5cb1baa31ec 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ forge pom Forge Parent - 1.6.43-SNAPSHOT + 1.6.44-SNAPSHOT Forge lets you play the card game Magic: The Gathering against a computer opponent using all of the rules.