diff --git a/forge-core/src/main/java/forge/ImageKeys.java b/forge-core/src/main/java/forge/ImageKeys.java index 681e3ead6ee..7b67f396603 100644 --- a/forge-core/src/main/java/forge/ImageKeys.java +++ b/forge-core/src/main/java/forge/ImageKeys.java @@ -25,6 +25,11 @@ public final class ImageKeys { public static final String FORETELL_IMAGE = "foretell"; public static final String BACKFACE_POSTFIX = "$alt"; + public static final String SPECFACE_W = "$wspec"; + public static final String SPECFACE_U = "$uspec"; + public static final String SPECFACE_B = "$bspec"; + public static final String SPECFACE_R = "$rspec"; + public static final String SPECFACE_G = "$gspec"; private static String CACHE_CARD_PICS_DIR, CACHE_TOKEN_PICS_DIR, CACHE_ICON_PICS_DIR, CACHE_BOOSTER_PICS_DIR, CACHE_FATPACK_PICS_DIR, CACHE_BOOSTERBOX_PICS_DIR, CACHE_PRECON_PICS_DIR, CACHE_TOURNAMENTPACK_PICS_DIR; diff --git a/forge-core/src/main/java/forge/StaticData.java b/forge-core/src/main/java/forge/StaticData.java index 5570e7ea63a..7fc3b1be604 100644 --- a/forge-core/src/main/java/forge/StaticData.java +++ b/forge-core/src/main/java/forge/StaticData.java @@ -803,7 +803,7 @@ public class StaticData { } // check the front image - imagePath = ImageUtil.getImageRelativePath(cp, false, true, false); + imagePath = ImageUtil.getImageRelativePath(cp, "", true, false); if (imagePath != null) { File file = ImageKeys.getImageFile(imagePath); if (file == null && ImageKeys.hasSetLookup(imagePath)) @@ -820,7 +820,7 @@ public class StaticData { // check the back face if (cp.hasBackFace()) { - imagePath = ImageUtil.getImageRelativePath(cp, true, true, false); + imagePath = ImageUtil.getImageRelativePath(cp, "back", true, false); if (imagePath != null) { File file = ImageKeys.getImageFile(imagePath); if (file == null && ImageKeys.hasSetLookup(imagePath)) diff --git a/forge-core/src/main/java/forge/item/IPaperCard.java b/forge-core/src/main/java/forge/item/IPaperCard.java index b71f774fdd6..5edece0287a 100644 --- a/forge-core/src/main/java/forge/item/IPaperCard.java +++ b/forge-core/src/main/java/forge/item/IPaperCard.java @@ -240,5 +240,10 @@ public interface IPaperCard extends InventoryItem, Serializable { boolean hasBackFace(); String getCardImageKey(); String getCardAltImageKey(); + String getCardWSpecImageKey(); + String getCardUSpecImageKey(); + String getCardBSpecImageKey(); + String getCardRSpecImageKey(); + String getCardGSpecImageKey(); } \ No newline at end of file diff --git a/forge-core/src/main/java/forge/item/PaperCard.java b/forge-core/src/main/java/forge/item/PaperCard.java index 9fe5b2039f7..69c9634de49 100644 --- a/forge-core/src/main/java/forge/item/PaperCard.java +++ b/forge-core/src/main/java/forge/item/PaperCard.java @@ -320,7 +320,7 @@ public final class PaperCard implements Comparable, InventoryItemFro @Override public String getCardImageKey() { if (this.cardImageKey == null) - this.cardImageKey = ImageUtil.getImageKey(this, false, true); + this.cardImageKey = ImageUtil.getImageKey(this, "", true); return cardImageKey; } @@ -329,13 +329,73 @@ public final class PaperCard implements Comparable, InventoryItemFro public String getCardAltImageKey() { if (this.cardAltImageKey == null){ if (this.hasBackFace()) - this.cardAltImageKey = ImageUtil.getImageKey(this, true, true); + this.cardAltImageKey = ImageUtil.getImageKey(this, "back", true); else // altImageKey will be the same as cardImageKey - this.cardAltImageKey = ImageUtil.getImageKey(this, false, true); + this.cardAltImageKey = ImageUtil.getImageKey(this, "", true); } return cardAltImageKey; } + private String cardWSpecImageKey = null; + @Override + public String getCardWSpecImageKey() { + if (this.cardWSpecImageKey == null) { + if (this.rules.getSplitType() == CardSplitType.Specialize) + this.cardWSpecImageKey = ImageUtil.getImageKey(this, "white", true); + else // just use cardImageKey + this.cardWSpecImageKey = ImageUtil.getImageKey(this, "", true); + } + return cardWSpecImageKey; + } + + private String cardUSpecImageKey = null; + @Override + public String getCardUSpecImageKey() { + if (this.cardUSpecImageKey == null) { + if (this.rules.getSplitType() == CardSplitType.Specialize) + this.cardUSpecImageKey = ImageUtil.getImageKey(this, "blue", true); + else // just use cardImageKey + this.cardUSpecImageKey = ImageUtil.getImageKey(this, "", true); + } + return cardUSpecImageKey; + } + + private String cardBSpecImageKey = null; + @Override + public String getCardBSpecImageKey() { + if (this.cardBSpecImageKey == null) { + if (this.rules.getSplitType() == CardSplitType.Specialize) + this.cardBSpecImageKey = ImageUtil.getImageKey(this, "black", true); + else // just use cardImageKey + this.cardBSpecImageKey = ImageUtil.getImageKey(this, "", true); + } + return cardBSpecImageKey; + } + + private String cardRSpecImageKey = null; + @Override + public String getCardRSpecImageKey() { + if (this.cardRSpecImageKey == null) { + if (this.rules.getSplitType() == CardSplitType.Specialize) + this.cardRSpecImageKey = ImageUtil.getImageKey(this, "red", true); + else // just use cardImageKey + this.cardRSpecImageKey = ImageUtil.getImageKey(this, "", true); + } + return cardRSpecImageKey; + } + + private String cardGSpecImageKey = null; + @Override + public String getCardGSpecImageKey() { + if (this.cardGSpecImageKey == null) { + if (this.rules.getSplitType() == CardSplitType.Specialize) + this.cardGSpecImageKey = ImageUtil.getImageKey(this, "green", true); + else // just use cardImageKey + this.cardGSpecImageKey = ImageUtil.getImageKey(this, "", true); + } + return cardGSpecImageKey; + } + @Override public boolean hasBackFace(){ CardSplitType cst = this.rules.getSplitType(); diff --git a/forge-core/src/main/java/forge/item/PaperToken.java b/forge-core/src/main/java/forge/item/PaperToken.java index b240c4644b6..88a8a491b96 100644 --- a/forge-core/src/main/java/forge/item/PaperToken.java +++ b/forge-core/src/main/java/forge/item/PaperToken.java @@ -169,6 +169,27 @@ public class PaperToken implements InventoryItemFromSet, IPaperCard { return getImageKey(true); } + @Override + public String getCardWSpecImageKey() { + return getImageKey(false); + } + @Override + public String getCardUSpecImageKey() { + return getImageKey(false); + } + @Override + public String getCardBSpecImageKey() { + return getImageKey(false); + } + @Override + public String getCardRSpecImageKey() { + return getImageKey(false); + } + @Override + public String getCardGSpecImageKey() { + return getImageKey(false); + } + // InventoryItem @Override public String getImageKey(boolean altState) { diff --git a/forge-core/src/main/java/forge/util/ImageUtil.java b/forge-core/src/main/java/forge/util/ImageUtil.java index 46917508d89..6bb53ececdc 100644 --- a/forge-core/src/main/java/forge/util/ImageUtil.java +++ b/forge-core/src/main/java/forge/util/ImageUtil.java @@ -26,8 +26,8 @@ public class ImageUtil { return cp; } - public static String getImageRelativePath(PaperCard cp, boolean backFace, boolean includeSet, boolean isDownloadUrl) { - final String nameToUse = cp == null ? null : getNameToUse(cp, backFace); + public static String getImageRelativePath(PaperCard cp, String face, boolean includeSet, boolean isDownloadUrl) { + final String nameToUse = cp == null ? null : getNameToUse(cp, face); if (nameToUse == null) { return null; } @@ -80,36 +80,55 @@ public class ImageUtil { } } - public static String getNameToUse(PaperCard cp, boolean backFace) { + public static String getNameToUse(PaperCard cp, String face) { final CardRules card = cp.getRules(); - if (backFace) { + if (face.equals("back")) { if (cp.hasBackFace()) if (card.getOtherPart() != null) { return card.getOtherPart().getName(); } else if (!card.getMeldWith().isEmpty()) { - final CardDb db = StaticData.instance().getCommonCards(); + final CardDb db = StaticData.instance().getCommonCards(); return db.getRules(card.getMeldWith()).getOtherPart().getName(); } else { return null; } else return null; - } else if(CardSplitType.Split == cp.getRules().getSplitType()) { + } else if (face.equals("white")) { + if (card.getWSpecialize() != null) { + return card.getWSpecialize().getName(); + } + } else if (face.equals("blue")) { + if (card.getUSpecialize() != null) { + return card.getUSpecialize().getName(); + } + } else if (face.equals("black")) { + if (card.getBSpecialize() != null) { + return card.getBSpecialize().getName(); + } + } else if (face.equals("red")) { + if (card.getRSpecialize() != null) { + return card.getRSpecialize().getName(); + } + } else if (face.equals("green")) { + if (card.getGSpecialize() != null) { + return card.getGSpecialize().getName(); + } + } else if (CardSplitType.Split == cp.getRules().getSplitType()) { return card.getMainPart().getName() + card.getOtherPart().getName(); - } else { - return cp.getName(); } + return cp.getName(); } - public static String getImageKey(PaperCard cp, boolean backFace, boolean includeSet) { - return getImageRelativePath(cp, backFace, includeSet, false); + public static String getImageKey(PaperCard cp, String face, boolean includeSet) { + return getImageRelativePath(cp, face, includeSet, false); } - public static String getDownloadUrl(PaperCard cp, boolean backFace) { - return getImageRelativePath(cp, backFace, true, true); + public static String getDownloadUrl(PaperCard cp, String face) { + return getImageRelativePath(cp, face, true, true); } - public static String getScryfallDownloadUrl(PaperCard cp, boolean backFace, String setCode, String langCode, boolean useArtCrop){ + public static String getScryfallDownloadUrl(PaperCard cp, String face, String setCode, String langCode, boolean useArtCrop){ String editionCode; if ((setCode != null) && (setCode.length() > 0)) editionCode = setCode; @@ -121,7 +140,7 @@ public class ImageUtil { String versionParam = useArtCrop ? "art_crop" : "normal"; String faceParam = ""; if (cp.getRules().getOtherPart() != null) { - faceParam = (backFace ? "&face=back" : "&face=front"); + faceParam = (face.equals("back") ? "&face=back" : "&face=front"); } return String.format("%s/%s/%s?format=image&version=%s%s", editionCode, cardCollectorNumber, langCode, versionParam, faceParam); diff --git a/forge-game/src/main/java/forge/game/GameAction.java b/forge-game/src/main/java/forge/game/GameAction.java index 1d1b217e75f..0ddb9d6fa79 100644 --- a/forge-game/src/main/java/forge/game/GameAction.java +++ b/forge-game/src/main/java/forge/game/GameAction.java @@ -17,53 +17,19 @@ */ package forge.game; -import java.util.Collections; -import java.util.Comparator; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import forge.util.*; - -import org.apache.commons.lang3.tuple.ImmutablePair; - import com.google.common.base.Predicate; -import com.google.common.collect.ComparisonChain; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Multimap; -import com.google.common.collect.Multimaps; -import com.google.common.collect.Sets; -import com.google.common.collect.Table; - +import com.google.common.collect.*; import forge.GameCommand; import forge.StaticData; import forge.card.CardStateName; +import forge.card.MagicColor; import forge.deck.DeckSection; import forge.game.ability.AbilityFactory; import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.ApiType; -import forge.game.card.Card; -import forge.game.card.CardCollection; -import forge.game.card.CardCollectionView; -import forge.game.card.CardDamageMap; -import forge.game.card.CardFactory; -import forge.game.card.CardLists; -import forge.game.card.CardPredicates; -import forge.game.card.CardUtil; -import forge.game.card.CardZoneTable; -import forge.game.card.CounterEnumType; -import forge.game.card.CounterType; -import forge.game.event.GameEventCardChangeZone; -import forge.game.event.GameEventCardDestroyed; -import forge.game.event.GameEventCardStatsChanged; -import forge.game.event.GameEventCardTapped; -import forge.game.event.GameEventFlipCoin; -import forge.game.event.GameEventGameStarted; -import forge.game.event.GameEventScry; +import forge.game.card.*; +import forge.game.event.*; import forge.game.keyword.Keyword; import forge.game.keyword.KeywordInterface; import forge.game.keyword.KeywordsChange; @@ -87,8 +53,12 @@ import forge.game.zone.PlayerZoneBattlefield; import forge.game.zone.Zone; import forge.game.zone.ZoneType; import forge.item.PaperCard; +import forge.util.*; import forge.util.collect.FCollection; import forge.util.collect.FCollectionView; +import org.apache.commons.lang3.tuple.ImmutablePair; + +import java.util.*; /** * Methods for common actions performed during a game. @@ -2148,6 +2118,13 @@ public class GameAction { return input.getName().equals("Emissary's Ploy"); } }); + CardCollectionView all = CardLists.filterControlledBy(game.getCardsInGame(), takesAction); + List spires = CardLists.filter(all, new Predicate() { + @Override + public boolean apply(Card input) { + return input.getName().equals("Cryptic Spires"); + } + }); int chosen = 1; List cmc = Lists.newArrayList(1, 2, 3); @@ -2160,6 +2137,17 @@ public class GameAction { c.setChosenNumber(chosen); } + for (Card c : spires) { + if (!c.hasChosenColor()) { + List colorChoices = new ArrayList<>(MagicColor.Constant.ONLY_COLORS); + String prompt = CardTranslation.getTranslatedName(c.getName()) + ": " + + Localizer.getInstance().getMessage("lblChooseNColors", Lang.getNumeral(2)); + SpellAbility sa = new SpellAbility.EmptySa(ApiType.ChooseColor, c, takesAction); + sa.putParam("AILogic", "MostProminentInComputerDeck"); + List chosenColors = takesAction.getController().chooseColors(prompt, sa, 2, 2, colorChoices); + c.setChosenColors(chosenColors); + } + } takesAction = game.getNextPlayerAfter(takesAction); } while (takesAction != first); } 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 d76fd21c7fe..ef0f8db6827 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 @@ -101,6 +101,7 @@ public class ChooseCardEffect extends SpellAbilityEffect { } for (final Player p : tgtPlayers) { + boolean dontRevealToOwner = true; if (sa.hasParam("EachBasicType")) { // Get all lands, List land = CardLists.filter(game.getCardsIn(ZoneType.Battlefield), Presets.LANDS); @@ -220,6 +221,7 @@ public class ChooseCardEffect extends SpellAbilityEffect { } else if ((tgt == null) || p.canBeTargetedBy(sa)) { if (sa.hasParam("AtRandom") && !choices.isEmpty()) { Aggregates.random(choices, validAmount, chosen); + dontRevealToOwner = false; } else { String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChooseaCard") + " "; if (sa.hasParam ("ChoiceTitleAppendDefined")) { @@ -248,12 +250,14 @@ public class ChooseCardEffect extends SpellAbilityEffect { } } if (sa.hasParam("Reveal") && !sa.hasParam("SecretlyChoose")) { - game.getAction().reveal(chosen, p, true, sa.hasParam("RevealTitle") ? sa.getParam("RevealTitle") : Localizer.getInstance().getMessage("lblChosenCards") + " "); + game.getAction().reveal(chosen, p, dontRevealToOwner, sa.hasParam("RevealTitle") ? + sa.getParam("RevealTitle") : Localizer.getInstance().getMessage("lblChosenCards") + " "); } } - if(sa.hasParam("Reveal") && sa.hasParam("SecretlyChoose")) { + if (sa.hasParam("Reveal") && sa.hasParam("SecretlyChoose")) { for (final Player p : tgtPlayers) { - game.getAction().reveal(chosen, p, true, sa.hasParam("RevealTitle") ? sa.getParam("RevealTitle") : Localizer.getInstance().getMessage("lblChosenCards") + " "); + game.getAction().reveal(chosen, p, true, sa.hasParam("RevealTitle") ? + sa.getParam("RevealTitle") : Localizer.getInstance().getMessage("lblChosenCards") + " "); } } host.setChosenCards(chosen); 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 a6a88fb5341..8cfe8a826bf 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 @@ -27,7 +27,7 @@ public class ChooseTypeEffect extends SpellAbilityEffect { for (final Player p : getTargetPlayers(sa)) { sb.append(p); } - sb.append(" chooses a type."); + sb.append(" chooses a ").append(sa.getParam("Type").toLowerCase()).append(" type."); } else { sb.append("Please improve the stack description."); } 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 3f94ffdac45..36a6c6564c8 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 @@ -360,10 +360,15 @@ public class PlayEffect extends SpellAbilityEffect { tgtSA = tgtSA.copyWithNoManaCost(); } else if (sa.hasParam("PlayCost")) { Cost abCost; - if ("ManaCost".equals(sa.getParam("PlayCost"))) { + String cost = sa.getParam("PlayCost"); + if (cost.equals("ManaCost")) { abCost = new Cost(source.getManaCost(), false); } else { - abCost = new Cost(sa.getParam("PlayCost"), false); + if (cost.contains("ConvertedManaCost")) { + final String costcmc = Integer.toString(tgtCard.getCMC()); + cost = cost.replace("ConvertedManaCost", costcmc); + } + abCost = new Cost(cost, false); } tgtSA = tgtSA.copyWithDefinedCost(abCost); diff --git a/forge-game/src/main/java/forge/game/card/CardFactory.java b/forge-game/src/main/java/forge/game/card/CardFactory.java index 047719e5520..f940ff9ded8 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactory.java +++ b/forge-game/src/main/java/forge/game/card/CardFactory.java @@ -280,6 +280,27 @@ public class CardFactory { } else if (c.isAdventureCard()) { c.setState(CardStateName.Adventure, false); c.setImageKey(originalPicture); + } else if (c.canSpecialize()) { + c.setState(CardStateName.SpecializeW, false); + c.setImageKey(cp.getImageKey(false) + ImageKeys.SPECFACE_W); + c.setSetCode(cp.getEdition()); + c.setRarity(cp.getRarity()); + c.setState(CardStateName.SpecializeU, false); + c.setImageKey(cp.getImageKey(false) + ImageKeys.SPECFACE_U); + c.setSetCode(cp.getEdition()); + c.setRarity(cp.getRarity()); + c.setState(CardStateName.SpecializeB, false); + c.setImageKey(cp.getImageKey(false) + ImageKeys.SPECFACE_B); + c.setSetCode(cp.getEdition()); + c.setRarity(cp.getRarity()); + c.setState(CardStateName.SpecializeR, false); + c.setImageKey(cp.getImageKey(false) + ImageKeys.SPECFACE_R); + c.setSetCode(cp.getEdition()); + c.setRarity(cp.getRarity()); + c.setState(CardStateName.SpecializeG, false); + c.setImageKey(cp.getImageKey(false) + ImageKeys.SPECFACE_G); + c.setSetCode(cp.getEdition()); + c.setRarity(cp.getRarity()); } c.setSetCode(cp.getEdition()); diff --git a/forge-game/src/main/java/forge/game/cost/CostTapType.java b/forge-game/src/main/java/forge/game/cost/CostTapType.java index 360c69a54b8..89079d67d19 100644 --- a/forge-game/src/main/java/forge/game/cost/CostTapType.java +++ b/forge-game/src/main/java/forge/game/cost/CostTapType.java @@ -26,6 +26,7 @@ import forge.game.card.CardPredicates.Presets; import forge.game.player.Player; import forge.game.spellability.SpellAbility; import forge.game.zone.ZoneType; +import forge.util.Lang; import forge.util.TextUtil; /** @@ -114,7 +115,7 @@ public class CostTapType extends CostPartWithList { sb.append(" you control"); } } else { - sb.append(Cost.convertAmountTypeToWords(i, this.getAmount(), "untapped " + desc)).append(" you control"); + sb.append(Lang.nounWithNumeralExceptOne(this.getAmount(), "untapped " + desc)).append(" you control"); } return sb.toString(); } diff --git a/forge-gui-desktop/src/main/java/forge/ImageCache.java b/forge-gui-desktop/src/main/java/forge/ImageCache.java index cc1d6e10574..c9e83c0fc28 100644 --- a/forge-gui-desktop/src/main/java/forge/ImageCache.java +++ b/forge-gui-desktop/src/main/java/forge/ImageCache.java @@ -172,12 +172,48 @@ public class ImageCache { IPaperCard ipc = null; boolean altState = imageKey.endsWith(ImageKeys.BACKFACE_POSTFIX); + String specColor = ""; + if (imageKey.endsWith(ImageKeys.SPECFACE_W)) { + specColor = "white"; + } else if (imageKey.endsWith(ImageKeys.SPECFACE_U)) { + specColor = "blue"; + } else if (imageKey.endsWith(ImageKeys.SPECFACE_B)) { + specColor = "black"; + } else if (imageKey.endsWith(ImageKeys.SPECFACE_R)) { + specColor = "red"; + } else if (imageKey.endsWith(ImageKeys.SPECFACE_G)) { + specColor = "green"; + } if (altState) imageKey = imageKey.substring(0, imageKey.length() - ImageKeys.BACKFACE_POSTFIX.length()); + if (!specColor.equals("")) + imageKey = imageKey.substring(0, imageKey.length() - ImageKeys.SPECFACE_W.length()); if (imageKey.startsWith(ImageKeys.CARD_PREFIX)) { ipc = ImageUtil.getPaperCardFromImageKey(imageKey); if (ipc != null) { - imageKey = altState ? ipc.getCardAltImageKey() : ipc.getCardImageKey(); + if (altState) { + imageKey = ipc.getCardAltImageKey(); + } else if (!specColor.equals("")) { + switch (specColor) { + case "white": + imageKey = ipc.getCardWSpecImageKey(); + break; + case "blue": + imageKey = ipc.getCardUSpecImageKey(); + break; + case "black": + imageKey = ipc.getCardBSpecImageKey(); + break; + case "red": + imageKey = ipc.getCardRSpecImageKey(); + break; + case "green": + imageKey = ipc.getCardGSpecImageKey(); + break; + } + } else { + imageKey = ipc.getCardImageKey(); + } if (StringUtils.isBlank(imageKey)) return Pair.of(_defaultImage, true); } diff --git a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/DeckHtmlSerializer.java b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/DeckHtmlSerializer.java index 7fb3b4fb2d5..aabe8d93e05 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/DeckHtmlSerializer.java +++ b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/DeckHtmlSerializer.java @@ -73,7 +73,7 @@ public class DeckHtmlSerializer { // System.out.println(card.getSets().get(card.getSets().size() - 1).URL); for (int i = card.getValue(); i > 0; --i ) { final PaperCard r = card.getKey(); - final String url = ForgeConstants.URL_PIC_DOWNLOAD + ImageUtil.getDownloadUrl(r, false); + final String url = ForgeConstants.URL_PIC_DOWNLOAD + ImageUtil.getDownloadUrl(r, ""); list.add(url); } } diff --git a/forge-gui-desktop/src/main/java/forge/toolbox/imaging/FImageUtil.java b/forge-gui-desktop/src/main/java/forge/toolbox/imaging/FImageUtil.java index 8f6fe9c231c..946c9db7273 100644 --- a/forge-gui-desktop/src/main/java/forge/toolbox/imaging/FImageUtil.java +++ b/forge-gui-desktop/src/main/java/forge/toolbox/imaging/FImageUtil.java @@ -77,15 +77,51 @@ public final class FImageUtil { } boolean altState = key.endsWith(ImageKeys.BACKFACE_POSTFIX); + String specColor = ""; + if (key.endsWith(ImageKeys.SPECFACE_W)) { + specColor = "white"; + } else if (key.endsWith(ImageKeys.SPECFACE_U)) { + specColor = "blue"; + } else if (key.endsWith(ImageKeys.SPECFACE_B)) { + specColor = "black"; + } else if (key.endsWith(ImageKeys.SPECFACE_R)) { + specColor = "red"; + } else if (key.endsWith(ImageKeys.SPECFACE_G)) { + specColor = "green"; + } String imageKey = key; if (prefix.equals(ImageKeys.CARD_PREFIX)) { PaperCard card = ImageUtil.getPaperCardFromImageKey(key); - if (card != null) - imageKey = altState ? card.getCardAltImageKey() : card.getCardImageKey(); + if (altState) { + imageKey = card.getCardAltImageKey(); + } else if (!specColor.equals("")) { + switch (specColor) { + case "white": + imageKey = card.getCardWSpecImageKey(); + break; + case "blue": + imageKey = card.getCardUSpecImageKey(); + break; + case "black": + imageKey = card.getCardBSpecImageKey(); + break; + case "red": + imageKey = card.getCardRSpecImageKey(); + break; + case "green": + imageKey = card.getCardGSpecImageKey(); + break; + } + } else { + imageKey = card.getCardImageKey(); + } } if(altState) { imageKey = imageKey.substring(0, imageKey.length() - ImageKeys.BACKFACE_POSTFIX.length()); imageKey += "full.jpg"; + } else if (!specColor.equals("")) { + imageKey = imageKey.substring(0, imageKey.length() - ImageKeys.SPECFACE_W.length()); + imageKey += "full.jpg"; } File file = ImageKeys.getImageFile(imageKey); diff --git a/forge-gui-mobile/src/forge/adventure/scene/NewGameScene.java b/forge-gui-mobile/src/forge/adventure/scene/NewGameScene.java index 801835c4e7f..24e23ff7b2b 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/NewGameScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/NewGameScene.java @@ -92,7 +92,7 @@ public class NewGameScene extends UIScene { mode.addListener(new ChangeListener() { @Override public void changed(ChangeEvent changeEvent, Actor actor) { - colorLabel.setText(mode.getCurrentIndex() < 2 ? colorIdLabel : Forge.getLocalizer().getMessage("lblDeck")+":"); + colorLabel.setText(mode.getCurrentIndex() < 2 ? colorIdLabel : "[BLACK]"+Forge.getLocalizer().getMessage("lblDeck")+":"); if (mode.getCurrentIndex() == 3) colorId.setTextList(custom); if (mode.getCurrentIndex() == 2) diff --git a/forge-gui-mobile/src/forge/adventure/scene/SaveLoadScene.java b/forge-gui-mobile/src/forge/adventure/scene/SaveLoadScene.java index 44c874aefd5..9b514aa3e45 100644 --- a/forge-gui-mobile/src/forge/adventure/scene/SaveLoadScene.java +++ b/forge-gui-mobile/src/forge/adventure/scene/SaveLoadScene.java @@ -107,13 +107,8 @@ public class SaveLoadScene extends UIScene { difficulty.setSelectedIndex(1); difficulty.setAlignment(Align.center); difficulty.getStyle().fontColor = Color.GOLD; - if (Forge.isLandscapeMode()) { - difficulty.setX(280); - difficulty.setY(220); - } else { - difficulty.setX(190); - difficulty.setY(336); - } + difficulty.setX(scrollPane.getWidth()-difficulty.getWidth()+5); + difficulty.setY(scrollPane.getTop()-difficulty.getHeight()-5); } diff --git a/forge-gui-mobile/src/forge/adventure/util/RewardActor.java b/forge-gui-mobile/src/forge/adventure/util/RewardActor.java index ffe0c05134c..7425d003bf7 100644 --- a/forge-gui-mobile/src/forge/adventure/util/RewardActor.java +++ b/forge-gui-mobile/src/forge/adventure/util/RewardActor.java @@ -183,7 +183,7 @@ public class RewardActor extends Actor implements Disposable, ImageFetcher.Callb } } } else { - String imagePath = ImageUtil.getImageRelativePath(reward.getCard(), false, true, false); + String imagePath = ImageUtil.getImageRelativePath(reward.getCard(), "", true, false); File lookup = ImageKeys.hasSetLookup(imagePath) ? ImageKeys.setLookUpFile(imagePath, imagePath+"border") : null; int count = 0; if (lookup != null) { diff --git a/forge-gui-mobile/src/forge/adventure/world/World.java b/forge-gui-mobile/src/forge/adventure/world/World.java index 4f611811f76..f32d507dfae 100644 --- a/forge-gui-mobile/src/forge/adventure/world/World.java +++ b/forge-gui-mobile/src/forge/adventure/world/World.java @@ -711,13 +711,26 @@ public class World implements Disposable, SaveFileContent { } for(Map.Entry>> entry:pixmapHash.entrySet()) { - entry.getValue().getLeft().dispose(); + try { + entry.getValue().getLeft().dispose(); + } catch (Exception e) { + e.printStackTrace(); + } for(Map.Entry pairEntry:entry.getValue().getRight().entrySet()) { - pairEntry.getValue().dispose(); + try { + pairEntry.getValue().dispose(); + } catch (Exception e) { + e.printStackTrace(); + } } } - drawPixmapNow(pix); + pixmapHash.clear(); + try { + drawPixmapNow(pix); + } catch (Exception e) { + e.printStackTrace(); + } currentTime[0] = measureGenerationTime("mini map", currentTime[0]); diff --git a/forge-gui/res/adventure/Shandalar/ui/hud_landscape.json b/forge-gui/res/adventure/Shandalar/ui/hud_landscape.json index 1021fa623cd..9573f141d72 100644 --- a/forge-gui/res/adventure/Shandalar/ui/hud_landscape.json +++ b/forge-gui/res/adventure/Shandalar/ui/hud_landscape.json @@ -62,7 +62,16 @@ "width": 64, "height": 16, "x": 442, - "y": 64 + "y": 56 + }, + { + "type": "Label", + "name": "mana", + "font": "default", + "width": 64, + "height": 16, + "x": 442, + "y": 73 }, { "type": "Label", @@ -71,7 +80,7 @@ "width": 64, "height": 16, "x": 442, - "y": 82 + "y": 90 }, { "type": "TextButton", diff --git a/forge-gui/res/cardsfolder/b/beckoning_will_o_wisp.txt b/forge-gui/res/cardsfolder/b/beckoning_will_o_wisp.txt index 916f03450fa..37b6deccb17 100644 --- a/forge-gui/res/cardsfolder/b/beckoning_will_o_wisp.txt +++ b/forge-gui/res/cardsfolder/b/beckoning_will_o_wisp.txt @@ -5,5 +5,5 @@ PT:1/3 K:Flying S:Mode$ Continuous | Affected$ Creature.attacking ChosenPlayer | AddPower$ 1 | Description$ Creatures attacking the last chosen player get +1/+0. T:Mode$ Phase | Phase$ BeginCombat | ValidPlayer$ You | Execute$ TrigChoose | TriggerZones$ Battlefield | TriggerDescription$ Lure the Unwary — At the beginning of combat on your turn, choose an opponent. -SVar:TrigChoose:DB$ ChoosePlayer | Defined$ You | Choices$ Player.Opponent | SetChosenPlayer$ True +SVar:TrigChoose:DB$ ChoosePlayer | Defined$ You | Choices$ Player.Opponent Oracle:Flying\nLure the Unwary — At the beginning of combat on your turn, choose an opponent.\nCreatures attacking the last chosen player get +1/+0. diff --git a/forge-gui/res/cardsfolder/b/bladegriff_prototype.txt b/forge-gui/res/cardsfolder/b/bladegriff_prototype.txt index c5a7061f12d..bba6d30fee5 100644 --- a/forge-gui/res/cardsfolder/b/bladegriff_prototype.txt +++ b/forge-gui/res/cardsfolder/b/bladegriff_prototype.txt @@ -4,5 +4,5 @@ Types:Artifact Creature Griffin PT:3/2 K:Flying T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigDestroy | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, destroy target nonland permanent of that player's choice that one of your opponents controls. -SVar:TrigDestroy:DB$ Destroy | TargetingPlayer$ TriggeredTarget | ValidTgts$ Permanent.nonLand+OppCtrl +SVar:TrigDestroy:DB$ Destroy | TargetingPlayer$ TriggeredTarget | ValidTgts$ Permanent.nonLand+OppCtrl | TgtPrompt$ Select target nonland permanent controlled by opponent of damaging player Oracle:Flying\nWhenever Bladegriff Prototype deals combat damage to a player, destroy target nonland permanent of that player's choice that one of your opponents controls. diff --git a/forge-gui/res/cardsfolder/b/blind_zealot.txt b/forge-gui/res/cardsfolder/b/blind_zealot.txt index 7b84a3ecb72..3fc033a44d8 100644 --- a/forge-gui/res/cardsfolder/b/blind_zealot.txt +++ b/forge-gui/res/cardsfolder/b/blind_zealot.txt @@ -4,5 +4,6 @@ Types:Creature Phyrexian Human Cleric PT:2/2 K:Intimidate T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigDestroy | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, you may sacrifice it. If you do, destroy target creature that player controls. -SVar:TrigDestroy:AB$ Destroy | Cost$ Sac<1/CARDNAME> | ValidTgts$ Creature.ControlledBy TriggeredDefendingPlayer | AITgts$ BetterThanSource | TgtPrompt$ Select target creature defending player controls +SVar:TrigDestroy:AB$ Destroy | Cost$ Sac<1/CARDNAME> | ValidTgts$ Creature.ControlledBy TriggeredTarget | AITgts$ BetterThanSource | TgtPrompt$ Select target creature damaged player controls +DeckHas:Ability$Sacrifice Oracle:Intimidate (This creature can't be blocked except by artifact creatures and/or creatures that share a color with it.)\nWhenever Blind Zealot deals combat damage to a player, you may sacrifice it. If you do, destroy target creature that player controls. diff --git a/forge-gui/res/cardsfolder/c/capricious_efreet.txt b/forge-gui/res/cardsfolder/c/capricious_efreet.txt index a1541471a5b..a2bc26d4fd2 100644 --- a/forge-gui/res/cardsfolder/c/capricious_efreet.txt +++ b/forge-gui/res/cardsfolder/c/capricious_efreet.txt @@ -3,10 +3,9 @@ ManaCost:4 R R Types:Creature Efreet PT:6/4 T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigPump | TriggerDescription$ At the beginning of your upkeep, choose target nonland permanent you control and up to two target nonland permanents you don't control. Destroy one of them at random. -SVar:TrigPump:DB$ Pump | ValidTgts$ Permanent.nonLand+YouCtrl | TgtPrompt$ Select target nonland permanent you control | Mandatory$ True | RememberObjects$ Targeted | IsCurse$ True | SubAbility$ DBPump | StackDescription$ None -SVar:DBPump:DB$ Pump | ValidTgts$ Permanent.nonLand+YouDontCtrl | TgtPrompt$ Select target nonland permanent you don't control | TargetMin$ 0 | TargetMax$ 1 | RememberObjects$ Targeted | IsCurse$ True | SubAbility$ DBPump2 | StackDescription$ None -SVar:DBPump2:DB$ Pump | ValidTgts$ Permanent.nonLand+YouDontCtrl | TgtPrompt$ Select another target nonland permanent you don't control | TargetMin$ 0 | TargetMax$ 1 | TargetUnique$ True | RememberObjects$ Targeted | IsCurse$ True | SubAbility$ DBChooseRandom | StackDescription$ None -SVar:DBChooseRandom:DB$ ChooseCard | Defined$ You | Amount$ 1 | AtRandom$ True | Choices$ Card.IsRemembered | SubAbility$ DBDestroy +SVar:TrigPump:DB$ Pump | ValidTgts$ Permanent.nonLand+YouCtrl | TgtPrompt$ Select target nonland permanent you control | Mandatory$ True | IsCurse$ True | SubAbility$ DBPump +SVar:DBPump:DB$ Pump | ValidTgts$ Permanent.nonLand+YouDontCtrl | TgtPrompt$ Select up to two target nonland permanents you don't control | TargetMin$ 0 | TargetMax$ 2 | IsCurse$ True | SubAbility$ DBChooseRandom +SVar:DBChooseRandom:DB$ ChooseCard | AtRandom$ True | Reveal$ True | RevealTitle$ OVERRIDE Randomly chosen permanent: | DefinedCards$ TargetedCard | SubAbility$ DBDestroy SVar:DBDestroy:DB$ Destroy | Defined$ ChosenCard | SubAbility$ DBCleanup -SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +SVar:DBCleanup:DB$ Cleanup | ClearChosenCard$ True Oracle:At the beginning of your upkeep, choose target nonland permanent you control and up to two target nonland permanents you don't control. Destroy one of them at random. diff --git a/forge-gui/res/cardsfolder/c/caustic_wasps.txt b/forge-gui/res/cardsfolder/c/caustic_wasps.txt index 8d0353dda92..27b5bdaa99e 100644 --- a/forge-gui/res/cardsfolder/c/caustic_wasps.txt +++ b/forge-gui/res/cardsfolder/c/caustic_wasps.txt @@ -4,5 +4,5 @@ Types:Creature Insect PT:1/1 K:Flying T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | Execute$ TrigDestroy | CombatDamage$ True | OptionalDecider$ You | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, you may destroy target artifact that player controls. -SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Artifact.ControlledBy TriggeredDefendingPlayer | TgtPrompt$ Select an artifact your opponent controls. +SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Artifact.ControlledBy TriggeredTarget | TgtPrompt$ Select target artifact damaged player controls Oracle:Flying\nWhenever Caustic Wasps deals combat damage to a player, you may destroy target artifact that player controls. diff --git a/forge-gui/res/cardsfolder/d/darigaaz_the_igniter.txt b/forge-gui/res/cardsfolder/d/darigaaz_the_igniter.txt index e2e85ae8435..d4227aa0401 100644 --- a/forge-gui/res/cardsfolder/d/darigaaz_the_igniter.txt +++ b/forge-gui/res/cardsfolder/d/darigaaz_the_igniter.txt @@ -3,7 +3,7 @@ ManaCost:3 B R G Types:Legendary Creature Dragon PT:6/6 K:Flying -T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | OptionalDecider$ You | Execute$ TrigChooseColor | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, you may pay {2}{R}. If you do, choose a color, then that player reveals their hand and Darigaaz deals damage to the player equal to the number of cards of that color revealed this way. +T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | OptionalDecider$ You | Execute$ TrigChooseColor | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, you may pay {2}{R}. If you do, choose a color, then that player reveals their hand and NICKNAME deals damage to the player equal to the number of cards of that color revealed this way. SVar:TrigChooseColor:AB$ ChooseColor | Cost$ 2 R | Defined$ You | AILogic$ MostProminentInHumanDeck | SubAbility$ DBRevealHand SVar:DBRevealHand:DB$ RevealHand | Defined$ TriggeredTarget | RememberRevealed$ True | SubAbility$ DBDamage SVar:DBDamage:DB$ DealDamage | Defined$ TriggeredTarget | NumDmg$ X | SubAbility$ DBCleanup diff --git a/forge-gui/res/cardsfolder/d/dawning_purist.txt b/forge-gui/res/cardsfolder/d/dawning_purist.txt index 6d089bceb54..d9a594d8e80 100644 --- a/forge-gui/res/cardsfolder/d/dawning_purist.txt +++ b/forge-gui/res/cardsfolder/d/dawning_purist.txt @@ -4,5 +4,5 @@ Types:Creature Human Cleric PT:2/2 K:Morph:1 W T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | Execute$ TrigDestroy | CombatDamage$ True | OptionalDecider$ You | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, you may destroy target enchantment that player controls. -SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Enchantment.ControlledBy TriggeredDefendingPlayer | TgtPrompt$ Select an enchantment your opponent controls. +SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Enchantment.ControlledBy TriggeredTarget | TgtPrompt$ Select target artifact damaged player controls Oracle:Whenever Dawning Purist deals combat damage to a player, you may destroy target enchantment that player controls.\nMorph {1}{W} (You may cast this card face down as a 2/2 creature for {3}. Turn it face up any time for its morph cost.) diff --git a/forge-gui/res/cardsfolder/d/dokuchi_silencer.txt b/forge-gui/res/cardsfolder/d/dokuchi_silencer.txt index 67328319635..0ad940140f3 100644 --- a/forge-gui/res/cardsfolder/d/dokuchi_silencer.txt +++ b/forge-gui/res/cardsfolder/d/dokuchi_silencer.txt @@ -5,7 +5,7 @@ PT:2/1 K:Ninjutsu:1 B T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | Execute$ TrigImmediateTrig | CombatDamage$ True | OptionalDecider$ You | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, you may discard a creature card. When you do, destroy target creature or planeswalker that player controls. SVar:TrigImmediateTrig:AB$ ImmediateTrigger | Cost$ Discard<1/Creature> | Execute$ TrigDestroy | CopyTriggeringObjects$ True | TriggerDescription$ When you do, destroy target creature or planeswalker that player controls. -SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Creature.ControlledBy TriggeredDefendingPlayer,Planeswalker.ControlledBy TriggeredDefendingPlayer | TgtPrompt$ Select target creature or planeswalker that player controls +SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Creature.ControlledBy TriggeredTarget,Planeswalker.ControlledBy TriggeredTarget | TgtPrompt$ Select target creature or planeswalker damaged player controls DeckHas:Ability$Discard SVar:AIPreference:DiscardCost$Creature.cmcLE3 Oracle:Ninjutsu {1}{B} ({1}{B}, Return an unblocked attacker you control to hand: Put this card onto the battlefield from your hand tapped and attacking.)\nWhenever Dokuchi Silencer deals combat damage to a player, you may discard a creature card. When you do, destroy target creature or planeswalker that player controls. diff --git a/forge-gui/res/cardsfolder/e/elven_bow.txt b/forge-gui/res/cardsfolder/e/elven_bow.txt index b5a34ddee35..1a9f803549a 100644 --- a/forge-gui/res/cardsfolder/e/elven_bow.txt +++ b/forge-gui/res/cardsfolder/e/elven_bow.txt @@ -7,5 +7,5 @@ T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.S SVar:TrigToken:AB$ Token | Cost$ 2 | TokenScript$ g_1_1_elf_warrior | RememberTokens$ True | SubAbility$ DBAttach SVar:DBAttach:DB$ Attach | Object$ TriggeredCard | Defined$ Remembered | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True -DeckHas:Ability$Token +DeckHas:Ability$Token & Type$Elf|Warrior Oracle:When Elven Bow enters the battlefield, you may pay {2}. If you do, create a 1/1 green Elf Warrior creature token, then attach Elven Bow to it.\nEquipped creature gets +1/+2 and has reach.\nEquip {3} diff --git a/forge-gui/res/cardsfolder/h/hammer_of_ruin.txt b/forge-gui/res/cardsfolder/h/hammer_of_ruin.txt index baeb993350c..b644848ea38 100644 --- a/forge-gui/res/cardsfolder/h/hammer_of_ruin.txt +++ b/forge-gui/res/cardsfolder/h/hammer_of_ruin.txt @@ -4,5 +4,5 @@ Types:Artifact Equipment K:Equip:2 S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddPower$ 2 | Description$ Equipped creature gets +2/+0. T:Mode$ DamageDone | ValidSource$ Creature.EquippedBy | ValidTarget$ Player | CombatDamage$ True | OptionalDecider$ You | Execute$ TrigDestroy | TriggerZones$ Battlefield | TriggerDescription$ Whenever equipped creature deals combat damage to a player, you may destroy target Equipment that player controls. -SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Equipment.ControlledBy TriggeredDefendingPlayer | TgtPrompt$ Select target equipment defending player controls +SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Equipment.ControlledBy TriggeredTarget | TgtPrompt$ Select target Equipment damaged player controls Oracle:Equipped creature gets +2/+0.\nWhenever equipped creature deals combat damage to a player, you may destroy target Equipment that player controls.\nEquip {2} diff --git a/forge-gui/res/cardsfolder/l/latullas_orders.txt b/forge-gui/res/cardsfolder/l/latullas_orders.txt index 7ad83cb9a0e..dd21e69d067 100644 --- a/forge-gui/res/cardsfolder/l/latullas_orders.txt +++ b/forge-gui/res/cardsfolder/l/latullas_orders.txt @@ -3,7 +3,7 @@ ManaCost:1 R Types:Enchantment Aura K:Flash K:Enchant creature -A:SP$ Attach | Cost$ 1 R | ValidTgts$ Creature | AITgts$ Card.powerGE1 | AILogic$ Pump +A:SP$ Attach | ValidTgts$ Creature | AITgts$ Card.powerGE1 | AILogic$ Pump T:Mode$ DamageDone | ValidSource$ Card.AttachedBy | ValidTarget$ Player.TriggeredDefendingPlayer | CombatDamage$ True | Execute$ TrigDestroy | OptionalDecider$ You | TriggerDescription$ Whenever enchanted creature deals combat damage to defending player, you may destroy target artifact that player controls. -SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Artifact.ControlledBy TriggeredDefendingPlayer | TgtPrompt$ Select target artifact +SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Artifact.ControlledBy TriggeredTarget | TgtPrompt$ Select target artifact damaged player controls Oracle:Flash\nEnchant creature\nWhenever enchanted creature deals combat damage to defending player, you may destroy target artifact that player controls. diff --git a/forge-gui/res/cardsfolder/p/phage_the_untouchable.txt b/forge-gui/res/cardsfolder/p/phage_the_untouchable.txt index a8d9050b90c..9d0fed93f0b 100644 --- a/forge-gui/res/cardsfolder/p/phage_the_untouchable.txt +++ b/forge-gui/res/cardsfolder/p/phage_the_untouchable.txt @@ -4,9 +4,9 @@ Types:Legendary Creature Avatar Minion PT:4/4 T:Mode$ ChangesZone | ValidCard$ Card.wasNotCastFromYourHandByYou+Self | Destination$ Battlefield | Execute$ TrigYouLose | TriggerDescription$ When CARDNAME enters the battlefield, if you didn't cast it from your hand, you lose the game. SVar:TrigYouLose:DB$ LosesGame | Defined$ You -T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Creature | CombatDamage$ True | Execute$ TrigDestroy | TriggerDescription$ Whenever CARDNAME deals combat damage to a creature, destroy that creature. It can't be regenerated. +T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Creature | CombatDamage$ True | Execute$ TrigDestroy | TriggerDescription$ Whenever NICKNAME deals combat damage to a creature, destroy that creature. It can't be regenerated. SVar:TrigDestroy:DB$ Destroy | Defined$ TriggeredTargetLKICopy | NoRegen$ True -T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigTheyLose | TriggerDescription$ Whenever Phage deals combat damage to a player, that player loses the game. +T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigTheyLose | TriggerDescription$ Whenever NICKNAME deals combat damage to a player, that player loses the game. SVar:TrigTheyLose:DB$ LosesGame | Defined$ TriggeredTarget SVar:MustBeBlocked:True Oracle:When Phage the Untouchable enters the battlefield, if you didn't cast it from your hand, you lose the game.\nWhenever Phage deals combat damage to a creature, destroy that creature. It can't be regenerated.\nWhenever Phage deals combat damage to a player, that player loses the game. diff --git a/forge-gui/res/cardsfolder/p/polis_crusher.txt b/forge-gui/res/cardsfolder/p/polis_crusher.txt index 73bc11662d1..fd46fd8192d 100644 --- a/forge-gui/res/cardsfolder/p/polis_crusher.txt +++ b/forge-gui/res/cardsfolder/p/polis_crusher.txt @@ -6,6 +6,6 @@ K:Trample K:Protection from enchantments K:Monstrosity:3:4 R G T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | IsPresent$ Card.Self+IsMonstrous | Execute$ TrigDestroy | CombatDamage$ True | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, if CARDNAME is monstrous, destroy target enchantment that player controls. -SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Enchantment | TgtPrompt$ Select target enchantment that player controls | TargetsWithDefinedController$ TriggeredTarget +SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Enchantment | TgtPrompt$ Select target enchantment damaged player controls | TargetsWithDefinedController$ TriggeredTarget DeckHas:Ability$Counters Oracle:Trample, protection from enchantments\n{4}{R}{G}: Monstrosity 3. (If this creature isn't monstrous, put three +1/+1 counters on it and it becomes monstrous.)\nWhenever Polis Crusher deals combat damage to a player, if Polis Crusher is monstrous, destroy target enchantment that player controls. diff --git a/forge-gui/res/cardsfolder/r/rustmouth_ogre.txt b/forge-gui/res/cardsfolder/r/rustmouth_ogre.txt index 228a96a70df..9fd687625cb 100644 --- a/forge-gui/res/cardsfolder/r/rustmouth_ogre.txt +++ b/forge-gui/res/cardsfolder/r/rustmouth_ogre.txt @@ -3,5 +3,5 @@ ManaCost:4 R R Types:Creature Ogre PT:5/4 T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | Execute$ TrigDestroy | CombatDamage$ True | OptionalDecider$ You | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, you may destroy target artifact that player controls. -SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Artifact.ControlledBy TriggeredDefendingPlayer | TgtPrompt$ Select an artifact your opponent controls. +SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Artifact.ControlledBy TriggeredTarget | TgtPrompt$ Select target artifact damaged player controls Oracle:Whenever Rustmouth Ogre deals combat damage to a player, you may destroy target artifact that player controls. diff --git a/forge-gui/res/cardsfolder/s/shatterskull_charger.txt b/forge-gui/res/cardsfolder/s/shatterskull_charger.txt index 044203c7284..0c94168b1d9 100644 --- a/forge-gui/res/cardsfolder/s/shatterskull_charger.txt +++ b/forge-gui/res/cardsfolder/s/shatterskull_charger.txt @@ -7,7 +7,7 @@ K:Trample K:Haste K:etbCounter:P1P1:1:CheckSVar$ WasKicked:If CARDNAME was kicked, it enters the battlefield with a +1/+1 counter on it. SVar:WasKicked:Count$Kicked.1.0 -T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | Execute$ TrigReturn | IsPresent$ Card.Self+counters_EQ0_P1P1 | TriggerDescription$ At the beginning of your end step, return Shatterskull Charger to its owner's hand unless it has a +1/+1 counter on it. +T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | Execute$ TrigReturn | IsPresent$ Card.Self+counters_EQ0_P1P1 | TriggerDescription$ At the beginning of your end step, return CARDNAME to its owner's hand unless it has a +1/+1 counter on it. SVar:TrigReturn:DB$ ChangeZone | Origin$ Battlefield | Destination$ Hand | Defined$ Self SVar:PlayMain1:TRUE DeckHas:Ability$Counters diff --git a/forge-gui/res/cardsfolder/s/sunder_shaman.txt b/forge-gui/res/cardsfolder/s/sunder_shaman.txt index 65ce6d16942..2b6635a1c5a 100644 --- a/forge-gui/res/cardsfolder/s/sunder_shaman.txt +++ b/forge-gui/res/cardsfolder/s/sunder_shaman.txt @@ -4,5 +4,5 @@ Types:Creature Giant Shaman PT:5/5 S:Mode$ MinMaxBlocker | ValidCard$ Card.Self | Max$ 1 | Description$ CARDNAME can't be blocked by more than one creature. T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigDestroy | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, destroy target artifact or enchantment that player controls. -SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Artifact.ControlledBy TriggeredDefendingPlayer,Enchantment.ControlledBy TriggeredDefendingPlayer | TgtPrompt$ Select target artifact or enchantment that player controls. +SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Artifact.ControlledBy TriggeredTarget,Enchantment.ControlledBy TriggeredTarget | TgtPrompt$ Select target artifact or enchantment damaged player controls Oracle:Sunder Shaman can't be blocked by more than one creature.\nWhenever Sunder Shaman deals combat damage to a player, destroy target artifact or enchantment that player controls. diff --git a/forge-gui/res/cardsfolder/s/syndicate_recruiter.txt b/forge-gui/res/cardsfolder/s/syndicate_recruiter.txt index e5777a15be3..8765c7826e8 100644 --- a/forge-gui/res/cardsfolder/s/syndicate_recruiter.txt +++ b/forge-gui/res/cardsfolder/s/syndicate_recruiter.txt @@ -1,6 +1,6 @@ Name:Syndicate Recruiter ManaCost: 2 U B -Types:Creature Vampire Assassin +Types:Creature Vampire Rogue PT:4/5 K:Flying K:Ward:1 diff --git a/forge-gui/res/cardsfolder/t/throat_slitter.txt b/forge-gui/res/cardsfolder/t/throat_slitter.txt index 1e1e5eb8426..bf05f72b79d 100644 --- a/forge-gui/res/cardsfolder/t/throat_slitter.txt +++ b/forge-gui/res/cardsfolder/t/throat_slitter.txt @@ -4,6 +4,6 @@ Types:Creature Rat Ninja PT:2/2 K:Ninjutsu:2 B T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | Execute$ TrigDestroy | CombatDamage$ True | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, destroy target nonblack creature that player controls. -SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Creature.nonBlack+ControlledBy TriggeredDefendingPlayer | TgtPrompt$ Select target nonblack creature defending player controls +SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Creature.nonBlack+ControlledBy TriggeredTarget | TgtPrompt$ Select target nonblack creature damaged player controls SVar:MustBeBlocked:True Oracle:Ninjutsu {2}{B} ({2}{B}, Return an unblocked attacker you control to hand: Put this card onto the battlefield from your hand tapped and attacking.)\nWhenever Throat Slitter deals combat damage to a player, destroy target nonblack creature that player controls. diff --git a/forge-gui/res/cardsfolder/t/trygon_predator.txt b/forge-gui/res/cardsfolder/t/trygon_predator.txt index 6d8067e4eb3..8cf17a34c84 100644 --- a/forge-gui/res/cardsfolder/t/trygon_predator.txt +++ b/forge-gui/res/cardsfolder/t/trygon_predator.txt @@ -4,5 +4,5 @@ Types:Creature Beast PT:2/3 K:Flying T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | OptionalDecider$ You | CombatDamage$ True | Execute$ TrigDestroy | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, you may destroy target artifact or enchantment that player controls. -SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Artifact.ControlledBy TriggeredDefendingPlayer,Enchantment.ControlledBy TriggeredDefendingPlayer | TgtPrompt$ Select target artifact or enchantment you don't control. +SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Artifact.ControlledBy TriggeredTarget,Enchantment.ControlledBy TriggeredTarget | TgtPrompt$ Select target artifact or enchantment damaged player controls Oracle:Flying\nWhenever Trygon Predator deals combat damage to a player, you may destroy target artifact or enchantment that player controls. diff --git a/forge-gui/res/cardsfolder/upcoming/and_they_shall_know_no_fear.txt b/forge-gui/res/cardsfolder/upcoming/and_they_shall_know_no_fear.txt new file mode 100644 index 00000000000..245c885eeb1 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/and_they_shall_know_no_fear.txt @@ -0,0 +1,6 @@ +Name:And They Shall Know No Fear +ManaCost:1 W +Types:Instant +A:SP$ ChooseType | Type$ Creature | SubAbility$ DBPumpAll | AILogic$ MostProminentComputerControls | SpellDescription$ Choose a creature type. +SVar:DBPumpAll:DB$ PumpAll | ValidCards$ Creature.YouCtrl+ChosenType | NumAtt$ +1 | KW$ Indestructible | SpellDescription$ Creatures you control of the chosen type get +1/+0 and gain indestructible until end of turn. +Oracle:Choose a creature type. Creatures you control of the chosen type get +1/+0 and gain indestructible until end of turn. diff --git a/forge-gui/res/cardsfolder/upcoming/anrakyr_the_traveller.txt b/forge-gui/res/cardsfolder/upcoming/anrakyr_the_traveller.txt new file mode 100644 index 00000000000..25f1856d56c --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/anrakyr_the_traveller.txt @@ -0,0 +1,10 @@ +Name:Anrakyr the Traveller +ManaCost:4 B +Types:Legendary Artifact Creature Necron +PT:4/4 +T:Mode$ Attacks | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigCast | OptionalDecider$ You | TriggerDescription$ Whenever CARDNAME attacks, you may cast an artifact spell from your hand or graveyard by paying life equal to its mana value rather than paying its mana cost. +SVar:TrigCast:DB$ Play | ValidZone$ Hand | Valid$ Artifact.YouOwn | ValidSA$ Spell | Controller$ You | ValidZone$ Hand,Graveyard | Optional$ True | Amount$ 1 | PlayCost$ PayLife +SVar:HasAttackEffect:TRUE +DeckHas:Ability$Graveyard +DeckHints:Type$Artifact +Oracle:Lord of the Pyrrhian Legions — Whenever Anrakyr the Traveller attacks, you may cast an artifact spell from your hand or graveyard by paying life equal to its mana value rather than paying its mana cost. diff --git a/forge-gui/res/cardsfolder/upcoming/assault_intercessor.txt b/forge-gui/res/cardsfolder/upcoming/assault_intercessor.txt new file mode 100644 index 00000000000..bce0061cfae --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/assault_intercessor.txt @@ -0,0 +1,9 @@ +Name:Assault Intercessor +ManaCost:1 W B +Types:Creature Astartes Warrior +PT:3/2 +K:First strike +K:Menace +T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.OppCtrl | TriggerZones$ Battlefield | Execute$ TrigLoseLife | TriggerDescription$ Chainsword — Whenever a creature an opponent controls dies, that player loses 2 life. +SVar:TrigLoseLife:DB$ LoseLife | LifeAmount$ 2 | Defined$ TriggeredCardController +Oracle:First strike, menace\nChainsword — Whenever a creature an opponent controls dies, that player loses 2 life. diff --git a/forge-gui/res/cardsfolder/upcoming/belisarius_cawl.txt b/forge-gui/res/cardsfolder/upcoming/belisarius_cawl.txt new file mode 100644 index 00000000000..4663ccd7344 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/belisarius_cawl.txt @@ -0,0 +1,10 @@ +Name:Belisarius Cawl +ManaCost:2 W U +Types:Legendary Artifact Creature Human +PT:2/4 +A:AB$ Token | PrecostDesc$ Ultima Founding — | Cost$ T tapXType<2/Artifact> | TokenScript$ w_2_2_astartes_warrior_vigilance | SpellDescription$ Create a 2/2 white Astartes Warrior creature token with vigilance. +A:AB$ Dig | PrecostDesc$ Master of Machines — | Cost$ T tapXType | DigNum$ X | ChangeNum$ 1 | Optional$ True | ChangeValid$ Artifact | ForceRevealToController$ True | RestRandomOrder$ True | SpellDescription$ Look at the top X cards of your library. You may reveal an artifact card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. +SVar:X:Count$xPaid +DeckHas:Ability$Token & Type$Astartes|Warrior +DeckNeeds:Type$Artifact +Oracle:Ultima Founding — {T}, Tap two untapped artifacts you control: Create a 2/2 white Astartes Warrior creature token with vigilance.\nMaster of Machines — {T}, Tap X untapped creatures you control: Look at the top X cards of your library. You may reveal an artifact card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. diff --git a/forge-gui/res/cardsfolder/upcoming/birth_of_the_imperium.txt b/forge-gui/res/cardsfolder/upcoming/birth_of_the_imperium.txt new file mode 100644 index 00000000000..5f7553091ae --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/birth_of_the_imperium.txt @@ -0,0 +1,11 @@ +Name:Birth of the Imperium +ManaCost:2 W U B +Types:Enchantment Saga +K:Saga:3:DBToken,DBSacrifice,DBDraw +SVar:DBToken:DB$ Token | TokenScript$ w_2_2_astartes_warrior_vigilance | TokenAmount$ X | SpellDescription$ Create a 2/2 white Astartes Warrior creature token with vigilance for each opponent you have. +SVar:X:PlayerCountOpponents$Amount +SVar:DBSacrifice:DB$ Sacrifice | Defined$ Opponent | SacValid$ Creature | SacMessage$ creature | SpellDescription$ Each opponent sacrifices a creature. +SVar:DBDraw:DB$ Draw | NumCards$ Y | NumCardsDesc$ two cards for each opponent who controls fewer creatures than you | SpellDescription$ Draw two cards for each opponent who controls fewer creatures than you. +SVar:Y:PlayerCountOpponents$HasPropertyhasFewerCreaturesInPlayThanYou/Times.2 +DeckHas:Ability$Token & Type$Astartes|Warrior +Oracle:(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)\nI — Create a 2/2 white Astartes Warrior creature token with vigilance for each opponent you have.\nII — Each opponent sacrifices a creature.\nIII — Draw two cards for each opponent who controls fewer creatures than you. diff --git a/forge-gui/res/cardsfolder/upcoming/chaos_terminator_lord.txt b/forge-gui/res/cardsfolder/upcoming/chaos_terminator_lord.txt new file mode 100644 index 00000000000..480b23cfcb7 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/chaos_terminator_lord.txt @@ -0,0 +1,9 @@ +Name:Chaos Terminator Lord +ManaCost:3 R +Types:Creature Astartes Warrior +PT:3/3 +T:Mode$ Phase | Phase$ BeginCombat | ValidPlayer$ You | Execute$ TrigPump | TriggerZones$ Battlefield | TriggerDescription$ Lord of Chaos — At the beginning of combat on your turn, another target creature you control gains double strike until end of turn. +SVar:TrigPump:DB$ Pump | ValidTgts$ Creature.Other+YouCtrl | TgtPrompt$ Select another target creature you control | KW$ Double Strike +SVar:PlayMain1:TRUE +DeckHas:Keyword$DoubleStrike +Oracle:Lord of Chaos — At the beginning of combat on your turn, another target creature you control gains double strike until end of turn. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/upcoming/chronomancer.txt b/forge-gui/res/cardsfolder/upcoming/chronomancer.txt new file mode 100644 index 00000000000..4d5c2b7a2c6 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/chronomancer.txt @@ -0,0 +1,10 @@ +Name:Chronomancer +ManaCost:1 B +Types:Artifact Creature Necron Wizard +PT:1/1 +K:Flying +A:AB$ Draw | PrecostDesc$ Atomic Transmutation — | Cost$ 1 T Sac<1/Artifact.Other/another artifact> | SpellDescription$ Draw a card. +K:Unearth:2 B +DeckHas:Ability$Sacrifice|Graveyard +DeckHints:Type$Artifact +Oracle:Flying\nAtomic Transmutation — {1}, {T}, Sacrifice another artifact: Draw a card.\nUnearth {2}{B} ({2}{B}: Return this card from your graveyard to the battlefield. It gains haste. Exile it at the beginning of the next end step or if it would leave the battlefield. Unearth only as a sorcery.) diff --git a/forge-gui/res/cardsfolder/upcoming/cryptic_spires.txt b/forge-gui/res/cardsfolder/upcoming/cryptic_spires.txt new file mode 100644 index 00000000000..144d43519ed --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/cryptic_spires.txt @@ -0,0 +1,7 @@ +Name:Cryptic Spires +ManaCost:no cost +Types:Land +Text:As you create your deck, circle two of the colors below. +K:CARDNAME enters the battlefield tapped. +A:AB$ Mana | Cost$ T | Produced$ Combo Chosen | SpellDescription$ Add mana of either of the circled colors. +Oracle:As you create your deck, circle two of the colors below.\nCryptic Spires enters the battlefield tapped.\n{T}: Add one mana of either of the circled colors. diff --git a/forge-gui/res/cardsfolder/upcoming/exterminatus.txt b/forge-gui/res/cardsfolder/upcoming/exterminatus.txt new file mode 100644 index 00000000000..c31860bc1e5 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/exterminatus.txt @@ -0,0 +1,6 @@ +Name:Exterminatus +ManaCost:5 W B +Types:Sorcery +A:SP$ AnimateAll | ValidCards$ Permanent.nonLand+OppCtrl | RemoveKeywords$ Indestructible | SubAbility$ DBDestroyAll | SpellDescription$ Nonland permanents your opponents control lose indestructible until end of turn. Destroy all nonland permanents. +SVar:DBDestroyAll:DB$ DestroyAll | ValidCards$ Permanent.nonLand +Oracle:Nonland permanents your opponents control lose indestructible until end of turn.\nDestroy all nonland permanents. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/upcoming/grey_knight_paragon.txt b/forge-gui/res/cardsfolder/upcoming/grey_knight_paragon.txt new file mode 100644 index 00000000000..e9adc947068 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/grey_knight_paragon.txt @@ -0,0 +1,11 @@ +Name:Grey Knight Paragon +ManaCost:4 W +Types:Creature Astartes Knight +PT:4/4 +K:Flash +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigBranch | TriggerDescription$ Rites of Banishment — When CARDNAME enters the battlefield, destroy target attacking creature. If that creature is a Demon, exile it instead. +SVar:TrigBranch:DB$ Branch | ValidTgts$ Creature.attacking | TgtPrompt$ Select target attacking creature | BranchConditionSVar$ X | BranchConditionSVarCompare$ EQ1 | TrueSubAbility$ ExileDemon | FalseSubAbility$ DestroyAttacker +SVar:DestroyAttacker:DB$ Destroy | Defined$ Targeted +SVar:ExileDemon:DB$ ChangeZone | Defined$ Targeted | Origin$ Battlefield | Destination$ Exile +SVar:X:Targeted$Valid Creature.Demon +Oracle:Flash\nRites of Banishment — When Grey Knight Paragon enters the battlefield, destroy target attacking creature. If that creature is a Demon, exile it instead. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/upcoming/helbrute.txt b/forge-gui/res/cardsfolder/upcoming/helbrute.txt new file mode 100644 index 00000000000..67d8a4ef663 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/helbrute.txt @@ -0,0 +1,8 @@ +Name:Helbrute +ManaCost:3 B R +Types:Artifact Creature Astartes Dreadnought +PT:5/4 +K:Haste +SVar:AltCost:Cost$ 3 B R ExileFromGrave<1/Creature.Other/another creature card> | PrecostDesc$ Sarcophagus — | ActivationZone$ Graveyard | Description$ You may cast CARDNAME from your graveyard by exiling another creature card from your graveyard in addition to paying its other costs. +DeckHas:Ability$Graveyard +Oracle:Haste\nSarcophagus — You may cast Helbrute from your graveyard by exiling another creature card from your graveyard in addition to paying its other costs. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/upcoming/lord_of_change.txt b/forge-gui/res/cardsfolder/upcoming/lord_of_change.txt new file mode 100644 index 00000000000..a11e3523abb --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/lord_of_change.txt @@ -0,0 +1,9 @@ +Name:Lord of Change +ManaCost:6 U +Types:Creature Demon +PT:6/6 +K:Flying +K:Ward:3 +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDraw | TriggerDescription$ Architect of Deception — When CARDNAME enters the battlefield, draw three cards. +SVar:TrigDraw:DB$ Draw | Defined$ You | NumCards$ 3 +Oracle:Flying, ward {3}\nArchitect of Deception — When Lord of Change enters the battlefield, draw three cards. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/upcoming/necron_deathmark.txt b/forge-gui/res/cardsfolder/upcoming/necron_deathmark.txt new file mode 100644 index 00000000000..3a9a6cc80c6 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/necron_deathmark.txt @@ -0,0 +1,10 @@ +Name:Necron Deathmark +ManaCost:3 B B +Types:Artifact Creature Necron +PT:5/3 +K:Flash +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDestroy | TriggerDescription$ Synaptic Disintegrator — When CARDNAME enters the battlefield, destroy up to one target creature and target player mills three cards. +SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Creature | TgtPrompt$ Select up to one target creature | TargetMin$ 0 | TargetMax$ 1 | SubAbility$ DBMill +SVar:DBMill:DB$ Mill | ValidTgts$ Player | NumCards$ 3 +DeckHas:Ability$Mill +Oracle:Flash\nSynaptic Disintegrator — When Necron Deathmark enters the battlefield, destroy up to one target creature and target player mills three cards. diff --git a/forge-gui/res/cardsfolder/upcoming/necron_monolith.txt b/forge-gui/res/cardsfolder/upcoming/necron_monolith.txt new file mode 100644 index 00000000000..cca44e2effd --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/necron_monolith.txt @@ -0,0 +1,15 @@ +Name:Necron Monolith +ManaCost:7 +Types:Artifact Vehicle +PT:7/7 +K:Flying +K:Indestructible +T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigMill | TriggerDescription$ Eternity Gate — Whenever CARDNAME attacks, mill three cards. For each creature card milled this way, create a 2/2 black Necron Warrior artifact creature token. +SVar:TrigMill:DB$ Mill | NumCards$ 3 | RememberMilled$ True | SubAbility$ DBToken +SVar:DBToken:DB$ Token | TokenAmount$ X | TokenScript$ b_2_2_a_necron_warrior | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +K:Crew:4 +SVar:X:Remembered$Valid Creature +DeckHas:Ability$Mill|Token & Type$Necron|Warrior +SVar:HasAttackEffect:TRUE +Oracle:Flying, indestructible\nEternity Gate — Whenever Necron Monolith attacks, mill three cards. For each creature card milled this way, create a 2/2 black Necron Warrior artifact creature token.\nCrew 4 (Tap any number of creatures you control with total power 4 or more: This Vehicle becomes an artifact creature until end of turn.) diff --git a/forge-gui/res/cardsfolder/upcoming/necron_overlord.txt b/forge-gui/res/cardsfolder/upcoming/necron_overlord.txt new file mode 100644 index 00000000000..7db1742fd2c --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/necron_overlord.txt @@ -0,0 +1,8 @@ +Name:Necron Overlord +ManaCost:2 B B +Types:Artifact Creature Necron Noble +PT:2/5 +A:AB$ LoseLife | PrecostDesc$ Relentless Mind — | Cost$ X T tapXType | ValidTgts$ Opponent | LifeAmount$ X | SpellDescription$ Target opponent loses X life. +SVar:X:Count$xPaid +DeckHints:Type$Artifact +Oracle:Relentless Mind — {X}, {T}, Tap X untapped artifacts you control: Target opponent loses X life. diff --git a/forge-gui/res/cardsfolder/upcoming/night_scythe.txt b/forge-gui/res/cardsfolder/upcoming/night_scythe.txt new file mode 100644 index 00000000000..f4d63651572 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/night_scythe.txt @@ -0,0 +1,10 @@ +Name:Night Scythe +ManaCost:3 +Types:Artifact Vehicle +PT:3/1 +K:Flying +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ Invasion Beams — When CARDNAME enters the battlefield, create a 2/2 black Necron Warrior artifact creature token. +SVar:TrigToken:DB$ Token | TokenScript$ b_2_2_a_necron_warrior +K:Crew:2 +DeckHas:Type$Necron|Warrior & Ability$Token +Oracle:Flying\nInvasion Beams — When Night Scythe enters the battlefield, create a 2/2 black Necron Warrior artifact creature token.\nCrew 2 (Tap any number of creatures you control with total power 2 or more: This Vehicle becomes an artifact creature until end of turn.) diff --git a/forge-gui/res/cardsfolder/upcoming/shadowheart_sharran_cleric.txt b/forge-gui/res/cardsfolder/upcoming/shadowheart_sharran_cleric.txt new file mode 100644 index 00000000000..ee153cf7202 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/shadowheart_sharran_cleric.txt @@ -0,0 +1,80 @@ +Name:Shadowheart, Sharran Cleric +ManaCost:1 B +Types:Legendary Creature Human Elf Cleric +PT:2/2 +K:Deathtouch +K:Specialize:2::Activate only if a player has 13 or less life.:CheckSVar$ X | SVarCompare$ LE13 +T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigDealDamage | TriggerDescription$ At the beginning of your end step, CARDNAME deals 1 damage to each player. +SVar:TrigDealDamage:DB$ DealDamage | Defined$ Player | NumDmg$ 1 +SVar:X:PlayerCountPlayers$LowestLifeTotal +AlternateMode:Specialize +DeckHas:Ability$Discard +Oracle:Deathtouch\nSpecialize {2}. Activate only if a player has 13 or less life.\nAt the beginning of your end step, Shadowheart, Sharran Cleric deals 1 damage to each player. + +SPECIALIZE:WHITE + +Name:Shadowheart, Cleric of Order +ManaCost:1 W B +Types:Legendary Creature Human Elf Cleric +PT:4/4 +K:Deathtouch +T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigDealDamage | TriggerDescription$ At the beginning of your end step, CARDNAME deals 1 damage to each player. +SVar:TrigDealDamage:DB$ DealDamage | Defined$ Player | NumDmg$ 1 +T:Mode$ LifeLost | ValidPlayer$ You | TriggerZones$ Battlefield | PlayerTurn$ True | Execute$ TrigToken | TriggerDescription$ Whenever you lose life during your turn, create a 2/2 white Knight creature token. +SVar:TrigToken:DB$ Token | TokenScript$ w_2_2_knight +DeckHas:Ability$Token & Type$Knight +Oracle:Deathtouch\nAt the beginning of your end step, Shadowheart, Cleric of Order deals 1 damage to each player.\nWhenever you lose life during your turn, create a 2/2 white Knight creature token. + +SPECIALIZE:BLUE + +Name:Shadowheart, Cleric of Trickery +ManaCost:1 U B +Types:Legendary Creature Human Elf Cleric +PT:4/4 +K:Deathtouch +T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigDealDamage | TriggerDescription$ At the beginning of your end step, CARDNAME deals 1 damage to each player. +SVar:TrigDealDamage:DB$ DealDamage | Defined$ Player | NumDmg$ 1 +T:Mode$ LifeLost | ValidPlayer$ You | TriggerZones$ Battlefield | PlayerTurn$ True | Execute$ TrigDraw | TriggerDescription$ Whenever you lose life during your turn, draw a card. +SVar:TrigDraw:DB$ Draw +Oracle:Deathtouch\nAt the beginning of your end step, Shadowheart, Cleric of Trickery deals 1 damage to each player.\nWhenever you lose life during your turn, draw a card. + +SPECIALIZE:BLACK + +Name:Shadowheart, Cleric of Graves +ManaCost:1 B B +Types:Legendary Creature Human Elf Cleric +PT:4/4 +K:Deathtouch +K:Lifelink +T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigDealDamage | TriggerDescription$ At the beginning of your end step, CARDNAME deals 1 damage to each player. +SVar:TrigDealDamage:DB$ DealDamage | Defined$ Player | NumDmg$ 1 +DeckHas:Ability$LifeGain +Oracle:Deathtouch, lifelink\nAt the beginning of your end step, Shadowheart, Cleric of Graves deals 1 damage to each player. + +SPECIALIZE:RED + +Name:Shadowheart, Cleric of War +ManaCost:1 B R +Types:Legendary Creature Human Elf Cleric +PT:4/4 +K:Deathtouch +T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigDamageAll | TriggerDescription$ At the beginning of your end step, CARDNAME deals 1 damage to each player. +SVar:TrigDamageAll:DB$ DealDamage | Defined$ Player | NumDmg$ 1 +T:Mode$ LifeLost | ValidPlayer$ You | TriggerZones$ Battlefield | PlayerTurn$ True | Execute$ TrigDamageOpp | TriggerDescription$ Whenever you lose life during your turn, NICKNAME deals that much damage to each opponent. +SVar:TrigDamageOpp:DB$ DealDamage | NumDmg$ X | Defined$ Opponent +SVar:X:TriggerCount$LifeAmount +Oracle:Deathtouch\nAt the beginning of your end step, Shadowheart, Cleric of War deals 1 damage to each player.\nWhenever you lose life during your turn, Shadowheart deals that much damage to each opponent. + +SPECIALIZE:GREEN + +Name:Shadowheart, Cleric of Twilight +ManaCost:1 B G +Types:Legendary Creature Human Elf Cleric +PT:4/4 +K:Deathtouch +S:Mode$ CantBlockBy | ValidAttacker$ Creature.Self | ValidBlocker$ Creature.powerLE2 | Description$ CARDNAME can't be blocked by creatures with power 2 or less. +T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigDealDamage | TriggerDescription$ At the beginning of your end step, NICKNAME deals 1 damage to each player. +SVar:TrigDealDamage:DB$ DealDamage | Defined$ Player | NumDmg$ 1 +T:Mode$ LifeLost | ValidPlayer$ You | TriggerZones$ Battlefield | PlayerTurn$ True | Execute$ TrigPutCounter | TriggerDescription$ Whenever you lose life during your turn, put a +1/+1 counter on NICKNAME. +SVar:TrigPutCounter:DB$ PutCounter | CounterType$ P1P1 +Oracle:Deathtouch\nShadowheart, Cleric of Twilight can't be blocked by creatures with power 2 or less.\nAt the beginning of your end step, Shadowheart deals 1 damage to each player.\nWhenever you lose life during your turn, put a +1/+1 counter on Shadowheart. diff --git a/forge-gui/res/cardsfolder/upcoming/sister_hostpitaller.txt b/forge-gui/res/cardsfolder/upcoming/sister_hostpitaller.txt new file mode 100644 index 00000000000..b4b1eb452a0 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/sister_hostpitaller.txt @@ -0,0 +1,10 @@ +Name:Sister Hospitaller +ManaCost:4 W B +Types:Creature Human Cleric +PT:3/2 +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigChangeZone | TriggerDescription$ Medicus Ministorum - When CARDNAME enters the battlefield, return target creature card from your graveyard to the battlefield. You gain life equal to that card's mana value. +SVar:TrigChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ValidTgts$ Creature.YouOwn | TgtPrompt$ Choose target creature card in your graveyard | ChangeNum$ 1 | SubAbility$ DBGainLife +SVar:DBGainLife:DB$ GainLife | Defined$ You | LifeAmount$ X +SVar:X:Targeted$CardManaCost +DeckHas:Ability$Graveyard|Lifegain +Oracle:Medicus Ministorum — When Sister Hospitaller enters the battlefield, return target creature card from your graveyard to the battlefield. You gain life equal to its mana value. diff --git a/forge-gui/res/cardsfolder/upcoming/thunderwolf_cavalry.txt b/forge-gui/res/cardsfolder/upcoming/thunderwolf_cavalry.txt new file mode 100644 index 00000000000..e8d5a01b7c9 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/thunderwolf_cavalry.txt @@ -0,0 +1,9 @@ +Name:Thunderwolf Cavalry +ManaCost:4 W +Types:Creature Astartes Warrior +PT:4/4 +K:First Strike +T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | Execute$ TrigPutCounter | CombatDamage$ True | TriggerDescription$ Crushing Teeth — Whenever CARDNAME deals combat damage to a player, put a +1/+1 counter on each other creature you control. +SVar:TrigPutCounter:DB$ PutCounterAll | ValidCards$ Creature.YouCtrl+Other | CounterType$ P1P1 | CounterNum$ 1 +DeckHas:Ability$Counters +Oracle:First strike\nCrushing Teeth — Whenever Thunderwolf Cavalry deals combat damage to a player, put a +1/+1 counter on each other creature you control. diff --git a/forge-gui/res/cardsfolder/upcoming/tomb_blade.txt b/forge-gui/res/cardsfolder/upcoming/tomb_blade.txt new file mode 100644 index 00000000000..cb5da2e5cba --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/tomb_blade.txt @@ -0,0 +1,12 @@ +Name:Tomb Blade +ManaCost:4 B B +Types:Artifact Creature Necron +PT:5/4 +K:Flying +T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | Execute$ TrigLoseLife | CombatDamage$ True | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, that player loses life equal to the number of creatures they control unless they sacrifice a creature. +SVar:TrigLoseLife:DB$ LoseLife | Defined$ TriggeredTarget | UnlessCost$ Sac<1/Creature> | UnlessPayer$ TriggeredTarget | LifeAmount$ X +SVar:X:TriggeredTarget$Valid Creature.YouCtrl +K:Unearth:6 B B +DeckHas:Ability$Sacrifice|Graveyard +SVar:HasAttackEffect:TRUE +Oracle:Flying\nWhenever Tomb Blade deals combat damage to a player, that player loses life equal to the number of creatures they control unless they sacrifice a creature.\nUnearth {6}{B}{B} diff --git a/forge-gui/res/cardsfolder/upcoming/tomb_fortress.txt b/forge-gui/res/cardsfolder/upcoming/tomb_fortress.txt new file mode 100644 index 00000000000..1638afbf486 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/tomb_fortress.txt @@ -0,0 +1,9 @@ +Name:Tomb Fortress +ManaCost:no cost +Types:Land +K:CARDNAME enters the battlefield tapped. +A:AB$ Mana | Cost$ T | Produced$ B | SpellDescription$ Add {B}. +A:AB$ Mill | Cost$ 2 B B B T Exile<1/CARDNAME> | Defined$ You | SorcerySpeed$ True | NumCards$ 4 | SubAbility$ DBReturn | SpellDescription$ Mill four cards, then return a creature card from your graveyard to the battlefield. Activate only as a sorcery. +SVar:DBReturn:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Creature.YouOwn | ChangeNum$ 1 | Hidden$ True +DeckHas:Ability$Graveyard|Mill +Oracle:Tomb Fortress enters the battlefield tapped.\n{T}: Add {B}.\n{2}{B}{B}{B}, {T}, Exile Tomb Fortress: Mill four cards, then return a creature card from your graveyard to the battlefield. Activate only as a sorcery. diff --git a/forge-gui/res/cardsfolder/upcoming/trazyn_the_infinite.txt b/forge-gui/res/cardsfolder/upcoming/trazyn_the_infinite.txt new file mode 100644 index 00000000000..827c9a203b4 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/trazyn_the_infinite.txt @@ -0,0 +1,7 @@ +Name:Trazyn the Infinite +ManaCost:4 B B +Types:Legendary Artifact Creature Necron +PT:4/6 +S:Mode$ Continuous | Affected$ Card.Self | EffectZone$ Battlefield | GainsAbilitiesOf$ Artifact.YouOwn | GainsAbilitiesOfZones$ Graveyard | Description$ As long as Trazyn the Infinite is on the battlefield, it has all activated abilities of all artifact cards in your graveyard. +DeckHints:Type$Artifact & Ability$Graveyard +Oracle:As long as Trazyn the Infinite is on the battlefield, it has all activated abilities of all artifact cards in your graveyard. diff --git a/forge-gui/res/cardsfolder/upcoming/triarch_praetorian.txt b/forge-gui/res/cardsfolder/upcoming/triarch_praetorian.txt new file mode 100644 index 00000000000..96513e0aa6f --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/triarch_praetorian.txt @@ -0,0 +1,11 @@ +Name:Triarch Praetorian +ManaCost:1 B +Types:Artifact Creature Necron +PT:2/1 +K:Flying +T:Mode$ ChangesZone | Origin$ Graveyard | Destination$ Battlefield | TriggerZones$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDraw | TriggerDescription$ Dynastic Codes — When CARDNAME enters the battlefield from a graveyard, you draw two cards and you lose 2 life. +SVar:TrigDraw:DB$ Draw | NumCards$ 2 | SubAbility$ DBLoseLife +SVar:DBLoseLife:DB$ LoseLife | LifeAmount$ 2 +K:Unearth:4 B +DeckHas:Ability$Graveyard +Oracle:Flying\nDynastic Codes — When Triarch Praetorian enters the battlefield from a graveyard, you draw two cards and you lose 2 life.\nUnearth {4}{B} ({4}{B}: Return this card from your graveyard to the battlefield. It gains haste. Exile it at the beginning of the next end step or if it would leave the battlefield. Unearth only as a sorcery.) diff --git a/forge-gui/res/cardsfolder/upcoming/triarch_stalker.txt b/forge-gui/res/cardsfolder/upcoming/triarch_stalker.txt new file mode 100644 index 00000000000..b08ec1b65b2 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/triarch_stalker.txt @@ -0,0 +1,9 @@ +Name:Triarch Stalker +ManaCost:3 B B +Types:Artifact Creature Necron +PT:4/5 +S:Mode$ Continuous | Affected$ Creature.attacking ChosenPlayer | AddKeyword$ Menace | Description$ Creatures attacking the last chosen player have menace. +T:Mode$ Phase | Phase$ BeginCombat | ValidPlayer$ You | Execute$ TrigChoose | TriggerZones$ Battlefield | TriggerDescriptionLure the Unwary — At the beginning of combat on your turn, choose an opponent. +SVar:TrigChoose:DB$ ChoosePlayer | Defined$ You | Choices$ Player.Opponent +DeckHas:Keyword$Menace +Oracle:Targeting Relay — At the beginning of combat on your turn, choose an opponent.\nCreatures attacking the last chosen player have menace. diff --git a/forge-gui/res/cardsfolder/upcoming/trygon_prime.txt b/forge-gui/res/cardsfolder/upcoming/trygon_prime.txt new file mode 100644 index 00000000000..3bd9e9f9a7b --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/trygon_prime.txt @@ -0,0 +1,12 @@ +Name:Trygon Prime +ManaCost:2 G U +Types:Creature Tyranid +PT:4/4 +K:Vigilance +T:Mode$ Attacks | ValidCard$ Creature.Self | Execute$ TrigCounters | TriggerDescription$ Subterranean Assault — Whenever cardname attacks, put a +1/+1 counter on it and a +1/+1 counter on up to one other target attacking creature. That creature can't be blocked this turn. +SVar:TrigCounters:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1 | SubAbility$ DBCounter +SVar:DBCounter:DB$ PutCounter | ValidTgts$ Creature.attacking+Other | TargetMin$ 0 | TargetMax$ 1 | CounterType$ P1P1 | CounterNum$ 1 | SubAbility$ DBPump +SVar:DBPump:DB$ Pump | Defined$ ParentTarget | KW$ HIDDEN Unblockable +DeckHas:Ability$Counters +SVar:HasAttackEffect:TRUE +Oracle:Subterranean Assault — Whenever Trygon Prime attacks, put a +1/+1 counter on it and a +1/+1 counter on up to one other target attacking creature. That creature can't be blocked this turn. diff --git a/forge-gui/res/cardsfolder/upcoming/tyranid_harridan.txt b/forge-gui/res/cardsfolder/upcoming/tyranid_harridan.txt new file mode 100644 index 00000000000..58bcfb9e422 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/tyranid_harridan.txt @@ -0,0 +1,10 @@ +Name:Tyranid Harridan +ManaCost:4 G U +Types:Creature Tyranid +K:Flying +K:Ward:4 +PT:4/4 +T:Mode$ DamageDone | ValidSource$ Card.Self,Tyranid.YouCtrl | ValidTarget$ Player | CombatDamage$ True | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ Shrieking Gargoyles — Whenever CARDNAME or another Tyranid you control deals combat damage to a player, create a 1/1 blue Tyranid Gargoyle creature token with flying. +SVar:TrigToken:DB$ Token | TokenScript$ u_1_1_tyranid_gargoyle_flying +DeckHas:Type$Gargoyle & Ability$Token +Oracle:Flying, ward {4}\nShrieking Gargoyles — Whenever Tyranid Harridan or another Tyranid you control deals combat damage to a player, create a 1/1 blue Tyranid Gargoyle creature token with flying. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/upcoming/tzaangor_shaman.txt b/forge-gui/res/cardsfolder/upcoming/tzaangor_shaman.txt new file mode 100644 index 00000000000..d6573fb4602 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/tzaangor_shaman.txt @@ -0,0 +1,10 @@ +Name:Tzaangor Shaman +ManaCost:2 U R +Types:Creature Mutant Shaman +PT:3/3 +K:Flying +T:Mode$ DamageDone | CombatDamage$ True | ValidTarget$ Player | ValidSource$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigDelayedTrigger | TriggerDescription$ Sorcerous Elixir — Whenever CARDNAME deals combat damage to a player, copy the next instant or sorcery spell you cast this turn when you cast it. You may choose new targets for the copy. +SVar:TrigDelayedTrigger:DB$ DelayedTrigger | AILogic$ SpellCopy | Execute$ EffTrigCopy | ThisTurn$ True | Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | SpellDescription$ When you cast your next instant or sorcery spell this turn, copy that spell. You may choose new targets for the copy. +SVar:EffTrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | MayChooseTarget$ True +DeckHints:Type$Instant|Sorcery +Oracle:Flying\nSorcerous Elixir — Whenever Tzaangor Shaman deals combat damage to a player, copy the next instant or sorcery spell you cast this turn when you cast it. You may choose new targets for the copy. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/upcoming/venomcrawler.txt b/forge-gui/res/cardsfolder/upcoming/venomcrawler.txt new file mode 100644 index 00000000000..f67748539ee --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/venomcrawler.txt @@ -0,0 +1,9 @@ +Name:Venomcrawler +ManaCost:3 B +Types:Artifact Creature Demon +PT:2/2 +K:Lifelink +T:Mode$ ChangesZone | Origin$ Battlefield | ValidCard$ Creature.Other | Destination$ Graveyard | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ Devourer of Souls — Whenever another creature dies, put a +1/+1 counter on CARDNAME. +SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1 +DeckHas:Ability$Counters +Oracle:Lifelink\nDevourer of Souls — Whenever another creature dies, put a +1/+1 counter on Venomcrawler. diff --git a/forge-gui/res/cardsfolder/upcoming/venomthrope.txt b/forge-gui/res/cardsfolder/upcoming/venomthrope.txt new file mode 100644 index 00000000000..d74b21d968a --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/venomthrope.txt @@ -0,0 +1,8 @@ +Name:Venomthrope +ManaCost:1 G U +Types:Creature Tyranid +PT:2/2 +K:Flying +K:Deathtouch +K:Hexproof +Oracle:Flying, deathtouch, hexproof \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/upcoming/vexilus_praetor.txt b/forge-gui/res/cardsfolder/upcoming/vexilus_praetor.txt new file mode 100644 index 00000000000..9776361ad81 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/vexilus_praetor.txt @@ -0,0 +1,10 @@ +Name:Vexilus Praetor +ManaCost:3 W +Types:Creature Custodes Warrior +PT:3/4 +K:Flash +K:Vilance +S:Mode$ Continuous | Affected$ Card.IsCommander+YouCtrl | AddKeyword$ Protection from everything | Description$ Aegis of the Emperor — Commanders you control have protection from everything. +SVar:PlayMain1:TRUE +AI:RemoveDeck:Random +Oracle:Flash\nVigilance\nAegis of the Emperor — Commanders you control have protection from everything. diff --git a/forge-gui/src/main/java/forge/gui/download/GuiDownloadPicturesHQ.java b/forge-gui/src/main/java/forge/gui/download/GuiDownloadPicturesHQ.java index 69034793916..921ddef503d 100644 --- a/forge-gui/src/main/java/forge/gui/download/GuiDownloadPicturesHQ.java +++ b/forge-gui/src/main/java/forge/gui/download/GuiDownloadPicturesHQ.java @@ -46,14 +46,14 @@ public class GuiDownloadPicturesHQ extends GuiDownloadService { existingSets = retrieveManifestDirectory(); for (final PaperCard c : FModel.getMagicDb().getCommonCards().getAllCards()) { - addDLObject(c, false); + addDLObject(c, ""); if (c.hasBackFace()) { - addDLObject(c, true); + addDLObject(c, "back"); } } for (final PaperCard c : FModel.getMagicDb().getVariantCards().getAllCards()) { - addDLObject(c, false); + addDLObject(c, ""); } // Add missing tokens to the list of things to download. @@ -62,8 +62,8 @@ public class GuiDownloadPicturesHQ extends GuiDownloadService { return downloads; } - private void addDLObject(final PaperCard c, final boolean backFace) { - final String imageKey = ImageUtil.getImageKey(c, backFace, false); + private void addDLObject(final PaperCard c, final String face) { + final String imageKey = ImageUtil.getImageKey(c, face, false); final String destPath = ForgeConstants.CACHE_CARD_PICS_DIR + imageKey + ".jpg"; if (existingImages.contains(imageKey + ".jpg")) { @@ -98,7 +98,7 @@ public class GuiDownloadPicturesHQ extends GuiDownloadService { cardname = cardname.replace("'", ""); String scryfallurl = ForgeConstants.URL_PIC_SCRYFALL_DOWNLOAD + "named?fuzzy=" + cardname; if(!setCode.equals("???")) scryfallurl += "&set=" + setCode.toLowerCase(); - if(backFace) scryfallurl += "&face=back"; + if(face.equals("back")) scryfallurl += "&face=back"; scryfallurl += "&format=image"; downloads.put(destPath, scryfallurl); diff --git a/forge-gui/src/main/java/forge/gui/download/GuiDownloadPicturesLQ.java b/forge-gui/src/main/java/forge/gui/download/GuiDownloadPicturesLQ.java index 080e2b4cbe9..a8e771ad338 100644 --- a/forge-gui/src/main/java/forge/gui/download/GuiDownloadPicturesLQ.java +++ b/forge-gui/src/main/java/forge/gui/download/GuiDownloadPicturesLQ.java @@ -40,14 +40,14 @@ public class GuiDownloadPicturesLQ extends GuiDownloadService { existingSets = retrieveManifestDirectory(); for (final PaperCard c : FModel.getMagicDb().getCommonCards().getAllCards()) { - addDLObject(c, false); + addDLObject(c, ""); if (c.hasBackFace()) { - addDLObject(c, true); + addDLObject(c, "back"); } } for (final PaperCard c : FModel.getMagicDb().getVariantCards().getAllCards()) { - addDLObject(c, false); + addDLObject(c, ""); } // Add missing tokens to the list of things to download. @@ -56,8 +56,8 @@ public class GuiDownloadPicturesLQ extends GuiDownloadService { return downloads; } - private void addDLObject(final PaperCard c, final boolean backFace) { - final String imageKey = ImageUtil.getImageKey(c, backFace, false); + private void addDLObject(final PaperCard c, final String face) { + final String imageKey = ImageUtil.getImageKey(c, face, false); final String destPath = ForgeConstants.CACHE_CARD_PICS_DIR + imageKey + ".jpg"; if (ImageKeys.getImageFile(imageKey) != null) { @@ -76,6 +76,6 @@ public class GuiDownloadPicturesLQ extends GuiDownloadService { return; } - downloads.put(destPath, ForgeConstants.URL_PIC_DOWNLOAD + ImageUtil.getDownloadUrl(c, backFace)); + downloads.put(destPath, ForgeConstants.URL_PIC_DOWNLOAD + ImageUtil.getDownloadUrl(c, face)); } } diff --git a/forge-gui/src/main/java/forge/gui/download/GuiDownloadSetPicturesLQ.java b/forge-gui/src/main/java/forge/gui/download/GuiDownloadSetPicturesLQ.java index 34fe252e44a..4a66e114fcb 100644 --- a/forge-gui/src/main/java/forge/gui/download/GuiDownloadSetPicturesLQ.java +++ b/forge-gui/src/main/java/forge/gui/download/GuiDownloadSetPicturesLQ.java @@ -72,10 +72,10 @@ public class GuiDownloadSetPicturesLQ extends GuiDownloadService { continue; } - addDLObject(ImageUtil.getDownloadUrl(c, false), ImageUtil.getImageKey(c, false, true), downloads); + addDLObject(ImageUtil.getDownloadUrl(c, ""), ImageUtil.getImageKey(c, "", true), downloads); if (c.hasBackFace()) { - addDLObject(ImageUtil.getDownloadUrl(c, true), ImageUtil.getImageKey(c, true, true), downloads); + addDLObject(ImageUtil.getDownloadUrl(c, "back"), ImageUtil.getImageKey(c, "back", true), downloads); } } diff --git a/forge-gui/src/main/java/forge/util/ImageFetcher.java b/forge-gui/src/main/java/forge/util/ImageFetcher.java index 011cf484b16..a6b578d4c32 100644 --- a/forge-gui/src/main/java/forge/util/ImageFetcher.java +++ b/forge-gui/src/main/java/forge/util/ImageFetcher.java @@ -39,7 +39,7 @@ public abstract class ImageFetcher { private HashMap> currentFetches = new HashMap<>(); private HashMap tokenImages; - private String getScryfallDownloadURL(PaperCard c, boolean backFace, boolean useArtCrop, boolean hasSetLookup, String imagePath, ArrayList downloadUrls) { + private String getScryfallDownloadURL(PaperCard c, String face, boolean useArtCrop, boolean hasSetLookup, String imagePath, ArrayList downloadUrls) { StaticData data = StaticData.instance(); CardEdition edition = data.getEditions().get(c.getEdition()); if (edition == null) // edition does not exist - some error occurred with card data @@ -53,7 +53,7 @@ public abstract class ImageFetcher { if (ed != null) { String setCode =ed.getScryfallCode(); String langCode = ed.getCardsLangCode(); - downloadUrls.add(ForgeConstants.URL_PIC_SCRYFALL_DOWNLOAD + ImageUtil.getScryfallDownloadUrl(pc, backFace, setCode, langCode, useArtCrop)); + downloadUrls.add(ForgeConstants.URL_PIC_SCRYFALL_DOWNLOAD + ImageUtil.getScryfallDownloadUrl(pc, face, setCode, langCode, useArtCrop)); } } } else {// original from set @@ -61,7 +61,7 @@ public abstract class ImageFetcher { if (ed != null) { String setCode =ed.getScryfallCode(); String langCode = ed.getCardsLangCode(); - downloadUrls.add(ForgeConstants.URL_PIC_SCRYFALL_DOWNLOAD + ImageUtil.getScryfallDownloadUrl(pc, backFace, setCode, langCode, useArtCrop)); + downloadUrls.add(ForgeConstants.URL_PIC_SCRYFALL_DOWNLOAD + ImageUtil.getScryfallDownloadUrl(pc, face, setCode, langCode, useArtCrop)); } } } @@ -71,7 +71,7 @@ public abstract class ImageFetcher { String setCode = edition.getScryfallCode(); String langCode = edition.getCardsLangCode(); return ForgeConstants.URL_PIC_SCRYFALL_DOWNLOAD + - ImageUtil.getScryfallDownloadUrl(c, backFace, setCode, langCode, useArtCrop); + ImageUtil.getScryfallDownloadUrl(c, face, setCode, langCode, useArtCrop); } } @@ -105,10 +105,46 @@ public abstract class ImageFetcher { // Skip fetching if artist info is not available for art crop if (useArtCrop && paperCard.getArtist().isEmpty()) return; - String imagePath = ImageUtil.getImageRelativePath(paperCard, false, true, false); + String imagePath = ImageUtil.getImageRelativePath(paperCard, "", true, false); final boolean hasSetLookup = ImageKeys.hasSetLookup(imagePath); - final boolean backFace = imageKey.endsWith(ImageKeys.BACKFACE_POSTFIX); - String filename = backFace ? paperCard.getCardAltImageKey() : paperCard.getCardImageKey(); + String face = ""; + if (imageKey.endsWith(ImageKeys.BACKFACE_POSTFIX)) { + face = "back"; + } else if (imageKey.endsWith(ImageKeys.SPECFACE_W)) { + face = "white"; + } else if (imageKey.endsWith(ImageKeys.SPECFACE_U)) { + face = "blue"; + } else if (imageKey.endsWith(ImageKeys.SPECFACE_B)) { + face = "black"; + } else if (imageKey.endsWith(ImageKeys.SPECFACE_R)) { + face = "red"; + } else if (imageKey.endsWith(ImageKeys.SPECFACE_G)) { + face = "green"; + } + String filename = ""; + switch (face) { + case "back": + filename = paperCard.getCardAltImageKey(); + break; + case "white": + filename = paperCard.getCardWSpecImageKey(); + break; + case "blue": + filename = paperCard.getCardUSpecImageKey(); + break; + case "black": + filename = paperCard.getCardBSpecImageKey(); + break; + case "red": + filename = paperCard.getCardRSpecImageKey(); + break; + case "green": + filename = paperCard.getCardGSpecImageKey(); + break; + default: + filename = paperCard.getCardImageKey(); + break; + } if (useArtCrop) { filename = TextUtil.fastReplace(filename, ".full", ".artcrop"); } @@ -119,7 +155,7 @@ public abstract class ImageFetcher { //move priority of ftp image here StringBuilder setDownload = new StringBuilder(ForgeConstants.URL_PIC_DOWNLOAD); if (!hasSetLookup) { - setDownload.append(ImageUtil.getDownloadUrl(paperCard, backFace)); + setDownload.append(ImageUtil.getDownloadUrl(paperCard, face)); downloadUrls.add(setDownload.toString()); } else { List clones = StaticData.instance().getCommonCards().getAllCards(paperCard.getName()); @@ -127,12 +163,12 @@ public abstract class ImageFetcher { if (clones.size() > 1) {//clones only if (!paperCard.getEdition().equalsIgnoreCase(pc.getEdition())) { StringBuilder set = new StringBuilder(ForgeConstants.URL_PIC_DOWNLOAD); - set.append(ImageUtil.getDownloadUrl(pc, backFace)); + set.append(ImageUtil.getDownloadUrl(pc, face)); downloadUrls.add(set.toString()); } } else {// original from set StringBuilder set = new StringBuilder(ForgeConstants.URL_PIC_DOWNLOAD); - set.append(ImageUtil.getDownloadUrl(pc, backFace)); + set.append(ImageUtil.getDownloadUrl(pc, face)); downloadUrls.add(set.toString()); } } @@ -140,7 +176,7 @@ public abstract class ImageFetcher { } final String cardCollectorNumber = paperCard.getCollectorNumber(); if (!cardCollectorNumber.equals(IPaperCard.NO_COLLECTOR_NUMBER)) { - final String scryfallURL = this.getScryfallDownloadURL(paperCard, backFace, useArtCrop, hasSetLookup, imagePath, downloadUrls); + final String scryfallURL = this.getScryfallDownloadURL(paperCard, face, useArtCrop, hasSetLookup, filename, downloadUrls); if (scryfallURL != null && !hasSetLookup) downloadUrls.add(scryfallURL); }