diff --git a/forge-ai/src/main/java/forge/ai/AiProps.java b/forge-ai/src/main/java/forge/ai/AiProps.java index 06436660893..ee162987ba9 100644 --- a/forge-ai/src/main/java/forge/ai/AiProps.java +++ b/forge-ai/src/main/java/forge/ai/AiProps.java @@ -75,6 +75,7 @@ public enum AiProps { /** */ ALWAYS_COPY_SPELL_IF_CMC_DIFF ("2"), /** */ ACTIVELY_DESTROY_ARTS_AND_NONAURA_ENCHS ("true"), /** */ ACTIVELY_DESTROY_IMMEDIATELY_UNBLOCKABLE ("false"), /** */ + ACTIVELY_PROTECT_VS_CURSE_AURAS("false"), /** */ DESTROY_IMMEDIATELY_UNBLOCKABLE_THRESHOLD ("2"), /** */ DESTROY_IMMEDIATELY_UNBLOCKABLE_ONLY_IN_DNGR ("true"), /** */ DESTROY_IMMEDIATELY_UNBLOCKABLE_LIFE_IN_DNGR ("5"), /** */ diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtil.java b/forge-ai/src/main/java/forge/ai/ComputerUtil.java index 60e0f02c05d..f3abf5c17c6 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtil.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtil.java @@ -1845,6 +1845,28 @@ public class ComputerUtil { } } } + //Generic curse auras + else if ((threatApi == ApiType.Attach && (topStack.isCurse() || "Curse".equals(topStack.getParam("AILogic"))))) { + AiController aic = aiPlayer.isAI() ? ((PlayerControllerAi)aiPlayer.getController()).getAi() : null; + boolean enableCurseAuraRemoval = aic != null ? aic.getBooleanProperty(AiProps.ACTIVELY_DESTROY_IMMEDIATELY_UNBLOCKABLE) : false; + if (enableCurseAuraRemoval) { + for (final Object o : objects) { + if (o instanceof Card) { + final Card c = (Card) o; + // give Shroud to targeted creatures + if ((saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll && tgt == null) && !grantShroud) { + continue; + } + if (saviourApi == ApiType.Protection) { + if (tgt == null || (ProtectAi.toProtectFrom(source, saviour) == null)) { + continue; + } + } + threatened.add(c); + } + } + } + } Iterables.addAll(threatened, ComputerUtil.predictThreatenedObjects(aiPlayer, saviour, topStack.getSubAbility())); return threatened; diff --git a/forge-ai/src/main/java/forge/ai/ability/AnimateAi.java b/forge-ai/src/main/java/forge/ai/ability/AnimateAi.java index b64a1fd84c5..c1e84bc35fb 100644 --- a/forge-ai/src/main/java/forge/ai/ability/AnimateAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/AnimateAi.java @@ -340,17 +340,19 @@ public class AnimateAi extends SpellAbilityAi { // select the worst of the best final Card worst = ComputerUtilCard.getWorstAI(maxList); - if (worst.isLand()) { - // e.g. Clan Guildmage, make sure we're not using the same land we want to animate to activate the ability - this.holdAnimatedTillMain2(ai, worst); - if (!ComputerUtilMana.canPayManaCost(sa, ai, 0)) { - this.releaseHeldTillMain2(ai, worst); - return false; + if (worst != null) { + if (worst.isLand()) { + // e.g. Clan Guildmage, make sure we're not using the same land we want to animate to activate the ability + this.holdAnimatedTillMain2(ai, worst); + if (!ComputerUtilMana.canPayManaCost(sa, ai, 0)) { + this.releaseHeldTillMain2(ai, worst); + return false; + } } + this.rememberAnimatedThisTurn(ai, worst); + sa.getTargets().add(worst); } - this.rememberAnimatedThisTurn(ai, worst); - sa.getTargets().add(worst); - return true; + return true; } // This is reasonable for now. Kamahl, Fist of Krosa and a sorcery or diff --git a/forge-core/src/main/java/forge/card/CardEdition.java b/forge-core/src/main/java/forge/card/CardEdition.java index c69b165d995..bc3d1854a28 100644 --- a/forge-core/src/main/java/forge/card/CardEdition.java +++ b/forge-core/src/main/java/forge/card/CardEdition.java @@ -124,6 +124,7 @@ public final class CardEdition implements Comparable { // immutable private boolean smallSetOverride = false; private String boosterMustContain = ""; private String boosterReplaceSlotFromPrintSheet = ""; + private String[] chaosDraftThemes = new String[0]; private boolean doublePickToStartRound = false; private final CardInSet[] cards; private final Map tokenNormalized; @@ -195,6 +196,7 @@ public final class CardEdition implements Comparable { // immutable public boolean getDoublePickToStartRound() { return doublePickToStartRound; } public String getBoosterMustContain() { return boosterMustContain; } public String getBoosterReplaceSlotFromPrintSheet() { return boosterReplaceSlotFromPrintSheet; } + public String[] getChaosDraftThemes() { return chaosDraftThemes; } public CardInSet[] getCards() { return cards; } public boolean isModern() { return getDate().after(parseDate("2003-07-27")); } //8ED and above are modern except some promo cards and others @@ -385,6 +387,9 @@ public final class CardEdition implements Comparable { // immutable res.boosterMustContain = section.get("BoosterMustContain", ""); // e.g. Dominaria guaranteed legendary creature res.boosterReplaceSlotFromPrintSheet = section.get("BoosterReplaceSlotFromPrintSheet", ""); // e.g. Zendikar Rising guaranteed double-faced card + + res.chaosDraftThemes = section.get("ChaosDraftThemes", "").split(";"); // semicolon separated list of theme names + return res; } diff --git a/forge-core/src/main/java/forge/card/MagicColor.java b/forge-core/src/main/java/forge/card/MagicColor.java index c21dedeac97..408b00d8080 100644 --- a/forge-core/src/main/java/forge/card/MagicColor.java +++ b/forge-core/src/main/java/forge/card/MagicColor.java @@ -139,16 +139,22 @@ public final class MagicColor { public static final ImmutableList SNOW_LANDS = ImmutableList.of("Snow-Covered Plains", "Snow-Covered Island", "Snow-Covered Swamp", "Snow-Covered Mountain", "Snow-Covered Forest"); public static final ImmutableMap ANY_COLOR_CONVERSION = new ImmutableMap.Builder() .put("ManaColorConversion", "Additive") - .put("WhiteConversion", "All") - .put("BlueConversion", "All") - .put("BlackConversion", "All") - .put("RedConversion", "All") - .put("GreenConversion", "All") + .put("WhiteConversion", "Color") + .put("BlueConversion", "Color") + .put("BlackConversion", "Color") + .put("RedConversion", "Color") + .put("GreenConversion", "Color") + .put("ColorlessConversion", "Color") .build(); public static final ImmutableMap ANY_TYPE_CONVERSION = new ImmutableMap.Builder() - .putAll(ANY_COLOR_CONVERSION) - .put("ColorlessConversion", "All") + .put("ManaColorConversion", "Additive") + .put("WhiteConversion", "Type") + .put("BlueConversion", "Type") + .put("BlackConversion", "Type") + .put("RedConversion", "Type") + .put("GreenConversion", "Type") + .put("ColorlessConversion", "Type") .build(); /** * Private constructor to prevent instantiation. diff --git a/forge-core/src/main/java/forge/item/generation/ChaosBoosterSupplier.java b/forge-core/src/main/java/forge/item/generation/ChaosBoosterSupplier.java index a6dc60d6d83..c4a38769dc1 100644 --- a/forge-core/src/main/java/forge/item/generation/ChaosBoosterSupplier.java +++ b/forge-core/src/main/java/forge/item/generation/ChaosBoosterSupplier.java @@ -3,23 +3,20 @@ package forge.item.generation; import forge.card.CardEdition; import forge.item.BoosterPack; import forge.item.PaperCard; +import forge.util.BagRandomizer; import java.util.List; public class ChaosBoosterSupplier implements IUnOpenedProduct { - private List sets; + private BagRandomizer randomizer; - public ChaosBoosterSupplier(List sets) { - this.sets = sets; + public ChaosBoosterSupplier(Iterable sets) throws IllegalArgumentException { + randomizer = new BagRandomizer<>(sets); } @Override public List get() { - if (sets.size() == 0) { - System.out.println("No chaos boosters left to supply."); - return null; - } - final CardEdition set = sets.remove(0); + final CardEdition set = randomizer.getNextItem(); final BoosterPack pack = new BoosterPack(set.getCode(), set.getBoosterTemplate()); return pack.getCards(); } diff --git a/forge-core/src/main/java/forge/util/BagRandomizer.java b/forge-core/src/main/java/forge/util/BagRandomizer.java new file mode 100644 index 00000000000..80bef2ac791 --- /dev/null +++ b/forge-core/src/main/java/forge/util/BagRandomizer.java @@ -0,0 +1,76 @@ +package forge.util; + +import java.security.SecureRandom; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Random; + +/** + * Data structure that allows random draws from a set number of items, + * where all items are returned once before the first will be retrieved. + * The bag will be shuffled after each time all items have been returned. + * @param an object + */ +public class BagRandomizer implements Iterable{ + private static Random random = new SecureRandom(); + + private T[] bag; + private int currentPosition = 0; + + public BagRandomizer(T[] items) throws IllegalArgumentException { + if (items.length == 0) { + throw new IllegalArgumentException("Must include at least one item!"); + } + bag = items; + shuffleBag(); + } + + public BagRandomizer(Iterable items) throws IllegalArgumentException { + ArrayList list = new ArrayList<>(); + for (T item : items) { + list.add(item); + } + if (list.size() == 0) { + throw new IllegalArgumentException("Must include at least one item!"); + } + bag = (T[]) list.toArray(); + shuffleBag(); + } + + public T getNextItem() { + // reset bag if last position is reached + if (currentPosition >= bag.length) { + shuffleBag(); + currentPosition = 0; + } + return bag[currentPosition++]; + } + + private void shuffleBag() { + int n = bag.length; + for (int i = 0; i < n; i++) { + int r = (int) (random.nextDouble() * (i + 1)); + T swap = bag[r]; + bag[r] = bag[i]; + bag[i] = swap; + } + } + + @Override + public Iterator iterator() { + return new BagRandomizerIterator(); + } + + private class BagRandomizerIterator implements Iterator { + + @Override + public boolean hasNext() { + return bag.length > 0; + } + + @Override + public T next() { + return (T) BagRandomizer.this.getNextItem(); + } + } +} diff --git a/forge-game/src/main/java/forge/game/GameOutcome.java b/forge-game/src/main/java/forge/game/GameOutcome.java index d6f3481c3d6..2cb077ef14a 100644 --- a/forge-game/src/main/java/forge/game/GameOutcome.java +++ b/forge-game/src/main/java/forge/game/GameOutcome.java @@ -6,12 +6,12 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ @@ -33,7 +33,7 @@ import java.util.Map.Entry; *

* GameInfo class. *

- * + * * @author Forge * @version $Id: GameOutcome.java 17608 2012-10-20 22:27:27Z Max mtg $ */ @@ -47,7 +47,7 @@ public final class GameOutcome implements Iterable lostCards; public final List wonCards; - + private AnteResult(List cards, boolean won) { // Need empty lists for other results for addition of change ownership cards if (won) { @@ -67,15 +67,20 @@ public final class GameOutcome implements Iterable cards) { return new AnteResult(cards, true); } - public static AnteResult lost(List cards) { return new AnteResult(cards, false); } + public static AnteResult won(List cards) { + return new AnteResult(cards, true); + } + + public static AnteResult lost(List cards) { + return new AnteResult(cards, false); + } } private int lastTurnNumber = 0; private int lifeDelta = 0; private int winningTeam = -1; - private final HashMap playerRating = new HashMap<>(); + private final HashMap playerRating = new HashMap<>(); private final HashMap playerNames = new HashMap<>(); public final Map anteResult = new HashMap<>(); @@ -83,21 +88,22 @@ public final class GameOutcome implements Iterable players) { winCondition = reason; - calculateLifeDelta(players); - - int winnersHealth = 0; - int opponentsHealth = 0; for (final Player p : players) { this.playerRating.put(p.getRegisteredPlayer(), p.getStats()); this.playerNames.put(p.getRegisteredPlayer(), p.getName()); - if (p.getOutcome().hasWon() && winCondition == GameEndReason.AllOpposingTeamsLost) { + if (winCondition == GameEndReason.AllOpposingTeamsLost && p.getOutcome().hasWon()) { // Only mark the WinningTeam when "Team mode" is on. winningTeam = p.getTeam(); } } + + // Unable to calculate lifeDelta between a winning and losing player whe a draw is in place + if (winCondition == GameEndReason.Draw) return; + int winnersHealth = 0; + int opponentsHealth = 0; for (final Player p : players) { if (p.getTeam() == winningTeam) { winnersHealth += p.getLife(); @@ -106,22 +112,22 @@ public final class GameOutcome implements Iterable players) { int opponentsHealth = 0; int winnersHealth = 0; - + for (Player p : players) { if (p.getOutcome().hasWon()) { winnersHealth += p.getLife(); - } - else { + } else { opponentsHealth += p.getLife(); } } - + lifeDelta = Math.max(0, winnersHealth - opponentsHealth); } @@ -150,7 +156,7 @@ public final class GameOutcome implements Iterable pair : playerRating.entrySet()) { + for (Entry pair : playerRating.entrySet()) { if (pair.getValue().getOutcome().hasWon()) { return pair.getKey(); } @@ -196,7 +202,7 @@ public final class GameOutcome implements Iterable getOutcomeStrings() { List outcomes = Lists.newArrayList(); - for(RegisteredPlayer player : playerNames.keySet()) { + for (RegisteredPlayer player : playerNames.keySet()) { outcomes.add(getOutcomeString(player)); } return outcomes; diff --git a/forge-game/src/main/java/forge/game/GameView.java b/forge-game/src/main/java/forge/game/GameView.java index eda68175be6..39c50ea2171 100644 --- a/forge-game/src/main/java/forge/game/GameView.java +++ b/forge-game/src/main/java/forge/game/GameView.java @@ -116,6 +116,14 @@ public class GameView extends TrackableObject { public boolean isMatchOver() { return get(TrackableProperty.MatchOver); } + public boolean isMulligan() { + if (get(TrackableProperty.Mulligan) == null) + return false; + return get(TrackableProperty.Mulligan); + } + public void updateIsMulligan(boolean value) { + set(TrackableProperty.Mulligan, value); + } public String getWinningPlayerName() { return get(TrackableProperty.WinningPlayerName); } diff --git a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java index c40b4eb64ea..9c45bc442a9 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java @@ -108,7 +108,7 @@ public class AbilityUtils { else if (defined.equals("Enchanted")) { c = hostCard.getEnchantingCard(); - if ((c == null) && (sa.getRootAbility() != null) + if ((c == null) && (sa != null) && (sa.getRootAbility() != null) && (sa.getRootAbility().getPaidList("Sacrificed") != null) && !sa.getRootAbility().getPaidList("Sacrificed").isEmpty()) { c = sa.getRootAbility().getPaidList("Sacrificed").get(0).getEnchantingCard(); @@ -168,8 +168,8 @@ public class AbilityUtils { if (crd instanceof Card) { c = game.getCardState((Card) crd); - } else if (crd instanceof List) { - cards.addAll((CardCollection) crd); + } else if (crd instanceof Iterable) { + cards.addAll(Iterables.filter((Iterable) crd, Card.class)); } } else if (defined.equals("Remembered") || defined.equals("RememberedCard")) { @@ -657,9 +657,7 @@ public class AbilityUtils { if (calcX[0].startsWith("TriggeredPlayers")) { key = "Triggered" + key.substring(16); } - final List players = new ArrayList<>(); - Iterables.addAll(players, getDefinedPlayers(card, key, sa)); - return CardFactoryUtil.playerXCount(players, calcX[1], card) * multiplier; + return CardFactoryUtil.playerXCount(getDefinedPlayers(card, key, sa), calcX[1], card) * multiplier; } if (calcX[0].startsWith("TriggeredPlayer") || calcX[0].startsWith("TriggeredTarget")) { final SpellAbility root = sa.getRootAbility(); @@ -1078,20 +1076,10 @@ public class AbilityUtils { } if (o != null) { if (o instanceof Player) { - final Player p = (Player) o; - if (!players.contains(p)) { - players.add(p); - } + players.add((Player) o); } - if (o instanceof List) { - final List pList = (List)o; - if (!pList.isEmpty()) { - for (final Object p : pList) { - if (p instanceof Player && !players.contains(p)) { - players.add((Player) p); - } - } - } + if (o instanceof Iterable) { + players.addAll(Iterables.filter((Iterable)o, Player.class)); } } } @@ -1802,9 +1790,12 @@ public class AbilityUtils { if (params.containsKey(key)) { String convertTo = params.get(key); byte convertByte = 0; - if ("All".equals(convertTo)) { + if ("Type".equals(convertTo)) { // IMPORTANT! We need to use Mana Color here not Card Color. convertByte = ManaAtom.ALL_MANA_TYPES; + } else if ("Color".equals(convertTo)) { + // IMPORTANT! We need to use Mana Color here not Card Color. + convertByte = ManaAtom.ALL_MANA_COLORS; } else { for (final String convertColor : convertTo.split(",")) { convertByte |= ManaAtom.fromName(convertColor); diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java index f8ca17ec578..c19eb435121 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java @@ -10,6 +10,7 @@ import forge.GameCommand; import forge.card.CardStateName; import forge.game.Game; import forge.game.GameEntity; +import forge.game.GameLogEntryType; import forge.game.GameObject; import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; @@ -431,6 +432,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { final Player player = sa.getActivatingPlayer(); final Card hostCard = sa.getHostCard(); final Game game = player.getGame(); + final CardCollection commandCards = new CardCollection(); ZoneType destination = ZoneType.smartValueOf(sa.getParam("Destination")); final List origin = Lists.newArrayList(); @@ -664,6 +666,12 @@ public class ChangeZoneEffect extends SpellAbilityEffect { tgtC.setExiledWith(host); } movedCard = game.getAction().moveTo(destination, tgtC, sa); + if (ZoneType.Hand.equals(destination) && ZoneType.Command.equals(originZone.getZoneType())) { + StringBuilder sb = new StringBuilder(); + sb.append(movedCard.getName()).append(" has moved from Command Zone to ").append(player).append("'s hand."); + game.getGameLog().add(GameLogEntryType.ZONE_CHANGE, sb.toString()); + commandCards.add(movedCard); //add to list to reveal the commandzone cards + } // If a card is Exiled from the stack, remove its spells from the stack if (sa.hasParam("Fizzle")) { if (tgtC.isInZone(ZoneType.Exile) || tgtC.isInZone(ZoneType.Hand) @@ -709,6 +717,11 @@ public class ChangeZoneEffect extends SpellAbilityEffect { } } + //reveal command cards that changes zone from command zone to player's hand + if (!commandCards.isEmpty()) { + game.getAction().reveal(commandCards, player, true, "Revealed cards in "); + } + triggerList.triggerChangesZoneAll(game); // for things like Gaea's Blessing diff --git a/forge-game/src/main/java/forge/game/ability/effects/CharmEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CharmEffect.java index 652d7728a33..73b5cc4b05a 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/CharmEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/CharmEffect.java @@ -56,8 +56,9 @@ public class CharmEffect extends SpellAbilityEffect { List list = CharmEffect.makePossibleOptions(sa); final int num; - // hotfix for Vindictive Lich when using getCardForUi - if (source.getController() == null && sa.getParamOrDefault("CharmNum", "1").contains("MaxUniqueOpponents")) { + boolean additionalDesc = sa.hasParam("AdditionalDescription"); + // hotfix for complex cards when using getCardForUi + if (source.getController() == null && additionalDesc) { // using getCardForUi game is not set, so can't guess max charm num = Integer.MAX_VALUE; } else { @@ -73,8 +74,8 @@ public class CharmEffect extends SpellAbilityEffect { sb.append(sa.getCostDescription()); sb.append(oppChooses ? "An opponent chooses " : "Choose "); - if (num == min) { - sb.append(Lang.getNumeral(num)); + if (num == min || num == Integer.MAX_VALUE) { + sb.append(Lang.getNumeral(min)); } else if (min == 0) { sb.append("up to ").append(Lang.getNumeral(num)); } else { @@ -97,7 +98,6 @@ public class CharmEffect extends SpellAbilityEffect { sb.append(". You may choose the same mode more than once."); } - boolean additionalDesc = sa.hasParam("AdditionalDescription"); if (additionalDesc) { sb.append(" ").append(sa.getParam("AdditionalDescription").trim()); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/DigEffect.java b/forge-game/src/main/java/forge/game/ability/effects/DigEffect.java index 343bb983c8d..6228bf0ce63 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/DigEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/DigEffect.java @@ -163,6 +163,11 @@ public class DigEffect extends SpellAbilityEffect { host.addRemembered(one); } } + if (sa.hasParam("ImprintRevealed") && hasRevealed) { + for (final Card one : top) { + host.addImprintedCard(one); + } + } if (sa.hasParam("Choser")) { final FCollectionView choosers = AbilityUtils.getDefinedPlayers(sa.getHostCard(), sa.getParam("Choser"), sa); if (!choosers.isEmpty()) { diff --git a/forge-game/src/main/java/forge/game/ability/effects/LifeExchangeEffect.java b/forge-game/src/main/java/forge/game/ability/effects/LifeExchangeEffect.java index c813793b545..f68a400a365 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/LifeExchangeEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/LifeExchangeEffect.java @@ -62,6 +62,11 @@ public class LifeExchangeEffect extends SpellAbilityEffect { final int life1 = p1.getLife(); final int life2 = p2.getLife(); + if (sa.hasParam("RememberDifference")) { + final int diff = life1 - life2; + source.addRemembered(diff); + } + if ((life1 > life2) && p1.canLoseLife() && p2.canGainLife()) { final int diff = life1 - life2; p1.loseLife(diff); diff --git a/forge-game/src/main/java/forge/game/ability/effects/SetStateEffect.java b/forge-game/src/main/java/forge/game/ability/effects/SetStateEffect.java index 2ab35c6b1dd..31fa50157a9 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/SetStateEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/SetStateEffect.java @@ -58,6 +58,7 @@ public class SetStateEffect extends SpellAbilityEffect { final boolean manifestUp = sa.hasParam("ManifestUp"); final boolean hiddenAgenda = sa.hasParam("HiddenAgenda"); final boolean optional = sa.hasParam("Optional"); + final CardCollection transformedCards = new CardCollection(); GameEntityCounterTable table = new GameEntityCounterTable(); @@ -130,8 +131,12 @@ public class SetStateEffect extends SpellAbilityEffect { if (remChanged) { host.addRemembered(tgt); } + transformedCards.add(tgt); } } table.triggerCountersPutAll(game); + if (!transformedCards.isEmpty()) { + game.getAction().reveal(transformedCards, p, true, "Transformed cards in "); + } } } diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java index 3d3d6b7379e..1ecff58ab29 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -1823,7 +1823,8 @@ public class Card extends GameEntity implements Comparable { || keyword.startsWith("Reinforce") || keyword.startsWith("Champion") || keyword.startsWith("Prowl") || keyword.startsWith("Amplify") || keyword.startsWith("Ninjutsu") || keyword.startsWith("Adapt") || keyword.startsWith("Transfigure") || keyword.startsWith("Aura swap") - || keyword.startsWith("Cycling") || keyword.startsWith("TypeCycling")) { + || keyword.startsWith("Cycling") || keyword.startsWith("TypeCycling") + || keyword.startsWith("Encore")) { // keyword parsing takes care of adding a proper description } else if (keyword.startsWith("CantBeBlockedByAmount")) { sbLong.append(getName()).append(" can't be blocked "); diff --git a/forge-game/src/main/java/forge/game/card/CardDamageMap.java b/forge-game/src/main/java/forge/game/card/CardDamageMap.java index a3359c43a83..141327d4592 100644 --- a/forge-game/src/main/java/forge/game/card/CardDamageMap.java +++ b/forge-game/src/main/java/forge/game/card/CardDamageMap.java @@ -25,14 +25,14 @@ public class CardDamageMap extends ForwardingTable { private Table dataMap = HashBasedTable.create(); public CardDamageMap(Table damageMap) { - this.putAll(damageMap); + putAll(damageMap); } public CardDamageMap() { } public void triggerPreventDamage(boolean isCombat) { - for (Map.Entry> e : this.columnMap().entrySet()) { + for (Map.Entry> e : columnMap().entrySet()) { int sum = 0; for (final int i : e.getValue().values()) { sum += i; @@ -51,7 +51,7 @@ public class CardDamageMap extends ForwardingTable { public void triggerDamageDoneOnce(boolean isCombat, final Game game, final SpellAbility sa) { // Source -> Targets - for (Map.Entry> e : this.rowMap().entrySet()) { + for (Map.Entry> e : rowMap().entrySet()) { final Card sourceLKI = e.getKey(); int sum = 0; for (final Integer i : e.getValue().values()) { @@ -71,7 +71,7 @@ public class CardDamageMap extends ForwardingTable { } } // Targets -> Source - for (Map.Entry> e : this.columnMap().entrySet()) { + for (Map.Entry> e : columnMap().entrySet()) { int sum = 0; for (final int i : e.getValue().values()) { sum += i; @@ -106,9 +106,16 @@ public class CardDamageMap extends ForwardingTable { return dataMap; } - public int filteredAmount(String validSource, String validTarget, Card host, SpellAbility sa) { + public int totalAmount() { int result = 0; + for (int i : values()) { + result += i; + } + return result; + } + public CardDamageMap filteredMap(String validSource, String validTarget, Card host, SpellAbility sa) { + CardDamageMap result = new CardDamageMap(); Set filteredSource = null; Set filteredTarget = null; if (validSource != null) { @@ -125,7 +132,8 @@ public class CardDamageMap extends ForwardingTable { if (filteredTarget != null && !filteredTarget.contains(c.getColumnKey())) { continue; } - result += c.getValue(); + + result.put(c.getRowKey(), c.getColumnKey(), c.getValue()); } return result; diff --git a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java index ade6156cdc5..d4a7bb506bf 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java @@ -1156,6 +1156,9 @@ public class CardFactoryUtil { if (sq[0].contains("Landfall")) { return doXMath(Integer.parseInt(sq[cc.hasLandfall() ? 1 : 2]), m, c); } + if (sq[0].contains("Monarch")) { + return doXMath(Integer.parseInt(sq[cc.equals(game.getMonarch()) ? 1 : 2]), m, c); + } if (sq[0].contains("Blessing")) { return doXMath(Integer.parseInt(sq[cc.hasBlessing() ? 1 : 2]), m, c); } @@ -2906,7 +2909,7 @@ public class CardFactoryUtil { final String repeatStr = "DB$ RepeatEach | RepeatPlayers$ OpponentsOtherThanDefendingPlayer | ChangeZoneTable$ True"; final String copyStr = "DB$ CopyPermanent | Defined$ Self | TokenTapped$ True | Optional$ True | TokenAttacking$ Remembered" - + " | ChoosePlayerOrPlaneswalker$ True | ImprintTokens$ True"; + + " | ChoosePlayerOrPlaneswalker$ True | ImprintTokens$ True"; final String delTrigStr = "DB$ DelayedTrigger | Mode$ Phase | Phase$ EndCombat | RememberObjects$ Imprinted" + " | TriggerDescription$ Exile the tokens at end of combat."; @@ -4344,6 +4347,52 @@ public class CardFactoryUtil { sa.setIntrinsic(intrinsic); inst.addSpellAbility(sa); + } else if (keyword.startsWith("Encore")) { + final String[] k = keyword.split(":"); + final String manacost = k[1]; + + String effect = "AB$ RepeatEach | Cost$ " + manacost + " ExileFromGrave<1/CARDNAME> " + + "| ActivationZone$ Graveyard | RepeatPlayers$ Opponent" + + "| PrecostDesc$ Encore | CostDesc$ " + ManaCostParser.parse(manacost) + + "| SpellDescription$ (" + inst.getReminderText() + ")"; + + final String copyStr = "DB$ CopyPermanent | Defined$ Self | ImprintTokens$ True " + + "| AddKeywords$ Haste | RememberTokens$ True | TokenRemembered$ Player.IsRemembered"; + + final String pumpStr = "DB$ PumpAll | ValidCards$ Creature.IsRemembered " + + "| KW$ HIDDEN CARDNAME attacks specific player each combat if able:Remembered"; + + final String pumpcleanStr = "DB$ Cleanup | ForgetDefined$ RememberedCard"; + + final String delTrigStr = "DB$ DelayedTrigger | Mode$ Phase | Phase$ End of Turn | RememberObjects$ Imprinted " + + "| StackDescription$ None | TriggerDescription$ Sacrifice them at the beginning of the next end step."; + + final String sacStr = "DB$ SacrificeAll | Defined$ DelayTriggerRemembered"; + + final String cleanupStr = "DB$ Cleanup | ClearImprinted$ True"; + + final SpellAbility sa = AbilityFactory.getAbility(effect, card); + sa.setIntrinsic(intrinsic); + inst.addSpellAbility(sa); + + AbilitySub copySA = (AbilitySub) AbilityFactory.getAbility(copyStr, card); + sa.setAdditionalAbility("RepeatSubAbility", copySA); + + AbilitySub pumpSA = (AbilitySub) AbilityFactory.getAbility(pumpStr, card); + copySA.setSubAbility(pumpSA); + + AbilitySub pumpcleanSA = (AbilitySub) AbilityFactory.getAbility(pumpcleanStr, card); + pumpSA.setSubAbility(pumpcleanSA); + + AbilitySub delTrigSA = (AbilitySub) AbilityFactory.getAbility(delTrigStr, card); + sa.setSubAbility(delTrigSA); + + AbilitySub sacSA = (AbilitySub) AbilityFactory.getAbility(sacStr, card); + delTrigSA.setAdditionalAbility("Execute", sacSA); + + AbilitySub cleanupSA = (AbilitySub) AbilityFactory.getAbility(cleanupStr, card); + delTrigSA.setSubAbility(cleanupSA); + } else if (keyword.startsWith("Spectacle")) { final String[] k = keyword.split(":"); final Cost cost = new Cost(k[1], false); @@ -4404,6 +4453,8 @@ public class CardFactoryUtil { String sb = TextUtil.concatWithSpace(getActivatingPlayer().toString(),"has suspended", c.getName(), "with", String.valueOf(counters),"time counters on it."); game.getGameLog().add(GameLogEntryType.STACK_RESOLVE, sb); + //reveal suspended card + game.getAction().reveal(new CardCollection(c), c.getOwner(), true, c.getName() + " is suspended with " + counters + " time counters in "); } }; final StringBuilder sbDesc = new StringBuilder(); @@ -4686,7 +4737,7 @@ public class CardFactoryUtil { altCostSA.setRestrictions(restriction); String costDescription = TextUtil.fastReplace(params.get("Description"),"CARDNAME", card.getName()); - if (costDescription.isEmpty()) { + if (costDescription == null || costDescription.isEmpty()) { costDescription = TextUtil.concatWithSpace("You may", abCost.toStringAlt(), "rather than pay", TextUtil.addSuffix(card.getName(), "'s mana cost.")); } @@ -4758,6 +4809,16 @@ public class CardFactoryUtil { String opName = Expressions.operatorName(part.substring(kwLength, kwLength + 2)); String operand = part.substring(kwLength + 2); postponedAdjectives.add(Pair.of(true, "power" + opName + operand)); + } else if (part.startsWith("toughness")) { + int kwLength = 9; + String operand = part.substring(kwLength + 2); + String opName = ""; + if (part.startsWith("toughnessGE")) { + opName = " or greater"; + } else { + opName = "update CardFactoryUtil line 4773"; + } + postponedAdjectives.add(Pair.of(true, "toughness " + operand + opName)); } else if (CardType.isACreatureType(part)) { if (creatures != null && CardType.isACreatureType(creatures)) { // e.g. Kor Castigator creatures = StringUtils.capitalize(Lang.getPlural(part)) + creatures; diff --git a/forge-game/src/main/java/forge/game/card/CardView.java b/forge-game/src/main/java/forge/game/card/CardView.java index d753c8acdcf..a2cd74fe17c 100644 --- a/forge-game/src/main/java/forge/game/card/CardView.java +++ b/forge-game/src/main/java/forge/game/card/CardView.java @@ -253,6 +253,13 @@ public class CardView extends GameEntityView { } return counters.equals(otherCard.getCounters()); } + public boolean hasSamePT(CardView otherCard) { + if (getCurrentState().getPower() != otherCard.getCurrentState().getPower()) + return false; + if (getCurrentState().getToughness() != otherCard.getCurrentState().getToughness()) + return false; + return true; + } void updateCounters(Card c) { set(TrackableProperty.Counters, c.getCounters()); updateLethalDamage(c); @@ -691,6 +698,20 @@ public class CardView extends GameEntityView { return get(TrackableProperty.AlternateState); } + public boolean hasLeftSplitState() { + return getLeftSplitState() != null; + } + public CardStateView getLeftSplitState() { + return get(TrackableProperty.LeftSplitState); + } + + public boolean hasRightSplitState() { + return getRightSplitState() != null; + } + public CardStateView getRightSplitState() { + return get(TrackableProperty.RightSplitState); + } + public boolean hasBackSide() { return get(TrackableProperty.HasBackSide); } @@ -731,9 +752,8 @@ public class CardView extends GameEntityView { CardState currentState = c.getCurrentState(); if (isSplitCard) { - if (c.getCurrentStateName() != CardStateName.LeftSplit && c.getCurrentStateName() != CardStateName.RightSplit && c.getCurrentStateName() != CardStateName.FaceDown) { - currentState = c.getState(CardStateName.LeftSplit); - } + set(TrackableProperty.LeftSplitState, c.getState(CardStateName.LeftSplit).getView()); + set(TrackableProperty.RightSplitState, c.getState(CardStateName.RightSplit).getView()); } CardStateView currentStateView = currentState.getView(); @@ -901,6 +921,12 @@ public class CardView extends GameEntityView { public ColorSet getOriginalColors() { return get(TrackableProperty.OriginalColors); } + public ColorSet getLeftSplitColors() { + return get(TrackableProperty.LeftSplitColors); + } + public ColorSet getRightSplitColors() { + return get(TrackableProperty.RightSplitColors); + } void updateColors(Card c) { set(TrackableProperty.Colors, c.determineColor()); } @@ -909,6 +935,10 @@ public class CardView extends GameEntityView { } void setOriginalColors(Card c) { set(TrackableProperty.OriginalColors, c.determineColor()); + if (c.isSplitCard()) { + set(TrackableProperty.LeftSplitColors, c.determineColor(c.getState(CardStateName.LeftSplit))); + set(TrackableProperty.RightSplitColors, c.determineColor(c.getState(CardStateName.RightSplit))); + } } void updateHasChangeColors(boolean hasChangeColor) { set(TrackableProperty.HasChangedColors, hasChangeColor); @@ -1082,6 +1112,7 @@ public class CardView extends GameEntityView { public String getProtectionKey() { return get(TrackableProperty.ProtectionKey); } public String getHexproofKey() { return get(TrackableProperty.HexproofKey); } public boolean hasDeathtouch() { return get(TrackableProperty.HasDeathtouch); } + public boolean hasDevoid() { return get(TrackableProperty.HasDevoid); } public boolean hasDefender() { return get(TrackableProperty.HasDefender); } public boolean hasDoubleStrike() { return get(TrackableProperty.HasDoubleStrike); } public boolean hasFirstStrike() { return get(TrackableProperty.HasFirstStrike); } @@ -1118,6 +1149,7 @@ public class CardView extends GameEntityView { void updateKeywords(Card c, CardState state) { c.updateKeywordsCache(state); set(TrackableProperty.HasDeathtouch, c.hasKeyword(Keyword.DEATHTOUCH, state)); + set(TrackableProperty.HasDevoid, c.hasKeyword(Keyword.DEVOID, state)); set(TrackableProperty.HasDefender, c.hasKeyword(Keyword.DEFENDER, state)); set(TrackableProperty.HasDoubleStrike, c.hasKeyword(Keyword.DOUBLE_STRIKE, state)); set(TrackableProperty.HasFirstStrike, c.hasKeyword(Keyword.FIRST_STRIKE, state)); diff --git a/forge-game/src/main/java/forge/game/cost/CostAdjustment.java b/forge-game/src/main/java/forge/game/cost/CostAdjustment.java index 3ead5f27d1b..c384212499c 100644 --- a/forge-game/src/main/java/forge/game/cost/CostAdjustment.java +++ b/forge-game/src/main/java/forge/game/cost/CostAdjustment.java @@ -337,15 +337,12 @@ public class CostAdjustment { return; } - int value = 0; - if (StringUtils.isNumeric(amount)) { - value = Integer.parseInt(amount); - } else { - if ("Min3".equals(amount)) { - int cmc = manaCost.getConvertedManaCost(); - if (cmc < 3) { - value = 3 - cmc; - } + int value = Integer.parseInt(amount); + + if (staticAbility.hasParam("RaiseTo")) { + int cmc = manaCost.getConvertedManaCost(); + if (cmc < value) { + value = Integer.parseInt(amount) - cmc; } } diff --git a/forge-game/src/main/java/forge/game/keyword/Keyword.java b/forge-game/src/main/java/forge/game/keyword/Keyword.java index d810408411c..bcf60c0a504 100644 --- a/forge-game/src/main/java/forge/game/keyword/Keyword.java +++ b/forge-game/src/main/java/forge/game/keyword/Keyword.java @@ -49,6 +49,7 @@ public enum Keyword { EMBALM("Embalm", KeywordWithCost.class, false, "%s, Exile this card from your graveyard: Create a token that's a copy of this card, except it's white, it has no mana cost, and it's a Zombie in addition to its other types. Embalm only as a sorcery."), EMERGE("Emerge", KeywordWithCost.class, false, "You may cast this spell by sacrificing a creature and paying the emerge cost reduced by that creature's converted mana cost."), ENCHANT("Enchant", KeywordWithType.class, false, "Target a %s as you cast this. This card enters the battlefield attached to that %s."), + ENCORE("Encore", KeywordWithCost.class, false, "%s, Exile this card from your graveyard: For each opponent, create a token copy that attacks that opponent this turn if able. They gain haste. Sacrifice them at the beginning of the next end step. Activate only as a sorcery."), ENTWINE("Entwine", KeywordWithCost.class, true, "You may choose all modes of this spell instead of just one. If you do, you pay an additional %s."), EPIC("Epic", SimpleKeyword.class, true, "For the rest of the game, you can't cast spells. At the beginning of each of your upkeeps for the rest of the game, copy this spell except for its epic ability. If the spell has any targets, you may choose new targets for the copy."), EQUIP("Equip", Equip.class, false, "%s: Attach to target %s you control. Equip only as a sorcery."), diff --git a/forge-game/src/main/java/forge/game/player/Player.java b/forge-game/src/main/java/forge/game/player/Player.java index 2503a669e52..572a4489f93 100644 --- a/forge-game/src/main/java/forge/game/player/Player.java +++ b/forge-game/src/main/java/forge/game/player/Player.java @@ -581,7 +581,7 @@ public class Player extends GameEntity implements Comparable { if (infect) { addPoisonCounters(amount, source, counterTable); } - else { + else if (!hasKeyword("Damage doesn't cause you to lose life.")) { // Worship does not reduce the damage dealt but changes the effect // of the damage if (hasKeyword("DamageLifeThreshold:7") && life - 7 <= amount) { @@ -741,6 +741,10 @@ public class Player extends GameEntity implements Comparable { restDamage = 0; } } + } else if (c.getName().equals("Obosh, the Preypiercer")) { + if (c.getController().equals(source.getController()) && source.getCMC() % 2 != 0) { + restDamage *= 2; + } } } diff --git a/forge-game/src/main/java/forge/game/player/PlayerView.java b/forge-game/src/main/java/forge/game/player/PlayerView.java index 1bf7565454b..fed3de925ef 100644 --- a/forge-game/src/main/java/forge/game/player/PlayerView.java +++ b/forge-game/src/main/java/forge/game/player/PlayerView.java @@ -439,6 +439,12 @@ public class PlayerView extends GameEntityView { return types.size(); } + public boolean hasDelirium() { + if (get(TrackableProperty.HasDelirium) == null) + return false; + return get(TrackableProperty.HasDelirium); + } + private static TrackableProperty getZoneProp(final ZoneType zone) { switch (zone) { case Ante: @@ -466,6 +472,10 @@ public class PlayerView extends GameEntityView { if (prop == null) { return; } set(prop, CardView.getCollection(zone.getCards(false))); + //update delirium + if (ZoneType.Graveyard == zone.getZoneType()) + set(TrackableProperty.HasDelirium, getZoneTypes(TrackableProperty.Graveyard) >= 4); + //update flashback zone when graveyard, library, or exile zones updated switch (zone.getZoneType()) { case Command: diff --git a/forge-game/src/main/java/forge/game/spellability/StackItemView.java b/forge-game/src/main/java/forge/game/spellability/StackItemView.java index efe19f0786e..1a0ef4755a5 100644 --- a/forge-game/src/main/java/forge/game/spellability/StackItemView.java +++ b/forge-game/src/main/java/forge/game/spellability/StackItemView.java @@ -38,6 +38,7 @@ public class StackItemView extends TrackableObject implements IHasCardView { updateAbility(si); updateOptionalTrigger(si); updateSubInstance(si); + updateOptionalCost(si); } public String getKey() { @@ -47,6 +48,55 @@ public class StackItemView extends TrackableObject implements IHasCardView { set(TrackableProperty.Key, si.getSpellAbility(false).yieldKey()); } + public String getOptionalCostString() { + return get(TrackableProperty.OptionalCosts); + } + void updateOptionalCost(SpellAbilityStackInstance si) { + String OptionalCostString = ""; + boolean kicked = false; + boolean entwined = false; + boolean buyback = false; + boolean retraced = false; + boolean jumpstart = false; + boolean additional = false; + boolean alternate = false; + boolean generic = false; + + for (OptionalCost cost : si.getSpellAbility(false).getOptionalCosts()) { + if (cost == OptionalCost.Kicker1 || cost == OptionalCost.Kicker2) + kicked = true; + if (cost == OptionalCost.Entwine) + entwined = true; + if (cost == OptionalCost.Buyback) + buyback = true; + if (cost == OptionalCost.Retrace) + retraced = true; + if (cost == OptionalCost.Jumpstart) + jumpstart = true; + if (cost == OptionalCost.Flash) + additional = true; + if (cost == OptionalCost.Generic) + generic = true; + if (cost == OptionalCost.AltCost) + alternate = true; + } + if (!alternate) { + if (kicked && !generic) + OptionalCostString += "Kicked"; + if (entwined) + OptionalCostString += OptionalCostString.equals("") ? "Entwined" : ", Entwined"; + if (buyback) + OptionalCostString += OptionalCostString.equals("") ? "Buyback" : ", Buyback"; + if (retraced) + OptionalCostString += OptionalCostString.equals("") ? "Retraced" : ", Retraced"; + if (jumpstart) + OptionalCostString += OptionalCostString.equals("") ? "Jumpstart" : ", Jumpstart"; + if (additional || generic) + OptionalCostString += OptionalCostString.equals("") ? "Additional" : ", Additional"; + } + set(TrackableProperty.OptionalCosts, OptionalCostString); + } + public int getSourceTrigger() { return get(TrackableProperty.SourceTrigger); } diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbility.java b/forge-game/src/main/java/forge/game/staticability/StaticAbility.java index 76c73ae0c70..830cd1c43b5 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbility.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbility.java @@ -631,6 +631,13 @@ public class StaticAbility extends CardTraitBase implements IIdentifiable, Clone } } + if (hasParam("UnlessDefinedPlayer")) { + List players = AbilityUtils.getDefinedPlayers(hostCard, getParam("UnlessDefinedPlayer"), null); + if (!players.isEmpty()) { + return false; + } + } + if (hasParam("TopCardOfLibraryIs")) { if (controller.getCardsIn(ZoneType.Library).isEmpty()) { return false; diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerDamageAll.java b/forge-game/src/main/java/forge/game/trigger/TriggerDamageAll.java index 4df7cf871b8..53f48c61cfb 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerDamageAll.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerDamageAll.java @@ -29,24 +29,25 @@ public class TriggerDamageAll extends Trigger { } } final CardDamageMap table = (CardDamageMap) runParams.get(AbilityKey.DamageMap); - return filterTable(table) > 0; + return !table.filteredMap(getParam("ValidSource"), getParam("ValidTarget"), getHostCard(), null).isEmpty(); } @Override public void setTriggeringObjects(SpellAbility sa, Map runParams) { - final CardDamageMap table = (CardDamageMap) runParams.get(AbilityKey.DamageMap); + CardDamageMap table = (CardDamageMap) runParams.get(AbilityKey.DamageMap); + table = table.filteredMap(getParam("ValidSource"), getParam("ValidTarget"), getHostCard(), null); - sa.setTriggeringObject(AbilityKey.DamageAmount, filterTable(table)); + sa.setTriggeringObject(AbilityKey.DamageAmount, table.totalAmount()); + sa.setTriggeringObject(AbilityKey.Sources, table.rowKeySet()); + sa.setTriggeringObject(AbilityKey.Targets, table.columnKeySet()); } @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); + sb.append(Localizer.getInstance().getMessage("lblDamageSource")).append(": ").append(sa.getTriggeringObject(AbilityKey.Sources)).append(", "); + sb.append(Localizer.getInstance().getMessage("lblDamaged")).append(": ").append(sa.getTriggeringObject(AbilityKey.Targets)).append(", "); sb.append(Localizer.getInstance().getMessage("lblAmount")).append(": ").append(sa.getTriggeringObject(AbilityKey.DamageAmount)); return sb.toString(); } - - private int filterTable(CardDamageMap table) { - return table.filteredAmount(getParam("ValidSource"), getParam("ValidTarget"), getHostCard(), null); - } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerHandler.java b/forge-game/src/main/java/forge/game/trigger/TriggerHandler.java index 06d31a5e0d9..24a7e1e6feb 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerHandler.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerHandler.java @@ -573,6 +573,11 @@ public class TriggerHandler { host.addRemembered(sa.getActivatingPlayer()); } + if (regtrig.hasParam("RememberTriggeringCard")) { + Card triggeredCard = ((Card) sa.getTriggeringObject(AbilityKey.Card)); + host.addRemembered(triggeredCard); + } + sa.setStackDescription(sa.toString()); if (sa.getApi() == ApiType.Charm && !sa.isWrapper()) { // need to be set for demonic pact to look for chosen modes diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerTapsForMana.java b/forge-game/src/main/java/forge/game/trigger/TriggerTapsForMana.java index 499e5426022..6b50f104eb6 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerTapsForMana.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerTapsForMana.java @@ -101,10 +101,10 @@ public class TriggerTapsForMana extends Trigger { if (!this.getHostCard().hasChosenColor() || !produced.contains(MagicColor.toShortString(this.getHostCard().getChosenColor()))) { return false; } - if (!produced.contains(MagicColor.toShortString(this.getParam("Produced")))) { + } + if (!produced.contains(MagicColor.toShortString(this.getParam("Produced")))) { return false; } - } } return true; diff --git a/forge-game/src/main/java/forge/trackable/TrackableProperty.java b/forge-game/src/main/java/forge/trackable/TrackableProperty.java index 99228d48b56..223e48c22a2 100644 --- a/forge-game/src/main/java/forge/trackable/TrackableProperty.java +++ b/forge-game/src/main/java/forge/trackable/TrackableProperty.java @@ -69,6 +69,8 @@ public enum TrackableProperty { PairedWith(TrackableTypes.CardViewType), CurrentState(TrackableTypes.CardStateViewType, FreezeMode.IgnoresFreeze), AlternateState(TrackableTypes.CardStateViewType, FreezeMode.IgnoresFreeze), + LeftSplitState(TrackableTypes.CardStateViewType, FreezeMode.IgnoresFreeze), + RightSplitState(TrackableTypes.CardStateViewType, FreezeMode.IgnoresFreeze), HiddenId(TrackableTypes.IntegerType), ExertedThisTurn(TrackableTypes.BooleanType), @@ -76,6 +78,8 @@ public enum TrackableProperty { Name(TrackableTypes.StringType), Colors(TrackableTypes.ColorSetType), OriginalColors(TrackableTypes.ColorSetType), + LeftSplitColors(TrackableTypes.ColorSetType), + RightSplitColors(TrackableTypes.ColorSetType), ImageKey(TrackableTypes.StringType), Type(TrackableTypes.CardTypeViewType), ManaCost(TrackableTypes.ManaCostType), @@ -92,6 +96,7 @@ public enum TrackableProperty { KeywordKey(TrackableTypes.StringType), HasDeathtouch(TrackableTypes.BooleanType), + HasDevoid(TrackableTypes.BooleanType), HasDefender(TrackableTypes.BooleanType), HasDoubleStrike(TrackableTypes.BooleanType), HasFirstStrike(TrackableTypes.BooleanType), @@ -160,6 +165,7 @@ public enum TrackableProperty { IsExtraTurn(TrackableTypes.BooleanType), ExtraTurnCount(TrackableTypes.IntegerType), HasPriority(TrackableTypes.BooleanType), + HasDelirium(TrackableTypes.BooleanType), //SpellAbility HostCard(TrackableTypes.CardViewType), @@ -181,6 +187,7 @@ public enum TrackableProperty { SubInstance(TrackableTypes.StackItemViewType), Ability(TrackableTypes.BooleanType), OptionalTrigger(TrackableTypes.BooleanType), + OptionalCosts(TrackableTypes.StringType), //Combat AttackersWithDefenders(TrackableTypes.GenericMapType, FreezeMode.IgnoresFreeze), @@ -199,6 +206,7 @@ public enum TrackableProperty { WinningPlayerName(TrackableTypes.StringType), WinningTeam(TrackableTypes.IntegerType), MatchOver(TrackableTypes.BooleanType), + Mulligan(TrackableTypes.BooleanType), NumGamesInMatch(TrackableTypes.IntegerType), NumPlayedGamesInMatch(TrackableTypes.IntegerType), Stack(TrackableTypes.StackItemViewListType), diff --git a/forge-gui-android/pom.xml b/forge-gui-android/pom.xml index f581ef4fd60..6d5bf55aa7c 100644 --- a/forge-gui-android/pom.xml +++ b/forge-gui-android/pom.xml @@ -102,7 +102,7 @@ com.badlogicgames.gdx gdx-backend-android - 1.9.10 + 1.9.11 diff --git a/forge-gui-desktop/src/main/java/forge/gui/CardDetailPanel.java b/forge-gui-desktop/src/main/java/forge/gui/CardDetailPanel.java index a32a99e971b..1451ae4b3d7 100644 --- a/forge-gui-desktop/src/main/java/forge/gui/CardDetailPanel.java +++ b/forge-gui-desktop/src/main/java/forge/gui/CardDetailPanel.java @@ -204,7 +204,7 @@ public class CardDetailPanel extends SkinnedPanel { } else { final String manaCost; if (card.isSplitCard() && card.hasAlternateState() && !card.isFaceDown() && card.getZone() != ZoneType.Stack) { //only display current state's mana cost when on stack - manaCost = card.getCurrentState().getManaCost() + " // " + card.getAlternateState().getManaCost(); + manaCost = card.getLeftSplitState().getManaCost() + " // " + card.getAlternateState().getManaCost(); } else { manaCost = state.getManaCost().toString(); } @@ -256,7 +256,7 @@ public class CardDetailPanel extends SkinnedPanel { idLabel.setText(mayView ? CardDetailUtil.formatCardId(state) : ""); // fill the card text - cdArea.setText(FSkin.encodeSymbols(CardDetailUtil.composeCardText(state, gameView, mayView), true)); + cdArea.setText(FSkin.encodeSymbols(CardDetailUtil.composeCardText( card.isSplitCard() && !isInAltState ? card.getLeftSplitState() : state, gameView, mayView), true)); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { diff --git a/forge-gui-desktop/src/main/java/forge/screens/match/GauntletWinLose.java b/forge-gui-desktop/src/main/java/forge/screens/match/GauntletWinLose.java index e3b48d2e151..21ad9b319b7 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/match/GauntletWinLose.java +++ b/forge-gui-desktop/src/main/java/forge/screens/match/GauntletWinLose.java @@ -28,6 +28,7 @@ import net.miginfocom.swing.MigLayout; import forge.assets.FSkinProp; import forge.game.GameView; import forge.gauntlet.GauntletWinLoseController; +import forge.util.Localizer; import forge.toolbox.FLabel; import forge.toolbox.FSkin; import forge.toolbox.FSkin.SkinnedPanel; @@ -50,7 +51,7 @@ public class GauntletWinLose extends ControlWinLose { controller = new GauntletWinLoseController(view0, game0) { @Override protected void showOutcome(boolean isMatchOver, String message1, String message2, FSkinProp icon, List lstEventNames, List lstEventRecords, int len, int num) { - final JLabel lblTitle = new FLabel.Builder().text("Gauntlet Progress") + final JLabel lblTitle = new FLabel.Builder().text(Localizer.getInstance().getMessage("lblGauntletProgress")) .fontAlign(SwingConstants.CENTER).fontSize(18).build(); final JPanel pnlResults = new JPanel(); diff --git a/forge-gui-desktop/src/main/java/forge/view/SimulateMatch.java b/forge-gui-desktop/src/main/java/forge/view/SimulateMatch.java index 49e3a1a6acc..35d2a2dbc35 100644 --- a/forge-gui-desktop/src/main/java/forge/view/SimulateMatch.java +++ b/forge-gui-desktop/src/main/java/forge/view/SimulateMatch.java @@ -1,34 +1,33 @@ package forge.view; +import forge.LobbyPlayer; +import forge.deck.Deck; +import forge.deck.DeckGroup; +import forge.deck.io.DeckSerializer; +import forge.game.*; +import forge.game.player.RegisteredPlayer; +import forge.model.FModel; +import forge.player.GamePlayerUtil; +import forge.properties.ForgeConstants; +import forge.tournament.system.*; +import forge.util.Lang; +import forge.util.TextUtil; +import forge.util.WordUtil; +import forge.util.storage.IStorage; +import org.apache.commons.lang3.time.StopWatch; + import java.io.File; import java.io.FilenameFilter; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import forge.LobbyPlayer; -import forge.deck.DeckGroup; -import forge.game.*; -import forge.properties.ForgeConstants; -import forge.tournament.system.*; -import forge.util.TextUtil; -import forge.util.WordUtil; -import forge.util.storage.IStorage; -import org.apache.commons.lang3.time.StopWatch; - -import forge.deck.Deck; -import forge.deck.io.DeckSerializer; -import forge.game.player.RegisteredPlayer; -import forge.model.FModel; -import forge.player.GamePlayerUtil; -import forge.util.Lang; - public class SimulateMatch { public static void simulate(String[] args) { FModel.initialize(null, null); System.out.println("Simulation mode"); - if(args.length < 4) { + if (args.length < 4) { argumentHelp(); return; } @@ -49,11 +48,9 @@ public class SimulateMatch { options = new ArrayList<>(); params.put(a.substring(1), options); - } - else if (options != null) { + } else if (options != null) { options.add(a); - } - else { + } else { System.err.println("Illegal parameter usage"); return; } @@ -97,7 +94,7 @@ public class SimulateMatch { int i = 1; if (params.containsKey("d")) { - for(String deck : params.get("d")) { + for (String deck : params.get("d")) { Deck d = deckFromCommandLineParameter(deck, type); if (d == null) { System.out.println(TextUtil.concatNoSpace("Could not load deck - ", deck, ", match cannot start")); @@ -130,7 +127,7 @@ public class SimulateMatch { if (matchSize != 0) { int iGame = 0; - while(!mc.isMatchOver()) { + while (!mc.isMatchOver()) { // play games until the match ends simulateSingleMatch(mc, iGame, outputGamelog); iGame++; @@ -159,38 +156,26 @@ public class SimulateMatch { } - public static void simulateSingleMatch(final Match mc, int iGame, boolean outputGamelog) { final StopWatch sw = new StopWatch(); sw.start(); final Game g1 = mc.createGame(); // will run match in the same thread - - long startTime = System.currentTimeMillis(); try { - TimeLimitedCodeBlock.runWithTimeout(new Runnable() { - @Override - public void run() { - mc.startGame(g1); - sw.stop(); - } + TimeLimitedCodeBlock.runWithTimeout(() -> { + mc.startGame(g1); + sw.stop(); }, 120, TimeUnit.SECONDS); - } - catch (TimeoutException e) { + } catch (TimeoutException e) { System.out.println("Stopping slow match as draw"); - g1.setGameOver(GameEndReason.Draw); - sw.stop(); - }catch (Exception e){ + } catch (Exception | StackOverflowError e) { e.printStackTrace(); - g1.setGameOver(GameEndReason.Draw); - sw.stop(); - }catch(StackOverflowError e){ + } finally { g1.setGameOver(GameEndReason.Draw); sw.stop(); } - List log; if (outputGamelog) { log = g1.getGameLog().getLogEntries(null); @@ -198,15 +183,15 @@ public class SimulateMatch { log = g1.getGameLog().getLogEntries(GameLogEntryType.MATCH_RESULTS); } Collections.reverse(log); - for(GameLogEntry l : log) { + for (GameLogEntry l : log) { System.out.println(l); } // If both players life totals to 0 in a single turn, the game should end in a draw - if(g1.getOutcome().isDraw()){ - System.out.println(String.format("Game %d ended in a Draw! Took %d ms.", 1+iGame, sw.getTime())); + if (g1.getOutcome().isDraw()) { + System.out.printf("\nGame Result: Game %d ended in a Draw! Took %d ms.%n", 1 + iGame, sw.getTime()); } else { - System.out.println(String.format("\nGame %d ended in %d ms. %s has won!\n", 1+iGame, sw.getTime(), g1.getOutcome().getWinningLobbyPlayer().getName())); + System.out.printf("\nGame Result: Game %d ended in %d ms. %s has won!\n%n", 1 + iGame, sw.getTime(), g1.getOutcome().getWinningLobbyPlayer().getName()); } } @@ -219,7 +204,7 @@ public class SimulateMatch { List players = new ArrayList<>(); int numPlayers = 0; if (params.containsKey("d")) { - for(String deck : params.get("d")) { + for (String deck : params.get("d")) { Deck d = deckFromCommandLineParameter(deck, rules.getGameType()); if (d == null) { System.out.println(TextUtil.concatNoSpace("Could not load deck - ", deck, ", match cannot start")); @@ -239,7 +224,7 @@ public class SimulateMatch { if (!folder.isDirectory()) { System.out.println("Directory not found - " + foldName); } else { - for(File deck : folder.listFiles(new FilenameFilter() { + for (File deck : folder.listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String name) { return name.endsWith(".dck"); @@ -281,16 +266,16 @@ public class SimulateMatch { System.out.println(TextUtil.concatNoSpace("Starting a ", tournament, " tournament with ", String.valueOf(numPlayers), " players over ", String.valueOf(tourney.getTotalRounds()), " rounds")); - while(!tourney.isTournamentOver()) { + while (!tourney.isTournamentOver()) { if (tourney.getActiveRound() != curRound) { if (curRound != 0) { System.out.println(TextUtil.concatNoSpace("End Round - ", String.valueOf(curRound))); } curRound = tourney.getActiveRound(); System.out.println(); - System.out.println(TextUtil.concatNoSpace("Round ", String.valueOf(curRound) ," Pairings:")); + System.out.println(TextUtil.concatNoSpace("Round ", String.valueOf(curRound), " Pairings:")); - for(TournamentPairing pairing : tourney.getActivePairings()) { + for (TournamentPairing pairing : tourney.getActivePairings()) { System.out.println(pairing.outputHeader()); } System.out.println(); @@ -311,10 +296,10 @@ public class SimulateMatch { int iGame = 0; while (!mc.isMatchOver()) { // play games until the match ends - try{ + try { simulateSingleMatch(mc, iGame, outputGamelog); iGame++; - } catch(Exception e) { + } catch (Exception e) { exceptions++; System.out.println(e.toString()); if (exceptions > 5) { @@ -349,10 +334,10 @@ public class SimulateMatch { private static Deck deckFromCommandLineParameter(String deckname, GameType type) { int dotpos = deckname.lastIndexOf('.'); - if(dotpos > 0 && dotpos == deckname.length()-4) { + if (dotpos > 0 && dotpos == deckname.length() - 4) { String baseDir = type.equals(GameType.Commander) ? ForgeConstants.DECK_COMMANDER_DIR : ForgeConstants.DECK_CONSTRUCTED_DIR; - return DeckSerializer.fromFile(new File(baseDir+deckname)); + return DeckSerializer.fromFile(new File(baseDir + deckname)); } IStorage deckStore = null; diff --git a/forge-gui-desktop/src/main/java/forge/view/arcane/CardPanel.java b/forge-gui-desktop/src/main/java/forge/view/arcane/CardPanel.java index 4e9b250687c..890065d4ecf 100644 --- a/forge-gui-desktop/src/main/java/forge/view/arcane/CardPanel.java +++ b/forge-gui-desktop/src/main/java/forge/view/arcane/CardPanel.java @@ -462,7 +462,7 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl PaperCard pc = StaticData.instance().getCommonCards().getCard(card.getName()); int ofs = pc != null && Card.getCardForUi(pc).hasKeyword(Keyword.AFTERMATH) ? -12 : 12; - drawManaCost(g, card.getCurrentState().getManaCost(), ofs); + drawManaCost(g, card.getLeftSplitState().getManaCost(), ofs); drawManaCost(g, card.getAlternateState().getManaCost(), -ofs); } } diff --git a/forge-gui-ios/pom.xml b/forge-gui-ios/pom.xml index a34a6d9e8fd..8b1a741a5ee 100644 --- a/forge-gui-ios/pom.xml +++ b/forge-gui-ios/pom.xml @@ -73,7 +73,7 @@ com.badlogicgames.gdx gdx-backend-robovm - 1.9.10 + 1.9.11 diff --git a/forge-gui-mobile-dev/pom.xml b/forge-gui-mobile-dev/pom.xml index ee5bb8d8fb0..4cd801f7408 100644 --- a/forge-gui-mobile-dev/pom.xml +++ b/forge-gui-mobile-dev/pom.xml @@ -60,18 +60,18 @@ com.badlogicgames.gdx gdx-backend-lwjgl - 1.9.10 + 1.9.11 com.badlogicgames.gdx gdx-platform - 1.2.0 + 1.9.11 natives-desktop com.badlogicgames.gdx gdx-freetype-platform - 1.9.10 + 1.9.11 natives-desktop diff --git a/forge-gui-mobile/pom.xml b/forge-gui-mobile/pom.xml index 339886fa293..b3eb00fd614 100644 --- a/forge-gui-mobile/pom.xml +++ b/forge-gui-mobile/pom.xml @@ -63,12 +63,12 @@ com.badlogicgames.gdx gdx - 1.9.10 + 1.9.11 com.badlogicgames.gdx gdx-freetype - 1.9.10 + 1.9.11 diff --git a/forge-gui-mobile/src/forge/Forge.java b/forge-gui-mobile/src/forge/Forge.java index 882bf66d0dc..b3c1766f26b 100644 --- a/forge-gui-mobile/src/forge/Forge.java +++ b/forge-gui-mobile/src/forge/Forge.java @@ -64,6 +64,7 @@ public class Forge implements ApplicationListener { public static float heigtModifier = 0.0f; private static boolean isloadingaMatch = false; public static boolean showFPS = false; + public static boolean altPlayerLayout = false; public static boolean enableUIMask = false; public static boolean enablePreloadExtendedArt = false; public static String locale = "en-US"; @@ -123,6 +124,7 @@ public class Forge implements ApplicationListener { textureFiltering = prefs.getPrefBoolean(FPref.UI_LIBGDX_TEXTURE_FILTERING); showFPS = prefs.getPrefBoolean(FPref.UI_SHOW_FPS); + altPlayerLayout = prefs.getPrefBoolean(FPref.UI_ALT_PLAYERINFOLAYOUT); enableUIMask = prefs.getPrefBoolean(FPref.UI_ENABLE_BORDER_MASKING); enablePreloadExtendedArt = prefs.getPrefBoolean(FPref.UI_ENABLE_PRELOAD_EXTENDED_ART); locale = prefs.getPref(FPref.UI_LANGUAGE); diff --git a/forge-gui-mobile/src/forge/Graphics.java b/forge-gui-mobile/src/forge/Graphics.java index a783f1f9674..d503653abaf 100644 --- a/forge-gui-mobile/src/forge/Graphics.java +++ b/forge-gui-mobile/src/forge/Graphics.java @@ -6,6 +6,7 @@ import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.graphics.glutils.ShaderProgram; import com.badlogic.gdx.graphics.glutils.ShapeRenderer; import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType; import com.badlogic.gdx.math.Matrix4; @@ -37,8 +38,75 @@ public class Graphics { private int failedClipCount; private float alphaComposite = 1; private int transformCount = 0; + private String sVertex = "uniform mat4 u_projTrans;\n" + + "\n" + + "attribute vec4 a_position;\n" + + "attribute vec2 a_texCoord0;\n" + + "attribute vec4 a_color;\n" + + "\n" + + "varying vec4 v_color;\n" + + "varying vec2 v_texCoord;\n" + + "\n" + + "uniform vec2 u_viewportInverse;\n" + + "\n" + + "void main() {\n" + + " gl_Position = u_projTrans * a_position;\n" + + " v_texCoord = a_texCoord0;\n" + + " v_color = a_color;\n" + + "}"; + private String sFragment = "#ifdef GL_ES\n" + + "precision mediump float;\n" + + "precision mediump int;\n" + + "#endif\n" + + "\n" + + "uniform sampler2D u_texture;\n" + + "\n" + + "// The inverse of the viewport dimensions along X and Y\n" + + "uniform vec2 u_viewportInverse;\n" + + "\n" + + "// Color of the outline\n" + + "uniform vec3 u_color;\n" + + "\n" + + "// Thickness of the outline\n" + + "uniform float u_offset;\n" + + "\n" + + "// Step to check for neighbors\n" + + "uniform float u_step;\n" + + "\n" + + "varying vec4 v_color;\n" + + "varying vec2 v_texCoord;\n" + + "\n" + + "#define ALPHA_VALUE_BORDER 0.5\n" + + "\n" + + "void main() {\n" + + " vec2 T = v_texCoord.xy;\n" + + "\n" + + " float alpha = 0.0;\n" + + " bool allin = true;\n" + + " for( float ix = -u_offset; ix < u_offset; ix += u_step )\n" + + " {\n" + + " for( float iy = -u_offset; iy < u_offset; iy += u_step )\n" + + " {\n" + + " float newAlpha = texture2D(u_texture, T + vec2(ix, iy) * u_viewportInverse).a;\n" + + " allin = allin && newAlpha > ALPHA_VALUE_BORDER;\n" + + " if (newAlpha > ALPHA_VALUE_BORDER && newAlpha >= alpha)\n" + + " {\n" + + " alpha = newAlpha;\n" + + " }\n" + + " }\n" + + " }\n" + + " if (allin)\n" + + " {\n" + + " alpha = 0.0;\n" + + " }\n" + + "\n" + + " gl_FragColor = vec4(u_color,alpha);\n" + + "}"; + + private final ShaderProgram shaderOutline = new ShaderProgram(sVertex, sFragment); public Graphics() { + ShaderProgram.pedantic = false; } public void begin(float regionWidth0, float regionHeight0) { @@ -60,6 +128,7 @@ public class Graphics { public void dispose() { batch.dispose(); shapeRenderer.dispose(); + shaderOutline.dispose(); } public SpriteBatch getBatch() { @@ -568,7 +637,7 @@ public class Graphics { public void drawBorderImage(FImage image, Color borderColor, Color tintColor, float x, float y, float w, float h, boolean tint) { float oldalpha = alphaComposite; - if(tint){ + if(tint && !tintColor.equals(borderColor)){ drawRoundRect(2f, borderLining(borderColor.toString()), x, y, w, h, (h-w)/12); fillRoundRect(tintColor, x, y, w, h, (h-w)/12); } else { @@ -604,6 +673,56 @@ public class Graphics { public void drawImage(TextureRegion image, float x, float y, float w, float h) { batch.draw(image, adjustX(x), adjustY(y, h), w, h); } + public void drawImage(TextureRegion image, TextureRegion glowImageReference, float x, float y, float w, float h, Color glowColor, boolean selected) { + //1st image is the image on top of the shader, 2nd image is for the outline reference for the shader glow... + // if the 1st image don't have transparency in the middle (only on the sides, top and bottom, use the 1st image as outline reference... + if (!selected) { + batch.draw(image, adjustX(x), adjustY(y, h), w, h); + } else { + batch.end(); + shaderOutline.begin(); + shaderOutline.setUniformf("u_viewportInverse", new Vector2(1f / w, 1f / h)); + shaderOutline.setUniformf("u_offset", 3f); + shaderOutline.setUniformf("u_step", Math.min(1f, w / 70f)); + shaderOutline.setUniformf("u_color", new Vector3(glowColor.r, glowColor.g, glowColor.b)); + shaderOutline.end(); + batch.setShader(shaderOutline); + batch.begin(); + //glow + batch.draw(glowImageReference, adjustX(x), adjustY(y, h), w, h); + batch.end(); + batch.setShader(null); + batch.begin(); + //img + batch.draw(image, adjustX(x), adjustY(y, h), w, h); + } + } + public void drawDeckBox(FImage cardArt, float scale, TextureRegion image, TextureRegion glowImageReference, float x, float y, float w, float h, Color glowColor, boolean selected) { + float yBox = y-(h*0.25f); + if (!selected) { + cardArt.draw(this,x+((w-w*scale)/2), y+((h-h*scale)/3f), w*scale, h*scale/1.85f); + batch.draw(image, adjustX(x), adjustY(yBox, h), w, h); + } else { + batch.end(); + shaderOutline.begin(); + shaderOutline.setUniformf("u_viewportInverse", new Vector2(1f / w, 1f / h)); + shaderOutline.setUniformf("u_offset", 3f); + shaderOutline.setUniformf("u_step", Math.min(1f, w / 70f)); + shaderOutline.setUniformf("u_color", new Vector3(glowColor.r, glowColor.g, glowColor.b)); + shaderOutline.end(); + batch.setShader(shaderOutline); + batch.begin(); + //glow + batch.draw(glowImageReference, adjustX(x), adjustY(yBox, h), w, h); + batch.end(); + batch.setShader(null); + batch.begin(); + //cardart + cardArt.draw(this,x+((w-w*scale)/2), y+((h-h*scale)/3f), w*scale, h*scale/1.85f); + //deckbox + batch.draw(image, adjustX(x), adjustY(yBox, h), w, h); + } + } public void drawRepeatingImage(Texture image, float x, float y, float w, float h) { if (startClip(x, y, w, h)) { //only render if clip successful, otherwise it will escape bounds diff --git a/forge-gui-mobile/src/forge/assets/BitmapFontWriter.java b/forge-gui-mobile/src/forge/assets/BitmapFontWriter.java index 3bec04e875b..5ec2993c392 100644 --- a/forge-gui-mobile/src/forge/assets/BitmapFontWriter.java +++ b/forge-gui-mobile/src/forge/assets/BitmapFontWriter.java @@ -23,6 +23,7 @@ import com.badlogic.gdx.graphics.g2d.BitmapFont.BitmapFontData; import com.badlogic.gdx.graphics.g2d.BitmapFont.Glyph; import com.badlogic.gdx.graphics.g2d.PixmapPacker.Page; import com.badlogic.gdx.utils.Array; +import forge.util.TextUtil; /** * This file is 'borrowed' from gdx-tools in the libgdx source @@ -201,7 +202,7 @@ public class BitmapFontWriter { : " alphaChnl=0 redChnl=0 greenChnl=0 blueChnl=0"; // INFO LINE - buf.append(xmlOpen).append("info face=\"").append(info.face == null ? "" : info.face.replaceAll("\"", "'")) + buf.append(xmlOpen).append("info face=\"").append(info.face == null ? "" : TextUtil.fastReplace(info.face,"\"", "'")) .append("\" size=").append(quote(info.size)).append(" bold=").append(quote(info.bold ? 1 : 0)).append(" italic=") .append(quote(info.italic ? 1 : 0)).append(" charset=\"").append(info.charset == null ? "" : info.charset) .append("\" unicode=").append(quote(info.unicode ? 1 : 0)).append(" stretchH=").append(quote(info.stretchH)) diff --git a/forge-gui-mobile/src/forge/assets/FSkin.java b/forge-gui-mobile/src/forge/assets/FSkin.java index 9f716df533a..1f9eacd9571 100644 --- a/forge-gui-mobile/src/forge/assets/FSkin.java +++ b/forge-gui-mobile/src/forge/assets/FSkin.java @@ -30,7 +30,8 @@ public class FSkin { private static final Map images = new HashMap<>(512); private static final Map avatars = new HashMap<>(150); private static final Map sleeves = new HashMap<>(64); - private static final Map borders = new HashMap<>(2); + private static final Map borders = new HashMap<>(); + private static final Map deckbox = new HashMap<>(); private static Array allSkins; private static FileHandle preferredDir; @@ -196,6 +197,7 @@ public class FSkin { final FileHandle f10 = getDefaultSkinFile(ForgeConstants.SPRITE_BORDER_FILE); final FileHandle f11 = getSkinFile(ForgeConstants.SPRITE_BUTTONS_FILE); final FileHandle f12 = getSkinFile(ForgeConstants.SPRITE_START_FILE); + final FileHandle f13 = getDefaultSkinFile(ForgeConstants.SPRITE_DECKBOX_FILE); try { textures.put(f1.path(), new Texture(f1)); @@ -331,10 +333,20 @@ public class FSkin { FSkin.sleeves.put(scount++, new TextureRegion(txDefaultSleeves, i, j, 360, 500)); } } - + //borders Texture bordersBW = new Texture(f10); FSkin.borders.put(0, new TextureRegion(bordersBW, 2, 2, 672, 936)); FSkin.borders.put(1, new TextureRegion(bordersBW, 676, 2, 672, 936)); + //deckboxes + Texture deckboxes = new Texture(f13, textureFilter); + if (textureFilter) + deckboxes.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear); + //gold bg + FSkin.deckbox.put(0, new TextureRegion(deckboxes, 2, 2, 488, 680)); + //deck box for card art + FSkin.deckbox.put(1, new TextureRegion(deckboxes, 492, 2, 488, 680)); + //generic deck box + FSkin.deckbox.put(2, new TextureRegion(deckboxes, 982, 2, 488, 680)); preferredIcons.dispose(); pxDefaultAvatars.dispose(); @@ -430,5 +442,9 @@ public class FSkin { return borders; } + public static Map getDeckbox() { + return deckbox; + } + public static boolean isLoaded() { return loaded; } } diff --git a/forge-gui-mobile/src/forge/assets/ImageCache.java b/forge-gui-mobile/src/forge/assets/ImageCache.java index 95e6d9a0345..bdaae96ac9a 100644 --- a/forge-gui-mobile/src/forge/assets/ImageCache.java +++ b/forge-gui-mobile/src/forge/assets/ImageCache.java @@ -288,15 +288,18 @@ public class ImageCache { public static FImage getBorderImage(String textureString) { return getBorder(textureString); } - public static Color getTint(CardView c) { + public static Color getTint(CardView c, Texture t) { if (c == null) - return Color.CLEAR; + return borderColor(t); if (c.isFaceDown()) - return Color.CLEAR; + return Color.valueOf("#171717"); CardView.CardStateView state = c.getCurrentState(); - if (state.getColors().isColorless()) //Moonlace -> target spell or permanent becomes colorless. + if (state.getColors().isColorless()) { //Moonlace -> target spell or permanent becomes colorless. + if (state.hasDevoid()) //devoid is colorless at all zones so return its corresponding border color... + return borderColor(t); return Color.valueOf("#A0A6A4"); + } else if (state.getColors().isMonoColor()) { if (state.getColors().hasBlack()) return Color.valueOf("#48494a"); @@ -311,6 +314,7 @@ public class ImageCache { } else if (state.getColors().isMulticolor()) return Color.valueOf("#F9E084"); - return Color.CLEAR; + + return borderColor(t); } } diff --git a/forge-gui-mobile/src/forge/card/CardFaceSymbols.java b/forge-gui-mobile/src/forge/card/CardFaceSymbols.java index 86942c1c3d9..96f355dd730 100644 --- a/forge-gui-mobile/src/forge/card/CardFaceSymbols.java +++ b/forge-gui-mobile/src/forge/card/CardFaceSymbols.java @@ -190,11 +190,17 @@ public class CardFaceSymbols { } public static void drawColorSet(Graphics g, ColorSet colorSet, float x, float y, final float imageSize) { + drawColorSet(g, colorSet, x, y, imageSize, false); + } + public static void drawColorSet(Graphics g, ColorSet colorSet, float x, float y, final float imageSize, boolean vertical) { final float dx = imageSize; for (final ManaCostShard s : colorSet.getOrderedShards()) { drawSymbol(s.getImageKey(), g, x, y, imageSize, imageSize); - x += dx; + if (!vertical) + x += dx; + else + y += dx; } } diff --git a/forge-gui-mobile/src/forge/card/CardImageRenderer.java b/forge-gui-mobile/src/forge/card/CardImageRenderer.java index 209642f87f2..a14e152b0bd 100644 --- a/forge-gui-mobile/src/forge/card/CardImageRenderer.java +++ b/forge-gui-mobile/src/forge/card/CardImageRenderer.java @@ -185,7 +185,7 @@ public class CardImageRenderer { ManaCost mainManaCost = state.getManaCost(); if (card.isSplitCard() && card.getAlternateState() != null) { //handle rendering both parts of split card - mainManaCost = state.getManaCost(); + mainManaCost = card.getLeftSplitState().getManaCost(); ManaCost otherManaCost = card.getAlternateState().getManaCost(); manaCostWidth = CardFaceSymbols.getWidth(otherManaCost, MANA_SYMBOL_SIZE) + HEADER_PADDING; CardFaceSymbols.drawManaCost(g, otherManaCost, x + w - manaCostWidth, y + (h - MANA_SYMBOL_SIZE) / 2, MANA_SYMBOL_SIZE); @@ -459,7 +459,7 @@ public class CardImageRenderer { y += cardNameBoxHeight + innerBorderThickness; Color[] textBoxColors = FSkinColor.tintColors(Color.WHITE, colors, CardRenderer.TEXT_BOX_TINT); - drawDetailsTextBox(g, state, gameView, canShow, textBoxColors, x, y, w, textBoxHeight); + drawDetailsTextBox(g, card.isSplitCard() && !altState ? card.getLeftSplitState() : state, gameView, canShow, textBoxColors, x, y, w, textBoxHeight); y += textBoxHeight + innerBorderThickness; Color[] ptColors = FSkinColor.tintColors(Color.WHITE, colors, CardRenderer.PT_BOX_TINT); @@ -506,7 +506,7 @@ public class CardImageRenderer { ManaCost mainManaCost = state.getManaCost(); if (card.isSplitCard() && card.hasAlternateState() && !card.isFaceDown() && card.getZone() != ZoneType.Stack) { //only display current state's mana cost when on stack //handle rendering both parts of split card - mainManaCost = state.getManaCost(); + mainManaCost = card.getLeftSplitState().getManaCost(); ManaCost otherManaCost = card.getAlternateState().getManaCost(); manaCostWidth = CardFaceSymbols.getWidth(otherManaCost, MANA_SYMBOL_SIZE) + HEADER_PADDING; CardFaceSymbols.drawManaCost(g, otherManaCost, x + w - manaCostWidth, y + (h - MANA_SYMBOL_SIZE) / 2, MANA_SYMBOL_SIZE); diff --git a/forge-gui-mobile/src/forge/card/CardRenderer.java b/forge-gui-mobile/src/forge/card/CardRenderer.java index 3f352afeedb..291b2d2a6ff 100644 --- a/forge-gui-mobile/src/forge/card/CardRenderer.java +++ b/forge-gui-mobile/src/forge/card/CardRenderer.java @@ -370,6 +370,7 @@ public class CardRenderer { ManaCost mainManaCost = card.getCurrentState().getManaCost(); if (card.isSplitCard()) { //handle rendering both parts of split card + mainManaCost = card.getLeftSplitState().getManaCost(); ManaCost otherManaCost = card.getAlternateState().getManaCost(); manaCostWidth = CardFaceSymbols.getWidth(otherManaCost, MANA_SYMBOL_SIZE) + MANA_COST_PADDING; CardFaceSymbols.drawManaCost(g, otherManaCost, x + w - manaCostWidth + MANA_COST_PADDING, y, MANA_SYMBOL_SIZE); @@ -522,7 +523,7 @@ public class CardRenderer { g.drawImage(image, x, y, w, h); else { boolean t = (card.getCurrentState().getOriginalColors() != card.getCurrentState().getColors()) || card.getCurrentState().hasChangeColors(); - g.drawBorderImage(ImageCache.getBorderImage(image.toString(), canshow), ImageCache.borderColor(image), ImageCache.getTint(card), x, y, w, h, t); //tint check for changed colors + g.drawBorderImage(ImageCache.getBorderImage(image.toString(), canshow), ImageCache.borderColor(image), ImageCache.getTint(card, image), x, y, w, h, t); //tint check for changed colors g.drawImage(ImageCache.croppedBorderImage(image), x + radius / 2.4f-minusxy, y + radius / 2-minusxy, w * croppedArea, h * croppedArea); } } else { @@ -543,9 +544,9 @@ public class CardRenderer { } public static void drawCardWithOverlays(Graphics g, CardView card, float x, float y, float w, float h, CardStackPosition pos) { - drawCardWithOverlays(g, card, x, y, w, h, pos, false, false); + drawCardWithOverlays(g, card, x, y, w, h, pos, false, false, false); } - public static void drawCardWithOverlays(Graphics g, CardView card, float x, float y, float w, float h, CardStackPosition pos, boolean stackview, boolean showAltState) { + public static void drawCardWithOverlays(Graphics g, CardView card, float x, float y, float w, float h, CardStackPosition pos, boolean stackview, boolean showAltState, boolean isChoiceList) { boolean canShow = MatchController.instance.mayView(card); float oldAlpha = g.getfloatAlphaComposite(); boolean unselectable = !MatchController.instance.isSelectable(card) && MatchController.instance.isSelecting(); @@ -560,7 +561,7 @@ public class CardRenderer { h -= 2 * padding; // TODO: A hacky workaround is currently used to make the game not leak the color information for Morph cards. - final CardStateView details = showAltState ? card.getAlternateState() : card.getCurrentState(); + final CardStateView details = showAltState ? card.getAlternateState() : isChoiceList && card.isSplitCard() ? card.getLeftSplitState() : card.getCurrentState(); final boolean isFaceDown = card.isFaceDown(); final DetailColors borderColor = isFaceDown ? CardDetailUtil.DetailColors.FACE_DOWN : CardDetailUtil.getBorderColor(details, canShow); // canShow doesn't work here for face down Morphs Color color = FSkinColor.fromRGB(borderColor.r, borderColor.g, borderColor.b); @@ -932,8 +933,8 @@ public class CardRenderer { dy *= -1; // flip card costs for Aftermath cards } - drawManaCost(g, card.getAlternateState().getManaCost(), x - padding, y - dy, w + 2 * padding, h, manaSymbolSize); - drawManaCost(g, card.getCurrentState().getManaCost(), x - padding, y + dy, w + 2 * padding, h, manaSymbolSize); + drawManaCost(g, card.getRightSplitState().getManaCost(), x - padding, y - dy, w + 2 * padding, h, manaSymbolSize); + drawManaCost(g, card.getLeftSplitState().getManaCost(), x - padding, y + dy, w + 2 * padding, h, manaSymbolSize); } } else { diff --git a/forge-gui-mobile/src/forge/deck/FDeckChooser.java b/forge-gui-mobile/src/forge/deck/FDeckChooser.java index 36378199774..ced6c89aa6d 100644 --- a/forge-gui-mobile/src/forge/deck/FDeckChooser.java +++ b/forge-gui-mobile/src/forge/deck/FDeckChooser.java @@ -63,6 +63,7 @@ public class FDeckChooser extends FScreen { private Callback callback; private NetDeckCategory netDeckCategory; private boolean refreshingDeckType; + private boolean firstactivation = true; private final DeckManager lstDecks; private final FButton btnNewDeck = new FButton(Localizer.getInstance().getMessage("lblNewDeck")); @@ -226,6 +227,11 @@ public class FDeckChooser extends FScreen { @Override public void onActivate() { + //somehow a loaded deck state from startup don't refresh accordingly for imageview so refresh it on first activation + if(firstactivation) { + needRefreshOnActivate = true; + firstactivation = false; + } if (needRefreshOnActivate) { needRefreshOnActivate = false; refreshDecksList(selectedDeckType, true, null); diff --git a/forge-gui-mobile/src/forge/itemmanager/views/ImageView.java b/forge-gui-mobile/src/forge/itemmanager/views/ImageView.java index d061dbc78e1..8456a248ad4 100644 --- a/forge-gui-mobile/src/forge/itemmanager/views/ImageView.java +++ b/forge-gui-mobile/src/forge/itemmanager/views/ImageView.java @@ -1,22 +1,28 @@ package forge.itemmanager.views; +import com.badlogic.gdx.graphics.g2d.TextureRegion; import forge.Forge; import forge.Forge.KeyInputAdapter; import forge.Graphics; import forge.assets.FImage; +import forge.assets.FImageComplex; +import forge.assets.FSkin; import forge.assets.FSkinColor; import forge.assets.FSkinImage; import forge.assets.FSkinColor.Colors; import forge.assets.FSkinFont; import forge.assets.ImageCache; +import forge.card.CardFaceSymbols; import forge.card.CardRenderer; import forge.card.CardRenderer.CardStackPosition; import forge.card.CardZoom; +import forge.card.ColorSet; import forge.deck.ArchetypeDeckGenerator; import forge.deck.CardThemedDeckGenerator; import forge.deck.CommanderDeckGenerator; import forge.deck.DeckProxy; import forge.deck.FDeckViewer; +import forge.deck.io.DeckPreferences; import forge.item.InventoryItem; import forge.item.PaperCard; import forge.itemmanager.ColumnDef; @@ -27,6 +33,7 @@ import forge.itemmanager.ItemManagerConfig; import forge.itemmanager.ItemManagerModel; import forge.itemmanager.SItemManagerUtil; import forge.itemmanager.filters.ItemFilter; +import forge.planarconquest.ConquestCommander; import forge.toolbox.FCardPanel; import forge.toolbox.FComboBox; import forge.toolbox.FDisplayObject; @@ -36,6 +43,7 @@ import forge.toolbox.FEvent.FEventHandler; import forge.toolbox.FLabel; import forge.toolbox.FScrollPane; import forge.util.Localizer; +import forge.util.TextUtil; import forge.util.Utils; import java.util.ArrayList; @@ -61,7 +69,7 @@ public class ImageView extends ItemView { private static final float GROUP_HEADER_GLYPH_WIDTH = Utils.scale(6); private static final float GROUP_HEADER_LINE_THICKNESS = Utils.scale(1); private static final float SEL_BORDER_SIZE = Utils.scale(1); - private static final int MIN_COLUMN_COUNT = 1; + private static final int MIN_COLUMN_COUNT = Forge.isLandscapeMode() ? 2 : 1; private static final int MAX_COLUMN_COUNT = 10; private final List selectedIndices = new ArrayList<>(); @@ -550,7 +558,8 @@ public class ImageView extends ItemView { } else if (count == 2) { if (item != null && item.selected) { - itemManager.activateSelectedItems(); + if (!(item.getKey() instanceof DeckProxy)) + itemManager.activateSelectedItems(); } } return true; @@ -854,6 +863,19 @@ public class ImageView extends ItemView { @Override public boolean tap(float x, float y, int count) { + ItemInfo item = getItemAtPoint(x + getLeft(), y + getTop()); + if (item != null) { + if(item.getKey() instanceof DeckProxy) { + DeckProxy dp = (DeckProxy)item.getKey(); + if (count >= 2 && !dp.isGeneratedDeck()) { + //double tap to add to favorites or remove.... + if (DeckPreferences.getPrefs(dp).getStarCount() > 0) + DeckPreferences.getPrefs(dp).setStarCount(0); + else + DeckPreferences.getPrefs(dp).setStarCount(1); + } + } + } if (groupBy != null && !items.isEmpty() && y < GROUP_HEADER_HEIGHT) { isCollapsed = !isCollapsed; btnExpandCollapseAll.updateIsAllCollapsed(); @@ -869,7 +891,7 @@ public class ImageView extends ItemView { ItemInfo item = getItemAtPoint(x + getLeft(), y + getTop()); if (item != null) { if(item.getKey() instanceof CardThemedDeckGenerator || item.getKey() instanceof CommanderDeckGenerator - || item.getKey() instanceof ArchetypeDeckGenerator){ + || item.getKey() instanceof ArchetypeDeckGenerator || item.getKey() instanceof DeckProxy){ FDeckViewer.show(((DeckProxy)item.getKey()).getDeck()); return true; } @@ -922,6 +944,7 @@ public class ImageView extends ItemView { private int index; private CardStackPosition pos; private boolean selected; + private final float IMAGE_SIZE = CardRenderer.MANA_SYMBOL_SIZE; private ItemInfo(T item0, Group group0) { item = item0; @@ -954,30 +977,100 @@ public class ImageView extends ItemView { final float y = getTop() - group.getTop() - getScrollValue(); final float w = getWidth(); final float h = getHeight(); - - if (selected) { //if round border is enabled, the select highlight is also rounded.. - if (Forge.enableUIMask) { - //fillroundrect has rough/aliased corner - g.fillRoundRect(Color.GREEN, x - SEL_BORDER_SIZE, y - SEL_BORDER_SIZE, - w + 2 * SEL_BORDER_SIZE, h + 2 * SEL_BORDER_SIZE, (h - w) / 10); - //drawroundrect has GL_SMOOTH to `smoothen/faux` the aliased corner - g.drawRoundRect(1f, Color.GREEN, x - SEL_BORDER_SIZE, y - SEL_BORDER_SIZE, - w + 1.5f * SEL_BORDER_SIZE, h + 1.5f * SEL_BORDER_SIZE, (h - w) / 10); + Texture dpImg = null; + boolean deckSelectMode = false; + if (item instanceof DeckProxy) { + dpImg = ImageCache.getImage(item); + deckSelectMode = true; + } + if (selected) { + if (!deckSelectMode) { + //if round border is enabled, the select highlight is also rounded.. + if (Forge.enableUIMask) { + //fillroundrect has rough/aliased corner + g.fillRoundRect(Color.GREEN, x - SEL_BORDER_SIZE, y - SEL_BORDER_SIZE, w + 2 * SEL_BORDER_SIZE, h + 2 * SEL_BORDER_SIZE, (h - w) / 10); + //drawroundrect has GL_SMOOTH to `smoothen/faux` the aliased corner + g.drawRoundRect(1f, Color.GREEN, x - SEL_BORDER_SIZE, y - SEL_BORDER_SIZE, w + 1.5f * SEL_BORDER_SIZE, h + 1.5f * SEL_BORDER_SIZE, (h - w) / 10); + } + else //default rectangle highlight + g.fillRect(Color.GREEN, x - SEL_BORDER_SIZE, y - SEL_BORDER_SIZE, w + 2 * SEL_BORDER_SIZE, h + 2 * SEL_BORDER_SIZE); } - else //default rectangle highlight - g.fillRect(Color.GREEN, x - SEL_BORDER_SIZE, y - SEL_BORDER_SIZE, - w + 2 * SEL_BORDER_SIZE, h + 2 * SEL_BORDER_SIZE); } if (item instanceof PaperCard) { - CardRenderer.drawCard(g, (PaperCard)item, x, y, w, h, pos); - } - else { + CardRenderer.drawCard(g, (PaperCard) item, x, y, w, h, pos); + } else if (item instanceof ConquestCommander) { + CardRenderer.drawCard(g, ((ConquestCommander) item).getCard(), x, y, w, h, pos); + } else if (deckSelectMode) { + DeckProxy dp = ((DeckProxy) item); + ColorSet deckColor = dp.getColor(); + float scale = 0.75f; + + if (dpImg != null) {//generated decks have missing info... + if (Forge.enableUIMask){ + //commander bg + g.drawImage(FSkin.getDeckbox().get(0), FSkin.getDeckbox().get(0), x, y, w, h, Color.GREEN, selected); + TextureRegion tr = ImageCache.croppedBorderImage(dpImg); + g.drawImage(tr, x+(w-w*scale)/2, y+(h-h*scale)/1.5f, w*scale, h*scale); + } else { + if (selected) + g.fillRect(Color.GREEN, x - SEL_BORDER_SIZE, y - SEL_BORDER_SIZE, w + 2 * SEL_BORDER_SIZE, h + 2 * SEL_BORDER_SIZE); + g.drawImage(dpImg, x, y, w, h); + } + //fake labelname shadow + g.drawText(item.getName(), GROUP_HEADER_FONT, Color.BLACK, (x + PADDING)-1f, (y + PADDING*2)+1f, w - 2 * PADDING, h - 2 * PADDING, true, Align.center, false); + //labelname + g.drawText(item.getName(), GROUP_HEADER_FONT, Color.WHITE, x + PADDING, y + PADDING*2, w - 2 * PADDING, h - 2 * PADDING, true, Align.center, false); + } else { + if (!dp.isGeneratedDeck()){ + FImageComplex cardArt = CardRenderer.getCardArt(dp.getHighestCMCCard().getImageKey(false), false, false, false); + //draw the deckbox + if (cardArt == null){ + //draw generic box if null or still loading + g.drawImage(FSkin.getDeckbox().get(2), FSkin.getDeckbox().get(2), x, y-(h*0.25f), w, h, Color.GREEN, selected); + } else { + g.drawDeckBox(cardArt, scale, FSkin.getDeckbox().get(1), FSkin.getDeckbox().get(2), x, y, w, h, Color.GREEN, selected); + } + } else { + //generic box + g.drawImage(FSkin.getDeckbox().get(2), FSkin.getDeckbox().get(2), x, y-(h*0.25f), w, h, Color.GREEN, selected); + } + if (deckColor != null) { + //deck color identity + float symbolSize = IMAGE_SIZE; + if (Forge.isLandscapeMode()) { + if (columnCount == 4) + symbolSize = IMAGE_SIZE * 1.5f; + else if (columnCount == 3) + symbolSize = IMAGE_SIZE * 2f; + else if (columnCount == 2) + symbolSize = IMAGE_SIZE * 3f; + else if (columnCount == 1) + symbolSize = IMAGE_SIZE * 4f; + } else { + if (columnCount > 2) + symbolSize = IMAGE_SIZE * (0.5f); + } + //vertical mana icons + CardFaceSymbols.drawColorSet(g, deckColor, x +(w-symbolSize), y+(h/8), symbolSize, true); + if(!dp.isGeneratedDeck()) { + if (Forge.hdbuttons) + g.drawImage(DeckPreferences.getPrefs(dp).getStarCount() > 0 ? FSkinImage.HDSTAR_FILLED : FSkinImage.HDSTAR_OUTLINE, x, y, symbolSize, symbolSize); + else + g.drawImage(DeckPreferences.getPrefs(dp).getStarCount() > 0 ? FSkinImage.STAR_FILLED : FSkinImage.STAR_OUTLINE, x, y, symbolSize, symbolSize); + } + } + String deckname = TextUtil.fastReplace(item.getName(),"] #", "]\n#"); + //deckname fakeshadow + g.drawText(deckname, GROUP_HEADER_FONT, Color.BLACK, (x + PADDING)-1f, (y + (h/10) + PADDING)+1f, w - 2 * PADDING, h - 2 * PADDING, true, Align.center, true); + //deck name + g.drawText(deckname, GROUP_HEADER_FONT, Color.WHITE, x + PADDING, y + (h/10) + PADDING, w - 2 * PADDING, h - 2 * PADDING, true, Align.center, true); + } + } else { Texture img = ImageCache.getImage(item); if (img != null) { g.drawImage(img, x, y, w, h); - } - else { + } else { g.fillRect(Color.BLACK, x, y, w, h); g.drawText(item.getName(), GROUP_HEADER_FONT, Color.WHITE, x + PADDING, y + PADDING, w - 2 * PADDING, h - 2 * PADDING, true, Align.center, false); } diff --git a/forge-gui-mobile/src/forge/screens/constructed/LobbyScreen.java b/forge-gui-mobile/src/forge/screens/constructed/LobbyScreen.java index 32abd93cbe5..876528b4dd3 100644 --- a/forge-gui-mobile/src/forge/screens/constructed/LobbyScreen.java +++ b/forge-gui-mobile/src/forge/screens/constructed/LobbyScreen.java @@ -628,7 +628,8 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView { } if (Forge.gameInProgress) { /*preload deck to cache*/ - ImageCache.preloadCache(decks[i]); + if(slot.getType() == LobbySlotType.LOCAL) + ImageCache.preloadCache(decks[i]); } Gdx.graphics.requestRendering(); } diff --git a/forge-gui-mobile/src/forge/screens/match/MatchScreen.java b/forge-gui-mobile/src/forge/screens/match/MatchScreen.java index 1bbc9435e0a..903b796ed80 100644 --- a/forge-gui-mobile/src/forge/screens/match/MatchScreen.java +++ b/forge-gui-mobile/src/forge/screens/match/MatchScreen.java @@ -358,10 +358,10 @@ public class MatchScreen extends FScreen { if(gameMenu!=null) { if(gameMenu.getChildCount()>3){ if(viewWinLose == null) { - gameMenu.getChildAt(0).setEnabled(true); - gameMenu.getChildAt(1).setEnabled(true); - gameMenu.getChildAt(2).setEnabled(true); - gameMenu.getChildAt(3).setEnabled(true); + gameMenu.getChildAt(0).setEnabled(!game.isMulligan()); + gameMenu.getChildAt(1).setEnabled(!game.isMulligan()); + gameMenu.getChildAt(2).setEnabled(!game.isMulligan()); + gameMenu.getChildAt(3).setEnabled(!game.isMulligan()); gameMenu.getChildAt(4).setEnabled(false); } else { gameMenu.getChildAt(0).setEnabled(false); diff --git a/forge-gui-mobile/src/forge/screens/match/views/VAvatar.java b/forge-gui-mobile/src/forge/screens/match/views/VAvatar.java index fed9fdb447f..4c28fcd56c8 100644 --- a/forge-gui-mobile/src/forge/screens/match/views/VAvatar.java +++ b/forge-gui-mobile/src/forge/screens/match/views/VAvatar.java @@ -4,6 +4,7 @@ import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.utils.Align; +import forge.Forge; import forge.Graphics; import forge.assets.FImage; import forge.assets.FSkinFont; @@ -69,6 +70,9 @@ public class VAvatar extends FDisplayObject { float h = getHeight(); g.drawImage(image, 0, 0, w, h); + if (Forge.altPlayerLayout && Forge.isLandscapeMode()) + return; + //display XP in lower right corner of avatar int xp = player.getCounters(CounterEnumType.EXPERIENCE); if (xp > 0) { diff --git a/forge-gui-mobile/src/forge/screens/match/views/VField.java b/forge-gui-mobile/src/forge/screens/match/views/VField.java index 1447408b257..da3d6587707 100644 --- a/forge-gui-mobile/src/forge/screens/match/views/VField.java +++ b/forge-gui-mobile/src/forge/screens/match/views/VField.java @@ -114,6 +114,7 @@ public class VField extends FContainer { if (!c.hasCardAttachments() && cardName.equals(c.getCurrentState().getName()) && card.hasSameCounters(c) && + card.hasSamePT(c) && //don't stack token with different PT card.getCurrentState().getKeywordKey().equals(c.getCurrentState().getKeywordKey()) && card.isTapped() == c.isTapped() && // don't stack tapped tokens on untapped tokens card.isSick() == c.isSick() && //don't stack sick tokens on non sick diff --git a/forge-gui-mobile/src/forge/screens/match/views/VGameMenu.java b/forge-gui-mobile/src/forge/screens/match/views/VGameMenu.java index d9bbc38166d..e13bcaf32ee 100644 --- a/forge-gui-mobile/src/forge/screens/match/views/VGameMenu.java +++ b/forge-gui-mobile/src/forge/screens/match/views/VGameMenu.java @@ -50,6 +50,12 @@ public class VGameMenu extends FDropDownMenu { addItem(new FMenuItem(localizer.getMessage("lblDeckList"), FSkinImage.DECKLIST, new FEventHandler() { @Override public void handleEvent(FEvent e) { + //pause game when spectating AI Match + if (!MatchController.instance.hasLocalPlayers()) { + if(!MatchController.instance.isGamePaused()) + MatchController.instance.pauseMatch(); + } + final Player player = MatchController.getHostedMatch().getGame().getPhaseHandler().getPlayerTurn(); if (player != null) { final Deck deck = player.getRegisteredPlayer().getDeck(); @@ -89,6 +95,11 @@ public class VGameMenu extends FDropDownMenu { addItem(new FMenuItem(localizer.getMessage("lblSettings"), Forge.hdbuttons ? FSkinImage.HDPREFERENCE : FSkinImage.SETTINGS, new FEventHandler() { @Override public void handleEvent(FEvent e) { + //pause game when spectating AI Match + if (!MatchController.instance.hasLocalPlayers()) { + if(!MatchController.instance.isGamePaused()) + MatchController.instance.pauseMatch(); + } SettingsScreen.show(false); } })); diff --git a/forge-gui-mobile/src/forge/screens/match/views/VPlayerPanel.java b/forge-gui-mobile/src/forge/screens/match/views/VPlayerPanel.java index 558fa4d8ee7..6caaa9b4b8c 100644 --- a/forge-gui-mobile/src/forge/screens/match/views/VPlayerPanel.java +++ b/forge-gui-mobile/src/forge/screens/match/views/VPlayerPanel.java @@ -6,6 +6,7 @@ import java.util.List; import java.util.Map; import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.utils.Align; import forge.Forge; @@ -30,8 +31,10 @@ import forge.util.Utils; public class VPlayerPanel extends FContainer { private static final FSkinFont LIFE_FONT = FSkinFont.get(18); private static final FSkinFont INFO_FONT = FSkinFont.get(12); + private static final FSkinFont INFO2_FONT = FSkinFont.get(14); private static final FSkinColor INFO_FORE_COLOR = FSkinColor.get(Colors.CLR_TEXT); private static final FSkinColor DISPLAY_AREA_BACK_COLOR = FSkinColor.get(Colors.CLR_INACTIVE).alphaColor(0.5f); + private static final FSkinColor DELIRIUM_HIGHLIGHT = FSkinColor.get(Colors.CLR_PHASE_ACTIVE_ENABLED).alphaColor(0.5f); private static final float INFO_TAB_PADDING_X = Utils.scale(2); private static final float INFO_TAB_PADDING_Y = Utils.scale(2); @@ -48,6 +51,7 @@ public class VPlayerPanel extends FContainer { private float avatarHeight = VAvatar.HEIGHT; private float displayAreaHeightFactor = 1.0f; private boolean forMultiPlayer = false; + public int adjustHeight = 1; public VPlayerPanel(PlayerView player0, boolean showHand, int playerCount) { player = player0; @@ -284,8 +288,14 @@ public class VPlayerPanel extends FContainer { float y = 0; avatar.setPosition(x, y); y += avatar.getHeight(); - lblLife.setBounds(x, y, avatar.getWidth(), LIFE_FONT.getLineHeight()); - y += lblLife.getHeight(); + + lblLife.setBounds(x, Forge.altPlayerLayout ? 0 : y, avatar.getWidth(), Forge.altPlayerLayout ? INFO_FONT.getLineHeight() : LIFE_FONT.getLineHeight()); + if (Forge.altPlayerLayout) { + if (adjustHeight > 2) + y += INFO_FONT.getLineHeight()/2; + } else + y += lblLife.getHeight(); + float infoTabWidth = avatar.getWidth(); float infoTabHeight = (height - y) / tabs.size(); for (InfoTab tab : tabs) { @@ -361,6 +371,7 @@ public class VPlayerPanel extends FContainer { private int life = player.getLife(); private int poisonCounters = player.getCounters(CounterEnumType.POISON); private int energyCounters = player.getCounters(CounterEnumType.ENERGY); + private int experienceCounters = player.getCounters(CounterEnumType.EXPERIENCE); private String lifeStr = String.valueOf(life); private LifeLabel() { @@ -388,6 +399,7 @@ public class VPlayerPanel extends FContainer { } energyCounters = player.getCounters(CounterEnumType.ENERGY); + experienceCounters = player.getCounters(CounterEnumType.EXPERIENCE); //when gui player loses life, vibrate device for a length of time based on amount of life lost if (vibrateDuration > 0 && MatchController.instance.isLocalPlayer(player) && @@ -405,22 +417,50 @@ public class VPlayerPanel extends FContainer { @Override public void draw(Graphics g) { - if (poisonCounters == 0 && energyCounters == 0) { - g.drawText(lifeStr, LIFE_FONT, INFO_FORE_COLOR, 0, 0, getWidth(), getHeight(), false, Align.center, true); - } - else { - float halfHeight = getHeight() / 2; - float textStart = halfHeight + Utils.scale(1); - float textWidth = getWidth() - textStart; - g.drawImage(FSkinImage.QUEST_LIFE, 0, 0, halfHeight, halfHeight); - g.drawText(lifeStr, INFO_FONT, INFO_FORE_COLOR, textStart, 0, textWidth, halfHeight, false, Align.center, true); - if (poisonCounters > 0) { //prioritize showing poison counters over energy counters - g.drawImage(FSkinImage.POISON, 0, halfHeight, halfHeight, halfHeight); - g.drawText(String.valueOf(poisonCounters), INFO_FONT, INFO_FORE_COLOR, textStart, halfHeight, textWidth, halfHeight, false, Align.center, true); + adjustHeight = 1; + if(Forge.altPlayerLayout && Forge.isLandscapeMode()) { + if (poisonCounters == 0 && energyCounters == 0 && experienceCounters == 0) { + g.drawOutlinedText(lifeStr, INFO2_FONT, INFO_FORE_COLOR.getColor(), Color.BLACK, 0, 0, getWidth(), getHeight(), false, Align.left, false); + } else { + float halfHeight = getHeight() / 2; + float textStart = halfHeight + Utils.scale(1); + float textWidth = getWidth() - textStart; + int mod = 1; + g.drawImage(FSkinImage.QUEST_LIFE, 0, 0, halfHeight, halfHeight); + g.drawOutlinedText(lifeStr, INFO_FONT, INFO_FORE_COLOR.getColor(), Color.BLACK, textStart, 0, textWidth, halfHeight, false, Align.left, false); + if (poisonCounters > 0) { + g.drawImage(FSkinImage.POISON, 0, halfHeight+2, halfHeight, halfHeight); + g.drawOutlinedText(String.valueOf(poisonCounters), INFO_FONT, INFO_FORE_COLOR.getColor(), Color.BLACK, textStart, halfHeight+2, textWidth, halfHeight, false, Align.left, false); + mod+=1; + } + if (energyCounters > 0) { + g.drawImage(FSkinImage.ENERGY, 0, (halfHeight*mod)+2, halfHeight, halfHeight); + g.drawOutlinedText(String.valueOf(energyCounters), INFO_FONT, INFO_FORE_COLOR.getColor(), Color.BLACK, textStart, (halfHeight*mod)+2, textWidth, halfHeight, false, Align.left, false); + mod+=1; + } + if (experienceCounters > 0) { + g.drawImage(FSkinImage.COMMANDER, 0, (halfHeight*mod)+2, halfHeight, halfHeight); + g.drawOutlinedText(String.valueOf(experienceCounters), INFO_FONT, INFO_FORE_COLOR.getColor(), Color.BLACK, textStart, (halfHeight*mod)+2, textWidth, halfHeight, false, Align.left, false); + mod+=1; + } + adjustHeight = (mod > 2) && (avatar.getHeight() < halfHeight*mod)? mod : 1; } - else { - g.drawImage(FSkinImage.ENERGY, 0, halfHeight, halfHeight, halfHeight); - g.drawText(String.valueOf(energyCounters), INFO_FONT, INFO_FORE_COLOR, textStart, halfHeight, textWidth, halfHeight, false, Align.center, true); + } else { + if (poisonCounters == 0 && energyCounters == 0) { + g.drawText(lifeStr, LIFE_FONT, INFO_FORE_COLOR, 0, 0, getWidth(), getHeight(), false, Align.center, true); + } else { + float halfHeight = getHeight() / 2; + float textStart = halfHeight + Utils.scale(1); + float textWidth = getWidth() - textStart; + g.drawImage(FSkinImage.QUEST_LIFE, 0, 0, halfHeight, halfHeight); + g.drawText(lifeStr, INFO_FONT, INFO_FORE_COLOR, textStart, 0, textWidth, halfHeight, false, Align.center, true); + if (poisonCounters > 0) { //prioritize showing poison counters over energy counters + g.drawImage(FSkinImage.POISON, 0, halfHeight, halfHeight, halfHeight); + g.drawText(String.valueOf(poisonCounters), INFO_FONT, INFO_FORE_COLOR, textStart, halfHeight, textWidth, halfHeight, false, Align.center, true); + } else { + g.drawImage(FSkinImage.ENERGY, 0, halfHeight, halfHeight, halfHeight); + g.drawText(String.valueOf(energyCounters), INFO_FONT, INFO_FORE_COLOR, textStart, halfHeight, textWidth, halfHeight, false, Align.center, true); + } } } } @@ -473,19 +513,22 @@ public class VPlayerPanel extends FContainer { yAcross = y; y--; h++; - } - else { + } else { h -= INFO_TAB_PADDING_Y; yAcross = h; y--; h += 2; } - g.fillRect(DISPLAY_AREA_BACK_COLOR, 0, isFlipped() ? INFO_TAB_PADDING_Y : 0, w, getHeight() - INFO_TAB_PADDING_Y); + //change the graveyard tab selection color to active phase color to indicate the player has delirium + if ((icon == FSkinImage.HDGRAVEYARD || icon == FSkinImage.GRAVEYARD) && player.hasDelirium()) { + g.fillRect(DELIRIUM_HIGHLIGHT, 0 ,isFlipped() ? INFO_TAB_PADDING_Y : 0, w, getHeight() - INFO_TAB_PADDING_Y); + } else { + g.fillRect(DISPLAY_AREA_BACK_COLOR, 0, isFlipped() ? INFO_TAB_PADDING_Y : 0, w, getHeight() - INFO_TAB_PADDING_Y); + } if (!Forge.isLandscapeMode()) { if (isFlipped()) { //use clip to ensure all corners connect g.startClip(-1, y, w + 2, h); - } - else { + } else { g.startClip(-1, y, w + 2, yAcross - y); } if (forMultiPlayer) { @@ -533,8 +576,7 @@ public class VPlayerPanel extends FContainer { if (lblLife.getRotate180()) { g.endTransform(); } - } - else { //show image above text if taller than wide + } else { //show image above text if taller than wide if (lblLife.getRotate180()) { g.startRotateTransform(getWidth() / 2, getHeight() / 2, 180); } diff --git a/forge-gui-mobile/src/forge/screens/match/views/VStack.java b/forge-gui-mobile/src/forge/screens/match/views/VStack.java index b3ae6edd666..763c8170e1f 100644 --- a/forge-gui-mobile/src/forge/screens/match/views/VStack.java +++ b/forge-gui-mobile/src/forge/screens/match/views/VStack.java @@ -364,6 +364,7 @@ public class VStack extends FDropDown { float y = 0; float w = getWidth(); float h = preferredHeight; + CardView sourceCard = stackInstance.getSourceCard(); boolean needAlpha = (activeStackInstance != stackInstance); if (needAlpha) { //use alpha for non-active items on stack @@ -382,16 +383,17 @@ public class VStack extends FDropDown { x += PADDING; y += PADDING; - CardRenderer.drawCardWithOverlays(g, stackInstance.getSourceCard(), x, y, CARD_WIDTH, CARD_HEIGHT, CardStackPosition.Top, true, false); + CardRenderer.drawCardWithOverlays(g, sourceCard, x, y, CARD_WIDTH, CARD_HEIGHT, CardStackPosition.Top, true, false, false); x += CARD_WIDTH + PADDING; w -= x + PADDING - BORDER_THICKNESS; h -= y + PADDING - BORDER_THICKNESS; - String name = stackInstance.getSourceCard().getName(); + String name = sourceCard.getName(); int index = text.indexOf(name); String newtext = ""; - String cId = "(" + stackInstance.getSourceCard().getId() + ")"; + String cId = "(" + sourceCard.getId() + ")"; + String optionalCostString = !stackInstance.getOptionalCostString().equals("") ? " ("+ stackInstance.getOptionalCostString() + ")" : ""; if (index == -1) { newtext = TextUtil.fastReplace(TextUtil.fastReplace(text.trim(),"--","-"),"- -","-"); @@ -405,7 +407,7 @@ public class VStack extends FDropDown { newtext = TextUtil.fastReplace(trimSecond, " "+cId, name); if(newtext.equals("\n"+name)) - textRenderer.drawText(g, name + " " + cId, FONT, foreColor, x, y, w, h, y, h, true, Align.left, true); + textRenderer.drawText(g, name + " " + cId + optionalCostString, FONT, foreColor, x, y, w, h, y, h, true, Align.left, true); else { newtext = TextUtil.fastReplace(TextUtil.fastReplace(newtext,name+" -","-"), "\n ", "\n"); newtext = "\n"+ TextUtil.fastReplace(newtext.trim(),"--","-"); diff --git a/forge-gui-mobile/src/forge/screens/match/winlose/GauntletWinLose.java b/forge-gui-mobile/src/forge/screens/match/winlose/GauntletWinLose.java index 69d634cd9e5..2ec95f48e13 100644 --- a/forge-gui-mobile/src/forge/screens/match/winlose/GauntletWinLose.java +++ b/forge-gui-mobile/src/forge/screens/match/winlose/GauntletWinLose.java @@ -21,6 +21,7 @@ import forge.FThreads; import forge.assets.FSkinProp; import forge.game.GameView; import forge.gauntlet.GauntletWinLoseController; +import forge.util.Localizer; import forge.util.gui.SOptionPane; import java.util.List; @@ -70,7 +71,7 @@ public class GauntletWinLose extends ControlWinLose { } } - SOptionPane.showMessageDialog(sb.toString(), "Gauntlet Progress", icon); + SOptionPane.showMessageDialog(sb.toString(), Localizer.getInstance().getMessage("lblGauntletProgress"), icon); } }); } diff --git a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestRewardDialog.java b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestRewardDialog.java index 239baa355d3..92953a47b3d 100644 --- a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestRewardDialog.java +++ b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestRewardDialog.java @@ -101,17 +101,22 @@ public class ConquestRewardDialog extends FScrollPane { float startX = x; int cardCount = cardRevealers.size(); - cardRevealers.get(0).setBounds(x, y, cardWidth, cardHeight); - for (int i = 1; i < cardCount; i++) { - if (i % columnCount == 0) { - x = startX; - y += cardHeight + PADDING; + try { + cardRevealers.get(0).setBounds(x, y, cardWidth, cardHeight); + for (int i = 1; i < cardCount; i++) { + if (i % columnCount == 0) { + x = startX; + y += cardHeight + PADDING; + } + else { + x += cardWidth + PADDING; + } + cardRevealers.get(i).setBounds(x, y, cardWidth, cardHeight); } - else { - x += cardWidth + PADDING; - } - cardRevealers.get(i).setBounds(x, y, cardWidth, cardHeight); + } catch (Exception ex) { + System.err.println(ex.getMessage()); } + return new ScrollBounds(visibleWidth, y + cardHeight + PADDING); } diff --git a/forge-gui-mobile/src/forge/screens/settings/SettingsPage.java b/forge-gui-mobile/src/forge/screens/settings/SettingsPage.java index 07ae5fe7f98..c55b92edbba 100644 --- a/forge-gui-mobile/src/forge/screens/settings/SettingsPage.java +++ b/forge-gui-mobile/src/forge/screens/settings/SettingsPage.java @@ -190,6 +190,16 @@ public class SettingsPage extends TabPage { localizer.getMessage("cbEscapeEndsTurn"), localizer.getMessage("nlEscapeEndsTurn")), 1); + lstSettings.addItem(new BooleanSetting(FPref.UI_ALT_PLAYERINFOLAYOUT, + localizer.getMessage("lblAltLifeDisplay"), + localizer.getMessage("nlAltLifeDisplay")){ + @Override + public void select() { + super.select(); + //update + Forge.altPlayerLayout = FModel.getPreferences().getPrefBoolean(FPref.UI_ALT_PLAYERINFOLAYOUT); + } + },1); //Random Deck Generation lstSettings.addItem(new BooleanSetting(FPref.DECKGEN_NOSMALL, diff --git a/forge-gui-mobile/src/forge/toolbox/FChoiceList.java b/forge-gui-mobile/src/forge/toolbox/FChoiceList.java index 96e19487634..5cd93132579 100644 --- a/forge-gui-mobile/src/forge/toolbox/FChoiceList.java +++ b/forge-gui-mobile/src/forge/toolbox/FChoiceList.java @@ -13,10 +13,13 @@ import forge.assets.FSkinProp; import forge.assets.IHasSkinProp; import forge.assets.TextRenderer; import forge.assets.FSkinColor.Colors; +import forge.card.CardFaceSymbols; import forge.card.CardRenderer; import forge.card.CardZoom; import forge.card.CardRenderer.CardStackPosition; import forge.card.CardZoom.ActivateHandler; +import forge.card.mana.ManaCost; +import forge.card.mana.ManaCostParser; import forge.game.card.CardView; import forge.game.card.IHasCardView; import forge.game.player.PlayerView; @@ -29,8 +32,11 @@ import forge.itemmanager.filters.ItemFilter; import forge.screens.match.MatchController; import forge.screens.match.views.VAvatar; import forge.screens.match.views.VStack; +import forge.util.TextUtil; import forge.util.Utils; +import static forge.card.CardRenderer.MANA_SYMBOL_SIZE; + public class FChoiceList extends FList implements ActivateHandler { public static final FSkinColor ITEM_COLOR = FSkinColor.get(Colors.CLR_ZEBRA); public static final FSkinColor ALT_ITEM_COLOR = ITEM_COLOR.getContrastColor(-20); @@ -337,7 +343,17 @@ public class FChoiceList extends FList implements ActivateHandler { @Override public void drawValue(Graphics g, T value, FSkinFont font, FSkinColor foreColor, boolean pressed, float x, float y, float w, float h) { - g.drawText(getChoiceText(value), font, foreColor, x, y, w, h, allowDefaultItemWrap(), Align.left, true); + //update manacost text to draw symbols instead + if (value.toString().contains(" {")){ + String[] values = value.toString().split(" "); + String cost = TextUtil.fastReplace(values[1],"}{", " "); + cost = TextUtil.fastReplace(TextUtil.fastReplace(cost,"{", ""),"}", ""); + ManaCost manaCost = new ManaCost(new ManaCostParser(cost)); + CardFaceSymbols.drawManaCost(g, manaCost, x + font.getBounds(values[0]+" ").width, y + (h - MANA_SYMBOL_SIZE) / 2, MANA_SYMBOL_SIZE); + g.drawText(values[0], font, foreColor, x, y, w, h, allowDefaultItemWrap(), Align.left, true); + } else { + g.drawText(getChoiceText(value), font, foreColor, x, y, w, h, allowDefaultItemWrap(), Align.left, true); + } } } protected class NumberRenderer extends DefaultItemRenderer { @@ -500,7 +516,7 @@ public class FChoiceList extends FList implements ActivateHandler { public void drawValue(Graphics g, T value, FSkinFont font, FSkinColor foreColor, boolean pressed, float x, float y, float w, float h) { CardView cv = ((IHasCardView)value).getCardView(); boolean showAlternate = showAlternate(cv, value.toString()); - CardRenderer.drawCardWithOverlays(g, cv, x, y, VStack.CARD_WIDTH, VStack.CARD_HEIGHT, CardStackPosition.Top, false, showAlternate); + CardRenderer.drawCardWithOverlays(g, cv, x, y, VStack.CARD_WIDTH, VStack.CARD_HEIGHT, CardStackPosition.Top, false, showAlternate, true); float dx = VStack.CARD_WIDTH + FList.PADDING; x += dx; diff --git a/forge-gui-mobile/src/forge/toolbox/FDialog.java b/forge-gui-mobile/src/forge/toolbox/FDialog.java index 19b8c8aec42..900d7b50c33 100644 --- a/forge-gui-mobile/src/forge/toolbox/FDialog.java +++ b/forge-gui-mobile/src/forge/toolbox/FDialog.java @@ -16,6 +16,7 @@ import forge.screens.match.views.VPrompt; import forge.toolbox.FButton.Corner; import forge.toolbox.FEvent.FEventHandler; import forge.util.PhysicsObject; +import forge.util.TextUtil; import forge.util.Utils; public abstract class FDialog extends FOverlay { @@ -48,7 +49,7 @@ public abstract class FDialog extends FOverlay { buttonCount = buttonCount0; prompt = add(new VPrompt("", "", null, null)); if (buttonCount < 3) { - title0 = title0.replaceAll(" - ", "\n"); //breakup into lines + title0 = TextUtil.fastReplace(title0," - ", "\n"); //breakup into lines btnMiddle = null; prompt.setMessage(title0); //only put title in message if no third button } diff --git a/forge-gui/res/ai/Cautious.ai b/forge-gui/res/ai/Cautious.ai index f91debe53f2..de33a3395b7 100644 --- a/forge-gui/res/ai/Cautious.ai +++ b/forge-gui/res/ai/Cautious.ai @@ -108,6 +108,9 @@ SAC_TO_REATTACH_TARGET_EVAL_THRESHOLD=500 PREDICT_SPELLS_FOR_MAIN2=true RESERVE_MANA_FOR_MAIN2_CHANCE=100 +# If enabled, the AI will protect its permanents against curse auras with Hexproof, Shroud, and Protection +ACTIVELY_PROTECT_VS_CURSE_AURAS=true + # If enabled, the AI will target artifacts and non-aura enchantments with removal aggressively ACTIVELY_DESTROY_ARTS_AND_NONAURA_ENCHS=true diff --git a/forge-gui/res/ai/Default.ai b/forge-gui/res/ai/Default.ai index c8762118617..9041fca56e2 100644 --- a/forge-gui/res/ai/Default.ai +++ b/forge-gui/res/ai/Default.ai @@ -108,6 +108,9 @@ SAC_TO_REATTACH_TARGET_EVAL_THRESHOLD=400 PREDICT_SPELLS_FOR_MAIN2=true RESERVE_MANA_FOR_MAIN2_CHANCE=100 +# If enabled, the AI will protect its permanents against curse auras with Hexproof, Shroud, and Protection +ACTIVELY_PROTECT_VS_CURSE_AURAS=false + # If enabled, the AI will target artifacts and non-aura enchantments with removal aggressively ACTIVELY_DESTROY_ARTS_AND_NONAURA_ENCHS=true diff --git a/forge-gui/res/ai/Experimental.ai b/forge-gui/res/ai/Experimental.ai index 06a9d7c91e9..151a5f8a009 100644 --- a/forge-gui/res/ai/Experimental.ai +++ b/forge-gui/res/ai/Experimental.ai @@ -108,6 +108,9 @@ SAC_TO_REATTACH_TARGET_EVAL_THRESHOLD=350 PREDICT_SPELLS_FOR_MAIN2=true RESERVE_MANA_FOR_MAIN2_CHANCE=100 +# If enabled, the AI will protect its permanents against curse auras with Hexproof, Shroud, and Protection +ACTIVELY_PROTECT_VS_CURSE_AURAS=true + # If enabled, the AI will target artifacts and non-aura enchantments with removal aggressively ACTIVELY_DESTROY_ARTS_AND_NONAURA_ENCHS=true diff --git a/forge-gui/res/ai/Reckless.ai b/forge-gui/res/ai/Reckless.ai index 6215a58e410..58f44c24067 100644 --- a/forge-gui/res/ai/Reckless.ai +++ b/forge-gui/res/ai/Reckless.ai @@ -108,6 +108,9 @@ SAC_TO_REATTACH_TARGET_EVAL_THRESHOLD=300 PREDICT_SPELLS_FOR_MAIN2=true RESERVE_MANA_FOR_MAIN2_CHANCE=100 +# If enabled, the AI will protect its permanents against curse auras with Hexproof, Shroud, and Protection +ACTIVELY_PROTECT_VS_CURSE_AURAS=false + # If enabled, the AI will target artifacts and non-aura enchantments with removal aggressively ACTIVELY_DESTROY_ARTS_AND_NONAURA_ENCHS=true diff --git a/forge-gui/res/blockdata/chaosdraftthemes.txt b/forge-gui/res/blockdata/chaosdraftthemes.txt new file mode 100644 index 00000000000..dd2e57914a8 --- /dev/null +++ b/forge-gui/res/blockdata/chaosdraftthemes.txt @@ -0,0 +1,10 @@ +# Order, Tag, Label +1, DEFAULT, All sets (default) +11, MODERN, Modern legal expansions +12, PIONEER, Pioneer legal expansions +13, STANDARD, Standard legal expansions +21, CORE_SET, Core Sets +22, MASTERS_SET, Masters Sets (paper only) +30, MIRRODIN, Mirrodin (Plane) +30, RAVNICA, Ravnica (Plane) +40, GRAVEYARD_MATTERS, Graveyard matters diff --git a/forge-gui/res/cardsfolder/c/celestial_dawn.txt b/forge-gui/res/cardsfolder/c/celestial_dawn.txt index d11697c5860..a2e9f626a8f 100644 --- a/forge-gui/res/cardsfolder/c/celestial_dawn.txt +++ b/forge-gui/res/cardsfolder/c/celestial_dawn.txt @@ -4,7 +4,7 @@ Types:Enchantment S:Mode$ Continuous | Affected$ Land.YouCtrl | AddType$ Plains | RemoveLandTypes$ True | RemoveIntrinsicAbilities$ True | Description$ Lands you control are Plains. S:Mode$ Continuous | Affected$ Card.YouOwn+nonLand | SetColor$ White | AffectedZone$ Hand,Library,Graveyard,Exile,Command | Description$ Nonland permanents you control are white. The same is true for spells you control and nonland cards you own that aren't on the battlefield. S:Mode$ Continuous | Affected$ Card.YouCtrl+nonLand | SetColor$ White | AffectedZone$ Battlefield,Stack -S:Mode$ Continuous | Affected$ You | ManaColorConversion$ Additive | WhiteConversion$ All | Description$ You may spend white mana as though it were mana of any color. +S:Mode$ Continuous | Affected$ You | ManaColorConversion$ Additive | WhiteConversion$ Color | Description$ You may spend white mana as though it were mana of any color. S:Mode$ Continuous | Affected$ You | ManaColorConversion$ Restrictive | BlueConversion$ Colorless | BlackConversion$ Colorless | RedConversion$ Colorless | GreenConversion$ Colorless | ColorlessConversion$ Colorless | Description$ You may spend other mana only as though it were colorless mana. SVar:NonStackingEffect:True AI:RemoveDeck:Random diff --git a/forge-gui/res/cardsfolder/c/chromatic_orrery.txt b/forge-gui/res/cardsfolder/c/chromatic_orrery.txt index 5f5221f099a..68f184423fb 100755 --- a/forge-gui/res/cardsfolder/c/chromatic_orrery.txt +++ b/forge-gui/res/cardsfolder/c/chromatic_orrery.txt @@ -1,7 +1,7 @@ Name:Chromatic Orrery ManaCost:7 Types:Legendary Artifact -S:Mode$ Continuous | Affected$ You | ManaColorConversion$ Additive | WhiteConversion$ All | BlueConversion$ All | BlackConversion$ All | RedConversion$ All | GreenConversion$ All | ColorlessConversion$ All | Description$ You may spend mana as though it were mana of any color. +S:Mode$ Continuous | Affected$ You | ManaColorConversion$ Additive | WhiteConversion$ Color | BlueConversion$ Color | BlackConversion$ Color | RedConversion$ Color | GreenConversion$ Color | ColorlessConversion$ Color | Description$ You may spend mana as though it were mana of any color. SVar:NonStackingEffect:True A:AB$ Mana | Cost$ T | Produced$ C | Amount$ 5 | SpellDescription$ Add {C}{C}{C}{C}{C}. A:AB$ Draw | Cost$ 5 T | NumCards$ X | References$ X | SpellDescription$ Draw a card for each color among permanents you control. diff --git a/forge-gui/res/cardsfolder/upcoming/SLD/daryl_hunter_of_walkers.txt b/forge-gui/res/cardsfolder/d/daryl_hunter_of_walkers.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/SLD/daryl_hunter_of_walkers.txt rename to forge-gui/res/cardsfolder/d/daryl_hunter_of_walkers.txt diff --git a/forge-gui/res/cardsfolder/d/djinn_of_wishes.txt b/forge-gui/res/cardsfolder/d/djinn_of_wishes.txt index 219048730e3..4cc5f116805 100644 --- a/forge-gui/res/cardsfolder/d/djinn_of_wishes.txt +++ b/forge-gui/res/cardsfolder/d/djinn_of_wishes.txt @@ -4,11 +4,9 @@ Types:Creature Djinn PT:4/4 K:Flying K:etbCounter:WISH:3 -A:AB$ Dig | Cost$ 2 U U SubCounter<1/WISH> | DigNum$ 1 | Reveal$ True | NoMove$ True | RememberRevealed$ True | SubAbility$ DBPlayIT | SpellDescription$ Reveal the top card of your library. You may play that card without paying its mana cost. If you don't, exile it. -SVar:DBPlayIT:DB$ Play | Defined$ Remembered | Controller$ You | WithoutManaCost$ True | Optional$ True | RememberPlayed$ True | SubAbility$ DBExileIfNotPlayed -SVar:DBExileIfNotPlayed:DB$ ChangeZone | Origin$ Library | Destination$ Exile | Defined$ Remembered | DefinedPlayer$ You | ConditionCheckSVar$ DjinnX | ConditionSVarCompare$ EQ1 | SubAbility$ DBDjinnCleanup | References$ DjinnX -SVar:DBDjinnCleanup:DB$ Cleanup | ClearRemembered$ True -SVar:DjinnX:Remembered$Valid Card.IsRemembered +A:AB$ Dig | Cost$ 2 U U SubCounter<1/WISH> | DigNum$ 1 | Reveal$ True | NoMove$ True | ImprintRevealed$ True | SubAbility$ DBPlay | StackDescription$ {p:You} reveals the top card of their library. {p:You} may play that card without paying its mana cost or exile it. | SpellDescription$ Reveal the top card of your library. You may play that card without paying its mana cost. If you don't, exile it. +SVar:DBPlay:DB$ Play | Defined$ Imprinted | Controller$ You | WithoutManaCost$ True | Optional$ True | RememberPlayed$ True | SubAbility$ DBExileIfNotPlayed | StackDescription$ None +SVar:DBExileIfNotPlayed:DB$ ChangeZone | Origin$ Library | Destination$ Exile | Defined$ Imprinted | DefinedPlayer$ You | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ EQ0 | SubAbility$ DBCleanup | StackDescription$ None +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearImprinted$ True AI:RemoveDeck:All -SVar:Picture:http://www.wizards.com/global/images/magic/general/djinn_of_wishes.jpg Oracle:Flying\nDjinn of Wishes enters the battlefield with three wish counters on it.\n{2}{U}{U}, Remove a wish counter from Djinn of Wishes: Reveal the top card of your library. You may play that card without paying its mana cost. If you don't, exile it. diff --git a/forge-gui/res/cardsfolder/f/false_dawn.txt b/forge-gui/res/cardsfolder/f/false_dawn.txt index 8eb635c8be1..f9edade399e 100644 --- a/forge-gui/res/cardsfolder/f/false_dawn.txt +++ b/forge-gui/res/cardsfolder/f/false_dawn.txt @@ -5,8 +5,7 @@ A:SP$ Effect | Cost$ 1 W | ReplacementEffects$ FDRep | StaticAbilities$ FDManaCo SVar:DBDraw:DB$ Draw | NumCards$ 1 SVar:FDRep:Event$ ProduceMana | ActiveZones$ Command | ValidCard$ Card.YouCtrl | NoTapCheck$ True | ManaReplacement$ ProduceW | Description$ Spells and abilities you control that would add colored mana add that much white mana instead. SVar:ProduceW:R->W & B->W & U->W & G->W -SVar:FDManaConvertion:Mode$ Continuous | EffectZone$ Command | Affected$ You | ManaColorConversion$ Additive | WhiteConversion$ All | Description$ You may spend white mana as though it were mana of any color. +SVar:FDManaConvertion:Mode$ Continuous | EffectZone$ Command | Affected$ You | ManaColorConversion$ Additive | WhiteConversion$ Color | Description$ You may spend white mana as though it were mana of any color. AI:RemoveDeck:All -AI:RemoveDeck:Random SVar:Picture:http://www.wizards.com/global/images/magic/general/false_dawn.jpg Oracle:Until end of turn, spells and abilities you control that would add colored mana add that much white mana instead. Until end of turn, you may spend white mana as though it were mana of any color.\nDraw a card. diff --git a/forge-gui/res/cardsfolder/upcoming/SLD/glenn_the_voice_of_calm.txt b/forge-gui/res/cardsfolder/g/glenn_the_voice_of_calm.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/SLD/glenn_the_voice_of_calm.txt rename to forge-gui/res/cardsfolder/g/glenn_the_voice_of_calm.txt diff --git a/forge-gui/res/cardsfolder/i/inscription_of_abundance.txt b/forge-gui/res/cardsfolder/i/inscription_of_abundance.txt index e022e047e90..7db043ce032 100644 --- a/forge-gui/res/cardsfolder/i/inscription_of_abundance.txt +++ b/forge-gui/res/cardsfolder/i/inscription_of_abundance.txt @@ -2,7 +2,7 @@ Name:Inscription of Abundance ManaCost:1 G Types:Instant K:Kicker:2 G -A:SP$ Charm | Cost$ 1 G | MinCharmNum$ X | CharmNum$ Y | References$ X,Y | Choices$ DBPutCounter,DBGainLife,DBPump | AdditionalDescription$ If this spell was kicked, choose any number instead. +A:SP$ Charm | Cost$ 1 G | MinCharmNum$ X | CharmNum$ Y | References$ X,Y | Choices$ DBPutCounter,DBGainLife,DBPump | AdditionalDescription$ . If this spell was kicked, choose any number instead. SVar:DBPutCounter:DB$ PutCounter | ValidTgts$ Creature | TgtPrompt$ Select target creature | CounterType$ P1P1 | CounterNum$ 2 | SpellDescription$ Put two +1/+1 counters on target creature. SVar:DBGainLife:DB$ GainLife | ValidTgts$ Player | TgtPrompt$ Select target player | LifeAmount$ Z | References$ Z | SpellDescription$ Target player gains X life, where X is the greatest power among creatures they control. SVar:DBPump:DB$ Pump | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | AILogic$ Fight | SubAbility$ DBFight | SpellDescription$ Target creature you control fights target creature you don't control. diff --git a/forge-gui/res/cardsfolder/i/inscription_of_insight.txt b/forge-gui/res/cardsfolder/i/inscription_of_insight.txt index 4752572a7eb..612a3e87019 100644 --- a/forge-gui/res/cardsfolder/i/inscription_of_insight.txt +++ b/forge-gui/res/cardsfolder/i/inscription_of_insight.txt @@ -2,7 +2,7 @@ Name:Inscription of Insight ManaCost:3 U Types:Sorcery K:Kicker:2 U U -A:SP$ Charm | Cost$ 3 U | MinCharmNum$ X | CharmNum$ Y | References$ X,Y | Choices$ DBReturn,DBScry,DBToken | AdditionalDescription$ If this spell was kicked, choose any number instead. +A:SP$ Charm | Cost$ 3 U | MinCharmNum$ X | CharmNum$ Y | References$ X,Y | Choices$ DBReturn,DBScry,DBToken | AdditionalDescription$ . If this spell was kicked, choose any number instead. SVar:DBReturn:DB$ ChangeZone | TargetMin$ 0 | TargetMax$ 2 | ValidTgts$ Creature | TgtPrompt$ Select up to two target creatures | Origin$ Battlefield | Destination$ Hand | SpellDescription$ Return up to two target creatures to their owners' hands. SVar:DBScry:DB$ Scry | ScryNum$ 2 | SubAbility$ DBDraw | SpellDescription$ Scry 2, then draw two cards. SVar:DBDraw:DB$ Draw | NumCards$ 2 diff --git a/forge-gui/res/cardsfolder/i/inscription_of_ruin.txt b/forge-gui/res/cardsfolder/i/inscription_of_ruin.txt index 8674495dcaf..0b97ab202ba 100644 --- a/forge-gui/res/cardsfolder/i/inscription_of_ruin.txt +++ b/forge-gui/res/cardsfolder/i/inscription_of_ruin.txt @@ -2,7 +2,7 @@ Name:Inscription of Ruin ManaCost:2 B Types:Sorcery K:Kicker:2 B B -A:SP$ Charm | Cost$ 2 B | MinCharmNum$ X | CharmNum$ Y | References$ X,Y | Choices$ DBDiscard,DBReturn,DBDestroy | AdditionalDescription$ If this spell was kicked, choose any number instead. +A:SP$ Charm | Cost$ 2 B | MinCharmNum$ X | CharmNum$ Y | References$ X,Y | Choices$ DBDiscard,DBReturn,DBDestroy | AdditionalDescription$ . If this spell was kicked, choose any number instead. SVar:DBDiscard:DB$ Discard | ValidTgts$ Opponent | NumCards$ 2 | Mode$ TgtChoose | SpellDescription$ Target opponent discards two cards. SVar:DBReturn:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ValidTgts$ Card.Creature+cmcLE2+YouOwn | TgtPrompt$ Select target creature card with converted mana cost 2 or less | SpellDescription$ Return target creature card with converted mana cost 2 or less from your graveyard to the battlefield. SVar:DBDestroy:DB$ Destroy | ValidTgts$ Creature.cmcLE3 | TgtPrompt$ Select target creature with converted mana cost 3 or less | SpellDescription$ Destroy target creature with converted mana cost 3 or less. diff --git a/forge-gui/res/cardsfolder/j/jace_mirror_mage.txt b/forge-gui/res/cardsfolder/j/jace_mirror_mage.txt index 870ed1df4d9..1fa866188c0 100644 --- a/forge-gui/res/cardsfolder/j/jace_mirror_mage.txt +++ b/forge-gui/res/cardsfolder/j/jace_mirror_mage.txt @@ -3,12 +3,12 @@ ManaCost:1 U U Types:Legendary Planeswalker Jace Loyalty:4 K:Kicker:2 -T:Mode$ ChangesZone | ValidCard$ Card.Self+kicked | Origin$ Any | Destination$ Battlefield | Execute$ TrigCopy | TriggerDescription$ When CARDNAME enters the battlefield, if it was kicked, create a token that's a copy of CARDNAME, except it's not legendary and its starting loyalty is 1. +T:Mode$ ChangesZone | ValidCard$ Card.Self+kicked | Origin$ Any | Destination$ Battlefield | Execute$ TrigCopy | TriggerDescription$ When CARDNAME enters the battlefield, if NICKNAME was kicked, create a token that's a copy of CARDNAME, except it's not legendary and its starting loyalty is 1. SVar:TrigCopy:DB$ CopyPermanent | Defined$ Self | NonLegendary$ True | SetLoyalty$ 1 -A:AB$ Scry | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | ScryNum$ 1 | SpellDescription$ Scry 1. -A:AB$ Draw | Cost$ AddCounter<0/LOYALTY> | Planeswalker$ True | NumCards$ 1 | Reveal$ True | RememberDrawn$ True | SubAbility$ DBRemoveCounters | SpellDescription$ Draw a card and reveal it. Remove a number of loyalty counters equal to that card's converted mana cost from CARDNAME. +A:AB$ Scry | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | ScryNum$ 2 | SpellDescription$ Scry 2. +A:AB$ Draw | Cost$ AddCounter<0/LOYALTY> | Planeswalker$ True | Ultimate$ True | NumCards$ 1 | Reveal$ True | RememberDrawn$ True | SubAbility$ DBRemoveCounters | SpellDescription$ Draw a card and reveal it. Remove a number of loyalty counters equal to that card's converted mana cost from CARDNAME. SVar:DBRemoveCounters:DB$ RemoveCounter | Defined$ Self | CounterType$ LOYALTY | CounterNum$ X | References$ X | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:X:Remembered$CardManaCost DeckHas:Ability$Token -Oracle:Kicker {2}\nWhen Jace, Mirror Mage enters the battlefield, if Jace was kicked, create a token that's a copy of Jace, Mirror Mage, except it's not legendary and its starting loyalty is 1.\n[+1]: Scry 1.\n[0]: Draw a card and reveal it. Remove a number of loyalty counters equal to that card's converted mana cost from Jace, Mirror Mage. +Oracle:Kicker {2}\nWhen Jace, Mirror Mage enters the battlefield, if Jace was kicked, create a token that's a copy of Jace, Mirror Mage, except it's not legendary and its starting loyalty is 1.\n[+1]: Scry 2.\n[0]: Draw a card and reveal it. Remove a number of loyalty counters equal to that card's converted mana cost from Jace, Mirror Mage. diff --git a/forge-gui/res/cardsfolder/l/light_of_promise.txt b/forge-gui/res/cardsfolder/l/light_of_promise.txt index 4d55340a156..60488e861a8 100644 --- a/forge-gui/res/cardsfolder/l/light_of_promise.txt +++ b/forge-gui/res/cardsfolder/l/light_of_promise.txt @@ -3,10 +3,10 @@ ManaCost:2 W Types:Enchantment Aura K:Enchant creature A:SP$ Attach | Cost$ 2 W | ValidTgts$ Creature -S:Mode$ Continuous | Affected$ Creature.EnchantedBy | AddTrigger$ LightOfPromiseTrig | AddSVar$ LightOfPromisePutCounter & X | Description$ Enchanted creature has "Whenever you gain life, put that many +1/+1 counters on this creature." -SVar:LightOfPromiseTrig:Mode$ LifeGained | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ LightOfPromisePutCounter | TriggerDescription$ Whenever you gain life, put that many +1/+1 counters on CARDNAME. -SVar:LightOfPromisePutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ X | References$ X -SVar:X:TriggerCount$LifeAmount -DeckHints:Ability$LifeGain +S:Mode$ Continuous | Affected$ Creature.EnchantedBy | AddTrigger$ LightOfPromiseTrig | AddSVar$ LightOfPromisePutCounter & LightOfPromiseAmount | Description$ Enchanted creature has "Whenever you gain life, put that many +1/+1 counters on this creature." +SVar:LightOfPromiseTrig:Mode$ LifeGained | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ LightOfPromisePutCounter | TriggerDescription$ Whenever you gain life, put that many +1/+1 counters on this creature. +SVar:LightOfPromisePutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ LightOfPromiseAmount | References$ LightOfPromiseAmount +SVar:LightOfPromiseAmount:TriggerCount$LifeAmount +DeckNeeds:Ability$LifeGain DeckHas:Ability$Counters Oracle:Enchant creature\nEnchanted creature has "Whenever you gain life, put that many +1/+1 counters on this creature." diff --git a/forge-gui/res/cardsfolder/upcoming/SLD/lucille.txt b/forge-gui/res/cardsfolder/l/lucille.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/SLD/lucille.txt rename to forge-gui/res/cardsfolder/l/lucille.txt diff --git a/forge-gui/res/cardsfolder/upcoming/SLD/michonne_ruthless_survivor.txt b/forge-gui/res/cardsfolder/m/michonne_ruthless_survivor.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/SLD/michonne_ruthless_survivor.txt rename to forge-gui/res/cardsfolder/m/michonne_ruthless_survivor.txt diff --git a/forge-gui/res/cardsfolder/m/mycosynth_lattice.txt b/forge-gui/res/cardsfolder/m/mycosynth_lattice.txt index 940dac5951c..bff1493b4cc 100644 --- a/forge-gui/res/cardsfolder/m/mycosynth_lattice.txt +++ b/forge-gui/res/cardsfolder/m/mycosynth_lattice.txt @@ -3,7 +3,7 @@ ManaCost:6 Types:Artifact S:Mode$ Continuous | Affected$ Permanent | AddType$ Artifact | Description$ All permanents are artifact in addition to their other types. S:Mode$ Continuous| Affected$ Card | SetColor$ Colorless | AffectedZone$ Battlefield,Hand,Library,Graveyard,Exile,Stack,Command | Description$ All cards that aren't on the battlefield, spells, and permanents are colorless. -S:Mode$ Continuous | Affected$ Player | ManaColorConversion$ Additive | WhiteConversion$ All | BlueConversion$ All | BlackConversion$ All | RedConversion$ All | GreenConversion$ All | ColorlessConversion$ All | Description$ Players may spend mana as though it were mana of any color. +S:Mode$ Continuous | Affected$ Player | ManaColorConversion$ Additive | WhiteConversion$ Color | BlueConversion$ Color | BlackConversion$ Color | RedConversion$ Color | GreenConversion$ Color | ColorlessConversion$ Color | Description$ Players may spend mana as though it were mana of any color. SVar:NonStackingEffect:True AI:RemoveDeck:Random SVar:Picture:http://www.wizards.com/global/images/magic/general/mycosynth_lattice.jpg diff --git a/forge-gui/res/cardsfolder/n/nahiris_lithoforming.txt b/forge-gui/res/cardsfolder/n/nahiris_lithoforming.txt index 9ed13fe961e..4d9fd8a3918 100755 --- a/forge-gui/res/cardsfolder/n/nahiris_lithoforming.txt +++ b/forge-gui/res/cardsfolder/n/nahiris_lithoforming.txt @@ -12,4 +12,5 @@ SVar:X:Count$xPaid SVar:Y:Count$RememberedSize SVar:XLands:Number$0 DeckHas:Ability$Sacrifice +AI:RemoveDeck:All Oracle:Sacrifice X lands. For each land sacrificed this way, draw a card. You may play X additional lands this turn. Lands you control enter the battlefield tapped this turn. diff --git a/forge-gui/res/cardsfolder/upcoming/SLD/negan_the_cold_blooded.txt b/forge-gui/res/cardsfolder/n/negan_the_cold_blooded.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/SLD/negan_the_cold_blooded.txt rename to forge-gui/res/cardsfolder/n/negan_the_cold_blooded.txt diff --git a/forge-gui/res/cardsfolder/o/orah_skyclave_hierophant.txt b/forge-gui/res/cardsfolder/o/orah_skyclave_hierophant.txt index f12bb686902..efbdbdc6a1b 100755 --- a/forge-gui/res/cardsfolder/o/orah_skyclave_hierophant.txt +++ b/forge-gui/res/cardsfolder/o/orah_skyclave_hierophant.txt @@ -4,7 +4,7 @@ Types:Legendary Creature Kor Cleric PT:3/3 K:Lifelink T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigReturn | TriggerDescription$ Whenever CARDNAME or another Cleric you control dies, return target Cleric with lesser converted mana cost from your graveyard to the battlefield. -T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | TriggerZone$ Battlefield | ValidCard$ Cleric.YouCtrl+Other | Execute$ TrigReturn | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another Cleric you control dies, return target Cleric card with lesser converted mana cost from your graveyard to the battlefield. +T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Cleric.YouCtrl+Other | Execute$ TrigReturn | Secondary$ True | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME or another Cleric you control dies, return target Cleric card with lesser converted mana cost from your graveyard to the battlefield. SVar:TrigReturn:DB$ ChangeZone | ValidTgts$ Cleric.cmcLTX+YouOwn | TgtPrompt$ Choose target Cleric card with lesser converted mana cost | References$ X | Origin$ Graveyard | Destination$ Battlefield SVar:X:TriggeredCard$CardManaCost DeckHas:Ability$Graveyard diff --git a/forge-gui/res/cardsfolder/upcoming/SLD/rick_steadfast_leader.txt b/forge-gui/res/cardsfolder/r/rick_steadfast_leader.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/SLD/rick_steadfast_leader.txt rename to forge-gui/res/cardsfolder/r/rick_steadfast_leader.txt diff --git a/forge-gui/res/cardsfolder/r/rushing_river.txt b/forge-gui/res/cardsfolder/r/rushing_river.txt index 4f83a95e0b2..e47062b8c27 100644 --- a/forge-gui/res/cardsfolder/r/rushing_river.txt +++ b/forge-gui/res/cardsfolder/r/rushing_river.txt @@ -2,9 +2,8 @@ Name:Rushing River ManaCost:2 U Types:Instant K:Kicker:Sac<1/Land> -A:SP$ ChangeZone | Cost$ 2 U | ValidTgts$ Permanent.nonLand | TgtPrompt$ Select target nonland permanent | TargetMin$ X | TargetMax$ X | References$ X | Origin$ Battlefield | Destination$ Hand | SpellDescription$ Return target nonland permanent to its owner's hand. If CARDNAME was kicked, return another target nonland permanent to its owner's hand. +A:SP$ ChangeZone | Cost$ 2 U | ValidTgts$ Permanent.nonLand | TgtPrompt$ Select target nonland permanent | TargetMin$ X | TargetMax$ X | References$ X,Z | Origin$ Battlefield | Destination$ Hand | SpellDescription$ Return target nonland permanent to its owner's hand. If CARDNAME was kicked, return another target nonland permanent to its owner's hand. SVar:X:Count$Kicked.2.1 SVar:NeedsToPlayKickedVar:Z GE2 SVar:Z:Count$Valid Permanent.nonLand+OppCtrl -SVar:Picture:http://www.wizards.com/global/images/magic/general/rushing_river.jpg Oracle:Kicker—Sacrifice a land. (You may sacrifice a land in addition to any other costs as you cast this spell.)\nReturn target nonland permanent to its owner's hand. If Rushing River was kicked, return another target nonland permanent to its owner's hand. diff --git a/forge-gui/res/cardsfolder/t/trinisphere.txt b/forge-gui/res/cardsfolder/t/trinisphere.txt index 6324a0c5bdb..9d938295bf4 100644 --- a/forge-gui/res/cardsfolder/t/trinisphere.txt +++ b/forge-gui/res/cardsfolder/t/trinisphere.txt @@ -1,7 +1,7 @@ Name:Trinisphere ManaCost:3 Types:Artifact -S:Mode$ SetCost | ValidCard$ Card | Type$ Spell | Amount$ Min3 | CheckSVar$ X | SVarCompare$ EQ1 | Description$ As long as CARDNAME is untapped, each spell that would cost less than three mana to cast costs three mana to cast. +S:Mode$ SetCost | ValidCard$ Card | Type$ Spell | Amount$ 3 | RaiseTo$ True | CheckSVar$ X | SVarCompare$ EQ1 | Description$ As long as CARDNAME is untapped, each spell that would cost less than three mana to cast costs three mana to cast. SVar:X:Count$Valid Card.Self+untapped AI:RemoveDeck:Random SVar:NonStackingEffect:True diff --git a/forge-gui/res/cardsfolder/upcoming/CMR/alena_kessig_trapper.txt b/forge-gui/res/cardsfolder/upcoming/alena_kessig_trapper.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/CMR/alena_kessig_trapper.txt rename to forge-gui/res/cardsfolder/upcoming/alena_kessig_trapper.txt diff --git a/forge-gui/res/cardsfolder/upcoming/amareth_the_lustrous.txt b/forge-gui/res/cardsfolder/upcoming/amareth_the_lustrous.txt new file mode 100755 index 00000000000..c652c9bba59 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/amareth_the_lustrous.txt @@ -0,0 +1,8 @@ +Name:Amareth, the Lustrous +ManaCost:3 G U W +Types:Legendary Creature Dragon +PT:6/6 +K:Flying +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Permanent.YouCtrl+Other | TriggerZones$ Battlefield | Execute$ TrigDig | TriggerDescription$ Whenever another permanent enters the battlefield under your control, look at the top card of your library. If it shares a card type with that permanent, you may reveal that card and put it into your hand. +SVar:TrigDig:DB$ Dig | DigNum$ 1 | ForceRevealToController$ True | ChangeNum$ 1 | Optional$ True | LibraryPosition$ 0 | LibraryPosition2$ 0 | ChangeValid$ Card.sharesCardTypeWith TriggeredCard +Oracle:Flying\nWhenever another permanent enters the battlefield under your control, look at the top card of your library. If it shares a card type with that permanent, you may reveal that card and put it into your hand. diff --git a/forge-gui/res/cardsfolder/upcoming/amphin_mutineer.txt b/forge-gui/res/cardsfolder/upcoming/amphin_mutineer.txt new file mode 100755 index 00000000000..05d110dee5f --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/amphin_mutineer.txt @@ -0,0 +1,9 @@ +Name:Amphin Mutineer +ManaCost:3 U +Types:Creature Salamander Pirate +PT:3/3 +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExile | TriggerDescription$ When CARDNAME enters the battlefield, exile up to one target non-Salamander creature. That creature's controller creates a 4/3 blue Salamander Warrior creature token. +SVar:TrigExile:DB$ ChangeZone | TargetMin$ 0 | TargetMax$ 1 | ValidTgts$ Creature.nonSalamander | TgtPrompt$ Select up to one target non-Salamander creature | Origin$ Battlefield | Destination$ Exile | SubAbility$ DBToken +SVar:DBToken:DB$ Token | TokenAmount$ 1 | TokenScript$ u_4_3_salamander_warrior | TokenOwner$ TargetedController +K:Encore:4 U U +Oracle:When Amphin Mutineer enters the battlefield, exile up to one target non-Salamander creature. That creature's controller creates a 4/3 blue Salamander Warrior creature token.\nEncore {4}{U}{U} ({4}{U}{U}, Exile this card from your graveyard: For each opponent, create a token copy that attacks that opponent this turn if able. They gain haste. Sacrifice them at the beginning of the next end step. Activate only as a sorcery.) diff --git a/forge-gui/res/cardsfolder/upcoming/apex_devastator.txt b/forge-gui/res/cardsfolder/upcoming/apex_devastator.txt new file mode 100644 index 00000000000..363d5bab049 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/apex_devastator.txt @@ -0,0 +1,10 @@ +Name:Apex Devastator +ManaCost:8 G G +Types:Creature Chimera Hydra +PT:10/10 +K:Cascade +K:Cascade +K:Cascade +K:Cascade +SVar:PlayMain1:True +Oracle:Cascade, cascade, cascade, cascade (When you cast this spell, exile cards from the top of your library until you exile a nonland card that costs less. You may cast it without paying its mana cost. Put the exiled cards on the bottom in a random order. Then do it again.) diff --git a/forge-gui/res/cardsfolder/upcoming/archon_of_coronation.txt b/forge-gui/res/cardsfolder/upcoming/archon_of_coronation.txt new file mode 100755 index 00000000000..f68662bebe9 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/archon_of_coronation.txt @@ -0,0 +1,9 @@ +Name:Archon of Coronation +ManaCost:4 W W +Types:Creature Archon +PT:5/5 +K:Flying +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigMonarch | TriggerDescription$ When CARDNAME enters the battlefield, you become the monarch. +SVar:TrigMonarch:DB$ BecomeMonarch | Defined$ You +S:Mode$ Continuous | Affected$ You | Condition$ You.isMonarch | AddKeyword$ Damage doesn't cause you to lose life. | Description$ As long as you're the monarch, damage doesn't cause you to lose life. +Oracle:Flying\nWhen Archon of Coronation enters the battlefield, you become the monarch.\nAs long as you're the monarch, damage doesn't cause you to lose life. diff --git a/forge-gui/res/cardsfolder/upcoming/aurora_phoenix.txt b/forge-gui/res/cardsfolder/upcoming/aurora_phoenix.txt new file mode 100644 index 00000000000..23b4dea1768 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/aurora_phoenix.txt @@ -0,0 +1,9 @@ +Name:Aurora Phoenix +ManaCost:4 R R +Types:Creature Phoenix +PT:5/3 +K:Flying +K:Cascade +T:Mode$ SpellCast | ValidCard$ Card.withCascade | ValidActivatingPlayer$ You | TriggerZones$ Graveyard | Execute$ TrigReturn | TriggerDescription$ Whenever you cast a spell with cascade, return CARDNAME from your graveyard to your hand. +SVar:TrigReturn:DB$ ChangeZone | Defined$ Self | Origin$ Graveyard | Destination$ Hand +Oracle:Flying\nCascade (When you cast this spell, exile cards from the top of your library until you exile a nonland card that costs less. You may cast it without paying its mana cost. Put the exiled cards on the bottom of your library in a random order.)\nWhenever you cast a spell with cascade, return Aurora Phoenix from your graveyard to your hand. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/upcoming/belbe_corrupted_observer.txt b/forge-gui/res/cardsfolder/upcoming/belbe_corrupted_observer.txt new file mode 100644 index 00000000000..a55faf178af --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/belbe_corrupted_observer.txt @@ -0,0 +1,8 @@ +Name:Belbe, Corrupted Observer +ManaCost:B G +Types:Legendary Creature Elf Zombie +PT:2/2 +T:Mode$ Phase | Phase$ Main2 | TriggerZones$ Battlefield | Execute$ TrigMana | TriggerDescription$ At the beginning of each player's postcombat main phase, that player adds {C}{C} for each of your opponents that lost life this turn. +SVar:TrigMana:DB$ Mana | Produced$ C | Amount$ X | References$ X | Defined$ TriggeredPlayer +SVar:X:PlayerCountOpponents$HasPropertyLostLifeThisTurn/Twice +Oracle:At the beginning of each player's postcombat main phase, that player adds {C}{C} for each of your opponents that lost life this turn. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/upcoming/bladegriff_prototype.txt b/forge-gui/res/cardsfolder/upcoming/bladegriff_prototype.txt new file mode 100644 index 00000000000..c5a7061f12d --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/bladegriff_prototype.txt @@ -0,0 +1,8 @@ +Name:Bladegriff Prototype +ManaCost: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 +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/upcoming/blim_comedic_genius.txt b/forge-gui/res/cardsfolder/upcoming/blim_comedic_genius.txt new file mode 100644 index 00000000000..b5534250498 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/blim_comedic_genius.txt @@ -0,0 +1,16 @@ +Name:Blim, Comedic Genius +ManaCost:2 B R +Types:Legendary Creature Imp +PT:4/3 +K:Flying +T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Opponent | CombatDamage$ True | TriggerZone$ Battlefield | Execute$ TrigPump | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, that player gains control of a permanent you control of your choice. Then each player loses life and discards cards equal to the number of permanents they control but don't own. +SVar:TrigPump:DB$ ChooseCard | Choices$ Permanent.YouCtrl | ChoiceTitle$ Choose a permanent you control for damaged player to gain control of | Defined$ You | SubAbility$ DBControl +SVar:DBControl:DB$ GainControl | Defined$ ChosenCard | NewController$ TriggeredTarget | SubAbility$ DBRepeatEach +SVar:DBRepeatEach:DB$ RepeatEach | RepeatPlayers$ Player | RepeatSubAbility$ DBLoseLife | SubAbility$ DBCleanup +SVar:DBLoseLife:DB$ LoseLife | Defined$ Player.IsRemembered | LifeAmount$ X | References$ X | SubAbility$ DBDiscard +SVar:DBDiscard:DB$ Discard | Defined$ Player.IsRemembered | NumCards$ X | References$ X | Mode$ TgtChoose +SVar:X:Count$Valid Permanent.RememberedPlayerCtrl/Minus.Y +SVar:Y:Count$Valid Permanent.RememberedPlayerCtrl+RememberedPlayerOwn +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearChosenCard$ True +DeckHints:Ability$Token +Oracle:Flying\nWhenever Blim, Comedic Genius deals combat damage to a player, that player gains control of a permanent you control of your choice. Then each player loses life and discards cards equal to the number of permanents they control but don't own. diff --git a/forge-gui/res/cardsfolder/upcoming/breeches_brazen_plunderer.txt b/forge-gui/res/cardsfolder/upcoming/breeches_brazen_plunderer.txt new file mode 100644 index 00000000000..659a5fa702e --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/breeches_brazen_plunderer.txt @@ -0,0 +1,14 @@ +Name:Breeches, Brazen Plunderer +ManaCost:3 R +Types:Legendary Creature Goblin Pirate +PT:3/3 +K:Menace +K:Partner +T:Mode$ DamageAll | ValidSource$ Pirate.YouCtrl | ValidTarget$ Opponent | TriggerZones$ Battlefield | Execute$ TrigExileTop | TriggerDescription$ Whenever one or more Pirates you control deal damage to your opponents, exile the top card of each of those opponents' libraries. You may play those cards this turn, and you may spend mana as though it were mana of any color to cast those spells. +SVar:TrigExileTop:DB$ Dig | DigNum$ 1 | ChangeNum$ All | Defined$ TriggeredTargets | DestinationZone$ Exile | RememberChanged$ True | SubAbility$ DBEffect +SVar:DBEffect:DB$ Effect | StaticAbilities$ EffPlay | EffectOwner$ You | RememberObjects$ Remembered | ForgetOnMoved$ Exile | SubAbility$ DBCleanup +SVar:EffPlay:Mode$ Continuous | MayPlay$ True | MayPlayIgnoreType$ True | EffectZone$ Command | Affected$ Card.IsRemembered | AffectedZone$ Exile | Description$ You may play those cards this turn, and you may spend mana as though it were mana of any color to cast those spells. +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +DeckHints:Type$Pirate +Oracle:Menace\nWhenever one or more Pirates you control deal damage to your opponents, exile the top card of each of those opponents' libraries. You may play those cards this turn, and you may spend mana as though it were mana of any color to cast those spells.\nPartner (You can have two commanders if both have partner.) + diff --git a/forge-gui/res/cardsfolder/upcoming/brinelin_the_moon_kraken.txt b/forge-gui/res/cardsfolder/upcoming/brinelin_the_moon_kraken.txt new file mode 100644 index 00000000000..a007b7bdfa7 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/brinelin_the_moon_kraken.txt @@ -0,0 +1,9 @@ +Name:Brinelin, the Moon Kraken +ManaCost:6 U U +Types:Legendary Creature Kraken +PT:6/8 +K:Partner +T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Any | Destination$ Battlefield | Execute$ TrigReturn | OptionalDecider$ You | TriggerDescription$ When CARDNAME enters the battlefield or whenever you cast a spell with converted mana cost 6 or greater, you may return target nonland permanent to its owner's hand. +T:Mode$ SpellCast | ValidCard$ Card.cmcGE6 | ValidActivatingPlayer$ You | Execute$ TrigReturn | TriggerZones$ Battlefield | OptionalDecider$ You | Secondary$ True | TriggerDescription$ When CARDNAME enters the battlefield or whenever you cast a spell with converted mana cost 6 or greater, you may return target nonland permanent to its owner's hand. +SVar:TrigReturn:DB$ ChangeZone | ValidTgts$ Permanent.nonLand | TgtPrompt$ Select target nonland permanent | Origin$ Battlefield | Destination$ Hand +Oracle:When Brinelin, the Moon Kraken enters the battlefield or whenever you cast a spell with converted mana cost 6 or greater, you may return target nonland permanent to its owner's hand.\nPartner (You can have two commanders if both have partner.) diff --git a/forge-gui/res/cardsfolder/upcoming/colfenor_the_last_yew.txt b/forge-gui/res/cardsfolder/upcoming/colfenor_the_last_yew.txt new file mode 100755 index 00000000000..d770936d55c --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/colfenor_the_last_yew.txt @@ -0,0 +1,13 @@ +Name:Colfenor, the Last Yew +ManaCost:3 W B G +Types:Legendary Creature Treefolk Shaman +PT:3/7 +K:Vigilance +K:Reach +T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.Other+YouCtrl | RememberTriggeringCard$ True | TriggerZones$ Battlefield | Execute$ TrigChange | TriggerDescription$ Whenever CARDNAME or another creature you control dies, return up to one other target creature card with lesser toughness from your graveyard to your hand. +T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigChange | Secondary$ True | TriggerController$ TriggeredCardController | TriggerDescription$ Whenever CARDNAME or another creature you control dies, return up to one other target creature card with lesser toughness from your graveyard to your hand. +SVar:TrigChange:DB$ ChangeZone | TargetMin$ 0 | TargetMax$ 1 | Origin$ Graveyard | Destination$ Hand | ValidTgts$ Creature.Other+IsNotRemembered+toughnessLTX+YouOwn | TgtPrompt$ Select up to one other target creature card with lesser toughness from your graveyard to return to your hand | References$ X | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +SVar:X:TriggeredCard$CardToughness +DeckHas:Ability$Graveyard +Oracle:Vigilance, reach\nWhenever Colfenor, the Last Yew or another creature you control dies, return up to one other target creature card with lesser toughness from your graveyard to your hand. diff --git a/forge-gui/res/cardsfolder/upcoming/court_of_ambition.txt b/forge-gui/res/cardsfolder/upcoming/court_of_ambition.txt new file mode 100644 index 00000000000..9491c395a34 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/court_of_ambition.txt @@ -0,0 +1,11 @@ +Name:Court of Ambition +ManaCost:2 B B +Types:Enchantment +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigMonarch | TriggerDescription$ When CARDNAME enters the battlefield, you become the monarch. +SVar:TrigMonarch:DB$ BecomeMonarch | Defined$ You +T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigRepeat | TriggerDescription$ At the beginning of your upkeep, each opponent loses 3 life unless they discard a card. If you’re the monarch, instead each opponent loses 6 life unless they discard two cards. +SVar:TrigRepeat:DB$ RepeatEach | RepeatPlayers$ Opponent | RepeatSubAbility$ DBDrain +SVar:DBDrain:DB$ LoseLife | Defined$ Player.IsRemembered | LifeAmount$ X | References$ X,Y | UnlessCost$ Discard | UnlessPayer$ Player.IsRemembered +SVar:X:Count$Monarch.6.3 +SVar:Y:Count$Monarch.2.1 +Oracle:When Court of Ambition enters the battlefield, you become the monarch. \n At the beginning of your upkeep, each opponent loses 3 life unless they discard a card. If you’re the monarch, instead each opponent loses 6 life unless they discard two cards. diff --git a/forge-gui/res/cardsfolder/upcoming/court_of_cunning.txt b/forge-gui/res/cardsfolder/upcoming/court_of_cunning.txt new file mode 100644 index 00000000000..0538da519c0 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/court_of_cunning.txt @@ -0,0 +1,10 @@ +Name:Court of Cunning +ManaCost:1 U U +Types:Enchantment +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigMonarch | TriggerDescription$ When CARDNAME enters the battlefield, you become the monarch. +SVar:TrigMonarch:DB$ BecomeMonarch | Defined$ You +T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigMill | TriggerDescription$ At the beginning of your upkeep, any number of target players each mill two cards. If you're the monarch, each of those players mills ten cards instead. (To mill a card, a player puts the top card of their library into their graveyard.) +SVar:TrigMill:DB$ Mill | ValidTgts$ Player | TgtPrompt$ Select target player | TargetMin$ 0 | TargetMax$ MaxTgt | NumCards$ X | References$ X,MaxTgt +SVar:X:Count$Monarch.10.2 +SVar:MaxTgt:PlayerCountPlayers$Amount +Oracle:When Court of Cunning enters the battlefield, you become the monarch.\nAt the beginning of your upkeep, any number of target players each mill two cards. If you're the monarch, each of those players mills ten cards instead. (To mill a card, a player puts the top card of their library into their graveyard.) \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/upcoming/emberwilde_captain.txt b/forge-gui/res/cardsfolder/upcoming/emberwilde_captain.txt new file mode 100644 index 00000000000..4717d007655 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/emberwilde_captain.txt @@ -0,0 +1,12 @@ +Name:Emberwilde Captain +ManaCost:3 R +Types:Creature Djinn Pirate +PT:4/2 +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigMonarch | TriggerDescription$ When CARDNAME enters the battlefield, you become the monarch. +SVar:TrigMonarch:DB$ BecomeMonarch | Defined$ You +T:Mode$ AttackersDeclared | AttackingPlayer$ Player.Opponent | AttackedTarget$ You | NoResolvingCheck$ True | CheckDefinedPlayer$ You.isMonarch | TriggerZones$ Battlefield | Execute$ TrigPump | TriggerDescription$ Whenever an opponent attacks you while you're the monarch, CARDNAME deals damage to that player equal to the number of cards in their hand. +SVar:TrigPump:DB$ Pump | RememberObjects$ TriggeredAttackingPlayer | SubAbility$ DBDmg +SVar:DBDmg:DB$ DealDamage | Defined$ Remembered | NumDmg$ X | References$ X | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +SVar:X:Count$ValidHand Card.RememberedPlayerCtrl +Oracle:When Emberwilde Captain enters the battlefield, you become the monarch.\nWhenever an opponent attacks you while you're the monarch, Emberwilde Captain deals damage to that player equal to the number of cards in their hand. diff --git a/forge-gui/res/cardsfolder/upcoming/eyeblight_cullers.txt b/forge-gui/res/cardsfolder/upcoming/eyeblight_cullers.txt new file mode 100755 index 00000000000..3edfe1c515f --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/eyeblight_cullers.txt @@ -0,0 +1,9 @@ +Name:Eyeblight Cullers +ManaCost:4 B +Types:Creature Elf Warrior +PT:3/3 +T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigToken | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME dies, create three 1/1 green Elf Warrior creature tokens, then mill three cards. (Put the top three cards of your library into your graveyard.) +SVar:TrigToken:DB$ Token | TokenAmount$ 3 | TokenScript$ g_1_1_elf_warrior | TokenOwner$ You | SubAbility$ DBMill +SVar:DBMill:DB$ Mill | NumCards$ 3 | Defined$ You +DeckHas:Ability$Graveyard & Ability$Token +Oracle:When Eyeblight Cullers dies, create three 1/1 green Elf Warrior creature tokens, then mill three cards. (Put the top three cards of your library into your graveyard.) diff --git a/forge-gui/res/cardsfolder/upcoming/fall_from_favor.txt b/forge-gui/res/cardsfolder/upcoming/fall_from_favor.txt new file mode 100644 index 00000000000..e3c7e870a39 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/fall_from_favor.txt @@ -0,0 +1,10 @@ +Name:Fall from Favor +ManaCost:2 U +Types:Enchantment Aura +K:Enchant creature +A:SP$ Attach | Cost$ 2 U | ValidTgts$ Creature | AILogic$ KeepTapped | AITgts$ Card.cmcGE2 +T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Any | Destination$ Battlefield | Execute$ TrigTap | TriggerDescription$ When CARDNAME enters the battlefield, tap enchanted creature and you become the monarch. +SVar:TrigTap:DB$ Tap | Defined$ Enchanted | SubAbility$ DBMonarch +SVar:DBMonarch:DB$ BecomeMonarch | Defined$ You +S:Mode$ Continuous | Affected$ Creature.EnchantedBy | AddHiddenKeyword$ CARDNAME doesn't untap during your untap step. | UnlessDefinedPlayer$ EnchantedController.isMonarch | Description$ Enchanted creature doesn't untap during its controller's untap step unless that player is the monarch. +Oracle:Enchant creature\nWhen Fall from Favor enters the battlefield, tap enchanted creature and you become the monarch.\nEnchanted creature doesn't untap during its controller's untap step unless that player is the monarch. diff --git a/forge-gui/res/cardsfolder/upcoming/forceful_denial.txt b/forge-gui/res/cardsfolder/upcoming/forceful_denial.txt new file mode 100644 index 00000000000..9ceb0df08d4 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/forceful_denial.txt @@ -0,0 +1,6 @@ +Name:Forceful Denial +ManaCost:3 U U +Types:Instant +K:Cascade +A:SP$ Counter | Cost$ 3 U U | TargetType$ Spell | TgtPrompt$ Select target spell | ValidTgts$ Card | SpellDescription$ Counter target spell. +Oracle:Cascade (When you cast this spell, exile cards from the top of your library until you exile a nonland card that costs less. You may cast it without paying its mana cost. Put the exiled cards on the bottom of your library in a random order.)\nCounter target spell. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/upcoming/ghost_of_ramirez_depietro.txt b/forge-gui/res/cardsfolder/upcoming/ghost_of_ramirez_depietro.txt new file mode 100755 index 00000000000..298a1b07fb8 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/ghost_of_ramirez_depietro.txt @@ -0,0 +1,11 @@ +Name:Ghost of Ramirez DePietro +ManaCost:2 U +Types:Legendary Creature Pirate Spirit +PT:2/3 +K:CantBeBlockedBy Creature.toughnessGE3 +T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigChangeZone | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, choose up to one target card in any graveyard that has been discarded or put there from a library this turn. Put that card into its owner's hand. +SVar:TrigChangeZone:DB$ ChangeZone | TargetMin$ 0 | TargetMax$ 1 | Origin$ Graveyard | Destination$ Hand | ValidTgts$ Card.DiscardedThisTurn,Card.ThisTurnEntered_Graveyard_from_Library | TgtPrompt$ Choose up to one target card in any graveyard that has been discarded or put there from a library this turn +K:Partner +DeckHas:Ability$Graveyard +DeckHints:Ability$Mill +Oracle:Ghost of Ramirez DePietro can't be blocked by creatures with toughness 3 or greater.\nWhenever Ghost of Ramirez DePietro deals combat damage to a player, choose up to one target card in any graveyard that has been discarded or put there from a library this turn. Put that card into its owner's hand.\nPartner (You can have two commanders if both have partner.) diff --git a/forge-gui/res/cardsfolder/upcoming/CMR/halana_kessig_ranger.txt b/forge-gui/res/cardsfolder/upcoming/halana_kessig_ranger.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/CMR/halana_kessig_ranger.txt rename to forge-gui/res/cardsfolder/upcoming/halana_kessig_ranger.txt diff --git a/forge-gui/res/cardsfolder/upcoming/jeskas_will.txt b/forge-gui/res/cardsfolder/upcoming/jeskas_will.txt new file mode 100644 index 00000000000..a0db10c3677 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/jeskas_will.txt @@ -0,0 +1,14 @@ +Name:Jeska's Will +ManaCost:2 R +Types:Sorcery +A:SP$ Charm | Cost$ 2 R | MinCharmNum$ 1 | CharmNum$ X | References$ X,Y | Choices$ DBHandTarget,DBExile | AdditionalDescription$ If you control a commander as you cast this spell, you may choose both. +SVar:DBHandTarget:DB$ Pump | ValidTgts$ Opponent | SubAbility$ DBMana | SpellDescription$ Add {R} for each card in target opponent's hand. +SVar:DBMana:DB$ Mana | Produced$ R | Amount$ Z | References$ Z | StackDescription$ None +SVar:DBExile:DB$ Dig | Defined$ You | DigNum$ 3 | ChangeNum$ All | DestinationZone$ Exile | RememberChanged$ True | SubAbility$ DBEffect | SpellDescription$ Exile the top three cards of your library. You may play them this turn. +SVar:DBEffect:DB$ Effect | RememberObjects$ RememberedCard | StaticAbilities$ Play | SubAbility$ DBCleanup | ForgetOnMoved$ Exile +SVar:Play:Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsRemembered | AffectedZone$ Exile | Description$ You may play the exiled cards this turn. +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +SVar:X:Count$Compare Y GE1.2.1 +SVar:Y:Count$Valid Card.IsCommander+YouCtrl +SVar:Z:TargetedPlayer$CardsInHand +Oracle:Choose one. If you control a commander as you cast this spell, you may choose both.\n• Add {R} for each card in target opponent's hand.\n• Exile the top three cards of your library. You may play them this turn. diff --git a/forge-gui/res/cardsfolder/upcoming/jewelled_lotus.txt b/forge-gui/res/cardsfolder/upcoming/jewelled_lotus.txt new file mode 100644 index 00000000000..9bcd538f07e --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/jewelled_lotus.txt @@ -0,0 +1,7 @@ +Name:Jeweled Lotus +ManaCost:0 +Types:Artifact +A:AB$ Mana | Cost$ T Sac<1/CARDNAME> | Produced$ Any | Amount$ 3 | RestrictValid$ Spell.IsCommander | SpellDescription$ Add three mana of any one color. Spend this mana only to cast your commander. +DeckHas:Ability$Sacrifice +AI:RemoveDeck:NonCommander +Oracle:{​T}, Sacrifice Jeweled Lotus: Add three mana of any one color. Spend this mana only to cast your commander. diff --git a/forge-gui/res/cardsfolder/upcoming/kamahl_heart_of_krosa.txt b/forge-gui/res/cardsfolder/upcoming/kamahl_heart_of_krosa.txt new file mode 100644 index 00000000000..3a98ff5d966 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/kamahl_heart_of_krosa.txt @@ -0,0 +1,9 @@ +Name:Kamahl, Heart of Krosa +ManaCost:6 G G +Types:Legendary Creature Human Druid +PT:5/5 +T:Mode$ Phase | Phase$ BeginCombat | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigPumpAll | TriggerDescription$ At the beginning of combat on your turn, creatures you control get +3/+3 and gain trample until end of turn. +SVar:TrigPumpAll:DB$ PumpAll | ValidCards$ Creature.YouCtrl | NumAtt$ 3 | NumDef$ 3 | KW$ Trample +A:AB$ Animate | Cost$ 1 G | ValidTgts$ Land.YouCtrl | TgtPrompt$ Select target land you control | Power$ 1 | Toughness$ 1 | Types$ Elemental,Creature | Keywords$ Indestructible & Haste & Vigilance | SpellDescription$ Until end of turn, target land you control becomes a 1/1 creature with vigilance, indestructible, and haste. It's still a land. +K:Partner +Oracle:At the beginning of combat on your turn, creatures you control get +3/+3 and gain trample until end of turn.\n{1}{G}: Until end of turn, target land you control becomes a 1/1 Elemental creature with vigilance, indestructible, and haste. It's still a land.\nPartner (You can have two commanders if both have partner.) diff --git a/forge-gui/res/cardsfolder/upcoming/kamahls_will.txt b/forge-gui/res/cardsfolder/upcoming/kamahls_will.txt new file mode 100644 index 00000000000..66c61c251b1 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/kamahls_will.txt @@ -0,0 +1,14 @@ +Name:Kamahl's Will +ManaCost:3 G +Types:Instant +A:SP$ Charm | Cost$ 3 G | MinCharmNum$ 1 | CharmNum$ X | References$ X,Y | Choices$ DBAnimate,DBGangUp | AdditionalDescription$ If you control a commander as you cast this spell, you may choose both. +SVar:DBAnimate:DB$ Animate | ValidTgts$ Land.YouCtrl | TgtPrompt$ Select any number of target lands you control | TargetMin$ 0 | TargetMax$ MaxTargets | References$ MaxTargets | Power$ 1 | Toughness$ 1 | Types$ Elemental,Creature | Keywords$ Vigilance & Indestructible & Haste | SpellDescription$ Until end of turn, any number of target lands you control become 1/1 Elemental creatures with vigilance, indestructible, and haste. They're still lands. +SVar:DBGangUp:DB$ Pump | ValidTgts$ Creature.YouDontCtrl | TgtPrompt$ Choose target creature you don't control | ImprintCards$ Targeted | SubAbility$ DBRepeatEach +SVar:DBRepeatEach:DB$ RepeatEach | RepeatCards$ Creature.YouCtrl | RepeatSubAbility$ DBDamage | DamageMap$ True | SubAbility$ DBCleanup | SpellDescription$ Choose target creature you don’t control. Each creature you control deals damage equal to its power to that creature. +SVar:DBDamage:DB$ DealDamage | Defined$ Imprinted | DamageSource$ Remembered | NumDmg$ Z | References$ Z +SVar:DBCleanup:DB$ Cleanup | ClearImprinted$ True +SVar:X:Count$Compare Y GE1.2.1 +SVar:Y:Count$Valid Card.IsCommander+YouCtrl +SVar:Z:Remembered$CardPower +SVar:MaxTargets:Count$Valid Land.YouCtrl +Oracle:Choose one. If you control a commander as you cast this spell, you may choose both.\n• Until end of turn, any number of target lands you control become 1/1 Elemental creatures with vigilance, indestructible, and haste. They're still lands.\n• Choose target creature you don’t control. Each creature you control deals damage equal to its power to that creature. diff --git a/forge-gui/res/cardsfolder/upcoming/CMR/keeper_of_the_accord.txt b/forge-gui/res/cardsfolder/upcoming/keeper_of_the_accord.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/CMR/keeper_of_the_accord.txt rename to forge-gui/res/cardsfolder/upcoming/keeper_of_the_accord.txt diff --git a/forge-gui/res/cardsfolder/upcoming/keskit_the_flesh_sculptor.txt b/forge-gui/res/cardsfolder/upcoming/keskit_the_flesh_sculptor.txt new file mode 100644 index 00000000000..1738c661382 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/keskit_the_flesh_sculptor.txt @@ -0,0 +1,8 @@ +Name:Keskit, the Flesh Sculptor +ManaCost:2 B +Types:Legendary Creature Human Artificer +PT:1/3 +K:Partner +A:AB$ Dig | Cost$ T Sac<3/Artifact.Other;Creature.Other/other artifacts and/or creature> | DigNum$ 3 | ChangeNum$ 2 | DestinationZone2$ Graveyard | SpellDescription$ Look at the top three cards of your library. Put two of them into your hand and the other into your graveyard. +DeckHas:Ability$Sacrifice & Ability$Graveyard +Oracle:{T}, Sacrifice three other artifacts and/or creatures: Look at the top three cards of your library. Put two of them into your hand and the other into your graveyard.\nPartner (You can have two commanders if both have partner.) diff --git a/forge-gui/res/cardsfolder/upcoming/kodis_emberclaw_familiar.txt b/forge-gui/res/cardsfolder/upcoming/kodis_emberclaw_familiar.txt new file mode 100644 index 00000000000..d813b74c320 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/kodis_emberclaw_familiar.txt @@ -0,0 +1,11 @@ +Name:Kodis, Emberclaw Familiar +ManaCost:1 R +Types:Legendary Creature Elemental Lizard +PT:1/1 +T:Mode$ DamageDone | ValidSource$ Creature.IsCommander+YouCtrl | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigSlug | TriggerZones$ Battlefield | TriggerDescription$ Whenever a commander you control deals combat damage to an opponent, it deals that much damage to each other opponent. +SVar:TrigSlug:DB$ DamageAll | ValidPlayers$ OppNonTriggeredTarget | NumDmg$ X | References$ X | DamageSource$ TriggeredSource +SVar:X:TriggerCount$DamageAmount +K:Partner +SVar:BuffedBy:Card.IsCommander +AI:RemoveDeck:NonCommander +Oracle:Whenever a commander you control deals combat damage to an opponent, it deals that much damage to each other opponent.\nPartner (You can have two commanders if they both have partner.) diff --git a/forge-gui/res/cardsfolder/upcoming/krark_the_thumbless.txt b/forge-gui/res/cardsfolder/upcoming/krark_the_thumbless.txt new file mode 100644 index 00000000000..123177d7d4c --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/krark_the_thumbless.txt @@ -0,0 +1,11 @@ +Name:Krark, the Thumbless +ManaCost:1 R +Types:Legendary Creature Goblin Wizard +PT:2/2 +K:Partner +T:Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigFlip | TriggerDescription$ Whenever you cast an instant or sorcery spell, flip a coin. If you lose the flip, return that spell to its owner’s hand. If you win the flip, copy that spell, and you may choose new targets for the copy. +SVar:TrigFlip:DB$ FlipACoin | WinSubAbility$ DBCopy | LoseSubAbility$ DBBounce +SVar:DBBounce:DB$ ChangeZone | Defined$ TriggeredCard | Origin$ Stack | Destination$ Hand | Fizzle$ True +SVar:DBCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | AILogic$ Always +DeckNeeds:Type$Instant|Sorcery +Oracle:Whenever you cast an instant or sorcery spell, flip a coin. If you lose the flip, return that spell to its owner’s hand. If you win the flip, copy that spell, and you may choose new targets for the copy.\nPartner (You can have two commanders if both have partner.) diff --git a/forge-gui/res/cardsfolder/upcoming/maelstrom_colossus.txt b/forge-gui/res/cardsfolder/upcoming/maelstrom_colossus.txt new file mode 100644 index 00000000000..8d7e51b6b01 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/maelstrom_colossus.txt @@ -0,0 +1,6 @@ +Name:Maelstrom Colossus +ManaCost:8 +Types:Artifact Creature Golem +PT:7/7 +K:Cascade +Oracle:Cascade (When you cast this spell, exile cards from the top of your library until you exile a nonland card that costs less. You may cast it without paying its mana cost. Put the exiled cards on the bottom of your library in a random order.) diff --git a/forge-gui/res/cardsfolder/upcoming/magus_of_the_order.txt b/forge-gui/res/cardsfolder/upcoming/magus_of_the_order.txt new file mode 100755 index 00000000000..778256a2d9a --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/magus_of_the_order.txt @@ -0,0 +1,9 @@ +Name:Magus of the Order +ManaCost:2 G G +Types:Creature Human Wizard +PT:3/3 +A:AB$ ChangeZone | Cost$ G T Sac<1/CARDNAME> Sac<1/Creature.Green+Other/another green creature> | CostDesc$ {G}, {T}, Sacrifice Magus of the Order and another green creature: | Origin$ Library | Destination$ Battlefield | ChangeType$ Creature.Green | ChangeNum$ 1 | StackDescription$ {p:You} searches their library for a green creature card, puts it onto the battlefield, then shuffles their library. | SpellDescription$ Search your library for a green creature card, put it onto the battlefield, then shuffle your library. +SVar:AIPreference:SacCost$Creature.Green +DeckNeeds:Type$Creature +DeckHas:Ability$Sacrifice +Oracle:{G}, {T}, Sacrifice Magus of the Order and another green creature: Search your library for a green creature card, put it onto the battlefield, then shuffle your library. diff --git a/forge-gui/res/cardsfolder/upcoming/malcolm_keen-eyed_navigator.txt b/forge-gui/res/cardsfolder/upcoming/malcolm_keen-eyed_navigator.txt new file mode 100644 index 00000000000..ddd59fc8fb0 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/malcolm_keen-eyed_navigator.txt @@ -0,0 +1,12 @@ +Name:Malcolm, Keen-Eyed Navigator +ManaCost:2 U +Types:Legendary Creature Siren Pirate +PT:2/2 +K:Flying +K:Partner +T:Mode$ DamageAll | ValidSource$ Pirate.YouCtrl | ValidTarget$ Opponent | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ Whenever one or more Pirates you control deal damage to your opponents, you create a Treasure token for each opponent dealt damage. (It's an artifact with "{T}, Sacrifice this artifact: Add one mana of any color.") +SVar:TrigToken:DB$ Token | TokenAmount$ X | References$ X | TokenScript$ c_a_treasure_sac | TokenOwner$ You +SVar:X:TriggeredPlayersTargets$Amount +DeckHints:Type$Pirate +DeckHas:Ability$Token +Oracle:Flying\nWhenever one or more Pirates you control deal damage to your opponents, you create a Treasure token for each opponent dealt damage. (It's an artifact with "{T}, Sacrifice this artifact: Add one mana of any color.")\nPartner (You can have two commanders if both have partner.) diff --git a/forge-gui/res/cardsfolder/upcoming/merchant_raiders.txt b/forge-gui/res/cardsfolder/upcoming/merchant_raiders.txt new file mode 100755 index 00000000000..2de5dead70f --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/merchant_raiders.txt @@ -0,0 +1,11 @@ +Name:Merchant Raiders +ManaCost:3 U +Types:Creature Human Pirate +PT:2/4 +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigTap | TriggerDescription$ Whenever CARDNAME or another Pirate enters the battlefield under your control, tap up to one target creature. That creature doesn't untap during its controller's untap step for as long as you control CARDNAME. +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Pirate.Other+YouCtrl | Execute$ TrigTap | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another Pirate enters the battlefield under your control, tap up to one target creature. That creature doesn't untap during its controller's untap step for as long as you control CARDNAME. +SVar:TrigTap:DB$ Tap | ValidTgts$ Creature | TgtPrompt$ Select target creature | TargetMin$ 0 | TargetMax$ 1 | SubAbility$ DBPump +SVar:DBPump:DB$ Pump | Defined$ Targeted | KW$ HIDDEN CARDNAME doesn't untap during your untap step. | UntilLoseControlOfHost$ True +SVar:PlayMain1:TRUE +DeckHints:Type$Pirate +Oracle:Whenever Merchant Raiders or another Pirate enters the battlefield under your control, tap up to one target creature. That creature doesn't untap during its controller's untap step for as long as you control Merchant Raiders. diff --git a/forge-gui/res/cardsfolder/upcoming/meteoric_mace.txt b/forge-gui/res/cardsfolder/upcoming/meteoric_mace.txt new file mode 100644 index 00000000000..c09767c868d --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/meteoric_mace.txt @@ -0,0 +1,7 @@ +Name:Meteoric Mace +ManaCost:4 R R +Types:Artifact Equipment +K:Equip:4 +K:Cascade +S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddPower$ 4 | AddKeyword$ Trample | Description$ Equipped creature gets +4/+0 and has trample. +Oracle:Equipped creature gets +4/+0 and has trample.\nEquip {4}\nCascade (When you cast this spell, exile cards from the top of your library until you exile a nonland card that costs less. You may cast it without paying its mana cost. Put the exiled cards on the bottom of your library in a random order.) \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/upcoming/mnemonic_deluge.txt b/forge-gui/res/cardsfolder/upcoming/mnemonic_deluge.txt new file mode 100644 index 00000000000..09c7d7487ca --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/mnemonic_deluge.txt @@ -0,0 +1,9 @@ +Name:Mnemonic Deluge +ManaCost:6 U U U +Types:Sorcery +A:SP$ ChangeZone | Cost$ 6 U U U | ValidTgts$ Instant,Sorcery | TgtPrompt$ Select target instant or sorcery card in a graveyard | Origin$ Graveyard | Destination$ Exile | RememberChanged$ True | SubAbility$ DBPlay | SpellDescription$ Exile target instant or sorcery card from a graveyard. Copy that card three times. You may cast the copies without paying their mana cost. Exile CARDNAME. +SVar:DBPlay:DB$ Play | Defined$ Remembered | WithoutManaCost$ True | CopyCard$ True | Amount$ 3 | AllowRepeats$ True | Controller$ You | Optional$ True | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | SubAbility$ DBExile +SVar:DBExile:DB$ ChangeZone | Defined$ Self | Origin$ Stack | Destination$ Exile +DeckHints:Type$Instant|Sorcery +Oracle:Exile target instant or sorcery card from a graveyard. Copy that card three times. You may cast the copies without paying their mana cost. Exile Mnemonic Deluge. diff --git a/forge-gui/res/cardsfolder/upcoming/natural_reclamation.txt b/forge-gui/res/cardsfolder/upcoming/natural_reclamation.txt new file mode 100644 index 00000000000..7f1c3a90d32 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/natural_reclamation.txt @@ -0,0 +1,6 @@ +Name:Natural Reclamation +ManaCost:4 G +Types:Instant +K:Cascade +A:SP$ Destroy | Cost$ 4 G | ValidTgts$ Artifact,Enchantment | TgtPrompt$ Select target artifact or enchantment | SpellDescription$ Destroy target artifact or enchantment. +Oracle:Cascade (When you cast this spell, exile cards from the top of your library until you exile a nonland card that costs less. You may cast it without paying its mana cost. Put the exiled cards on the bottom of your library in a random order.)\nDestroy target artifact or enchantment. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/upcoming/nymris_oonas_trickster.txt b/forge-gui/res/cardsfolder/upcoming/nymris_oonas_trickster.txt new file mode 100644 index 00000000000..76bd783ca42 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/nymris_oonas_trickster.txt @@ -0,0 +1,10 @@ +Name:Nymris, Oona's Trickster +ManaCost:3 U B +Types:Legendary Creature Faerie Knight +PT:1/6 +K:Flash +K:Flying +T:Mode$ SpellCast | ValidCard$ Card | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | OpponentTurn$ True | ActivatorThisTurnCast$ EQ1 | NoResolvingCheck$ True | Execute$ TrigDig | TriggerDescription$ Whenever you cast your first spell during each opponent's turn, look at the top two cards of your library. Put one of those cards into your hand and the other into your graveyard. +SVar:TrigDig:DB$ Dig | DigNum$ 2 | ChangeNum$ 1 | DestinationZone2$ Graveyard +DeckHas:Ability$Graveyard +Oracle:Flash\nFlying\nWhenever you cast your first spell during each opponent's turn, look at the top two cards of your library. Put one of those cards into your hand and the other into your graveyard. diff --git a/forge-gui/res/cardsfolder/upcoming/profane_transfusion.txt b/forge-gui/res/cardsfolder/upcoming/profane_transfusion.txt new file mode 100755 index 00000000000..d2d09f49ece --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/profane_transfusion.txt @@ -0,0 +1,10 @@ +Name:Profane Transfusion +ManaCost:6 B B B +Types:Sorcery +A:SP$ ExchangeLife | Cost$ 6 B B B | TargetMin$ 2 | TargetMax$ 2 | ValidTgts$ Player | TgtPrompt$ Select target player | RememberDifference$ True | SubAbility$ DBToken | SpellDescription$ Two target players exchange life totals. You create an X/X colorless Horror artifact creature token, where X is the difference between those players' life totals. +SVar:DBToken:DB$ Token | TokenAmount$ 1 | TokenScript$ c_x_x_a_horror | TokenOwner$ You | TokenPower$ X | TokenToughness$ X | References$ X | SubAbility$ DBCleanup | StackDescription$ {p:You} creates an X/X colorless Horror artifact creature token, where X is the difference between those players' life totals. +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +SVar:X:Count$RememberedNumber/Abs +DeckHas:Ablity$Token +AI:RemoveDeck:All +Oracle:Two target players exchange life totals. You create an X/X colorless Horror artifact creature token, where X is the difference between those players' life totals. diff --git a/forge-gui/res/cardsfolder/upcoming/radiant_serra_archangel.txt b/forge-gui/res/cardsfolder/upcoming/radiant_serra_archangel.txt new file mode 100755 index 00000000000..f8064dfae48 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/radiant_serra_archangel.txt @@ -0,0 +1,10 @@ +Name:Radiant, Serra Archangel +ManaCost:6 W +Types:Legendary Creature Angel +PT:6/4 +K:Flying +K:Partner +A:AB$ Protection | Cost$ tapXType<1/Creature.untapped+withFlying+Other/another creature you control> | CostDesc$ Tap another untapped creature you control with flying: | Gains$ Choice | Choices$ AnyColor | SpellDescription$ CARDNAME gains protection from the color of your choice until end of turn. +SVar:BuffedBy:Creature.withFlying +DeckNeeds:Keyword$Flying +Oracle:Flying\nTap another untapped creature you control with flying: Radiant, Serra Archangel gains protection from the color of your choice until end of turn.\nPartner (You can have two commanders if they both have partner) diff --git a/forge-gui/res/cardsfolder/upcoming/CMR/rejuvenating_springs.txt b/forge-gui/res/cardsfolder/upcoming/rejuvenating_springs.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/CMR/rejuvenating_springs.txt rename to forge-gui/res/cardsfolder/upcoming/rejuvenating_springs.txt diff --git a/forge-gui/res/cardsfolder/upcoming/seraphic_greatsword.txt b/forge-gui/res/cardsfolder/upcoming/seraphic_greatsword.txt new file mode 100755 index 00000000000..ddd96460f34 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/seraphic_greatsword.txt @@ -0,0 +1,10 @@ +Name:Seraphic Greatsword +ManaCost:1 W +Types:Artifact Equipment +S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddPower$ 2 | AddToughness$ 2 | Description$ Equipped creature gets +2/+2. +T:Mode$ Attacks | ValidCard$ Card.AttachedBy | Attacked$ Player.withMostLife | Execute$ TrigToken | TriggerDescription$ Whenever equipped creature attacks the player with the most life or tied for most life, create a 4/4 white Angel creature token with flying that's tapped and attacking that player. +SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ w_4_4_angel_flying | TokenOwner$ You | TokenTapped$ True | TokenAttacking$ True +SVar:HasAttackEffect:TRUE +K:Equip:4 +DeckHas:Ability$Token +Oracle:Equipped creature gets +2/+2.\nWhenever equipped creature attacks the player with the most life or tied for most life, create a 4/4 white Angel creature token with flying that's tapped and attacking that player.\nEquip {4} diff --git a/forge-gui/res/cardsfolder/upcoming/siani_eye_of_the_storm.txt b/forge-gui/res/cardsfolder/upcoming/siani_eye_of_the_storm.txt new file mode 100644 index 00000000000..3db4176f4c3 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/siani_eye_of_the_storm.txt @@ -0,0 +1,11 @@ +Name:Siani, Eye of the Storm +ManaCost:3 U +Types:Legendary Creature Djinn Monk +PT:3/2 +K:Flying +K:Partner +T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigScry | TriggerDescription$ Whenever CARDNAME attacks, scry X, where X is the number of attacking creatures with flying. +SVar:TrigScry:DB$ Scry | ScryNum$ X | References$ X +SVar:X:Count$Valid Creature.attacking+withFlying +SVar:HasAttackEffect:TRUE +Oracle:Flying\nWhenever Siani, Eye of the Storm attacks, scry X, where X is the number of attacking creatures with flying.\nPartner (You can have two commanders if both have partner.) diff --git a/forge-gui/res/cardsfolder/upcoming/CMR/spectator_seating.txt b/forge-gui/res/cardsfolder/upcoming/spectator_seating.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/CMR/spectator_seating.txt rename to forge-gui/res/cardsfolder/upcoming/spectator_seating.txt diff --git a/forge-gui/res/cardsfolder/upcoming/szats_will.txt b/forge-gui/res/cardsfolder/upcoming/szats_will.txt new file mode 100644 index 00000000000..f2da6b6694b --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/szats_will.txt @@ -0,0 +1,15 @@ +Name:Szat's Will +ManaCost:4 B +Types:Instant +A:SP$ Charm | Cost$ 4 B | MinCharmNum$ 1 | CharmNum$ X | References$ X,Y | Choices$ DBOppSac,DBExile | AdditionalDescription$ If you control a commander as you cast this spell, you may choose both. +SVar:DBOppSac:DB$ RepeatEach | RepeatPlayers$ Player.Opponent | RepeatSubAbility$ DBChooseCard | SubAbility$ DBSac | SpellDescription$ Each opponent sacrifices a creature they control with the greatest power. +SVar:DBChooseCard:DB$ ChooseCard | Defined$ Player.IsRemembered | Choices$ Creature.greatestPowerControlledByRemembered | ChoiceTitle$ Choose a creature you control with the greatest power | Mandatory$ True | RememberChosen$ True +SVar:DBSac:DB$ SacrificeAll | ValidCards$ Card.IsRemembered | SubAbility$ DBCleanup | StackDescription$ None +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearChosenCard$ True +SVar:DBExile:DB$ ChangeZoneAll | ChangeType$ Card.OppCtrl | Origin$ Graveyard | Destination$ Exile | RememberChanged$ True | SubAbility$ DBToken | SpellDescription$ Exile all cards from all opponents' graveyards, then create X 0/1 black Thrull creature tokens, where X is the greatest power among creature cards exiled this way. +SVar:DBToken:DB$ Token | TokenScript$ b_0_1_thrull | TokenAmount$ Z | References$ Z | SubAbility$ DBCleanup +SVar:X:Count$Compare Y GE1.2.1 +SVar:Y:Count$Valid Card.IsCommander+YouCtrl +SVar:Z:Count$GreatestPowerExile_Creature.IsRemembered +DeckHas:Ability$Token +Oracle:Choose one. If you control a commander as you cast this spell, you may choose both.\n• Each opponent sacrifices a creature they control with the greatest power.\n• Exile all cards from all opponents' graveyards, then create X 0/1 black Thrull creature tokens, where X is the greatest power among creature cards exiled this way. diff --git a/forge-gui/res/cardsfolder/upcoming/tevesh_szat_doom_of_fools.txt b/forge-gui/res/cardsfolder/upcoming/tevesh_szat_doom_of_fools.txt new file mode 100644 index 00000000000..30c1adc8653 --- /dev/null +++ b/forge-gui/res/cardsfolder/upcoming/tevesh_szat_doom_of_fools.txt @@ -0,0 +1,15 @@ +Name:Tevesh Szat, Doom of Fools +ManaCost:4 B +Types:Legendary Planeswalker Szat +Loyalty:4 +Text:CARDNAME can be your commander. +K:Partner +A:AB$ Token | Cost$ AddCounter<2/LOYALTY> | Planeswalker$ True | TokenScript$ b_0_1_thrull | TokenAmount$ 2 | SpellDescription$ Create two 0/1 black Thrull creature tokens. +A:AB$ Sacrifice | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | SacValid$ Creature,Planeswalker | SacMessage$ creature or planeswalker | Optional$ True | RememberSacrificed$ True | SubAbility$ DBDraw | SpellDescription$ You may sacrifice another creature or planeswalker. If you do, draw two cards, then draw another card if the sacrificed permanent was a commander. +SVar:DBDraw:DB$ Draw | Defined$ You | NumCards$ 2 | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ GE1 | SubAbility$ DBDraw2 +SVar:DBDraw2:DB$ Draw | Defined$ You | NumCards$ 1 | ConditionDefined$ Remembered | ConditionPresent$ Card.IsCommander | ConditionCompare$ GE1 +A:AB$ GainControl | Cost$ SubCounter<10/LOYALTY> | Planeswalker$ True | Ultimate$ True | AllValid$ Card.IsCommander | NewController$ You | SubAbility$ DBChangeZone | SpellDescription$ Gain control of all commanders. Put all commanders from the commander zone onto the battlefield under your control. +SVar:DBChangeZone:DB$ ChangeZoneAll | ValidCards$ Card.IsCommander | Origin$ Command | Destination$ Battlefield | GainControl$ True +DeckHas:Ability$Token & Ability$Sacrifice +SVar:AIPreference:SacCost$Creature.token+powerLE2+toughnessLE2 +Oracle:[+2]: Create two 0/1 black Thrull creature tokens.\n[+1]: You may sacrifice a creature or planeswalker. If you do, draw two cards, then draw an additional card if the sacrificed permanent was a commander.\n[-10]: Gain control of all commanders, then put all commanders from the command zone onto the battlefield under your control.\nTevesh Szat, Doom of Fools can be your commander.\nPartner diff --git a/forge-gui/res/cardsfolder/upcoming/CMR/training_center.txt b/forge-gui/res/cardsfolder/upcoming/training_center.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/CMR/training_center.txt rename to forge-gui/res/cardsfolder/upcoming/training_center.txt diff --git a/forge-gui/res/cardsfolder/upcoming/CMR/undergrowth_stadium.txt b/forge-gui/res/cardsfolder/upcoming/undergrowth_stadium.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/CMR/undergrowth_stadium.txt rename to forge-gui/res/cardsfolder/upcoming/undergrowth_stadium.txt diff --git a/forge-gui/res/cardsfolder/upcoming/CMR/vault_of_champions.txt b/forge-gui/res/cardsfolder/upcoming/vault_of_champions.txt similarity index 100% rename from forge-gui/res/cardsfolder/upcoming/CMR/vault_of_champions.txt rename to forge-gui/res/cardsfolder/upcoming/vault_of_champions.txt diff --git a/forge-gui/res/cardsfolder/v/vindictive_lich.txt b/forge-gui/res/cardsfolder/v/vindictive_lich.txt index e8c91bbf45c..d0263f62754 100644 --- a/forge-gui/res/cardsfolder/v/vindictive_lich.txt +++ b/forge-gui/res/cardsfolder/v/vindictive_lich.txt @@ -3,7 +3,7 @@ ManaCost:3 B Types:Creature Zombie Wizard PT:4/1 T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigCharm | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME dies, ABILITY -SVar:TrigCharm:DB$ Charm | MinCharmNum$ 1 | CharmNum$ MaxUniqueOpponents | Choices$ SacCreature,DiscardCards,LoseLife | References$ MaxUniqueOpponents | AdditionalDescription$ Each mode must target a different player. +SVar:TrigCharm:DB$ Charm | MinCharmNum$ 1 | CharmNum$ MaxUniqueOpponents | Choices$ SacCreature,DiscardCards,LoseLife | References$ MaxUniqueOpponents | AdditionalDescription$ or more. Each mode must target a different player. SVar:SacCreature:DB$ Sacrifice | ValidTgts$ Opponent | TargetUnique$ True | SacValid$ Creature | SacMessage$ Creature | SpellDescription$ Target opponent sacrifices a creature. SVar:DiscardCards:DB$ Discard | ValidTgts$ Opponent | TargetUnique$ True | NumCards$ 2 | Mode$ TgtChoose | SpellDescription$ Target opponent discards two cards. SVar:LoseLife:DB$ LoseLife | ValidTgts$ Opponent | TargetUnique$ True | LifeAmount$ 5 | SpellDescription$ Target opponent loses 5 life. diff --git a/forge-gui/res/conquest/planes/Zendikar/sets.txt b/forge-gui/res/conquest/planes/Zendikar/sets.txt index 9103dfff24b..010248bcdef 100644 --- a/forge-gui/res/conquest/planes/Zendikar/sets.txt +++ b/forge-gui/res/conquest/planes/Zendikar/sets.txt @@ -3,4 +3,5 @@ WWK ROE BFZ OGW -C16 \ No newline at end of file +C16 +ZNR diff --git a/forge-gui/res/conquest/planes/planes.txt b/forge-gui/res/conquest/planes/planes.txt index 96512b6e89c..7dab9f26030 100644 --- a/forge-gui/res/conquest/planes/planes.txt +++ b/forge-gui/res/conquest/planes/planes.txt @@ -16,4 +16,4 @@ Name:Tarkir|RegionSize:9|Desc:A plane dominated by five powerful clans... or fiv Name:Theros|RegionSize:9|Desc:Mortals tremble before an awe-inspiring pantheon of gods.\nConsists of 45 events. Contains cards from THS, BNG, JOU, HOP, PCA, THB, and more. Name:Time_Vault|RegionSize:6|Unreachable:True|Desc:A mysterious and legendary Time Vault, allowing one to travel back in time and revisit the ages long past and challenge the legends of Dominaria.\nConsists of 12 events. Contains cards from the early core sets up to 9th edition, Dominaria-themed expansions (Ice Age, Mirage, Urza's Saga, Invasion, Odyssey, Onslaught, and Time Spiral blocks), the original Commander, and Modern Horizons.\n\nThe portal to this plane is unstable and will close soon, so hasten your step, planeswalker, while you have the chance... Name:Ulgrotha|RegionSize:6|Unreachable:True|Desc: -Name:Zendikar|RegionSize:9|Desc:This land of primal mana was lethal even before its Eldrazi prisoners escaped.\nConsists of 60 events. Contains cards from ZEN, WWK, ROE, BFZ, OGW, and C16. +Name:Zendikar|RegionSize:9|Desc:This land of primal mana was lethal even before its Eldrazi prisoners escaped.\nConsists of 60 events. Contains cards from ZEN, WWK, ROE, BFZ, OGW, C16, and ZNR. diff --git a/forge-gui/res/cube/MTGA Cube 2020 April.dck b/forge-gui/res/cube/MTGA Cube 2020 April.dck new file mode 100644 index 00000000000..2dcab70784b --- /dev/null +++ b/forge-gui/res/cube/MTGA Cube 2020 April.dck @@ -0,0 +1,558 @@ +[metadata] +Name=MTGA Cube 2020 April +[main] +1 Adanto Vanguard|XLN +1 Admiral's Order|RIX +1 Agent of Treachery|M20 +1 Agonizing Remorse|THB +1 Ajani's Pridemate|WAR +1 Ajani, Strength of the Pride|M20 +1 Ajani, the Greathearted|WAR +1 Alirios, Enraptured|THB +1 All That Glitters|ELD +1 Alseid of Life's Bounty|THB +1 Anax, Hardened in the Forge|THB +1 Angrath's Rampage|WAR +1 Angrath, Captain of Chaos|WAR +1 Animating Faerie|ELD +1 Anticipate|IKO +1 Aphemia, the Cacophony|THB +1 Arasta of the Endless Web|THB +1 Arcane Encyclopedia|M19 +1 Arcanist's Owl|ELD +1 Arch of Orazca|RIX +1 Archon of Sun's Grace|THB +1 Ardenvale Tactician|ELD +1 Arguel's Blood Fast|XLN +1 Arrester's Zeal|RNA +1 Aryel, Knight of Windgrace|DOM +1 Ashiok, Dream Render|WAR +1 Ashiok, Nightmare Muse|THB +1 Assassin's Trophy|GRN +1 Atris, Oracle of Half-Truths|THB +1 Audacious Thief|M20 +1 Augur of Bolas|WAR +1 Aurelia, Exemplar of Justice|GRN +1 Baffling End|RIX +1 Bake into a Pie|ELD +1 Banefire|M19 +1 Banishing Light|THB +1 Barkhide Troll|M20 +1 Barren Moor|MH1 +1 Beanstalk Giant|ELD +1 Beast Whisperer|GRN +1 Benthic Biomancer|RNA +1 Biogenic Ooze|RNA +1 Blackblade Reforged|DOM +1 Blacklance Paragon|ELD +1 Blade Juggler|RNA +1 Blast Zone|WAR +1 Blink of an Eye|DOM +1 Blood Aspirant|THB +1 Blood Crypt|RNA +1 Blood Divination|M19 +1 Blood for Bones|M20 +1 Bloodfell Caves|M21 +1 Bloom Hulk|WAR +1 Blossoming Sands|M21 +1 Board the Weatherlight|DOM +1 Bolas's Citadel|WAR +1 Bond of Insight|WAR +1 Bonecrusher Giant|ELD +1 Brain Maggot|JOU +1 Brazen Borrower|ELD +1 Breeding Pool|RNA +1 Brineborn Cutthroat|M20 +1 Burning-Tree Emissary|MM3 +1 Captain Lannery Storm|XLN +1 Captain Sisay|INV +1 Captivating Crew|XLN +1 Careless Celebrant|THB +1 Cast Down|2XM +1 Castle Ardenvale|ELD +1 Castle Embereth|ELD +1 Castle Garenbrig|ELD +1 Castle Locthwain|ELD +1 Castle Vantress|ELD +1 Casualties of War|WAR +1 Cauldron Familiar|ELD +1 Cauldron's Gift|ELD +1 Cavalcade of Calamity|RNA +1 Cavalier of Dawn|M20 +1 Cavalier of Flame|M20 +1 Cavalier of Night|M20 +1 Cavalier of Thorns|M20 +1 Cavalry Drillmaster|M19 +1 Chainweb Aracnir|THB +1 Chandra's Pyrohelix|WAR +1 Chandra, Acolyte of Flame|M20 +1 Chandra, Awakened Inferno|M20 +1 Charging Monstrosaur|XLN +1 Charming Prince|ELD +1 Chart a Course|XLN +1 Chemister's Insight|GRN +1 Chromatic Lantern|GRN +1 Clifftop Retreat|DOM +1 Clockwork Servant|ELD +1 Cloudkin Seer|M20 +1 Colossal Majesty|M19 +1 Command the Dreadhorde|WAR +1 Commence the Endgame|WAR +1 Conclave Tribunal|GRN +1 Corpse Knight|M20 +1 Crash Through|AKR +1 Crucible of Worlds|M19 +1 Cryptbreaker|EMN +1 Cryptic Caves|M20 +1 Curious Obsession|RIX +1 Dalakos, Crafter of Wonders|THB +1 Dark-Dweller Oracle|M19 +1 Dauntless Bodyguard|DOM +1 Daxos, Blessed by the Sun|THB +1 Dead Weight|IKO +1 Deeproot Champion|XLN +1 Demonlord Belzenlok|DOM +1 Depose // Deploy|RNA +1 Despark|WAR +1 Destiny Spinner|THB +1 Didn't Say Please|ELD +1 Dire Fleet Daredevil|RIX +1 Diregraf Ghoul|M19 +1 Disdainful Stroke|GRN +1 Disenchant|ZNR +1 Disfigure|M20 +1 Dismal Backwater|M21 +1 Dive Down|XLN +1 Divine Visitation|GRN +1 Domri, Anarch of Bolas|WAR +1 Doom Whisperer|GRN +1 Dragonmaster Outcast|BFZ +1 Dragonskull Summit|XLN +1 Drakuseth, Maw of Flames|M20 +1 Dread Presence|M20 +1 Dreadhorde Butcher|WAR +1 Dreadhorde Invasion|WAR +1 Dream Trawler|THB +1 Dreamstalker Manticore|THB +1 Drill Bit|RNA +1 Drowned Catacomb|XLN +1 Dryad Greenseeker|M19 +1 Dryad of the Ilysian Grove|THB +1 Dungeon Geists|M20 +1 Duress|M21 +1 Dusk Legion Zealot|A25 +1 Eat to Extinction|THB +1 Electrodominance|RNA +1 Elspeth Conquers Death|THB +1 Elspeth's Nightmare|THB +1 Elspeth, Sun's Nemesis|THB +1 Elvish Reclaimer|M20 +1 Elvish Rejuvenator|M19 +1 Elvish Visionary|ORI +1 Ember Hauler|M20 +1 Embercleave|ELD +1 Embereth Shieldbreaker|ELD +1 Embodiment of Agonies|M20 +1 Empyrean Eagle|M20 +1 Emry, Lurker of the Loch|ELD +1 End-Raze Forerunners|RNA +1 Enter the God-Eternals|WAR +1 Entrancing Lyre|THB +1 Entrancing Melody|XLN +1 Erebos's Intervention|THB +1 Erebos, Bleak-Hearted|THB +1 Eternal Taskmaster|WAR +1 Ethereal Absolution|RNA +1 Evolution Sage|WAR +1 Evolving Wilds|AKR +1 Exclusion Mage|M19 +1 Expansion // Explosion|GRN +1 Experimental Frenzy|GRN +1 Fabled Passage|M21 +1 Fae of Wishes|ELD +1 Faeburrow Elder|ELD +1 Faerie Formation +1 Faerie Guidemother|ELD +1 Fanatical Firebrand|RIX +1 Fauna Shaman|UMA +1 Favorable Winds|XLN +1 Fblthp, the Lost|WAR +1 Field of Ruin|THB +1 Field of the Dead|M20 +1 Fiery Cannonade|XLN +1 Fight with Fire|DOM +1 Finale of Devastation|WAR +1 Finale of Eternity|WAR +1 Finale of Glory|WAR +1 Find // Finality|GRN +1 Firemind Vessel|WAR +1 Fires of Invention|ELD +1 Flame Sweep|M20 +1 Flaxen Intruder|ELD +1 Fling|ELD +1 Flood of Tears|M20 +1 Folio of Fancies|ELD +1 Foreboding Fruit|ELD +1 Forgotten Cave|MH1 +1 Foulmire Knight|ELD +1 Fountain of Renewal|M19 +1 Frilled Sandwalla|HOU +1 Furious Rise|M21 +1 Gallia of the Endless Dance|THB +1 Garruk, Cursed Huntsman|ELD +1 Ghalta, Primal Hunger|RIX +1 Ghitu Lavarunner|DOM +1 Giant Growth|WAR +1 Giant Killer|ELD +1 Gideon Blackblade|WAR +1 Gilded Goose|ELD +1 Gilded Lotus|DOM +1 Gingerbrute|ELD +1 Glacial Fortress|XLN +1 Glass Casket|ELD +1 Gleaming Barrier|2XM +1 Goblin Banneret|GRN +1 Goblin Cratermaker|GRN +1 Goblin Electromancer|GRN +1 Goblin Instigator|M19 +1 Goblin Motivator|M19 +1 Goblin Ruinblaster|ZEN +1 Goblin Trashmaster|M19 +1 God-Eternal Bontu|WAR +1 God-Eternal Kefnet|WAR +1 God-Eternal Oketra|WAR +1 Godless Shrine|RNA +1 Gods Willing|M20 +1 Golden Demise|RIX +1 Golden Egg|ELD +1 Golos, Tireless Pilgrim|M20 +1 Goreclaw, Terror of Qal Sisma|M19 +1 Graveyard Marshal|M19 +1 Gray Merchant of Asphodel|THB +1 Grim Initiate|WAR +1 Grow from the Ashes|DOM +1 Growth Spiral|RNA +1 Gruul Spellbreaker|RNA +1 Guild Globe|WAR +1 Gutterbones|RNA +1 Guttersnipe|M19 +1 Hallowed Fountain|RNA +1 Hanged Executioner|M20 +1 Harmonious Archon|ELD +1 Heliod, Sun-Crowned|THB +1 Helm of the Host|DOM +1 Heraldic Banner|ELD +1 Hinterland Harbor|DOM +1 History of Benalia|DOM +1 Hostage Taker|XLN +1 Huatli, Warrior Poet|XLN +1 Hunted Witness|GRN +1 Hydroid Krasis|RNA +1 Hypnotic Specter|M10 +1 Hypnotic Sprite|ELD +1 Icy Manipulator|DOM +1 Ilharg, the Raze-Boar|WAR +1 Ilysian Caryatid|THB +1 Imperial Aerosaur|XLN +1 Imperious Perfect|EMA +1 In Bolas's Clutches|DOM +1 Incubation Druid|RNA +1 Inevitable End|THB +1 Into the Story|ELD +1 Ionize|GRN +1 Isareth the Awakener|M19 +1 Isolated Chapel|DOM +1 Jadelight Ranger|RIX +1 Jaya's Greeting|WAR +1 Jaya's Immolating Inferno|DOM +1 Jhoira, Weatherlight Captain|2XM +1 Josu Vess, Lich Knight|DOM +1 Judith, the Scourge Diva|RNA +1 Juggernaut|DOM +1 Jungle Hollow|M21 +1 Karn's Bastion|WAR +1 Karn's Temporal Sundering|DOM +1 Karn, Scion of Urza|DOM +1 Keeper of Fables|ELD +1 Kenrith's Transformation|ELD +1 Kiln Fiend|IMA +1 Kinjalli's Sunwing|XLN +1 Kiora Bests the Sea God|THB +1 Kiora, Behemoth Beckoner|WAR +1 Kitesail Freebooter|M21 +1 Klothys, God of Destiny|THB +1 Knight of Autumn|GRN +1 Knight of Grace|DOM +1 Knight of Malice|DOM +1 Knight of the Ebon Legion|M20 +1 Kraul Harpooner|GRN +1 Kronch Wrangler|WAR +1 Kroxa, Titan of Death's Hunger|THB +1 Kunoros, Hound of Athreos|THB +1 Labyrinth of Skophos|THB +1 Lava Coil|GRN +1 Law-Rune Enforcer|WAR +1 Lazav, the Multifarious|GRN +1 Leafkin Druid|M20 +1 Legion Warboss|GRN +1 Legion's Landing|XLN +1 Leonin of the Lost Pride|THB +1 Leonin Vanguard|M19 +1 Leonin Warleader|M19 +1 Light Up the Stage|RNA +1 Lightning Strike|M19 +1 Liliana, Dreadhorde General|WAR +1 Llanowar Elves|DOM +1 Lonely Sandbar|MH1 +1 Lotleth Giant|GRN +1 Lotus Field|M20 +1 Lovestruck Beast|ELD +1 Loyal Pegasus|M20 +1 Lyra Dawnbringer|DOM +1 Mace of the Valiant +1 Manifold Key|M20 +1 Mantle of the Wolf|THB +1 Massacre Girl|WAR +1 Mastermind's Acquisition|RIX +1 Medomai's Prophecy|THB +1 Mentor of the Meek|M19 +1 Merfolk Secretkeeper|ELD +1 Merfolk Trickster|DOM +1 Midnight Clock|ELD +1 Midnight Reaper|GRN +1 Militia Bugler|M19 +1 Mind Stone|IMA +1 Ministrant of Obligation|RNA +1 Mire's Grasp|THB +1 Mist-Cloaked Herald|RIX +1 Mortify|RNA +1 Mox Amber|DOM +1 Murder|M20 +1 Murderous Rider|ELD +1 Murmuring Mystic|GRN +1 Nadir Kraken|THB +1 Negate|ZNR +1 Nessian Hornbeetle|THB +1 Nessian Wanderer|THB +1 Nightmare Shepherd|THB +1 Nightmare's Thirst|M19 +1 Niv-Mizzet Reborn|WAR +1 Nylea, Keen-Eyed|THB +1 Nyx Lotus|THB +1 Nyxbloom Ancient|THB +1 Oathsworn Knight|ELD +1 Omenspeaker|M19 +1 Once and Future|ELD +1 Once Upon a Time|ELD +1 Opt|M21 +1 Order of Midnight|ELD +1 Orzhov Enforcer|RNA +1 Outlaws' Merriment|ELD +1 Overgrown Tomb|GRN +1 Ox of Agonas|THB +1 Pacifism|IKO +1 Paradise Druid|WAR +1 Patient Rebuilding|M19 +1 Pelt Collector|GRN +1 Phoenix of Ash|THB +1 Phyrexian Arena|CN2 +1 Piper of the Swarm|ELD +1 Plaguecrafter|GRN +1 Planar Cleansing|M20 +1 Planewide Celebration|WAR +1 Platinum Angel|MPS_KLD +1 Polukranos, Unchained|THB +1 Portal of Sanctuary|M20 +1 Prey Upon|UMA +1 Priest of Forgotten Gods|RNA +1 Prime Speaker Vannifar|RNA +1 Prison Realm|WAR +1 Psychic Corrosion|M19 +1 Pteramander|RNA +1 Purphoros's Intervention|THB +1 Quench|RNA +1 Questing Beast|ELD +1 Rabid Bite|ZNR +1 Ral, Izzet Viceroy|GRN +1 Rampaging Ferocidon|XLN +1 Rankle, Master of Pranks|ELD +1 Realm-Cloaked Giant|ELD +1 Reclamation Sage|2XM +1 Rekindling Phoenix|RIX +1 Relentless Pursuit|THB +1 Relentless Raptor|RIX +1 Remorseful Cleric|M19 +1 Resplendent Angel|M19 +1 Response // Resurgence|GRN +1 Return to Nature|M21 +1 Revoke Existence|2XM +1 Rhys the Redeemed|2XM +1 Rigging Runner|XLN +1 Rimrock Knight|ELD +1 Risen Reef|M20 +1 Risk Factor|GRN +1 Roalesk, Apex Hybrid|WAR +1 Robber of the Rich|ELD +1 Rootbound Crag|XLN +1 Rotting Regisaur|M20 +1 Rugged Highlands|M21 +1 Ruin Raider|XLN +1 Rupture Spire|M19 +1 Sacred Foundry|GRN +1 Saheeli, Sublime Artificer|WAR +1 Sai, Master Thopterist|M19 +1 Saproling Migration|DOM +1 Sarkhan the Masterless|WAR +1 Savage Stomp|XLN +1 Savvy Hunter|ELD +1 Scorch Spitter|M20 +1 Scorching Dragonfire|M21 +1 Scoured Barrens|M21 +1 Seal Away|DOM +1 Search for Azcanta|XLN +1 Season of Growth|M20 +1 Secluded Steppe|MH1 +1 Sentinel's Eyes|THB +1 Sentinel's Mark|RNA +1 Seraph of the Scales|RNA +1 Setessan Champion|THB +1 Settle the Wreckage|XLN +1 Shadowspear|THB +1 Shanna, Sisay's Legacy|DOM +1 Shatter the Sky|THB +1 Shepherd of the Flock|ELD +1 Shivan Fire|DOM +1 Shock|M21 +1 Siege-Gang Commander|DOM +1 Sigil of the Empty Throne|ORI +1 Sigiled Sword of Valeron|M19 +1 Silverbeak Griffin +1 Sinister Sabotage|GRN +1 Siren Stormtamer|XLN +1 Skarrgan Hellkite|RNA +1 Skewer the Critics|RNA +1 Skilled Animator|M19 +1 Sky Terror|XLN +1 Skymarcher Aspirant|RIX +1 Slaying Fire|ELD +1 Soul Warden|MM3 +1 Spark Double|WAR +1 Spark Harvest|WAR +1 Sparring Construct|DOM +1 Spawn of Mayhem|RNA +1 Spectral Sailor|M20 +1 Spell Pierce|XLN +1 Sprouting Renewal|GRN +1 Squee, the Immortal|DOM +1 Staggering Insight|THB +1 Starfield Mystic|M20 +1 Starlit Mantle|THB +1 Steam Vents|GRN +1 Steel Overseer|M20 +1 Stolen by the Fae|ELD +1 Stomping Ground|RNA +1 Stonecoil Serpent|ELD +1 Storm Fleet Aerialist|XLN +1 Storm's Wrath|THB +1 Stormfist Crusader|ELD +1 Sulfur Falls|DOM +1 Summary Judgment|RNA +1 Sunhome Stalwart|GRN +1 Sunpetal Grove|XLN +1 Swiftwater Cliffs|M21 +1 Sword-Point Diplomacy|XLN +1 Syr Faren, the Hengehammer|ELD +1 Tajic, Legion's Edge|GRN +1 Talrand, Sky Summoner|M13 +1 Taranika, Akroan Veteran|THB +1 Taste of Death +1 Tectonic Giant|THB +1 Teferi, Hero of Dominaria|DOM +1 Temple Garden|GRN +1 Temple of Abandon|THB +1 Temple of Deceit|THB +1 Temple of Enlightenment|THB +1 Temple of Epiphany|M21 +1 Temple of Malady|M21 +1 Temple of Malice|THB +1 Temple of Mystery|M21 +1 Temple of Plenty|THB +1 Temple of Silence|M21 +1 Temple of Triumph|M21 +1 Tendershoot Dryad|RIX +1 Tetsuko Umezawa, Fugitive|DOM +1 Tezzeret, Artifice Master|M19 +1 Thalia, Guardian of Thraben|A25 +1 Thassa's Intervention|THB +1 Thassa's Oracle|THB +1 Thassa, Deep-Dwelling|THB +1 The Akroan War|THB +1 The Birth of Meletis|THB +1 The Circle of Loyalty|ELD +1 The Eldest Reborn|DOM +1 The First Iroan Games|THB +1 The Great Henge|ELD +1 The Immortal Sun|RIX +1 The Mending of Dominaria|DOM +1 The Mirari Conjecture|DOM +1 Theater of Horrors|RNA +1 Thirst for Meaning|THB +1 Thorn Lieutenant|M19 +1 Thorn Mammoth +1 Thornwood Falls|M21 +1 Thought Erasure|GRN +1 Thrash // Threat|RNA +1 Thrashing Brontodon|M21 +1 Threnody Singer|THB +1 Thryx, the Sudden Storm|THB +1 Tibalt, Rakish Instigator|WAR +1 Time Wipe|WAR +1 Tin Street Dodger|RNA +1 Tolsimir, Friend to Wolves|WAR +1 Tomik, Distinguished Advokist|WAR +1 Tranquil Cove|M21 +1 Tranquil Thicket|MH1 +1 Trapped in the Tower|ELD +1 Traveler's Amulet|THB +1 Traxos, Scourge of Kroog|DOM +1 Treasure Map|XLN +1 Tymaret, Chosen from Death|THB +1 Ugin, the Ineffable|WAR +1 Unbreakable Formation|RNA +1 Underworld Rage-Hound|THB +1 Unsummon|M20 +1 Untamed Kavu|DOM +1 Uro, Titan of Nature's Wrath|THB +1 Vantress Gargoyle|ELD +1 Venerable Knight|ELD +1 Venerated Loxodon|GRN +1 Verix Bladewing|DOM +1 Viashino Pyromancer|M19 +1 Vivien's Arkbow|WAR +1 Vivien, Arkbow Ranger|M20 +1 Voltaic Servant|DOM +1 Voracious Hydra|M20 +1 Vraska, Golgari Queen|GRN +1 Warbriar Blessing|THB +1 Warkite Marauder|RIX +1 Warlord's Fury|DOM +1 Watery Grave|GRN +1 Wavebreak Hippocamp|THB +1 Wayward Swordtooth|RIX +1 Weaselback Redcap|ELD +1 Weatherlight|DOM +1 Wilderness Reclamation|RNA +1 Wildwood Tracker|ELD +1 Wind-Scarred Crag|M21 +1 Winged Words|M20 +1 Witch's Oven|ELD +1 Witch's Vengeance|ELD +1 Witching Well|ELD +1 Woe Strider|THB +1 Wolfwillow Haven|THB +1 Woodland Cemetery|DOM +1 Woodland Champion|2XM +1 Yawgmoth's Vile Offering|DOM +1 Zetalpa, Primal Dawn|RIX +1 Zhalfirin Void|DOM +1 Zhur-Taa Goblin|RNA diff --git a/forge-gui/res/cube/MTGO Vintage Cube April 2020.dck b/forge-gui/res/cube/MTGO Vintage Cube April 2020.dck new file mode 100644 index 00000000000..303fe079b48 --- /dev/null +++ b/forge-gui/res/cube/MTGO Vintage Cube April 2020.dck @@ -0,0 +1,543 @@ +[metadata] +Name=MTGO Vintage Cube April 2020 +[main] +1 Kytheon, Hero of Akros|ORI +1 Mother of Runes|EMA +1 Student of Warfare|ROE +1 Adanto Vanguard|XLN +1 Containment Priest|M21 +1 Leonin Relic-Warder|C17 +1 Porcelain Legionnaire|NPH +1 Selfless Spirit|EMN +1 Soulfire Grand Master|FRF +1 Stoneforge Mystic|2XM +1 Thalia, Guardian of Thraben|A25 +1 Tithe Taker|RNA +1 Wall of Omens|EMA +1 Blade Splicer|2XM +1 Brightling +1 Brimaz, King of Oreskos|BNG +1 Fairgrounds Warden|KLD +1 Flickerwisp|2XM +1 Monastery Mentor|FRF +1 Recruiter of the Guard|CN2 +1 Silverblade Paladin|AVR +1 Emeria Angel|IMA +1 Hero of Bladehold|MBS +1 Linvala, Keeper of Silence|MM3 +1 Restoration Angel|IMA +1 Angel of Invention|KLD +1 Elspeth Conquers Death|THB +1 Archangel Avacyn|SOI +1 Baneslayer Angel|M21 +1 Lyra Dawnbringer|DOM +1 Reveillark|UMA +1 Sun Titan|M12 +1 Angel of Serenity|RTR +1 Elesh Norn, Grand Cenobite|IMA +1 Iona, Shield of Emeria|MM2 +1 Gideon Blackblade|WAR +1 Elspeth, Sun's Nemesis|THB +1 Gideon, Ally of Zendikar|BFZ +1 Gideon Jura|M12 +1 Elspeth, Sun's Champion|THS +1 Condemn|M11 +1 Enlightened Tutor|EMA +1 Mana Tithe|PLC +1 Path to Exile|2XM +1 Swords to Plowshares|A25 +1 Disenchant|ZNR +1 Unexpectedly Absent|EMA +1 Balance|EMA +1 Council's Judgment|2XM +1 Spectral Procession|MM2 +1 Armageddon|A25 +1 Day of Judgment|M12 +1 Ravages of War|PTK +1 Wrath of God|AKR +1 Terminus|MM3 +1 Land Tax|2XM +1 Legion's Landing|XLN +1 Honor of the Pure|M12 +1 Banishing Light|THB +1 Oblivion Ring|MM2 +1 Faith's Fetters|M21 +1 Moat|LEG +1 Parallax Wave|VMA +1 Spear of Heliod|THS +1 Karakas|UMA +1 Thassa's Oracle|THB +1 Baral, Chief of Compliance|AER +1 Jace, Vryn's Prodigy|ORI +1 Looter il-Kor|TSP +1 Phantasmal Image|MM3 +1 Snapcaster Mage|UMA +1 Thing in the Ice|SOI +1 Arcane Artisan +1 Deceiver Exarch|CN2 +1 Pestermite|MMA +1 Spellseeker +1 Trinket Mage|SOM +1 Vendilion Clique|A25 +1 Glen Elendra Archmage|UMA +1 Phyrexian Metamorph|2XM +1 Sower of Temptation|LRW +1 Venser, Shaper Savant|MM3 +1 Mulldrifter|MM2 +1 Riftwing Cloudskate|MMA +1 Consecrated Sphinx|IMA +1 Frost Titan|M12 +1 Torrential Gearhulk|MPS_KLD +1 Palinchron|VMA +1 Inkwell Leviathan|2XM +1 Jace Beleren|M11 +1 Jace, the Mind Sculptor|VMA +1 Tezzeret the Seeker|MM2 +1 Ancestral Recall|VMA +1 Brainstorm|2XM +1 High Tide|VMA +1 Mystical Tutor|EMA +1 Spell Pierce|XLN +1 Brain Freeze|VMA +1 Counterspell|A25 +1 Daze|MPS_AKH +1 Impulse|VIS +1 Mana Drain|IMA +1 Mana Leak|IMA +1 Miscalculation|ULG +1 Remand|MM2 +1 Frantic Search|UMA +1 Thirst for Knowledge|2XM +1 Cryptic Command|IMA +1 Fact or Fiction|MH1 +1 Gifts Ungiven|MM3 +1 Turnabout|VMA +1 Force of Will|2XM +1 Gush|VMA +1 Mystic Confluence|C15 +1 Repeal|IMA +1 Dig Through Time|UMA +1 Ancestral Vision|IMA +1 Gitaxian Probe|NPH +1 Ponder|M12 +1 Preordain|M11 +1 Chart a Course|XLN +1 Time Walk|VMA +1 Show and Tell|CN2 +1 Timetwister|VMA +1 Tinker|ULG +1 Bribery|8ED +1 Time Warp|TPR +1 Mind's Desire|SCG +1 Time Spiral|USG +1 Upheaval|VMA +1 Treasure Cruise|UMA +1 Search for Azcanta|XLN +1 Control Magic|EMA +1 Opposition|MPS_AKH +1 Treachery|UDS +1 Shelldock Isle|LRW +1 Tolarian Academy|VMA +1 Putrid Imp|VMA +1 Dark Confidant|2XM +1 Kitesail Freebooter|M21 +1 Mesmeric Fiend|A25 +1 Oona's Prowler|LRW +1 Pack Rat|RTR +1 Vampire Hexmage|2XM +1 Bone Shredder|ULG +1 Hypnotic Specter|M10 +1 Ophiomancer|C13 +1 Plaguecrafter|GRN +1 Vampire Nighthawk|MM3 +1 Gonti, Lord of Luxury|KLD +1 Nekrataal|EMA +1 Ravenous Chupacabra|A25 +1 Shriekmaw|UMA +1 Grave Titan|M12 +1 Ink-Eyes, Servant of Oni|PCA +1 Massacre Wurm|M21 +1 Tasigur, the Golden Fang|FRF +1 Sheoldred, Whispering One|IMA +1 Griselbrand|MM3 +1 Liliana of the Veil|UMA +1 Liliana, Death's Majesty|AKR +1 Dark Ritual|A25 +1 Entomb|UMA +1 Fatal Push|2XM +1 Vampiric Tutor|EMA +1 Cabal Ritual|VMA +1 Go for the Throat|MBS +1 Liliana's Triumph|WAR +1 Shallow Grave|MIR +1 Ultimate Price|DTK +1 Corpse Dance|TPR +1 Dismember|MM2 +1 Hero's Downfall|THS +1 Makeshift Mannequin|LRW +1 Duress|M21 +1 Imperial Seal|PTK +1 Inquisition of Kozilek|MM3 +1 Reanimate|UMA +1 Thoughtseize|AKR +1 Collective Brutality|EMN +1 Demonic Tutor|UMA +1 Exhume|USG +1 Hymn to Tourach|EMA +1 Night's Whisper|EMA +1 Buried Alive|UMA +1 Toxic Deluge|2XM +1 Yawgmoth's Will|USG +1 Damnation|MPS_AKH +1 Languish|ORI +1 Mastermind's Acquisition|RIX +1 Tendrils of Agony|VMA +1 Dark Petition|ORI +1 Living Death|A25 +1 Mind Twist|MPS_AKH +1 Animate Dead|EMA +1 Bitterblossom|UMA +1 Necromancy|VIS +1 Phyrexian Arena|CN2 +1 Recurring Nightmare|TPR +1 Yawgmoth's Bargain|UDS +1 Goblin Guide|2XM +1 Goblin Welder|ULG +1 Grim Lavamancer|2XM +1 Jackal Pup|A25 +1 Monastery Swiftspear|IMA +1 Zurgo Bellstriker|DTK +1 Abbot of Keral Keep|ORI +1 Dire Fleet Daredevil|RIX +1 Eidolon of the Great Revel|A25 +1 Runaway Steam-Kin|GRN +1 Young Pyromancer|UMA +1 Goblin Rabblemaster|M15 +1 Imperial Recruiter|2XM +1 Magus of the Moon|IMA +1 Avalanche Riders|TSB +1 Flametongue Kavu|VMA +1 Hazoret the Fervent|AKR +1 Hellrider|MM3 +1 Pia and Kiran Nalaar|ORI +1 Rekindling Phoenix|RIX +1 Glorybringer|AKR +1 Goblin Dark-Dwellers|OGW +1 Kiki-Jiki, Mirror Breaker|IMA +1 Siege-Gang Commander|DOM +1 Thundermaw Hellkite|IMA +1 Zealous Conscripts|MM3 +1 Inferno Titan|M12 +1 Chandra, Torch of Defiance|KLD +1 Daretti, Scrap Savant|C16 +1 Koth of the Hammer|SOM +1 Burst Lightning|MM2 +1 Lightning Bolt|A25 +1 Abrade|AKR +1 Ancient Grudge|MM3 +1 Desperate Ritual|UMA +1 Fire // Ice|UMA +1 Incinerate|M12 +1 Lightning Strike|M19 +1 Pyretic Ritual|M11 +1 Char|RAV +1 Seething Song|9ED +1 Through the Breach|UMA +1 Fireblast|VMA +1 Chain Lightning|MPS_AKH +1 Faithless Looting|UMA +1 Firebolt|MH1 +1 Flame Slash|CN2 +1 Mizzium Mortars|MM3 +1 Pyroclasm|A25 +1 Light Up the Stage|RNA +1 Underworld Breach|THB +1 Wheel of Fortune|VMA +1 Empty the Warrens|MMA +1 Fiery Confluence|C15 +1 Past in Flames|MM3 +1 Banefire|M19 +1 Burning of Xinye|VMA +1 Wildfire|MM2 +1 Bonfire of the Damned|MM3 +1 Mana Flare|5ED +1 Sulfuric Vortex|EMA +1 Sneak Attack|2XM +1 Splinter Twin|MM2 +1 Arbor Elf|A25 +1 Avacyn's Pilgrim|MM3 +1 Birds of Paradise|CN2 +1 Elves of Deep Shadow|RAV +1 Elvish Mystic|M15 +1 Fyndhorn Elves|VMA +1 Joraga Treespeaker|ROE +1 Llanowar Elves|DOM +1 Noble Hierarch|2XM +1 Den Protector|DTK +1 Devoted Druid|UMA +1 Fauna Shaman|UMA +1 Gilded Goose|ELD +1 Lotus Cobra|ZNR +1 Rofellos, Llanowar Emissary|VMA +1 Sakura-Tribe Elder|CNS +1 Scavenging Ooze|M21 +1 Sylvan Caryatid|THS +1 Wall of Blossoms|MH1 +1 Wall of Roots|IMA +1 Courser of Kruphix|A25 +1 Eternal Witness|UMA +1 Ramunap Excavator|AKR +1 Reclamation Sage|2XM +1 Tireless Tracker|SOI +1 Yavimaya Elder|VMA +1 Master of the Wild Hunt|A25 +1 Oracle of Mul Daya|ZEN +1 Polukranos, World Eater|THS +1 Acidic Slime|M13 +1 Biogenic Ooze|RNA +1 Deranged Hermit|VMA +1 Thragtusk|2XM +1 Whisperwood Elemental|FRF +1 Carnage Tyrant|XLN +1 Primeval Titan|IMA +1 Avenger of Zendikar|2XM +1 Craterhoof Behemoth|MM3 +1 Terastodon|2XM +1 Woodfall Primus|UMA +1 Dryad of the Ilysian Grove|THB +1 Garruk Relentless|ISD +1 Garruk Wildspeaker|M11 +1 Garruk, Primal Hunter|M13 +1 Vivien Reid|M19 +1 Nature's Claim|IMA +1 Beast Within|CN2 +1 Channel|IMA +1 Regrowth|MH1 +1 Kodama's Reach|UMA +1 Search for Tomorrow|IMA +1 Eureka|VMA +1 Harmonize|MM3 +1 Natural Order|EMA +1 Plow Under|8ED +1 Primal Command|MM3 +1 Green Sun's Zenith|EMA +1 Finale of Devastation|WAR +1 Tooth and Nail|MMA +1 Fastbond|VMA +1 Oath of Druids|TPR +1 Survival of the Fittest|TPR +1 Sylvan Library|EMA +1 Heartbeat of Spring|2XM +1 Wilderness Reclamation|RNA +1 Gaea's Cradle|USG +1 Geist of Saint Traft|2XM +1 Teferi, Hero of Dominaria|DOM +1 Sphinx's Revelation|AKR +1 Fractured Identity|C17 +1 Celestial Colonnade|UMA +1 Flooded Strand|EXP +1 Hallowed Fountain|RNA +1 Seachrome Coast|SOM +1 Tundra|VMA +1 Thief of Sanity|GRN +1 The Scarab God|AKR +1 Ashiok, Nightmare Weaver|THS +1 Baleful Strix|2XM +1 Creeping Tar Pit|UMA +1 Darkslick Shores|SOM +1 Polluted Delta|EXP +1 Underground Sea|VMA +1 Watery Grave|GRN +1 Daretti, Ingenious Iconoclast|CN2 +1 Kroxa, Titan of Death's Hunger|THB +1 Kolaghan's Command|DTK +1 Rakdos's Return|RTR +1 Badlands|VMA +1 Blackcleave Cliffs|SOM +1 Blood Crypt|RNA +1 Bloodstained Mire|EXP +1 Lavaclaw Reaches|UMA +1 Bloodbraid Elf|EMA +1 Huntmaster of the Fells|DKA +1 Dragonlord Atarka|DTK +1 Manamorphose|2XM +1 Copperline Gorge|SOM +1 Raging Ravine|UMA +1 Stomping Ground|RNA +1 Taiga|VMA +1 Wooded Foothills|EXP +1 Kitchen Finks|UMA +1 Knight of Autumn|GRN +1 Knight of the Reliquary|IMA +1 Trostani Discordant|GRN +1 Mirari's Wake|CNS +1 Razorverge Thicket|SOM +1 Savannah|VMA +1 Stirring Wildwood|UMA +1 Temple Garden|GRN +1 Windswept Heath|EXP +1 Ashen Rider|THS +1 Kaya, Orzhov Usurper|RNA +1 Tidehollow Sculler|MMA +1 Anguished Unmaking|SOI +1 Lingering Souls|MM3 +1 Vindicate|A25 +1 Unburial Rites|UMA +1 Concealed Courtyard|KLD +1 Godless Shrine|RNA +1 Marsh Flats|MM3 +1 Scrubland|VMA +1 Shambling Vent|BFZ +1 Vraska, Golgari Queen|GRN +1 Assassin's Trophy|GRN +1 Maelstrom Pulse|2XM +1 Pernicious Deed|A25 +1 Bayou|VMA +1 Blooming Marsh|KLD +1 Hissing Quagmire|OGW +1 Overgrown Tomb|GRN +1 Verdant Catacombs|MM3 +1 Edric, Spymaster of Trest|VMA +1 Trygon Predator|EMA +1 Hydroid Krasis|RNA +1 Uro, Titan of Nature's Wrath|THB +1 Botanical Sanctum|KLD +1 Breeding Pool|RNA +1 Lumbering Falls|BFZ +1 Misty Rainforest|MM3 +1 Tropical Island|VMA +1 Goblin Electromancer|GRN +1 Dack Fayden|EMA +1 Thousand-Year Storm|GRN +1 Scalding Tarn|MM3 +1 Spirebluff Canal|KLD +1 Steam Vents|GRN +1 Volcanic Island|VMA +1 Wandering Fumarole|OGW +1 Figure of Destiny|MMA +1 Ajani Vengeant|ALA +1 Nahiri, the Harbinger|SOI +1 Wear // Tear|DGM +1 Lightning Helix|IMA +1 Arid Mesa|MM3 +1 Inspiring Vantage|KLD +1 Needle Spires|OGW +1 Plateau|VMA +1 Sacred Foundry|GRN +1 Sphinx of the Steel Wind|EMA +1 Nicol Bolas, Dragon-God|WAR +1 Leovold, Emissary of Trest|UMA +1 Progenitus|MMA +1 Kozilek, Butcher of Truth|UMA +1 Ulamog, the Ceaseless Hunger|BFZ +1 Ulamog, the Infinite Gyre|UMA +1 Emrakul, the Promised End|EMN +1 Emrakul, the Aeons Torn|UMA +1 Karn, Scion of Urza|DOM +1 Karn Liberated|2XM +1 Ugin, the Spirit Dragon|FRF +1 Bomat Courier|KLD +1 Hangarback Walker|MPS_KLD +1 Phyrexian Revoker|2XM +1 Metalworker|UDS +1 Lodestone Golem|MM2 +1 Solemn Simulacrum|M21 +1 Kuldotha Forgemaster|2XM +1 Wurmcoil Engine|2XM +1 Myr Battlesphere|2XM +1 Sundering Titan|2XM +1 Walking Ballista|2XM +1 Blightsteel Colossus|2XM +1 Black Lotus|VMA +1 Chrome Mox|2XM +1 Everflowing Chalice|2XM +1 Lion's Eye Diamond|MIR +1 Lotus Bloom|MMA +1 Mana Crypt|2XM +1 Mox Diamond|TPR +1 Mox Emerald|VMA +1 Mox Jet|VMA +1 Mox Pearl|VMA +1 Mox Ruby|VMA +1 Mox Sapphire|VMA +1 Mana Vault|UMA +1 Relic of Progenitus|EMA +1 Sensei's Divining Top|EMA +1 Skullclamp|VMA +1 Sol Ring|MPS_KLD +1 Azorius Signet|MM3 +1 Boros Signet|MM3 +1 Dimir Signet|MM3 +1 Golgari Signet|MM3 +1 Grim Monolith|ULG +1 Gruul Signet|MM3 +1 Izzet Signet|MM3 +1 Lightning Greaves|2XM +1 Orzhov Signet|MM3 +1 Rakdos Signet|MM3 +1 Selesnya Signet|MM3 +1 Shrine of Burning Rage|NPH +1 Simic Signet|MM3 +1 Smuggler's Copter|KLD +1 Umezawa's Jitte|BOK +1 Winter Orb|EMA +1 Basalt Monolith|2XM +1 Coalition Relic|A25 +1 Crucible of Worlds|M19 +1 Oblivion Stone|2XM +1 Sword of Body and Mind|2XM +1 Sword of Feast and Famine|2XM +1 Sword of Fire and Ice|2XM +1 Sword of Light and Shadow|2XM +1 Sword of War and Peace|2XM +1 Tangle Wire|NMS +1 Worn Powerstone|EMA +1 Coercive Portal|VMA +1 Smokestack|VMA +1 Thran Dynamo|IMA +1 Batterskull|2XM +1 Memory Jar|VMA +1 Mindslaver|SOM +1 Academy Ruins|2XM +1 Ancient Tomb|UMA +1 Bazaar of Baghdad|VMA +1 Blast Zone|WAR +1 Field of Ruin|THB +1 Library of Alexandria|VMA +1 Maze of Ith|2XM +1 Mishra's Factory|2XM +1 Mishra's Workshop|ATQ +1 Mutavault|M14 +1 Nykthos, Shrine to Nyx|THS +1 Rishadan Port|A25 +1 Strip Mine|EXP +1 Wasteland|EMA +1 Expansion // Explosion|GRN +1 Giver of Runes|MH1 +1 Winds of Abandon|MH1 +1 Hallowed Spiritkeeper|C14 +1 Thraben Inspector|2XM +1 Narset, Parter of Veils|WAR +1 Force of Negation|MH1 +1 Urza, Lord High Artificer|MH1 +1 Emry, Lurker of the Loch|ELD +1 Brazen Borrower|ELD +1 Bolas's Citadel|WAR +1 Yawgmoth, Thran Physician|MH1 +1 Rotting Regisaur|M20 +1 Murderous Rider|ELD +1 Wishclaw Talisman|ELD +1 Dreadhorde Arcanist|WAR +1 Seasoned Pyromancer|MH1 +1 Embereth Shieldbreaker|ELD +1 Nissa, Who Shakes the World|WAR +1 Questing Beast|ELD +1 Teferi, Time Raveler|WAR +1 Angrath's Rampage|WAR +1 Fallen Shinobi|MH1 +1 Wrenn and Six|MH1 +1 Oko, Thief of Crowns|ELD +1 Garruk, Cursed Huntsman|ELD +1 Prismatic Vista|MH1 +1 Golos, Tireless Pilgrim|M20 +1 Stonecoil Serpent|ELD diff --git a/forge-gui/res/draft/MTGA Cube 2020 April.draft b/forge-gui/res/draft/MTGA Cube 2020 April.draft new file mode 100644 index 00000000000..2cdf4f5c10e --- /dev/null +++ b/forge-gui/res/draft/MTGA Cube 2020 April.draft @@ -0,0 +1,6 @@ +Name:MTGA Cube 2020 April +DeckFile:MTGA Cube 2020 April +Singleton:True + +Booster: 15 Any +NumPacks: 3 diff --git a/forge-gui/res/draft/MTGO Vintage Cube April 2020.draft b/forge-gui/res/draft/MTGO Vintage Cube April 2020.draft new file mode 100644 index 00000000000..bcfed364059 --- /dev/null +++ b/forge-gui/res/draft/MTGO Vintage Cube April 2020.draft @@ -0,0 +1,6 @@ +Name:MTGO Vintage Cube April 2020 +DeckFile:MTGO Vintage Cube April 2020 +Singleton:True + +Booster: 15 Any +NumPacks: 3 diff --git a/forge-gui/res/editions/Amonkhet Remastered.txt b/forge-gui/res/editions/Amonkhet Remastered.txt index 9381fed95b2..7dd1569dee6 100644 --- a/forge-gui/res/editions/Amonkhet Remastered.txt +++ b/forge-gui/res/editions/Amonkhet Remastered.txt @@ -337,7 +337,7 @@ Type=Expansion 328 R Scavenger Grounds 329 U Shefet Dunes 330 R Sheltered Thicket -331 C Sun scorched Desert +331 C Sunscorched Desert 332 L Swamp 333 L Swamp 334 L Swamp diff --git a/forge-gui/res/editions/Amonkhet.txt b/forge-gui/res/editions/Amonkhet.txt index 96365a69612..2e7e9a002ab 100644 --- a/forge-gui/res/editions/Amonkhet.txt +++ b/forge-gui/res/editions/Amonkhet.txt @@ -9,6 +9,7 @@ BoosterCovers=5 Booster=10 Common:!fromSheet("AKH Planeswalker Decks and Toolkit"), 3 Uncommon:!fromSheet("AKH Planeswalker Decks and Toolkit"), 1 RareMythic:!fromSheet("AKH Planeswalker Decks and Toolkit"), 1 BasicLand AKH AdditionalSheetForFoils=fromSheet("MPS Amonkhet Invocations") AdditionalSetUnlockedInQuest=MPS_AKH +ChaosDraftThemes=GRAVEYARD_MATTERS [cards] 1 M Angel of Sanctions diff --git a/forge-gui/res/editions/Avacyn Restored.txt b/forge-gui/res/editions/Avacyn Restored.txt index 3d3de349056..22d9dc9e78e 100644 --- a/forge-gui/res/editions/Avacyn Restored.txt +++ b/forge-gui/res/editions/Avacyn Restored.txt @@ -7,6 +7,7 @@ MciCode=avr Type=Expansion BoosterCovers=5 Booster=10 Common, 3 Uncommon, 1 RareMythic, 1 BasicLand +ChaosDraftThemes=GRAVEYARD_MATTERS [cards] 167 C Abundant Growth diff --git a/forge-gui/res/editions/Classic Sixth Edition.txt b/forge-gui/res/editions/Classic Sixth Edition.txt index 56499cc924a..1993eade79c 100644 --- a/forge-gui/res/editions/Classic Sixth Edition.txt +++ b/forge-gui/res/editions/Classic Sixth Edition.txt @@ -9,6 +9,7 @@ Border=White BoosterCovers=1 Booster=11 Common, 3 Uncommon, 1 Rare Foil=NotSupported +ChaosDraftThemes=CORE_SET [cards] 163 U AEther Flash diff --git a/forge-gui/res/editions/Commander Legends.txt b/forge-gui/res/editions/Commander Legends.txt index 43310a37422..da8598289c2 100644 --- a/forge-gui/res/editions/Commander Legends.txt +++ b/forge-gui/res/editions/Commander Legends.txt @@ -6,29 +6,259 @@ Type=Other [cards] 1 C The Prismatic Piper +5 C Ancestral Blade +9 M Archon of Coronation +12 U "Tuia Bearclaw" +14 C Cage of Hands +15 C Captain's Call +16 R Court of Grace +17 C Court Street Denizen +19 C Doomed Traveler +22 U First Response 27 R Keeper of the Accord +28 U Keleth, Sunmane Familiar +29 C Kinsbaile Courier +30 C Kor Cartographer +31 R Livio, Oathsworn Sentinel +33 C Ninth Bridge Patrol +37 U Patron of the Valiant +38 U Prava of the Steel Legion +39 R Promise of Tomorrow +40 U Radiant, Serra Archangel +41 C Raise the Alarm +42 U Rebbec, Architect of Ascension +43 U Return to Dust +45 M Seraphic Greatsword +47 R Slash the Ranks +55 R Amphin Mutineer +60 U Brinelin, the Moon Kraken +62 U Confiscate +63 R Court of Cunning +66 R Eligeth, Crossroads Augur +68 C Fall from Favor +69 C Forceful Denial +71 U Ghost of Ramirez DePietro +73 U Horizon Scholar +75 U Interpret the Signs +76 C Kitesail Corsair +77 C Kitesail Skirmisher +78 R Laboratory Drudge +79 U Malcolm, Keen-Eyed Navigator +81 U Merchant Raiders +82 M Mnemonic Deluge +83 C Omenspeaker +84 C Preordain +86 C Prying Eyes +87 C Run Away Together +95 U Siani, Eye of the Storm +96 U Siren Stormtamer +99 M Sphinx of the Second Sun +102 U Supreme Will +106 U Warden of Evos Isle +111 C Briarblade Adept +112 U Cast Down +114 R Court of Ambition +118 U Demonic Lore +122 C Exquisite Huntmaster +124 C Eyeblight Cullers +128 C Fleshbag Marauder +131 U Keskit, the Flesh Sculptor +140 U Null Caller +141 R Opposition Agent +142 C Phyrexian Rager +145 M Profane Transfusion 149 R Sengir, the Dark Baron +152 R Szat's Will +153 M Tevesh Szat, Doom of Fools +154 C Thorn of the Black Rose +156 M Vampiric Tutor +159 U Vow of Torment 160 U Alena, Kessig Trapper +161 R Aurora Phoenix +164 C Brazen Freebooter +165 U Breeches, Brazen Plunderer +168 U Coastline Marauders +172 U Dargo, the Shipwrecker +174 C Dragon Mantle +175 R Emberwilde Captain +181 U Furnace Celebration +186 M Jeska, Thrice Reborn +187 R Jeska's Will +188 U Kediss, Emberclaw Familiar +189 R Krark, the Thumbless +191 C Makeshift Munitions +192 U Meteoric Mace +193 M Port Razer +197 U Rograkh, Son of Rohgahh +200 C Soul's Fire +204 U "Toggo, Goblin Weaponsmith" +206 C Valakut Invoker +211 R "Wheel of Misfortune" +224 C Entourage of Trest +225 C Farhaven Elf +228 C Fyndhorn Elves +229 C Gift of Paradise 231 U Halana, Kessig Ranger +232 U Hunter's Insight +234 R Immaculate Magistrate +235 U Imperious Perfect +237 M Kamahl, Heart of Krosa +238 R Kamahl's Will +239 R Kodama of the East Tree +242 R Magus of the Order +245 C Natural Reclamation +246 U Numa, Joraga Chieftain +257 C Soul's Might +260 R Sweet-Gum Recluse +261 U Three Visits +266 R Amareth, the Lustrous +268 R Archelos, Lagoon Mystic +269 R Averna, the Chaos Bloom +270 R Belbe, Corrupted Observer +272 R Blim, Comedic Genius +274 R Colfenor, the Last Yew +275 R Ghen, Arcanum Weaver +277 R Gor Muldrak, Amphinologist +286 R Liesa, Shroud of Dusk +288 R Nymris, Oona's Trickster +291 U Thalisse, Reverent Medium +293 R Yurlok of Scorch Thrash +294 R Zara, Renegade Recruiter +297 U Arcane Signet +300 R Bladegriff Prototype +303 C Charcoal Diamond 306 C Commander's Sphere +315 R Horizon Stone +319 M Jeweled Lotus +322 C Maelstrom Colossus +323 C Marble Diamond +324 U Mask of Memory +326 U Mindless Automaton +331 M Phyrexian Triniform +334 C Prophetic Prism +335 R Rings of Brighthearth +336 U Sandstone Oracle +337 M Scroll Rack +341 C Sky Diamond +343 R Staff of Domination +349 R Command Beacon 350 C Command Tower +353 C Path of Ancestry 354 R Rejuvenating Springs 356 R Spectator Seating 358 R Training Center 359 R Undergrowth Stadium 360 R Vault of Champions +361 R War Room +400 U Mulldrifter +421 U Acidic Slime +479 C Command Tower +487 U Myriad Landscape +488 U Reliquary Tower +512 M Tevesh Szat, Doom of Fools +513 M Jeska, Thrice Reborn +514 M Najeela, the Blade-Blossom +516 M Brago, King Eternal +519 M Ikra Shidiqi, the Usurper +524 M Kydele, Chosen of Kruphix +525 M Ludevic, Necro-Alchemist +526 M Maelstrom Wanderer +529 M Nekusar, the Mindrazer 530 M Prossh, Skyraider of Kher +531 M Queen Marchesa +532 M Rakdos, Lord of Riots +535 M Sidar Kondo of Jamuraa +536 M Silas Renn, Seeker Adept +538 M Thrasios, Triton Hero +539 M Tymna the Weaver +540 M Vial Smasher the Fierce +541 M Xenagos, God of Revels +544 M Zur the Enchanter +545 M Ramos, Dragon Engine 546 C The Prismatic Piper +550 U Keleth, Sunmane Familiar +551 R Livio, Oathsworn Sentinel +552 U Prava of the Steel Legion +553 U Radiant, Serra Archangel +554 U Rebbec, Architect of Ascension +555 U Brinelin, the Moon Kraken +556 R Eligeth, Crossroads Augur +558 U Ghost of Ramirez DePietro +560 U Malcolm, Keen-Eyed Navigator +562 U Siani, Eye of the Storm +565 U Keskit, the Flesh Sculptor 568 R Sengir, the Dark Baron 570 U Alena, Kessig Trapper +571 U Breeches, Brazen Plunderer +572 U Dargo, the Shipwrecker +573 U Kediss, Emberclaw Familiar +574 R Krark, the Thumbless +575 U Rograkh, Son of Rohgahh +576 U "Toggo, Goblin Weaponsmith" 579 U Halana, Kessig Ranger +581 M Kamahl, Heart of Krosa +582 R Kodama of the East Tree +583 U Numa, Joraga Chieftain +586 R Amareth, the Lustrous +588 R Archelos, Lagoon Mystic +589 R Averna, the Chaos Bloom +590 R Belbe, Corrupted Observer +592 R Blim, Comedic Genius +594 R Colfenor, the Last Yew +595 R Ghen, Arcanum Weaver +597 R Gor Muldrak, Amphinologist +606 R Liesa, Shroud of Dusk +608 R Nymris, Oona's Trickster +611 U Thalisse, Reverent Medium +613 R Yurlok of Scorch Thrash +614 R Zara, Renegade Recruiter +616 M Archon of Coronation +619 R Court of Grace 621 R Keeper of the Accord +622 R Promise of Tomorrow +623 U Return to Dust +624 M Seraphic Greatsword +625 R Slash the Ranks +629 R Amphin Mutineer +633 R Court of Cunning +636 R Laboratory Drudge +638 M Mnemonic Deluge +639 U Mulldrifter +640 C Preordain +643 M Sphinx of the Second Sun +645 R Court of Ambition +651 R Opposition Agent +653 M Profane Transfusion +655 R Szat's Will +656 M Vampiric Tutor +660 R Aurora Phoenix +664 R Emberwilde Captain +668 R Jeska's Will +669 M Port Razer +672 R "Wheel of Misfortune" +673 U Acidic Slime +678 C Fyndhorn Elves +679 R Immaculate Magistrate +680 R Kamahl's Will +682 R Magus of the Order +685 R Sweet-Gum Recluse +686 U Three Visits +689 U Arcane Signet +690 R Bladegriff Prototype 693 C Commander's Sphere +694 R Horizon Stone +695 M Jeweled Lotus +698 R Rings of Brighthearth +699 M Scroll Rack +701 R Staff of Domination 705 C Command Tower +706 U Myriad Landscape 709 R Rejuvenating Springs +710 U Reliquary Tower 711 R Spectator Seating 713 R Training Center 714 R Undergrowth Stadium 715 R Vault of Champions +716 R War Room 721 M Mana Confluence 722 R Sengir, the Dark Baron diff --git a/forge-gui/res/editions/Dark Ascension.txt b/forge-gui/res/editions/Dark Ascension.txt index c39a28fd4a9..4b4044e6ca2 100644 --- a/forge-gui/res/editions/Dark Ascension.txt +++ b/forge-gui/res/editions/Dark Ascension.txt @@ -7,6 +7,7 @@ MciCode=dka Type=Expansion BoosterCovers=3 Booster=9 Common:!dfc, 3 Uncommon:!dfc, 1 RareMythic:!dfc, 1 dfc, 1 BasicLand ISD +ChaosDraftThemes=GRAVEYARD_MATTERS [cards] 81 U Afflicted Deserter diff --git a/forge-gui/res/editions/Darksteel.txt b/forge-gui/res/editions/Darksteel.txt index fc5084bec80..414babc1ea8 100644 --- a/forge-gui/res/editions/Darksteel.txt +++ b/forge-gui/res/editions/Darksteel.txt @@ -8,6 +8,7 @@ Type=Expansion BoosterCovers=3 Booster=11 Common, 3 Uncommon, 1 Rare FoilAlwaysInCommonSlot=False +ChaosDraftThemes=MIRRODIN [cards] 37 R AEther Snap diff --git a/forge-gui/res/editions/Dissension.txt b/forge-gui/res/editions/Dissension.txt index 34179da950d..503c21d5cb3 100644 --- a/forge-gui/res/editions/Dissension.txt +++ b/forge-gui/res/editions/Dissension.txt @@ -8,6 +8,7 @@ Type=Expansion BoosterCovers=3 Booster=11 Common, 3 Uncommon, 1 Rare FoilAlwaysInCommonSlot=False +ChaosDraftThemes=RAVNICA [cards] 1 C Aurora Eidolon diff --git a/forge-gui/res/editions/Double Masters.txt b/forge-gui/res/editions/Double Masters.txt index 5dec0146172..91197ed1e46 100644 --- a/forge-gui/res/editions/Double Masters.txt +++ b/forge-gui/res/editions/Double Masters.txt @@ -7,6 +7,7 @@ BoosterCovers=3 Booster=8 Common, 3 Uncommon, 2 RareMythic, 2 fromSheet("2XM Foils") Foil=NotSupported DoublePick=true +ChaosDraftThemes=MASTERS_SET [cards] 1 M Karn Liberated diff --git a/forge-gui/res/editions/Dragon's Maze.txt b/forge-gui/res/editions/Dragon's Maze.txt index e6b83cee621..ba9091da0ff 100644 --- a/forge-gui/res/editions/Dragon's Maze.txt +++ b/forge-gui/res/editions/Dragon's Maze.txt @@ -7,6 +7,7 @@ MciCode=dgm Type=Expansion BoosterCovers=3 Booster=10 Common:!land, 3 Uncommon, 1 RareMythic:!land, 1 fromSheet("DGM Lands") +ChaosDraftThemes=RAVNICA [cards] 1 C Boros Mastiff diff --git a/forge-gui/res/editions/Eighth Edition.txt b/forge-gui/res/editions/Eighth Edition.txt index 19ca2c2083e..74e85840549 100644 --- a/forge-gui/res/editions/Eighth Edition.txt +++ b/forge-gui/res/editions/Eighth Edition.txt @@ -9,6 +9,7 @@ Border=White BoosterCovers=5 Booster=10 Common, 3 Uncommon, 1 Rare, 1 BasicLand FoilAlwaysInCommonSlot=False +ChaosDraftThemes=CORE_SET [cards] 117 U Abyssal Specter diff --git a/forge-gui/res/editions/Eldritch Moon.txt b/forge-gui/res/editions/Eldritch Moon.txt index e3b743bd969..865db975d3e 100644 --- a/forge-gui/res/editions/Eldritch Moon.txt +++ b/forge-gui/res/editions/Eldritch Moon.txt @@ -9,6 +9,7 @@ BoosterCovers=3 Booster=9 Common:!dfc, 3 Uncommon:!dfc, 1 RareMythic:!dfc, 1 dfc:!Rare:!Mythic, 1 BasicLand SOI ChanceReplaceCommonWith=.125F dfc:RareMythic TreatAsSmallSet=true +ChaosDraftThemes=GRAVEYARD_MATTERS [cards] 1 U Abundant Maw diff --git a/forge-gui/res/editions/Eternal Masters.txt b/forge-gui/res/editions/Eternal Masters.txt index 29d5548c6b0..0a389e78f9a 100644 --- a/forge-gui/res/editions/Eternal Masters.txt +++ b/forge-gui/res/editions/Eternal Masters.txt @@ -7,6 +7,7 @@ Type=Reprint BoosterCovers=3 Booster=11 Common, 3 Uncommon, 1 RareMythic FoilChanceInBooster=100 +ChaosDraftThemes=MASTERS_SET [cards] 1 C Aven Riftwatcher diff --git a/forge-gui/res/editions/Fate Reforged.txt b/forge-gui/res/editions/Fate Reforged.txt index e3810f09b24..04e5ca0f0a2 100644 --- a/forge-gui/res/editions/Fate Reforged.txt +++ b/forge-gui/res/editions/Fate Reforged.txt @@ -6,6 +6,7 @@ MciCode=frf Type=Expansion BoosterCovers=3 Booster=10 Common:!land, 3 Uncommon, 1 RareMythic, 1 fromSheet("FRF Lands"), 0 fromSheet("FRF Basic Lands") +ChaosDraftThemes=GRAVEYARD_MATTERS [cards] 1 M Ugin, the Spirit Dragon diff --git a/forge-gui/res/editions/Fifth Dawn.txt b/forge-gui/res/editions/Fifth Dawn.txt index 48d6c8868cf..c973dbb7db3 100644 --- a/forge-gui/res/editions/Fifth Dawn.txt +++ b/forge-gui/res/editions/Fifth Dawn.txt @@ -8,6 +8,7 @@ Type=Expansion BoosterCovers=3 Booster=11 Common, 3 Uncommon, 1 Rare FoilAlwaysInCommonSlot=False +ChaosDraftThemes=MIRRODIN [cards] 1 C Abuna's Chant diff --git a/forge-gui/res/editions/Fifth Edition.txt b/forge-gui/res/editions/Fifth Edition.txt index 3b8505bbb2e..e64a00f7bc9 100644 --- a/forge-gui/res/editions/Fifth Edition.txt +++ b/forge-gui/res/editions/Fifth Edition.txt @@ -9,6 +9,7 @@ Border=White BoosterCovers=5 Booster=11 Common, 3 Uncommon, 1 Rare Foil=NotSupported +ChaosDraftThemes=CORE_SET [cards] U AEther Storm diff --git a/forge-gui/res/editions/Fourth Edition.txt b/forge-gui/res/editions/Fourth Edition.txt index e8f7bbffc9f..6f17253c343 100644 --- a/forge-gui/res/editions/Fourth Edition.txt +++ b/forge-gui/res/editions/Fourth Edition.txt @@ -9,6 +9,7 @@ Border=White BoosterCovers=5 Booster=11 Common, 3 Uncommon, 1 Rare Foil=NotSupported +ChaosDraftThemes=CORE_SET [cards] U Abomination diff --git a/forge-gui/res/editions/Gatecrash.txt b/forge-gui/res/editions/Gatecrash.txt index 4aa1ef9bf83..f11064b7914 100644 --- a/forge-gui/res/editions/Gatecrash.txt +++ b/forge-gui/res/editions/Gatecrash.txt @@ -7,6 +7,7 @@ MciCode=gtc Type=Expansion BoosterCovers=5 Booster=10 Common, 3 Uncommon, 1 RareMythic, 1 BasicLand RTR +ChaosDraftThemes=RAVNICA [cards] 29 U AEtherize diff --git a/forge-gui/res/editions/Guildpact.txt b/forge-gui/res/editions/Guildpact.txt index b13ecda5861..d6226592ab9 100644 --- a/forge-gui/res/editions/Guildpact.txt +++ b/forge-gui/res/editions/Guildpact.txt @@ -8,6 +8,7 @@ Type=Expansion BoosterCovers=3 Booster=11 Common, 3 Uncommon, 1 Rare FoilAlwaysInCommonSlot=False +ChaosDraftThemes=RAVNICA [cards] 22 U AEtherplasm diff --git a/forge-gui/res/editions/Guilds of Ravnica.txt b/forge-gui/res/editions/Guilds of Ravnica.txt index 606558dcf9d..63a2f016a6e 100644 --- a/forge-gui/res/editions/Guilds of Ravnica.txt +++ b/forge-gui/res/editions/Guilds of Ravnica.txt @@ -8,6 +8,7 @@ Type=Expansion BoosterCovers=5 Booster=10 Common:!fromSheet("GRN Secret Cards"), 3 Uncommon:!fromSheet("GRN Secret Cards"), 1 RareMythic:!fromSheet("GRN Secret Cards"), 1 fromSheet("GRN Lands") AdditionalSetUnlockedInQuest=GK1 +ChaosDraftThemes=RAVNICA;GRAVEYARD_MATTERS [cards] 1 C Blade Instructor diff --git a/forge-gui/res/editions/Hour of Devastation.txt b/forge-gui/res/editions/Hour of Devastation.txt index 71192b7c2b8..9c3c2483381 100644 --- a/forge-gui/res/editions/Hour of Devastation.txt +++ b/forge-gui/res/editions/Hour of Devastation.txt @@ -10,6 +10,7 @@ Booster=10 Common:!fromSheet("HOU Planeswalker Decks and Toolkit"), 3 Uncommon:! AdditionalSheetForFoils=fromSheet("MPS Hour of Devastation Invocations") AdditionalSetUnlockedInQuest=MPS_AKH TreatAsSmallSet=true +ChaosDraftThemes=GRAVEYARD_MATTERS [cards] 1 C Act of Heroism diff --git a/forge-gui/res/editions/Iconic Masters.txt b/forge-gui/res/editions/Iconic Masters.txt index 902079fd311..16b2327147b 100644 --- a/forge-gui/res/editions/Iconic Masters.txt +++ b/forge-gui/res/editions/Iconic Masters.txt @@ -7,6 +7,7 @@ Type=Reprint BoosterCovers=3 Booster=11 Common, 3 Uncommon, 1 RareMythic FoilChanceInBooster=100 +ChaosDraftThemes=MASTERS_SET [cards] 1 C Scion of Ugin diff --git a/forge-gui/res/editions/Innistrad.txt b/forge-gui/res/editions/Innistrad.txt index 7655c58e08f..161fd42ffda 100644 --- a/forge-gui/res/editions/Innistrad.txt +++ b/forge-gui/res/editions/Innistrad.txt @@ -7,6 +7,7 @@ MciCode=isd Type=Expansion BoosterCovers=5 Booster=9 Common:!dfc, 3 Uncommon:!dfc, 1 RareMythic:!dfc, 1 dfc, 1 BasicLand +ChaosDraftThemes=GRAVEYARD_MATTERS [cards] 85 U Abattoir Ghoul diff --git a/forge-gui/res/editions/Judgment.txt b/forge-gui/res/editions/Judgment.txt index 26e92e549eb..ce71ba23ef2 100644 --- a/forge-gui/res/editions/Judgment.txt +++ b/forge-gui/res/editions/Judgment.txt @@ -9,6 +9,7 @@ BoosterCovers=1 Booster=11 Common, 3 Uncommon, 1 Rare Foil=OldStyle FoilAlwaysInCommonSlot=False +ChaosDraftThemes=GRAVEYARD_MATTERS [cards] 1 U Ancestor's Chosen diff --git a/forge-gui/res/editions/Khans of Tarkir.txt b/forge-gui/res/editions/Khans of Tarkir.txt index b1b96ce023e..b8fde746cc6 100644 --- a/forge-gui/res/editions/Khans of Tarkir.txt +++ b/forge-gui/res/editions/Khans of Tarkir.txt @@ -7,6 +7,7 @@ MciCode=ktk Type=Expansion BoosterCovers=5 Booster=10 Common, 3 Uncommon, 1 RareMythic, 1 BasicLand KTK +ChaosDraftThemes=GRAVEYARD_MATTERS [cards] 1 U Abzan Battle Priest diff --git a/forge-gui/res/editions/Limited Edition Beta.txt b/forge-gui/res/editions/Limited Edition Beta.txt index f312ed2a90a..c428fa67b8f 100644 --- a/forge-gui/res/editions/Limited Edition Beta.txt +++ b/forge-gui/res/editions/Limited Edition Beta.txt @@ -8,6 +8,7 @@ Type=Core BoosterCovers=1 Booster=11 Common, 3 Uncommon, 1 Rare Foil=NotSupported +ChaosDraftThemes=CORE_SET [cards] U Air Elemental diff --git a/forge-gui/res/editions/Magic 2010.txt b/forge-gui/res/editions/Magic 2010.txt index 39141f5576a..6b4ddf84592 100644 --- a/forge-gui/res/editions/Magic 2010.txt +++ b/forge-gui/res/editions/Magic 2010.txt @@ -7,6 +7,7 @@ MciCode=m10 Type=Core BoosterCovers=5 Booster=10 Common, 3 Uncommon, 1 RareMythic, 1 BasicLand +ChaosDraftThemes=CORE_SET [cards] 165 U Acidic Slime diff --git a/forge-gui/res/editions/Magic 2011.txt b/forge-gui/res/editions/Magic 2011.txt index 945a4d29d2a..790b7760fd1 100644 --- a/forge-gui/res/editions/Magic 2011.txt +++ b/forge-gui/res/editions/Magic 2011.txt @@ -7,6 +7,7 @@ MciCode=m11 Type=Core BoosterCovers=5 Booster=10 Common, 3 Uncommon, 1 RareMythic, 1 BasicLand +ChaosDraftThemes=CORE_SET [cards] 41 C AEther Adept diff --git a/forge-gui/res/editions/Magic 2012.txt b/forge-gui/res/editions/Magic 2012.txt index 86bb22faed6..0d71d2afad6 100644 --- a/forge-gui/res/editions/Magic 2012.txt +++ b/forge-gui/res/editions/Magic 2012.txt @@ -7,6 +7,7 @@ MciCode=m12 Type=Core BoosterCovers=5 Booster=10 Common, 3 Uncommon, 1 RareMythic, 1 BasicLand +ChaosDraftThemes=CORE_SET [cards] 41 C AEther Adept diff --git a/forge-gui/res/editions/Magic 2013.txt b/forge-gui/res/editions/Magic 2013.txt index 2dab22e50c0..21e5555ae31 100644 --- a/forge-gui/res/editions/Magic 2013.txt +++ b/forge-gui/res/editions/Magic 2013.txt @@ -7,6 +7,7 @@ MciCode=m13 Type=Core BoosterCovers=5 Booster=10 Common, 3 Uncommon, 1 RareMythic, 1 BasicLand +ChaosDraftThemes=CORE_SET [cards] 159 U Acidic Slime diff --git a/forge-gui/res/editions/Magic 2014.txt b/forge-gui/res/editions/Magic 2014.txt index 0934c02e1ef..005c769c514 100644 --- a/forge-gui/res/editions/Magic 2014.txt +++ b/forge-gui/res/editions/Magic 2014.txt @@ -7,6 +7,7 @@ MciCode=m14 Type=Core BoosterCovers=5 Booster=10 Common, 3 Uncommon, 1 RareMythic, 1 BasicLand +ChaosDraftThemes=CORE_SET [cards] 1 M Ajani, Caller of the Pride diff --git a/forge-gui/res/editions/Magic 2015.txt b/forge-gui/res/editions/Magic 2015.txt index 8d560ecd154..597577e6985 100644 --- a/forge-gui/res/editions/Magic 2015.txt +++ b/forge-gui/res/editions/Magic 2015.txt @@ -7,6 +7,7 @@ MciCode=m15 Type=Core BoosterCovers=5 Booster=10 Common:!fromSheet("M15 Sample Cards"), 3 Uncommon:!fromSheet("M15 Sample Cards"), 1 RareMythic:!fromSheet("M15 Sample Cards"), 1 BasicLand +ChaosDraftThemes=CORE_SET [cards] 1 M Ajani Steadfast diff --git a/forge-gui/res/editions/Magic 2019.txt b/forge-gui/res/editions/Magic 2019.txt index 157a0a2cf18..f7cc4829eb1 100644 --- a/forge-gui/res/editions/Magic 2019.txt +++ b/forge-gui/res/editions/Magic 2019.txt @@ -7,6 +7,7 @@ MciCode=m19 Type=Core BoosterCovers=5 Booster=10 Common:!fromSheet("M19 Secret Cards"), 3 Uncommon:!fromSheet("M19 Secret Cards"), 1 RareMythic:!fromSheet("M19 Secret Cards"), 1 fromSheet("M19 Lands") +ChaosDraftThemes=CORE_SET [cards] 1 U Aegis of the Heavens diff --git a/forge-gui/res/editions/Magic 2020.txt b/forge-gui/res/editions/Magic 2020.txt index 89184a08add..2a099ef55ba 100644 --- a/forge-gui/res/editions/Magic 2020.txt +++ b/forge-gui/res/editions/Magic 2020.txt @@ -6,6 +6,7 @@ MciCode=m20 Type=Core BoosterCovers=3 Booster=10 Common:!fromSheet("M20 Secret Cards"), 3 Uncommon:!fromSheet("M20 Secret Cards"), 1 RareMythic:!fromSheet("M20 Secret Cards"), 1 fromSheet("M20 Lands") +ChaosDraftThemes=CORE_SET [cards] 1 C Aerial Assault diff --git a/forge-gui/res/editions/Magic 2021.txt b/forge-gui/res/editions/Magic 2021.txt index ed49e37ba09..125329342ae 100644 --- a/forge-gui/res/editions/Magic 2021.txt +++ b/forge-gui/res/editions/Magic 2021.txt @@ -6,6 +6,7 @@ Type=Core BoosterCovers=3 Booster=10 Common:!fromSheet("M21 Secret Cards"), 3 Uncommon:!fromSheet("M21 Secret Cards"), 1 RareMythic:!fromSheet("M21 Secret Cards"), 1 fromSheet("M21 Lands") Prerelease=6 Boosters, 1 RareMythic+ +ChaosDraftThemes=CORE_SET [cards] 1 M Ugin, the Spirit Dragon diff --git a/forge-gui/res/editions/Magic Origins.txt b/forge-gui/res/editions/Magic Origins.txt index 2204e442dd9..aa0093974de 100644 --- a/forge-gui/res/editions/Magic Origins.txt +++ b/forge-gui/res/editions/Magic Origins.txt @@ -7,6 +7,7 @@ MciCode=ori Type=Core BoosterCovers=5 Booster=10 Common:!fromSheet("ORI Sample Cards"), 3 Uncommon:!fromSheet("ORI Sample Cards"), 1 RareMythic:!fromSheet("ORI Sample Cards"), 1 BasicLand +ChaosDraftThemes=CORE_SET [cards] 1 C Akroan Jailer diff --git a/forge-gui/res/editions/Masters 25.txt b/forge-gui/res/editions/Masters 25.txt index 041803b48aa..9bfe3430f3d 100644 --- a/forge-gui/res/editions/Masters 25.txt +++ b/forge-gui/res/editions/Masters 25.txt @@ -7,6 +7,7 @@ Type=Reprint BoosterCovers=3 Booster=11 Common, 3 Uncommon, 1 RareMythic FoilChanceInBooster=100 +ChaosDraftThemes=MASTERS_SET [cards] 1 C Act of Heroism diff --git a/forge-gui/res/editions/Mirrodin Besieged.txt b/forge-gui/res/editions/Mirrodin Besieged.txt index d91196d2e92..069270b54e3 100644 --- a/forge-gui/res/editions/Mirrodin Besieged.txt +++ b/forge-gui/res/editions/Mirrodin Besieged.txt @@ -7,6 +7,7 @@ MciCode=mbs Type=Expansion BoosterCovers=3 Booster=10 Common, 3 Uncommon, 1 RareMythic, 1 BasicLand +ChaosDraftThemes=MIRRODIN [cards] 1 U Accorder Paladin diff --git a/forge-gui/res/editions/Mirrodin.txt b/forge-gui/res/editions/Mirrodin.txt index 4185ca1b114..17ee49445d9 100644 --- a/forge-gui/res/editions/Mirrodin.txt +++ b/forge-gui/res/editions/Mirrodin.txt @@ -8,6 +8,7 @@ Type=Expansion BoosterCovers=5 Booster=11 Common, 3 Uncommon, 1 Rare FoilAlwaysInCommonSlot=False +ChaosDraftThemes=MIRRODIN [cards] 141 C AEther Spellbomb diff --git a/forge-gui/res/editions/Modern Horizons.txt b/forge-gui/res/editions/Modern Horizons.txt index bed63eab73c..ae1ce47d837 100644 --- a/forge-gui/res/editions/Modern Horizons.txt +++ b/forge-gui/res/editions/Modern Horizons.txt @@ -7,6 +7,7 @@ MciCode=mh1 Type=Other BoosterCovers=5 Booster=10 Common:!fromSheet("MH1 Secret Cards"), 3 Uncommon:!fromSheet("MH1 Secret Cards"), 1 RareMythic:!fromSheet("MH1 Secret Cards"), 1 fromSheet("MH1 Lands") +ChaosDraftThemes=MASTERS_SET;GRAVEYARD_MATTERS [cards] diff --git a/forge-gui/res/editions/Modern Masters 2015.txt b/forge-gui/res/editions/Modern Masters 2015.txt index 1548ad57511..ceb09d77f71 100644 --- a/forge-gui/res/editions/Modern Masters 2015.txt +++ b/forge-gui/res/editions/Modern Masters 2015.txt @@ -7,6 +7,7 @@ Type=Reprint BoosterCovers=3 Booster=11 Common, 3 Uncommon, 1 RareMythic FoilChanceInBooster=100 +ChaosDraftThemes=MASTERS_SET [cards] 1 R All Is Dust diff --git a/forge-gui/res/editions/Modern Masters 2017.txt b/forge-gui/res/editions/Modern Masters 2017.txt index 4cd03184bb7..257b2a84d85 100644 --- a/forge-gui/res/editions/Modern Masters 2017.txt +++ b/forge-gui/res/editions/Modern Masters 2017.txt @@ -7,6 +7,7 @@ Type=Reprint BoosterCovers=3 Booster=11 Common, 3 Uncommon, 1 RareMythic FoilChanceInBooster=100 +ChaosDraftThemes=MASTERS_SET;GRAVEYARD_MATTERS [cards] 1 C Attended Knight diff --git a/forge-gui/res/editions/Modern Masters.txt b/forge-gui/res/editions/Modern Masters.txt index ddc3e94db80..a1bf70b93eb 100644 --- a/forge-gui/res/editions/Modern Masters.txt +++ b/forge-gui/res/editions/Modern Masters.txt @@ -7,6 +7,7 @@ Type=Reprint BoosterCovers=3 Booster=11 Common, 3 Uncommon, 1 RareMythic FoilChanceInBooster=100 +ChaosDraftThemes=MASTERS_SET [cards] 1 R Adarkar Valkyrie diff --git a/forge-gui/res/editions/New Phyrexia.txt b/forge-gui/res/editions/New Phyrexia.txt index e3001c0aa00..34ef161abb8 100644 --- a/forge-gui/res/editions/New Phyrexia.txt +++ b/forge-gui/res/editions/New Phyrexia.txt @@ -7,6 +7,7 @@ MciCode=nph Type=Expansion BoosterCovers=3 Booster=10 Common, 3 Uncommon, 1 RareMythic, 1 BasicLand +ChaosDraftThemes=MIRRODIN [cards] 78 U Act of Aggression diff --git a/forge-gui/res/editions/Ninth Edition.txt b/forge-gui/res/editions/Ninth Edition.txt index 6f9dbcc9584..dce5aa6170c 100644 --- a/forge-gui/res/editions/Ninth Edition.txt +++ b/forge-gui/res/editions/Ninth Edition.txt @@ -9,6 +9,7 @@ Border=White BoosterCovers=5 Booster=10 Common, 3 Uncommon, 1 Rare, 1 BasicLand FoilAlwaysInCommonSlot=False +ChaosDraftThemes=CORE_SET [cards] 317 R Adarkar Wastes diff --git a/forge-gui/res/editions/Odyssey.txt b/forge-gui/res/editions/Odyssey.txt index 60b1164d686..7e1e0f47eeb 100644 --- a/forge-gui/res/editions/Odyssey.txt +++ b/forge-gui/res/editions/Odyssey.txt @@ -9,6 +9,7 @@ BoosterCovers=3 Booster=11 Common, 3 Uncommon, 1 Rare Foil=OldStyle FoilAlwaysInCommonSlot=False +ChaosDraftThemes=GRAVEYARD_MATTERS [cards] 60 C AEther Burst diff --git a/forge-gui/res/editions/Ravnica Allegiance.txt b/forge-gui/res/editions/Ravnica Allegiance.txt index c614de27d60..889ac8f637c 100644 --- a/forge-gui/res/editions/Ravnica Allegiance.txt +++ b/forge-gui/res/editions/Ravnica Allegiance.txt @@ -7,6 +7,7 @@ MciCode=rna Type=Expansion BoosterCovers=5 Booster=10 Common:!fromSheet("RNA Secret Cards"), 3 Uncommon:!fromSheet("RNA Secret Cards"), 1 RareMythic:!fromSheet("RNA Secret Cards"), 1 fromSheet("RNA Lands") +ChaosDraftThemes=RAVNICA [cards] 1 M Angel of Grace diff --git a/forge-gui/res/editions/Ravnica City of Guilds.txt b/forge-gui/res/editions/Ravnica City of Guilds.txt index fdb72964748..bc98825cf3f 100644 --- a/forge-gui/res/editions/Ravnica City of Guilds.txt +++ b/forge-gui/res/editions/Ravnica City of Guilds.txt @@ -8,6 +8,7 @@ Type=Expansion BoosterCovers=5 Booster=11 Common, 3 Uncommon, 1 Rare FoilAlwaysInCommonSlot=False +ChaosDraftThemes=RAVNICA [cards] 190 R Agrus Kos, Wojek Veteran diff --git a/forge-gui/res/editions/Return to Ravnica.txt b/forge-gui/res/editions/Return to Ravnica.txt index 0d0ad645ebb..2d4aada621d 100644 --- a/forge-gui/res/editions/Return to Ravnica.txt +++ b/forge-gui/res/editions/Return to Ravnica.txt @@ -7,6 +7,7 @@ MciCode=rtr Type=Expansion BoosterCovers=5 Booster=10 Common, 3 Uncommon, 1 RareMythic, 1 BasicLand +ChaosDraftThemes=RAVNICA;GRAVEYARD_MATTERS [cards] 141 R Abrupt Decay diff --git a/forge-gui/res/editions/Revised Edition.txt b/forge-gui/res/editions/Revised Edition.txt index 101947233c7..ccc051bebe1 100644 --- a/forge-gui/res/editions/Revised Edition.txt +++ b/forge-gui/res/editions/Revised Edition.txt @@ -9,6 +9,7 @@ Border=White BoosterCovers=1 Booster=11 Common, 3 Uncommon, 1 Rare Foil=NotSupported +ChaosDraftThemes=CORE_SET [cards] U Air Elemental diff --git a/forge-gui/res/editions/Scars of Mirrodin.txt b/forge-gui/res/editions/Scars of Mirrodin.txt index 481198839fe..606ecf4d937 100644 --- a/forge-gui/res/editions/Scars of Mirrodin.txt +++ b/forge-gui/res/editions/Scars of Mirrodin.txt @@ -7,6 +7,7 @@ MciCode=som Type=Expansion BoosterCovers=5 Booster=10 Common, 3 Uncommon, 1 RareMythic, 1 BasicLand +ChaosDraftThemes=MIRRODIN [cards] 1 U Abuna Acolyte diff --git a/forge-gui/res/editions/Scourge.txt b/forge-gui/res/editions/Scourge.txt index eb932a6c227..9a7a5354a2a 100644 --- a/forge-gui/res/editions/Scourge.txt +++ b/forge-gui/res/editions/Scourge.txt @@ -9,6 +9,7 @@ BoosterCovers=3 Booster=11 Common, 3 Uncommon, 1 Rare Foil=OldStyle FoilAlwaysInCommonSlot=False +ChaosDraftThemes=GRAVEYARD_MATTERS [cards] 109 C Accelerated Mutation diff --git a/forge-gui/res/editions/Secret Lair Drop Series.txt b/forge-gui/res/editions/Secret Lair Drop Series.txt index 08974c079ef..9b03d7c6c27 100644 --- a/forge-gui/res/editions/Secret Lair Drop Series.txt +++ b/forge-gui/res/editions/Secret Lair Drop Series.txt @@ -111,6 +111,10 @@ Type=Other 147 M Negan, the Cold-Blooded 154 M Admonition Angel 155 R Roil Elemental +164 R Teferi's Protection +165 M Consecrated Sphinx +166 R Collected Company +167 R Amulet of Vigor 156 R Zulaport Cutthroat 157 M Warren Instigator 158 M Avenger of Zendikar diff --git a/forge-gui/res/editions/Seventh Edition.txt b/forge-gui/res/editions/Seventh Edition.txt index 8da1f7d6838..3feaac56c79 100644 --- a/forge-gui/res/editions/Seventh Edition.txt +++ b/forge-gui/res/editions/Seventh Edition.txt @@ -10,6 +10,7 @@ BoosterCovers=5 Booster=10 Common, 3 Uncommon, 1 Rare, 1 BasicLand Foil=OldStyle FoilAlwaysInCommonSlot=False +ChaosDraftThemes=CORE_SET [cards] 172 U AEther Flash diff --git a/forge-gui/res/editions/Shadows over Innistrad.txt b/forge-gui/res/editions/Shadows over Innistrad.txt index 224c0915cfe..7cd7a64fbda 100644 --- a/forge-gui/res/editions/Shadows over Innistrad.txt +++ b/forge-gui/res/editions/Shadows over Innistrad.txt @@ -8,6 +8,7 @@ MciCode=soi BoosterCovers=5 Booster=9 Common:!dfc, 3 Uncommon:!dfc, 1 RareMythic:!dfc, 1 dfc:!Rare:!Mythic, 1 BasicLand ChanceReplaceCommonWith=.125F dfc:RareMythic +ChaosDraftThemes=GRAVEYARD_MATTERS [cards] diff --git a/forge-gui/res/editions/Tenth Edition.txt b/forge-gui/res/editions/Tenth Edition.txt index 7ed4e1896c5..69f99486b31 100644 --- a/forge-gui/res/editions/Tenth Edition.txt +++ b/forge-gui/res/editions/Tenth Edition.txt @@ -7,6 +7,7 @@ MciCode=10e Type=Core BoosterCovers=5 Booster=10 Common, 3 Uncommon, 1 Rare, 1 BasicLand +ChaosDraftThemes=CORE_SET [cards] 249 R Abundance diff --git a/forge-gui/res/editions/Theros Beyond Death.txt b/forge-gui/res/editions/Theros Beyond Death.txt index 7d38b479b01..12b9eb14c51 100644 --- a/forge-gui/res/editions/Theros Beyond Death.txt +++ b/forge-gui/res/editions/Theros Beyond Death.txt @@ -7,6 +7,7 @@ Type=Expansion BoosterCovers=3 Booster=10 Common:!fromSheet("THB Secret Cards"), 3 Uncommon:!fromSheet("THB Secret Cards"), 1 RareMythic:!fromSheet("THB Secret Cards"), 1 BasicLand Prerelease=6 Boosters, 1 RareMythic+ +ChaosDraftThemes=GRAVEYARD_MATTERS [cards] 1 U Alseid of Life's Bounty diff --git a/forge-gui/res/editions/Torment.txt b/forge-gui/res/editions/Torment.txt index 5bf2e07e83e..033ea556ec8 100644 --- a/forge-gui/res/editions/Torment.txt +++ b/forge-gui/res/editions/Torment.txt @@ -9,6 +9,7 @@ BoosterCovers=1 Booster=11 Common, 3 Uncommon, 1 Rare Foil=OldStyle FoilAlwaysInCommonSlot=False +ChaosDraftThemes=GRAVEYARD_MATTERS [cards] 90 C Accelerate diff --git a/forge-gui/res/editions/Ultimate Masters.txt b/forge-gui/res/editions/Ultimate Masters.txt index 0c799d1cb69..de468aa72da 100644 --- a/forge-gui/res/editions/Ultimate Masters.txt +++ b/forge-gui/res/editions/Ultimate Masters.txt @@ -8,6 +8,7 @@ Type=Reprint BoosterCovers=3 Booster=11 Common, 3 Uncommon, 1 RareMythic FoilChanceInBooster=100 +ChaosDraftThemes=MASTERS_SET;GRAVEYARD_MATTERS [cards] 1 R All Is Dust diff --git a/forge-gui/res/editions/Unlimited Edition.txt b/forge-gui/res/editions/Unlimited Edition.txt index ead1be21f6e..54e891f24bf 100644 --- a/forge-gui/res/editions/Unlimited Edition.txt +++ b/forge-gui/res/editions/Unlimited Edition.txt @@ -9,6 +9,7 @@ Border=White BoosterCovers=1 Booster=11 Common, 3 Uncommon, 1 Rare Foil=NotSupported +ChaosDraftThemes=CORE_SET [cards] U Air Elemental diff --git a/forge-gui/res/editions/War of the Spark.txt b/forge-gui/res/editions/War of the Spark.txt index 01c65804bf3..9ab696b37a5 100644 --- a/forge-gui/res/editions/War of the Spark.txt +++ b/forge-gui/res/editions/War of the Spark.txt @@ -8,6 +8,7 @@ Type=Expansion BoosterCovers=3 Booster=10 Common:!fromSheet("WAR Secret Cards"), 3 Uncommon:!fromSheet("WAR Secret Cards"), 1 RareMythic:!fromSheet("WAR Secret Cards"), 1 BasicLand BoosterMustContain=Planeswalker +ChaosDraftThemes=RAVNICA [cards] 1 R Karn, the Great Creator diff --git a/forge-gui/res/editions/Weatherlight.txt b/forge-gui/res/editions/Weatherlight.txt index 1ef49097fbf..c6b40184429 100644 --- a/forge-gui/res/editions/Weatherlight.txt +++ b/forge-gui/res/editions/Weatherlight.txt @@ -8,6 +8,7 @@ Type=Expansion BoosterCovers=1 Booster=11 Common, 3 Uncommon, 1 Rare Foil=NotSupported +ChaosDraftThemes=GRAVEYARD_MATTERS [cards] U AEther Flash diff --git a/forge-gui/res/editions/Zendikar Rising Commander.txt b/forge-gui/res/editions/Zendikar Rising Commander.txt index c968d4dd6d2..8e9ee5ea5ba 100644 --- a/forge-gui/res/editions/Zendikar Rising Commander.txt +++ b/forge-gui/res/editions/Zendikar Rising Commander.txt @@ -148,3 +148,16 @@ Type=Other 141 U Submerged Boneyard 142 C Terramorphic Expanse +[tokens] +w_1_1_bird_flying +w_1_1_kor_ally +g_1_1_saproling +g_2_2_elemental +g_4_4_beast +b_0_0_germ +b_1_1_faerie_rogue_flying +b_1_1_goblin_rogue +b_1_1_rat +rg_5_5_elemental +c_1_1_a_thopter_flying + diff --git a/forge-gui/res/formats/Casual/Brawl.txt b/forge-gui/res/formats/Casual/Brawl.txt index 2730bf5e4c1..88a66643528 100644 --- a/forge-gui/res/formats/Casual/Brawl.txt +++ b/forge-gui/res/formats/Casual/Brawl.txt @@ -4,4 +4,4 @@ Order:101 Type:Casual Subtype:Commander Sets:ELD, THB, IKO, M21, ZNR -Banned:Drannith Magistrate; Lutri, the Spellchaser; Oko, Thief of Crowns; Sorcerous Spyglass; Winota, Joiner of Forces; +Banned:Drannith Magistrate; Lutri, the Spellchaser; Oko, Thief of Crowns; Omnath, Locus of Creation; Sorcerous Spyglass; Winota, Joiner of Forces; diff --git a/forge-gui/res/formats/Digital/Historic.txt b/forge-gui/res/formats/Digital/Historic.txt index 5982278d88e..856735a6f6f 100644 --- a/forge-gui/res/formats/Digital/Historic.txt +++ b/forge-gui/res/formats/Digital/Historic.txt @@ -5,5 +5,5 @@ Subtype:Arena Effective:2019-11-21 Order:142 Sets:XLN, RIX, DOM, M19, GRN, G18, RNA, WAR, M20, ELD, HA1, THB, HA2, IKO, HA3, M21, JMP, AKR, ZNR -Banned:Agent of Treachery; Burning-Tree Emissary; Field of the Dead; Fires of Invention; Oko, Thief of Crowns; Nexus of Fate; Once Upon a Time; Teferi, Time Raveler; Veil of Summer; Wilderness Reclamation; Winota, Joiner of Forces -#Suspended:Burning-Tree Emissary; Teferi, Time Raveler; Wilderness Reclamation +Banned:Agent of Treachery; Field of the Dead; Fires of Invention; Oko, Thief of Crowns; Omnath, Locus of Creation; Nexus of Fate; Once Upon a Time; Teferi, Time Raveler; Veil of Summer; Wilderness Reclamation; Winota, Joiner of Forces +#Suspended:Omnath, Locus of Creation diff --git a/forge-gui/res/formats/Sanctioned/Standard.txt b/forge-gui/res/formats/Sanctioned/Standard.txt index f9eb4b75357..67f428bb7ba 100644 --- a/forge-gui/res/formats/Sanctioned/Standard.txt +++ b/forge-gui/res/formats/Sanctioned/Standard.txt @@ -4,4 +4,4 @@ Order:101 Subtype:Standard Type:Sanctioned Sets:ELD, THB, IKO, M21, ZNR -Banned:Cauldron Familiar; Fires of Invention; Oko, Thief of Crowns; Once Upon a Time; Uro, Titan of Nature's Wrath; Veil of Summer +Banned:Cauldron Familiar; Escape to the Wilds; Fires of Invention; Lucky Clover; Oko, Thief of Crowns; Omnath, Locus of Creation; Once Upon a Time; Uro, Titan of Nature's Wrath; Veil of Summer diff --git a/forge-gui/res/languages/de-DE.properties b/forge-gui/res/languages/de-DE.properties index 9f2b4294fed..c4ca9c9dd17 100644 --- a/forge-gui/res/languages/de-DE.properties +++ b/forge-gui/res/languages/de-DE.properties @@ -113,6 +113,8 @@ cbpAutoYieldMode=Automatische Bestätigung cbpCounterDisplayType=Markeranzeige Art cbpCounterDisplayLocation=Markeranzeige Ort cbpGraveyardOrdering=Genaue Reihenfolge im Friedhof einhalten +lblAltLifeDisplay=Alternatives Spieler-Layout (Landscape-Modus) +nlAltLifeDisplay=Alternative Anzeige von Lebens-, Gift-, Energie- und Erfahrungspunkten. Troubleshooting=Fehlerbehebung GeneralConfiguration=Allgemeine Einstellungen lblPlayerName=Spielername @@ -446,7 +448,7 @@ cbLaunchZeppelin=Starte Zeppelin lblQuestData=Quest Daten lblLoadQuestData=Lade Quest-Daten lblStartanewQuest=Starte neue Quest -lblOldQuestData=Alte Questdaten? Kopiere sie nach %n und starte Forge neu. +lblOldQuestData=Alte Questdaten? Kopiere sie nach %s und starte Forge neu. rbEasy=Einfach rbMedium=Mittel rbHard=Hart @@ -494,6 +496,7 @@ lblCreateaDeck=Erzeuge ein Deck. #CSubmenuQuestPrefs.java lblEnteraNumber=Nummer eingeben lblSavefailed=Speichern fehlgeschlagen +lblEnteraDecimal=Eine Zahl eingeben #DialogChooseFormats.java cbWantReprints=Erlaube passende Drucke aus anderen Sets lblChooseFormats=Wähle Format @@ -734,6 +737,8 @@ lblWinsperDraftRotation=Siege pro Draft notwendig ttWinsperDraftRotation=Wenn ein Draft nicht soweit fertig gespielt wird, wird er entfernt oder ersetzt. lblRotationType=Austauschtyp ttRotationType=Bei 0 verschwinden alte Drafts, bei 1 wird er durch einen neuen ersetzt. +lblWildOpponentMultiplier=Wild-Multiplikator +lblWildOpponentNumber=Anzahl der Wild-Gegner #StatTypeFilter.java lblclicktotoogle=Klicke zum Umschalten des Filters, Rechtsklick für Einzelanzeige von: #SItemManagerUtil.java @@ -1926,6 +1931,7 @@ lblPlanarDeckZone=Weltendeck lblNoneZone=Keine #BoosterDraft.java lblChooseBlock=Wähle Block +lblChooseChaosTheme=Wähle ein Chaos-Draft-Thema lblBlockNotContainSetCombinations={0} enthält keine Set-Auswahl. lblChooseSetCombination=Treffe Set-Auswahl lblNotFoundCustomDraftFiles=Keine angepaßte Draft-Datei gefunden. @@ -2587,7 +2593,7 @@ lblEnterMessageToSend=Nachricht zum Senden eingeben lblDetectedInvalidHostAddress=Ungültige Host-Adresse ({0}) wurde festgestellt. #Player.java lblChooseACompanion=Wähle einen Gefährten -lblWildOpponentMultiplier=Wild-Multiplikator -lblEnteraDecimal=Eine Zahl eingeben -lblWildOpponentNumber=Anzahl der Wild-Gegner +#QuestPreferences.java lblWildOpponentNumberError=Anzahl der Wild-Gegner kann nur 0 bis 3 sein +#GauntletWinLose.java +lblGauntletProgress=Spießrutenlauf-Fortschritt diff --git a/forge-gui/res/languages/en-US.properties b/forge-gui/res/languages/en-US.properties index 458070f8a55..34539fa15c2 100644 --- a/forge-gui/res/languages/en-US.properties +++ b/forge-gui/res/languages/en-US.properties @@ -113,6 +113,8 @@ cbpAutoYieldMode=Auto-Yield cbpCounterDisplayType=Counter Display Type cbpCounterDisplayLocation=Counter Display Location cbpGraveyardOrdering=Allow Ordering Cards Put in Graveyard +lblAltLifeDisplay=Alternate Player Layout (Landscape Mode) +nlAltLifeDisplay=Enables alternate layout for displaying Player Life, Poison, Energy and Experience counters. Troubleshooting=Troubleshooting GeneralConfiguration=General Configuration lblPlayerName=Player Name @@ -494,6 +496,7 @@ lblCreateaDeck=Create a Deck. #CSubmenuQuestPrefs.java lblEnteraNumber=Enter a number lblSavefailed=Save failed +lblEnteraDecimal=Enter a decimal #DialogChooseFormats.java cbWantReprints=Allow compatible reprints from other sets lblChooseFormats=Choose formats @@ -734,6 +737,8 @@ lblWinsperDraftRotation=Wins per Draft Rotation ttWinsperDraftRotation=If a Draft is not played for this many match wins, it will be removed or replaced. lblRotationType=Rotation Type ttRotationType=If set to 0, old drafts disappear, if set to 1, they are replaced with another one using different sets. +lblWildOpponentNumber=Number of Wild Opponents +lblWildOpponentMultiplier=Wild Multiplier #StatTypeFilter.java lblclicktotoogle=click to toggle the filter, right-click to show only #SItemManagerUtil.java @@ -1926,6 +1931,7 @@ lblPlanarDeckZone=planardeck lblNoneZone=none #BoosterDraft.java lblChooseBlock=Choose Block +lblChooseChaosTheme=Choose Chaos Draft Theme lblBlockNotContainSetCombinations={0} does not contain any set combinations. lblChooseSetCombination=Choose Set Combination lblNotFoundCustomDraftFiles=No custom draft files found. @@ -2587,7 +2593,7 @@ lblEnterMessageToSend=Enter message to send lblDetectedInvalidHostAddress=Invalid host address ({0}) was detected. #Player.java lblChooseACompanion=Choose a companion -lblWildOpponentMultiplier=Wild Multiplier -lblEnteraDecimal=Enter a decimal -lblWildOpponentNumber=Number of Wild Opponents +#QuestPreferences.java lblWildOpponentNumberError=Wild Opponents can only be 0 to 3 +#GauntletWinLose.java +lblGauntletProgress=Gauntlet Progress diff --git a/forge-gui/res/languages/es-ES.properties b/forge-gui/res/languages/es-ES.properties index 05f2462797f..9f69c518280 100644 --- a/forge-gui/res/languages/es-ES.properties +++ b/forge-gui/res/languages/es-ES.properties @@ -8,9 +8,9 @@ splash.loading.processingimagesprites=Procesando imágenes de cartas #FControl.java lblOpeningMainWindow=Abriendo ventana principal... lblCloseScreen=Cerrar Pantalla -txCloseAction1=Forge ahora admite pestañas de navegación que permiten cerrar y cambiar entre diferentes pantallas con facilidad. Como resultado, ya no necesita usar el botón X en la esquina superior derecha para cerrar la pantalla actual y regresar. -txCloseAction2=Seleccione lo que desea que suceda al hacer clic en el botón X en la parte superior derecha. Esta opción se utilizará en el futuro y no volverá a ver este mensaje. Puedes cambiar este comportamiento en cualquier momento en Preferencias. -titCloseAction=Seleccione su Acción al Cerrar +txCloseAction1=Forge ahora admite pestañas de navegación que permiten cerrar y cambiar entre diferentes pantallas con facilidad. Como resultado, ya no necesitas usar el botón X en la esquina superior derecha para cerrar la pantalla actual y regresar. +txCloseAction2=Selecciona lo que quieres que suceda al hacer clic en el botón X en la parte superior derecha. Esta opción se utilizará en el futuro y no volverás a ver este mensaje. Puedes cambiar este comportamiento en cualquier momento en Preferencias. +titCloseAction=Selecciona tu Acción al Cerrar lblAreYouSureYouWishRestartForge=¿Estás seguro de que deseas reiniciar Forge? lblAreYouSureYouWishExitForge=¿Estás seguro de que deseas salir de Forge? lblOneOrMoreGamesActive=Una o más partidas están actualmente activos @@ -28,7 +28,7 @@ lblOathbreakerDeckEditor=Editor Mazos Oathbreaker lblTinyLeadersDeckEditor=Editor Mazos Tiny Leaders lblBrawlDeckEditor=Editor Mazos Brawl lblDraftDeckEditor=Editor Mazo Draft -lblSealedDeckEditor=Editor Mazo Sellao +lblSealedDeckEditor=Editor Mazo Cerrado lblTokenViewer=Visor de Tokens lblCloseViewer=Cerrar Visor lblQuestDeckEditor=Editor Mazos Aventura @@ -39,7 +39,7 @@ lblLeaveDraft=Abandonar Draft lblBazaar=Bazar lblConcedeGame=Conceder Partida txerrFailedtodeletelayoutfile=Fallo al borrar el archivo de disposición -lblLeaveBazaar=Leave Bazaar +lblLeaveBazaar=Abandonar Bazar #VSubmenuPreferences.java Preferences=Preferencias btnReset=Restablecer la configuración predeterminada @@ -55,9 +55,9 @@ btnCopyToClipboard=Copiar al portapapeles cbpAutoUpdater=Actualizar Forge nlAutoUpdater=Selecciona la versión a utilizar para actualizar Forge cbpSelectLanguage=Idioma -nlSelectLanguage=Seleccionar idioma (excepto partida). Todavía un trabajo en progreso) (Es necesario reiniciar Forge) -cbRemoveSmall=Eliminar Pequeñas Criaturas -cbCardBased=Incluye la generación de mazo basado en carta +nlSelectLanguage=Seleccionar idioma (excepto textos en partida). Todavía un trabajo en progreso (Es necesario reiniciar Forge) +cbRemoveSmall=Eliminar Criaturas pequeñas +cbCardBased=Generación de mazos basados en carta cbSingletons=Mode Singleton cbRemoveArtifacts=Quitar artefactos cbAnte=Jugar con apuesta (Ante) @@ -103,16 +103,18 @@ cbFilterLandsByColorId=Filtrar tierras por color en habilidades activadas cbShowStormCount=Mostrar el contador de tormenta (Storm) en el panel de aviso cbRemindOnPriority=Alerta visual al recibir la prioridad cbUseSentry=Enviar automáticamente informes de errores. -cbpGameLogEntryType=Verbosidad del registro del juego +cbpGameLogEntryType=Registro del juego cbpCloseAction=Acción al cerrar cbpDefaultFontSize=Tamaño de fuente predeterminado cbpAiProfiles=Personalidad de la IA -cbpStackAdditions=Stack effect notifications -cbpDisplayCurrentCardColors=Mostrar color detallado de la carta +cbpStackAdditions=Efecto de la pila de notificaciones +cbpDisplayCurrentCardColors=Mostrar color de la carta cbpAutoYieldMode=Auto-Ceder -cbpCounterDisplayType=Forma en la que se muestran los contadores +cbpCounterDisplayType=Estilo de los contadores cbpCounterDisplayLocation=Ubicación del contador cbpGraveyardOrdering=Permitir ordenar cartas puestas en el cementerio +lblAltLifeDisplay=Alternate Player Layout (Landscape Mode) +nlAltLifeDisplay=Enables alternate layout for displaying Player Life, Poison, Energy and Experience counters. Troubleshooting=Solución de problemas GeneralConfiguration=Configuración general lblPlayerName=Nombre Jugador @@ -132,9 +134,9 @@ nlEnforceDeckLegality=Aplica la legalidad del mazo correspondiente a cada entorn nlSideboardForAI=Permite a los usuarios sideboard con el mazo de la IA y el sideboard en formatos de juego construidos. nlPerformanceMode=Desactiva las comprobaciones de habilidades estáticas adicionales para acelerar el motor del juego. (Advertencia: rompe algunos escenarios ''como si tuviera flash'' cuando se lanzan cartas de propiedad de los oponentes). nlFilteredHands=Genera dos manos iniciales y mantiene la que tiene el recuento de tierras más cercano al promedio del mazo (Requiere reinicio) -nlCloneImgSource=Cuando se habilite, los clones usarán su arte original en lugar del arte de la carta clonada. -nlPromptFreeBlocks=Cuando esté habilitado, si tuviera que pagar 0 para bloquear, pague automáticamente sin aviso. -nlPauseWhileMinimized=Cuando está habilitado, Forge hace una pausa cuando está minimizado (principalmente para AI contra AI). +nlCloneImgSource=Cuando se habilita, los clones usarán su arte original en lugar del arte de la carta clonada. +nlPromptFreeBlocks=Cuando está habilitado, si tuvieses que pagar 0 para bloquear, paga automáticamente sin aviso. +nlPauseWhileMinimized=Cuando está habilitado, Forge hace una pausa cuando está minimizado (principalmente para IA contra IA). nlEscapeEndsTurn=Cuando está habilitada, la tecla Escape funciona como un atajo alternativo para finalizar el turno actual. nlDetailedPaymentDesc=Cuando está habilitado, se muestran descripciones detalladas de hechizos / habilidades al elegir objetivos y pagar costos. nlShowStormCount=Cuando está habilitado, muestra el recuento de tormentas actual en el panel de solicitud. @@ -149,14 +151,14 @@ nlRemoveArtifacts=Deshabilita las cartas de artefactos en los mazos generados. nlCardBased=Crea mazos aleatorios más sinérgicos (requiere reinicio) DeckEditorOptions=Opciones del editor de mazo nlFilterLandsByColorId=Al usar filtros de color de cartas, filtre las tierras de manera que sea más fácil encontrar tierras que produzcan ese color de maná. -AdvancedSettings=Ajustes avanzados +AdvancedSettings=Ajustes Avanzados nlDevMode=Habilita el menú con funciones para probar durante el desarrollo. nlWorkshopSyntax=Habilita la comprobación de sintaxis de los guiones de cartas en el taller. Nota: funcionalidad aún en fase de prueba! nlGameLogEntryType=Cambia la cantidad de información que se muestra en el registro del juego. Ordenado de menos a más detallado. nlCloseAction=Cambia lo que sucede al hacer clic en el botón X en la parte superior derecha. nlLoadCardsLazily=Si está activado, Forge cargará los scripts de las cartas según sea necesario en lugar de al inicio. (Advertencia: Experimental) nlLoadHistoricFormats=Si está activado, Forge cargará todas los formatos históricos, esto puede demorar un poco más en cargarse en el inicio. -GraphicOptions=Opciones gráficas +GraphicOptions=Opciones Gráficas nlDefaultFontSize=El tamaño de fuente predeterminado dentro de la interfaz de usuario. Todos los elementos de fuente se escalan en relación a esto. (Necesita reinicio) cbpMulliganRule=Regla de Mulligan nlImageFetcher=Permite la descarga instantánea de imágenes de cartas faltantes. @@ -178,8 +180,8 @@ nlCounterDisplayType=Selecciona el estilo en el que se mostrarán los contadores nlCounterDisplayLocation=Determina dónde colocar los contadores basados en texto en la carta: cerca de la parte superior o cerca de la parte inferior. nlDisplayCurrentCardColors=Muestra el color actual de las cartas en el panel de información detallada de la carta. SoundOptions=Opciones de Sonido -nlEnableSounds=Habilitar efectos de sonido durante el juego -nlEnableMusic=Habilitar música de fondo durante el juego +nlEnableSounds=Habilita los efectos de sonido durante el juego +nlEnableMusic=Habilita la música de fondo durante el juego nlAltSoundSystem=Use el sistema de sonido alternativo (solo use si tiene problemas con el sonido que no se reproduce o desaparece) nlSrOptimize=Set various options to make FOrge work better with screen readers KeyboardShortcuts=Atajos de teclado @@ -446,7 +448,7 @@ cbLaunchZeppelin=Lanzar Zeppelin lblQuestData=Datos de Aventura lblLoadQuestData=Cargar Datos de Aventura lblStartanewQuest=Comenzar una nueva Aventura -lblOldQuestData=Viejos datos de Aventura? Poner en %n y reiniciar Forge. +lblOldQuestData=¿Datos antiguos de Aventura? Ponlos en %s y reinicia Forge. rbEasy=Fácil rbMedium=Medio rbHard=Difícil @@ -492,11 +494,12 @@ lblQuestExists=Ya existe una aventura con ese nombre. Por favor, elija otro nomb #CSubmenuQuestDecks.java lblCreateaDeck=Crear un Mazo. #CSubmenuQuestPrefs.java -lblEnteraNumber=Ingrese un numero +lblEnteraNumber=Introduce un número lblSavefailed=Error al guardar +lblEnteraDecimal=Introduce un decimal #DialogChooseFormats.java cbWantReprints=Permitir reimpresiones compatibles de otras ediciones. -lblChooseFormats=Elije Formatos +lblChooseFormats=Elige Formatos lblSanctioned=Oficial lblOther=Otro lblHistoric=Histórico @@ -570,7 +573,7 @@ lblRandomStandardColorDecks=Mazos Standard Aleatorio por Color lblRandomModernColorDecks=Mazos Standard Aleatorio por Color lblRandomThemeDecks=Mazos Aleatorios Temáticos lblRandomDecks=Mazos Aleatorios -lblNetDecks=Mazos en línea +lblNetDecks=Mazos en Línea lblNetCommanderDecks=Mazos Commander en línea #VSubmenuTutorial lblTutorial=Tutorial @@ -581,12 +584,12 @@ lblPuzzleModeSolve=Modo Puzzle: Resolver #VSubmenuPuzzleCreate.java lblPuzzleModeCreate=Modo Puzzle: Crear lblCreate=Crear -lblCreateNewPuzzle=Create a New Puzzle -lblCreatePuzzleDest1=In this mode, you will start with a clean battlefield and empty zones. -lblCreatePuzzleDest2=You will need to use the Developer Mode tools to create a game state for your puzzle. -lblCreatePuzzleDest3=Then, use the Dump Game State command to export your game state with metadata template. -lblCreatePuzzleDest4=You can edit the exported file in a text editor to change the puzzle name, description, and objectives. -lblCreatePuzzleDest5=The puzzle file needs to have the .pzl extension and must be placed in res/puzzles. +lblCreateNewPuzzle=Crear un Nuevo Puzzle +lblCreatePuzzleDest1=En este modo, comenzarás con un campo de batalla limpio y zonas vacías. +lblCreatePuzzleDest2=Tendrás que usar las herramientas del Modo de Desarrollador para crear un estado de juego para tu puzzle. +lblCreatePuzzleDest3=Luego, usa el comando Volcar el Estado de Juego para exportar tu estado de juego con la plantilla de metadatos. +lblCreatePuzzleDest4=Puedes editar el archivo exportado en un editor de texto para cambiar el nombre, la descripción y los objetivos del puzzle. +lblCreatePuzzleDest5=El archivo del puzzle debe tener la extensión .pzl y debe ser colocado en res/puzzles. #VSubmenuGauntletLoad.java lblQuickGauntlets=Desafíos Rápidos lblQuickGauntlet=Desafío Rápido @@ -647,12 +650,12 @@ lblNoQuest=No Aventura lblVisitTheSpellShop=Visita la Tienda de Hechizos. lblVisitTheBazaar=Visita al Bazar. lblUnlockEditions=Desbloquear Ediciones. -lblUnlocked=Has desbloqueado con éxito %n! -titleUnlocked=%n desbloqueado! +lblUnlocked=¡Has desbloqueado con éxito %n! +titleUnlocked=¡%n desbloqueado! lblStartADuel=Comienza un duelo. lblSelectAQuestDeck=Por favor, seleccione un mazo de aventura. lblInvalidDeck=Mazo no válido -lblInvalidDeckDesc=Su mazo %n\nPor favor, edite o elija un mazo diferente. +lblInvalidDeckDesc=Tu mazo %n\nPor favor, edita o elige un mazo diferente. #VSubmenuQuestPrefs.java lblQuestPreferences=Preferencias de la Aventura lblRewardsError=Error de recompensas @@ -734,8 +737,10 @@ lblWinsperDraftRotation=Victorias Rotación de Draft ttWinsperDraftRotation=Si no se juega un Draft para esta cantidad de victorias, se eliminará o reemplazará. lblRotationType=Tipo de Rotación ttRotationType=Si se establece en 0, los anteriores Draft desaparecen, si se establece en 1, se reemplazan por otros que utilizan sets diferentes. +lblWildOpponentNumber=Número de Oponentes Salvajes +lblWildOpponentMultiplier=Multiplicador Salvaje #StatTypeFilter.java -lblclicktotoogle=haga clic para alternar el filtro, haga clic con el botón derecho para mostrar solo +lblclicktotoogle=haz clic para alternar el filtro, haz clic con el botón derecho para solo mostrar #SItemManagerUtil.java lblWhitecards=Cartas Blancas lblBluecards=Cartas Azules @@ -839,7 +844,7 @@ lblDock=Dock lblViewDeckList=Ver Lista del Mazo lblRevertLayout=Revertir Disposición de Elementos lblOpenLayout=Abrir Disposición de Elementos -lblSaveLayout=Salvar Disposición de Elementos +lblSaveLayout=Guardar Disposición de Elementos #GroupDef.java lblColor=Color lblColorIdentity=Identidad de Color @@ -920,8 +925,8 @@ ttPrice=Price lblRanking=Ranking lblDraftRanking=Ranking en el Draft lblToughness=Resistencia -ttToughness=Toughness -ttType=Type +ttToughness=Resistencia +ttType=Tipo #HomeScreen.java lblNewGame=Nueva partida lblLoadGame=Cargar partida @@ -933,10 +938,10 @@ lblBattlefieldTextureFiltering=Filtrado de la Textura del Campo de batalla lblCompactListItems=Items de la lista compactos lblCompactTabs=Pestañas compactas lblCardOverlays=Superposiciones de las cartas -lblDisableCardEffect=Desactivar las imágenes de ''Efecto'' de las cartas +lblDisableCardEffect=Desactivar imágenes de ''Efecto'' de las cartas lblDynamicBackgroundPlanechase=Fondo Dinámico Planechase lblGameplayOptions=Opciones de Juego -lblGeneralSettings=Configuración general +lblGeneralSettings=Configuración General lblHotSeatMode=Modo de Silla Caliente lblLandscapeMode=Modo apaisado lblLater=Más tarde @@ -944,17 +949,17 @@ lblMinimizeScreenLock=Minimizar al bloquear la pantalla lblOrderGraveyard=Orden del Cementerio lblRestartForge=Reiniciar Forge lblRestartForgeDescription=Debes reiniciar Forge para que este cambio surta efecto. -lblRotateZoomPlanesPhenomena=Girar la imagen ampliada de Planos/Fenómenos -lblRotateZoomSplit=Girar la imagen ampliada de las cartas divididas -lblShowAbilityIconsOverlays=Mostrar iconos de habilidades -lblShowCardIDOverlays=Mostrar superposiciones de identificador de carta -lblShowCardManaCostOverlays=Mostrar superposiciones de costes de maná de cartas -lblShowCardNameOverlays=Mostrar superposiciones de nombres de cartas -lblShowCardOverlays=Mostrar superposiciones de cartas -lblShowCardPTOverlays=Mostrar la superposición en la carta de P/T -lblShowMatchBackground=Mostrar el fondo de la partida -lblVibrateAfterLongPress=Vibrar después de una pulsación larga -lblVibrateWhenLosingLife=Vibrar al perder vida +lblRotateZoomPlanesPhenomena=Girar imagen ampliada de Planos/Fenómenos +lblRotateZoomSplit=Girar imagen ampliada de las cartas divididas +lblShowAbilityIconsOverlays=Iconos de habilidad +lblShowCardIDOverlays=Identificador de la carta +lblShowCardManaCostOverlays=Coste de maná de la carta +lblShowCardNameOverlays=Nombre de la carta +lblShowCardOverlays=Superposiciones de cartas +lblShowCardPTOverlays=P/T de la carta +lblShowMatchBackground=Mostrar fondo de la partida +lblVibrateAfterLongPress=Vibrar tras pulsación larga +lblVibrateWhenLosingLife=Vibrar al perder vidas lblVibrationOptions=Opciones de Vibración nlAutomaticBugReports=Envía automáticamente informes de errores a los desarrolladores, sin preguntar. nlBattlefieldTextureFiltering=Filtra el arte de la carta en el campo de batalla para que sea menos pixelada en pantallas grandes (se requiere reiniciar, puede reducir el rendimiento). @@ -968,26 +973,26 @@ nlMinimizeScreenLock=Minimiza Forge cuando la pantalla está bloqueada (habilít nlOrderGraveyard=Determina cuándo permitir ordenar las cartas que van al cementerio (nunca/siempre/solo con cartas relevantes). nlRotateZoomPlanesPhenomena=Gira la imagen ampliada de las cartas Plano o Fenómeno. nlRotateZoomSplit=Gira la imagen ampliada de las cartas divididas. -nlShowAbilityIconsOverlays=Muestra los iconos de habilidad de las cartas, de lo contrario, estarán ocultos. -nlShowCardIDOverlays=Muestra superposiciones del identificador de la carta, de lo contrario, ocúltalas. -nlShowCardManaCostOverlays=Muestra superposiciones de coste de maná para las cartas, de lo contrario, ocúltalas. -nlShowCardNameOverlays=Muestra superposiciones de nombres para las cartas, de lo contrario, ocúltalas. -nlShowCardOverlays=Muestra superposiciones de nombre, coste de maná, P/T, e identificador de las cartas, de lo contrario, ocúltalas. -nlShowCardPTOverlays=Muestra superposiciones de fuerza/resistencia/lealtad para las cartas, de lo contrario, ocúltalas. +nlShowAbilityIconsOverlays=Muestra u oculta los iconos de habilidad de las cartas. +nlShowCardIDOverlays=Muestra u oculta el identificador de la carta. +nlShowCardManaCostOverlays=Muestra u oculta el coste de maná de la carta. +nlShowCardNameOverlays=Muestra u oculta el nombre de la carta. +nlShowCardOverlays=Muestra u oculta superposiciones del nombre, coste de maná, P/T, e identificador de las cartas. +nlShowCardPTOverlays=Muestra u oculta superposiciones de fuerza/resistencia/lealtad para las cartas. nlShowMatchBackground=Muestra la imagen de fondo de la partida en el campo de batalla; de lo contrario, se muestra la textura de fondo. nlTheme=Establece el tema que determina el aspecto global del juego. nlVibrateAfterLongPress=Habilita la vibración rápida cuando se realice una pulsación prolongada, como p.ej. al realizar zoom de la carta. -nlVibrateWhenLosingLife=Habilita la vibración cuando tu jugador pierde vida o sufre daños durante un juego. +nlVibrateWhenLosingLife=Habilita la vibración cuando tu jugador pierde vidas o sufre daños durante un juego. lblEnableRoundBorder=Habilitar máscara de bordes redondeados nlEnableRoundBorder=Cuando está habilitado, las esquinas de las cartas se redondean (Preferiblemente Cartas con bordes completos). lblPreloadExtendedArtCards=Precargar Cartas de Arte Extendido nlPreloadExtendedArtCards=Cuando está habilitado, carga previamente las cartas de arte ampliadas en la caché al iniciar el programa (Alto uso de RAM). lblShowFPSDisplay=Mostrar FPS nlShowFPSDisplay=Cuando está habilitado, muestra los FPS (Experimental). -lblEnableUnknownCards=Enable Unknown Cards -nlEnableUnknownCards=Enable Unknown Cards to be loaded to Unknown Set. (Requires restart) -lblExperimentalNetworkCompatibility=Experimental Network Compatibility -nlExperimentalNetworkCompatibility=Forge switches to compatible network stream. (If unsure, turn OFF this option) +lblEnableUnknownCards=Habilitar Cartas Desconocidas +nlEnableUnknownCards=Habilitar que las cartas desconocidas se carguen en el Unknown Set. (Requiere reinicio) +lblExperimentalNetworkCompatibility=Compatibilidad de red experimental +nlExperimentalNetworkCompatibility=Forge cambia a un flujo de red compatible. (Si no estás seguro, deshabilita esta opción) #MatchScreen.java lblPlayers=Jugadores lblLog=Log @@ -1014,7 +1019,7 @@ lblTo=a lblAvatar=Avatar lblCards=Cartas lblPlanes=Planos -lblSchemes=Schemes +lblSchemes=Esquemas lblToMainDeck=al Mazo Principal lblHowMany=¿cuántos? lblInventory=Inventario @@ -1032,7 +1037,7 @@ lblPreloadExtendedArt=Precargando Arte Extendido... #LobbyScreen.java lblMore=Más... lblLoadingNewGame=Cargando nueva partida... -lblSelectVariants=Selecciona Variants +lblSelectVariants=Selecciona Variantes msgSelectAdeckBeforeReadying=¡Selecciona un mazo antes de estar listo! #PlayerPanel.java lblLoadingDeck=Cargando mazo... @@ -1087,15 +1092,15 @@ lblSwipeUpTo=Desliza hacia arriba para %s lblSwipeDownDetailView=Desliza hacia abajo para cambiar a la vista de detalle lblSwipeDownPictureView=Desliza hacia abajo para cambiar a la vista de imagen #VGameMenu.java -lblShowWinLoseOverlay=Show WinLose Overlay +lblShowWinLoseOverlay=Superposición GanarPerder lblNoPlayerPriorityNoDeckListViewed=Ningún jugador tiene prioridad en este momento, por lo que la lista de mazos no se puede ver. #FilesPage.java lblFiles=Archivos lblStorageLocations=Ubicación del almacenamiento -lblCardPicsLocation=Ubicación de las Imágenes de las Cartas +lblCardPicsLocation=Ubicación de Imágenes de las Cartas lblDecksLocation=Ubicación de los Mazos -lblDataLocation=Ubicación de los Datos (por ejemplo, Configuración y Aventuras) -lblImageCacheLocation=Ubicación de la Caché de imágenes +lblDataLocation=Ubicación de Datos (p.ej. Configuración y Aventuras) +lblImageCacheLocation=Ubicación de Caché de imágenes lblRestartForgeMoveFilesNewLocation=Necesitarás reiniciar Forge para que este cambio tenga efecto. Asegúrate de mover todos los archivos necesarios a la nueva ubicación antes de hacerlo. lblRestartRequired=Reinicio Requerido lblSelect=Seleccionar %s @@ -1117,10 +1122,10 @@ lblFollowingCardsCannotBeImported=Las siguientes cartas no pueden ser importadas lblImportRemainingCards=¿Importar las cartas restantes? lblNoKnownCardsOnClipboard=No se han encontrado cartas conocidas en el portapapeles.\n\nCopia la lista del mazo en el portapapeles y, a continuación, vuelve a abrir este cuadro de diálogo. #FDeckViewer.java -lblChangeSection=Change Section +lblChangeSection=Cambiar Sección lblDeckListCopiedClipboard=Lista de Mazo para ''{0}'' copiada al portapapeles. #FSideboardDialog.java -lblUpdateMainFromSideboard=Actualiza el mazo principal desde el banquillo%s +lblUpdateMainFromSideboard=Actualiza el mazo principal desde el banquillo de %s #FVanguardChooser.java lblRandomVanguard=Vanguard Aleatorio #FOptionPane.java @@ -1253,8 +1258,8 @@ lblLeft=Izquierda lblRight=Derecha lblAddCounter=Añadir Contador lblRemoveCounter=Eliminar Contador -lblWinTheFlip=ganar el lanzamiento -lblLoseTheFlip=perder el lanzamiento +lblWinTheFlip=gana el lanzamiento +lblLoseTheFlip=pierde el lanzamiento lblChooseAResult=Elige un resultado lblSelectPreventionShieldToUse=selecciona qué escudo de prevención utilizar lblPlayerActivatedCardChooseMode={0} activó {1} - Elige un modo @@ -1321,7 +1326,7 @@ lblGameLog=Registro del Juego #NewDraftScreen.java lblLoadingNewDraft=Cargando nuevo Draft... #LoadDraftScreen.java -lblDoubleTapToEditDeck=Pulsa 2 veces para editar el mazo (Pulsación prologanda para ver) +lblDoubleTapToEditDeck=Pulsa 2 veces para editar el mazo (Pulsación prologanda para verlo) lblMode=Modo: lblYouMustSelectExistingDeck=Debes seleccionar un mazo existente o construir un mazo a partir de un nuevo juego de booster draft. lblWhichOpponentWouldYouLikeToFace=¿A qué oponente te gustaría enfrentarte? @@ -1330,7 +1335,7 @@ lblSingleMatch=Partida individual lblGauntletText1=En el modo Desafío, selecciona un mazo y juega contra varios oponentes. lblGauntletText2=Configura a cuántos oponentes deseas enfrentarte y qué mazos o tipos de mazos jugarán. lblGauntletText3=Luego, intenta derrotar a todos los oponentes de la IA sin perder una partida. -lblSelectGauntletType=Seleccione el Tipo de Desafío +lblSelectGauntletType=Selecciona el Tipo de Desafío lblCustomGauntlet=Desafío Personalizado lblGauntletContest=Concurso de Desafío lblSelectYourDeck=Seleccciona Tu Mazo @@ -1345,16 +1350,16 @@ lblLoadingThePuzzle=Cargando el puzzle... #InputPassPriority.java lblCastSpell=lanzar hechizo lblPlayLand=jugar tierra -lblActivateAbility=activar abilidad +lblActivateAbility=activar habilidad lblYouHaveManaFloatingInYourManaPoolCouldBeLostIfPassPriority=Tienes maná flotando en tu reserva de maná que podría perderse si pasas la prioridad ahora. lblYouWillTakeManaBurnDamageEqualAmountFloatingManaLostThisWay=Recibirás un daño por quemadura de maná igual a la cantidad de maná flotante perdido de esta manera. lblManaFloating=Maná Flotante #InputPayManaOfCostPayment.java lblPayManaCost=Paga el coste de maná: -lblLifePaidForPhyrexianMana=(%d de vida pagado por el maná filaxiano) -lblClickOnYourLifeTotalToPayLifeForPhyrexianMana=Haga clic en el total de su vida para pagar la vida por el maná filaxiano. -lblClickOnYourLifeTotalToPayLifeForBlackMana=Haga clic en el total de su vida para pagar la vida de maná negro. -lblClickOnYourLifeTotalToPayLifeForPhyrexianOrBlackMana=Haga clic en el total de su vida para pagar la vida por maná filoxiano o maná negro. +lblLifePaidForPhyrexianMana=(%d de vida pagado por el maná pirexiano) +lblClickOnYourLifeTotalToPayLifeForPhyrexianMana=Haz clic en el total de su vida para pagar la vida por el maná pirexiano. +lblClickOnYourLifeTotalToPayLifeForBlackMana=Haz clic en el total de su vida para pagar la vida de maná negro. +lblClickOnYourLifeTotalToPayLifeForPhyrexianOrBlackMana=Haz clic en el total de su vida para pagar la vida por maná pirexiano o maná negro. #GameLogFormatter.java lblLogScryTopBottomLibrary=%s adivinó %top carta(s) de la parte superior de la biblioteca y %bottom carta(s) de la parte inferior de la biblioteca lblLogScryTopLibrary=%s adivinó %top carta(s) de la parte superior de la biblioteca @@ -1569,7 +1574,7 @@ lbl1stPlace=1er Puesto: lbl2ndPlace=2o Puesto: lbl3rdPlace=3er Puesto: lbl4thPlace=4o Puesto: -lblTime= tiempo +lblTime= veces lblCollectPrizes=Recoger Premios lblCurrentlyInDraft=Actualmente estás en un draft.\nDeberías dejar o terminar ese draft antes de empezar otro. lblYouNeed=Necesitas @@ -1585,7 +1590,7 @@ lblAlreadyMatchPleaseWait=Ya hay un partida en curso.\nPor favor, espera a que t #DraftingProcessScreen.java lblSaveDraftAs=Guardar este draft como lblAlreadyDeckName=Ya hay un mazo llamado '' -lblOverwriteConfirm=''. ¿Sobreescribir? +lblOverwriteConfirm=''. ¿Sobreescribirlo? lblOverwriteDeck=¿Sobreescribir Mazo? lblEndDraftConfirm=Esto terminará con el draft actual y no podrás reanudarlo.\n\n¿Abandonar de todos modos? lblLeaveDraft=Abandonar Draft @@ -1595,8 +1600,8 @@ lblAnteCardsRemoved=Estas cartas de ante fueron eliminadas #CEditorDraftingProcess.java lblQuitWithoutSaving=Salir sin guardar lblQuitDraft=Salir de Draft -lblDraftPicks=Draft Picks -lblPackNCards=Pack {0} - Cards +lblDraftPicks=Selecciones de Draft +lblPackNCards=Pack {0} - Cartas #LoadQuestScreen.java lblLoadingExistingQuests=Cargando las Aventuras existentes... lblNewQuest=Nuevo @@ -1644,7 +1649,7 @@ lblSell=Vender lblItem=ítem lblCardsForSale=Cartas en Venta lblSellAllExtras=Vender todos los extras -lblSelectAllCards=Select All +lblSelectAllCards=Seleccionar Todo lblYourCards=Tus Cartas #QuestStatsScreen.java lblTournamentResults=Resultados de los Torneos @@ -1672,11 +1677,11 @@ lblDoYouWantDiscardYourHand=¿Quieres descartar tu mano? lblDoYouWantSpendNTargetTypeCounter=¿Quieres gastar {0} {1} contador? lblDoYouWantLetThatPlayerDrawNCardOrDoAction=¿Quieres dejar que ese jugador robe {0} carta(s)?{1} lblDoYouWantDrawNCardOrDoAction=¿Quieres robar {0} carta(s)?{1} -lblSelectRemoveCounterCard=Seleccione una carta para eliminar un contador +lblSelectRemoveCounterCard=Selecciona una carta para eliminar un contador lblSelectRemoveCounterType=Selecciona el tipo de contadores que deseas eliminar lblExileFromZone=Exiliar de {0} lblPutCardFromWhoseZone=¿Poner cartas de quién {0}? -lblPutCardToLibrary=Ponga las cartas en la Biblioteca +lblPutCardToLibrary=Pon las cartas en la Biblioteca lblPutIntoLibrary=poner en la biblioteca. lblGainControl=obtener el control. lblReturnToHand=devolver a la mano. @@ -1702,7 +1707,7 @@ lblSelectACardAttachSourceTo={0} - Seleccione una carta a la que anexar. #BidLifeEffect.java lblBidLife=Elige una puja más alta lblChooseStartingBid=Elige una apuesta inicial -lblDoYouWantTopBid=Do you want to top bid? Current Bid \= +lblDoYouWantTopBid=¿Quieres hacer una apuesta máxima? Apuesta actual \= lblTopBidWithValueLife=oferta más alta con {0} de vida #BondEffect.java lblSelectACardPair=Selecciona una carta para emparejarla con @@ -1728,7 +1733,7 @@ lblCancelSearchUpToSelectNumCards=¿Cancelar la Búsqueda? Se pueden seleccionar lblMoveTargetFromOriginToDestination=¿Mover {0} de {1} a {2}? #ChooseCardEffect.java lblChoose=Elegir -lblSelectCreatureWithTotalPowerLessOrEqualTo=Seleccione la(s) criatura(s) con una fuerza total menor o igual a {0}. +lblSelectCreatureWithTotalPowerLessOrEqualTo=Selecciona la(s) criatura(s) con una fuerza total menor o igual a {0}. lblTotalPowerNum=Fuerza Total: {0} lblCancelChooseConfirm=¿Cancelar Elegir? #ChooseCardNameEffect.java @@ -1826,8 +1831,8 @@ lblPutThisCardToYourGraveyard=¿Poner esta carta en tu cementerio? lblHeads=cara lblTails=cruz lblCallCoinFlip=Llamar al lanzamiento de la moneda -lblWin=ganar -lblLose=perder +lblWin=gana +lblLose=pierde #LifeSetEffect.java lblLifeTotal=Vida Total #ManaEffect.java @@ -2020,8 +2025,8 @@ lblCardEffectToTargetValueIs=El valor del efecto de {0} para {1} es {2} lblAreYouSureWantPickCard=¿Estás seguro de que quieres elegir ''{0}''? lblSelectThisCardConfirm=¿Selecciona esta carta? #PlayerView.java -lblCommanderCastCard=Cast from command zone {0} times -lblCommanderCastPlayer={0} cast from command zone {1} times +lblCommanderCastCard=Lanzado desde la zona de comandante {0} veces +lblCommanderCastPlayer={0} lanzado desde la zona de comandante {1} veces lblCommanderDealNDamageToPlayer=Daño del comandante a {0} de {1}: {2}\r\n lblNCommanderDamageFromOwnCommander=Daño al comandante por parte de su propio comandante {0}: {1}\r\n lblNCommanderDamageFromPlayerCommander=Daño del comandante desde {0} {1}: {2}\r\n @@ -2033,11 +2038,11 @@ lblLandsPlayed=Tierras jugadas: {0}/{1} lblCardDrawnThisTurnHas=Cartas robadas este turno: {0} lblDamagepreventionHas=Prevención de daños: {0} lblIsExtraTurn=Turno Extra: Sí -lblExtraTurnCountHas=Contadore de Turno Extra: {0} +lblExtraTurnCountHas=Contador de Turno Extra: {0} lblAntedHas=Apostado: {0} -lblAdditionalVotes=You get {0} additional votes. -lblOptionalAdditionalVotes=You may vote {0} additional times. -lblControlsVote=You choose how each player votes. +lblAdditionalVotes=Tienes {0} votos adicionales. +lblOptionalAdditionalVotes=Puedes votar {0} veces más. +lblControlsVote=Eliges cómo vota cada jugador. #VStack.java lblAlwaysYes=Siempre Sí lblAlwaysNo=Siempre No @@ -2060,11 +2065,11 @@ lblOrigin=Origen lblDeckAverageCMC=Media de CMC del Mazo lblDeckContents=Contenidos del Mazo lblDeckSize=Tamaño del Mazo -lblBuyPrice=Buy Price -lblSellPrice=Sell Price -lblUsedInQuestDecks=Used in # Quest Decks -lblIsTrue=es true -lblIsFalse=es false +lblBuyPrice=Precio de Compra +lblSellPrice=Precio de Venta +lblUsedInQuestDecks=Utilizado en # Mazos de Aventura +lblIsTrue=es verdadero +lblIsFalse=es falso lblEqual=\= lblNotEqual=<> lblGreaterThan=> @@ -2388,7 +2393,7 @@ lblCardScript=Códigos de Cartas lblCardPicture=Imagen de la Carta #VProbabilities.java lblDrawOrder=Orden de Robo -lblClickHereToReshuffle=HAGA CLIC AQUÍ PARA VOLVER A BARAJAR +lblClickHereToReshuffle=HAZ CLIC AQUÍ PARA VOLVER A BARAJAR lblSeeANewSampleShuffle=Ver una nueva muestra de mano barajada lblSampleHand=MANO DE MUESTRA lblRemainingDraws=ROBOS RESTANTES @@ -2425,14 +2430,14 @@ lblNewFolder=Nueva Carpeta lblInvalidFolder=Carpeta No Válida lblInvalidName=Nombre No Válido lblInvalidFile=Archivo No Válido -lblCannotAddNewFolderToInvaildFolder=No se puede agregar una nueva carpeta a una carpeta no válida. -lblEnterNewFolderName=Introduzca el nombre para la nueva carpeta. +lblCannotAddNewFolderToInvaildFolder=No se puede añadir una nueva carpeta a una carpeta no válida. +lblEnterNewFolderName=Introduce el nombre para la nueva carpeta. lblEnterFolderNameNotValid="{0}" no es un nombre de carpeta válido. lblNoFolderExistsWithSelectPath=No existe una carpeta con la ruta seleccionada. lblNoFileExistsWithSelectPath=No existe ningún archivo con la ruta seleccionada. lblCannotRenameFileInInvalidFolder=No se puede cambiar el nombre del archivo en una carpeta no válida. -lblEnterNewNameForFolder=Introduzca un nuevo nombre para la carpeta -lblEnterNewNameForFile=Introduzca un nuevo nombre para el archivo +lblEnterNewNameForFolder=Introduce un nuevo nombre para la carpeta +lblEnterNewNameForFile=Introduce un nuevo nombre para el archivo lblEnterNameNotValid="{0}" no es un nombre válido. lblAreYouSureProceedDelete=¿Estás seguro de que deseas continuar con la eliminación? Esta acción no se puede deshacer. lblDeleteFolder=Borrar Carpeta @@ -2442,16 +2447,16 @@ lblRenameFile=Renombrar Fichero lblCouldBotDeleteFile=No se pudo eliminar el archivo. #FloatingZone.java lblRightClickToUnSort=- ordenado por nombre (clic derecho en el título para no ordenar) -lblRightClickToSort=(haga clic derecho en el título para ordenar) +lblRightClickToSort=(clic derecho en el título para ordenar) lblPlayerZoneNCardSortStatus={0} {1} ({2}) {3} #OnlineMenu.java lblOnline=En Línea -lblShowChatPanel=Mostrar Panel Chat +lblShowChatPanel=Mostrar Panel de Chat lblDisconnect=Desconectar #CardOverlaysMenu.java lblCardName=Nombre de la Carta lblPowerOrToughness=Fuerza/Resistencia -lblAbilityIcon=Ícono de habilidad +lblAbilityIcon=Icono de habilidad lblShow=Mostrar #VField.java lblField=Campo @@ -2459,8 +2464,8 @@ lblPlayField={0} Campo lblNoPlayerForEDocID=NO JUGADOR PARA {0} #VHand.java lblYourHand=Tu Mano -lblPlayerHand={0} Mano -lblNoPlayerHand=NO JUGADOR Mano +lblPlayerHand=Mano de {0} +lblNoPlayerHand=Mano de NO JUGADOR #PlayerDetailsPanel.java lblHandNOfMax=Mano ({0}/{1}) lblGraveyardNCardsNTypes=Cementerio ({0}) Tipos[{1}] @@ -2504,10 +2509,10 @@ lblPleaseFirstSelectAPuzzleFromList=¡Seleccione un rompecabezas de la lista pri lblNoSelectedPuzzle=Ningún rompecabezas seleccionado #CSubmenuPuzzleCreate.java lblWhoShouldBeFirstTakeTurn=¿Quién debería ser el primero en tomar un turno? -lblWelcomePuzzleModeMessage=Bienvenido al modo Crear un rompecabezas.\n\nAsegúrese de que el Modo desarrollador esté habilitado en las preferencias de Forge.\nRecuerde que la aplicación de reglas está activa, por lo que los jugadores perderán el juego\npor robar de una biblioteca vacía. +lblWelcomePuzzleModeMessage=Bienvenido al modo Crear un rompecabezas.\n\nAsegúrate de que el Modo Dev está habilitado en las preferencias de Forge.\nRecuerda que la aplicación de reglas está activa, por lo que los jugadores perderán el juego\npor robar de una biblioteca vacía. #CDock.java lblTargetingArcsOff=Flechas de objetivos: Desactivadas -lblTargetingArcsCardMouseover=Flechas de objetivos: En Carta al Pasar el Mouse +lblTargetingArcsCardMouseover=Flechas de objetivos: En Carta al Pasar el ratón lblTargetingArcsAlwaysOn=Flechas de objetivos: Siempre Activadas #ListCardArea.java lblDone=Hecho @@ -2515,26 +2520,26 @@ lblDone=Hecho lblSideboardSummayLine=Línea para el resumen del banquillo lblImportedDeckSummay=El resumen del mazo importado aparecerá aquí lblDeckImporter=Importador de Mazos -lblPasteTypeDecklist=Pega o estribe una Lista de Mazo -lblExpectRecognizedLines=Espere que aparezcan las líneas reconocidas +lblPasteTypeDecklist=Pega o escribe una Lista de Mazo +lblExpectRecognizedLines=Espera que aparezcan las líneas reconocidas lblDeckImporterSummaryOfMain=Principal: {0} cartas reconocidas, {1} cartas desconocidas lblDeckImporterSummaryOfSideboard=Banquillo: {0} cartas reconocidas, {1} cartas desconocidas #CEditorTokenViewer.java lblAllTokens=Todas las Fichas #StartRenderer.java -lblClickToAddTargetToFavorites=Clic para añadir {0} a sus favoritos -lblClickToremoveTargetToFavorites=Clic para eliminar {0} a sus favoritos +lblClickToAddTargetToFavorites=Clic para añadir {0} a tus favoritos +lblClickToremoveTargetToFavorites=Clic para eliminar {0} de tus favoritos #PhaseIndicator.java #translate html*** please keep HTML Tags htmlPhaseUpkeepTooltip=Fase: Mantenimiento
Clic para alternar. -htmlPhaseDrawTooltip=Fase: Robo
Clic para alternar. +htmlPhaseDrawTooltip=Fase: Robar
Clic para alternar. htmlPhaseMain1Tooltip=Fase: Principal 1
Clic para alternar. htmlPhaseBeginCombatTooltip=Fase: Inicio del Combate
Clic para alternar. htmlPhaseDeclareAttackersTooltip=Fase: Declarar Atacantes
Clic para alternar. -htmlPhaseDeclareBlockersTooltip=Fase: Declarar Bloqueadores
Clic para alternar. +htmlPhaseDeclareBlockersTooltip=Fase: Declarar Bloqueadoras
Clic para alternar. htmlPhaseFirstStrikeDamageTooltip=Fase: Daño Dañar Primero
Clic para alternar. htmlPhaseCombatDamageTooltip=Fase: Daño de Combate
Clic para alternar. -htmlPhaseEndCombatTooltip=Fase: Fin del Combate
Clic para alternar. +htmlPhaseEndCombatTooltip=Fase: Final del Combate
Clic para alternar. htmlPhaseMain2Tooltip=Fase: Principal 2
Clic para alternar. htmlPhaseEndTurnTooltip=Fase: Fin del Turno
Clic para alternar. htmlPhaseCleanupTooltip=Fase: Limpieza
Clic para alternar. @@ -2542,7 +2547,7 @@ htmlPhaseCleanupTooltip=Fase: Limpieza
Clic para alternar. lblSideboardForPlayer=Banquillo para {0} lblOtherInteger=Otro... #DeckImportController.java -lblReplaceCurrentDeckConfirm=Esto reemplazará el contenido de tu mazo actual con estas cartas.\n\n¿Continuar? +lblReplaceCurrentDeckConfirm=Se reemplazará el contenido de tu mazo actual con estas cartas.\n\n¿Continuar? lblReplaceCurrentDeck=Reemplazar Mazo Actual lblReplace=Reemplazar #FNetOverlay.java @@ -2553,37 +2558,41 @@ lblUnableStartServerPortAlreadyUse=¡No se puede iniciar el servidor, el puerto lblStartingServer=Iniciando servidor... lblConnectingToServer=Conectando al servidor... #NetConnectUtil.java -lblOnlineMultiplayerDest=Esta característica está en desarrollo activo.\nEs probable que encuentre errores.\n\n - = * AQUÍ HAY ELDRAZIS * = -\n\nIngrese la URL del servidor para unirse.\nDeje en blanco para alojar su propio servidor. +lblOnlineMultiplayerDest=Esta característica está en desarrollo activo.\nEs probable que encuentres errores.\n\n - = * AQUÍ HAY ELDRAZIS * = -\n\Introduce la URL del servidor para unirte.\nDeja en blanco para crear tu propio servidor. lblHostingPortOnN=Alojando en el puerto {0}. -lblShareURLToMakePlayerJoinServer=Comparta la siguiente URL con cualquier persona que desee unirse a su servidor. Ha sido copiado a su portapapeles por conveniencia.\n\n {0}\n\nPara juegos internos, use la siguiente URL: {1} +lblShareURLToMakePlayerJoinServer=Comparte la siguiente URL con cualquier persona que desee unirse a tu servidor. Se ha copiado la URL al portapapeles.\n\n {0}\n\nPara jugar en red local, usa la siguiente URL: {1} lblForgeUnableDetermineYourExternalIP=¡Forge no pudo determinar su IP externa!\n\n{0} lblServerURL=URL del Servidor -lblYourConnectionToHostWasInterrupted=Su conexión con el host ({0}) fue interrumpida. +lblYourConnectionToHostWasInterrupted=Tu conexión con el host ({0}) fue interrumpida. lblConnectedIPPort=Conectado a {0}: {1} #GameLobby.java lblRequiredLeastTwoPlayerStartGame=Se requieren al menos dos jugadores para comenzar un juego. -lblNotEnoughTeams=¡No hay suficientes equipos! Por favor, ajuste las asignaciones del equipo. +lblNotEnoughTeams=¡No hay suficientes equipos! Por favor, ajusta las asignaciones del equipo. lblPlayerIsNotReady=El jugador {0} no está listo -lblPleaseSpecifyPlayerDeck=Por favor, especifique un mazo para {0} +lblPleaseSpecifyPlayerDeck=Por favor, especifica un mazo para {0} lblPlayerDoesntHaveCommander={0} no tiene un comandante lblPlayerDeckError={0} mazo {1} lblInvalidCommanderGameTypeDeck=Mazo {0} no válido lblInvalidSchemeDeck=Mazo de Esquema no válido lblInvalidPlanarDeck=Mazo Planar no válido -lblNoSelectedVanguardAvatarForPlayer=No se seleccionó ningún avatar de Vanguard para {0}. Elija uno o desactive la variante Vanguard +lblNoSelectedVanguardAvatarForPlayer=No seleccionaste ningún avatar de Vanguard para {0}. Elige uno o desactiva la variante Vanguard #AutoUpdater.java -lblYouHaventSetUpdateChannel=No ha establecido un canal de actualización. ¿Quieres establecer un canal ahora? +lblYouHaventSetUpdateChannel=No has establecido un canal de actualización. ¿Quieres establecer un canal ahora? lblManualCheck=Comprobación Manual -lblNewVersionForgeAvailableUpdateConfirm=Hay disponible una nueva versión de Forge ({0}).\nActualmente está en la versión ({1})\n\n¿Desea actualizar a la nueva versión ahora? +lblNewVersionForgeAvailableUpdateConfirm=Hay disponible una nueva versión de Forge ({0}).\nActualmente está en la versión ({1})\n\n¿Quieres actualizar a la nueva versión ahora? lblUpdateNow=Actualizar Ahora lblUpdateLater=Actualizar Después lblNewVersionAvailable=Nueva Versión Disponible -lblNewVersionDownloading=Descargue la nueva versión .. -lblForgeHasBeenUpdateRestartForgeToUseNewVersion=Forge ha sido descargado. Debe extraer el paquete y reiniciar Forge para la nueva versión. -lblExitNowConfirm=Salir ahora? +lblNewVersionDownloading=Descargando la nueva versión... +lblForgeHasBeenUpdateRestartForgeToUseNewVersion=Forge se ha descargado. Extrae el fichero y reinicia Forge para cargar la nueva versión. +lblExitNowConfirm=¿Salir ahora? #OnlineChatScreen.java -lblEnterMessageToSend=Ingrese el mensaje para enviar +lblEnterMessageToSend=Introduce el mensaje para enviar #OnlineLobbyScreen.java lblDetectedInvalidHostAddress=Se detectó una dirección de host no válida ({0}). #Player.java lblChooseACompanion=Elige un compañero +#QuestPreferences.java +lblWildOpponentNumberError=Los Oponentes Salvajes sólo pueden ser de 0 a 3 +#GauntletWinLose.java +lblGauntletProgress=Gauntlet Progress diff --git a/forge-gui/res/languages/it-IT.properties b/forge-gui/res/languages/it-IT.properties index f4d2e2f1a89..ab02bf062f0 100644 --- a/forge-gui/res/languages/it-IT.properties +++ b/forge-gui/res/languages/it-IT.properties @@ -113,6 +113,8 @@ cbpAutoYieldMode=Auto-Yield cbpCounterDisplayType=Tipo di display contatore cbpCounterDisplayLocation=Posizione display contatore cbpGraveyardOrdering=Consenti l''ordinazione di carte messe nel cimitero +lblAltLifeDisplay=Alternate Player Layout (Landscape Mode) +nlAltLifeDisplay=Enables alternate layout for displaying Player Life, Poison, Energy and Experience counters. Troubleshooting=Risoluzione dei problemi GeneralConfiguration=Configurazione generale lblPlayerName=Nome del giocatore @@ -494,6 +496,7 @@ lblCreateaDeck=Crea un mazzo. #CSubmenuQuestPrefs.java lblEnteraNumber=Inserisci un numero lblSavefailed=Salvataggio fallito +lblEnteraDecimal=Enter a decimal #DialogChooseFormats.java cbWantReprints=Consenti ristampe compatibili da altri set lblChooseFormats=Scegli i formati @@ -734,6 +737,8 @@ lblWinsperDraftRotation=Vittorie per Draft Rotation ttWinsperDraftRotation=Se una Draft non viene giocata per questo numero di vittorie, verrà rimossa o sostituita. lblRotationType=Tipo di rotazione ttRotationType=Se impostato su 0, le vecchie bozze scompaiono, se impostate su 1, vengono sostituite con un''altra utilizzando set diversi. +lblWildOpponentNumber=Number of Wild Opponents +lblWildOpponentMultiplier=Wild Multiplier #StatTypeFilter.java lblclicktotoogle=fai clic per attivare o disattivare il filtro, fai clic con il pulsante destro del mouse per mostrare solo #SItemManagerUtil.java @@ -2586,4 +2591,8 @@ lblEnterMessageToSend=Enter message to send #OnlineLobbyScreen.java lblDetectedInvalidHostAddress=Invalid host address ({0}) was detected. #Player.java -lblChooseACompanion=Choose a companion \ No newline at end of file +lblChooseACompanion=Choose a companion +#QuestPreferences.java +lblWildOpponentNumberError=Wild Opponents can only be 0 to 3 +#GauntletWinLose.java +lblGauntletProgress=Gauntlet Progress diff --git a/forge-gui/res/languages/zh-CN.properties b/forge-gui/res/languages/zh-CN.properties index 9f3f3203536..ccfaa1649c7 100644 --- a/forge-gui/res/languages/zh-CN.properties +++ b/forge-gui/res/languages/zh-CN.properties @@ -113,6 +113,8 @@ cbpAutoYieldMode=自动让过 cbpCounterDisplayType=计数器显示类型 cbpCounterDisplayLocation=计数器显示区域 cbpGraveyardOrdering=允许指衍生物进入墓地 +lblAltLifeDisplay=备用牌手布局(横向模式) +nlAltLifeDisplay=启用备用牌手布局以显示玩家的生命以及中毒,能量和经验指示物。 Troubleshooting=故障排除 GeneralConfiguration=常规配置 lblPlayerName=玩家名称 @@ -494,6 +496,7 @@ lblCreateaDeck=创建一个套牌 #CSubmenuQuestPrefs.java lblEnteraNumber=输入一个数 lblSavefailed=保存错误 +lblEnteraDecimal=输入一个十进制小数 #DialogChooseFormats.java cbWantReprints=允许来自其他系列的重印牌 lblChooseFormats=选择赛制 @@ -734,6 +737,8 @@ lblWinsperDraftRotation=每次轮抓胜利轮替 ttWinsperDraftRotation=如果轮抓没有赢这么多场,那么它将被删除或者替换。 lblRotationType=轮替类型 ttRotationType=如果设置为0,旧系列消失,如果设置为1,则用不同系列替换。 +lblWildOpponentNumber=野外对手数量 +lblWildOpponentMultiplier=野外对手倍数 #StatTypeFilter.java lblclicktotoogle=单击以切换筛选器,右键单机以仅显示 #SItemManagerUtil.java @@ -904,7 +909,7 @@ lblDeleteEdit=删除/编辑 lblSetEdition=神秘行。我们不知道他做了什么和能做什么。 ttFavorite=喜好 lblFolder=文件夹 -ttFormats=套牌在赛制中合法 +ttFormats=套牌的合法赛制 lblMain=主牌 ttMain=主牌 lblQty=数量 @@ -1103,7 +1108,7 @@ lblSelect=选择%s lblLandSet=地牌的系列 lblAddBasicLandsAutoSuggest=添加基本地到%s\n(双击自动添加) lblDeckStatisticsAutoSuggest=套牌统计。 双击自动添加基本地。 -lblAssortedArt=各种画 +lblAssortedArt=什锦卡图 lblCardArtN=卡图{0} lblNonLandCount=%d张非地牌 lblOldLandCount=%d张地牌 @@ -1120,7 +1125,7 @@ lblNoKnownCardsOnClipboard=在剪切板找不到已知的卡牌。\n\n将套牌 lblChangeSection=切换部分 lblDeckListCopiedClipboard=套牌列表''{0}''已经复制到剪切板 #FSideboardDialog.java -lblUpdateMainFromSideboard=从备牌更新%s到主牌 +lblUpdateMainFromSideboard=为%s进行换备 #FVanguardChooser.java lblRandomVanguard=随机先锋 #FOptionPane.java @@ -2586,4 +2591,8 @@ lblEnterMessageToSend=输入要发送的信息 #OnlineLobbyScreen.java lblDetectedInvalidHostAddress=检测到无效的主机地址({0})。 #Player.java -lblChooseACompanion=选择一个行侣 \ No newline at end of file +lblChooseACompanion=选择一个行侣 +#QuestPreferences.java +lblWildOpponentNumberError=野外对手数只能在0-3之间 +#GauntletWinLose.java +lblGauntletProgress=决斗进度 diff --git a/forge-gui/res/puzzle/PS_ZNR1.pzl b/forge-gui/res/puzzle/PS_ZNR1.pzl new file mode 100644 index 00000000000..85b1606cd86 --- /dev/null +++ b/forge-gui/res/puzzle/PS_ZNR1.pzl @@ -0,0 +1,16 @@ +[metadata] +Name:Possibility Storm - Zendikar Rising #01 +URL:https://i2.wp.com/www.possibilitystorm.com/wp-content/uploads/2020/09/157.-ZNR1-scaled.jpg +Goal:Win +Turns:1 +Difficulty:Mythic +Description:Win this turn. Remember that your solution must satisfy all blocking scenarios. +[state] +humanlife=15 +ailife=11 +turn=1 +activeplayer=human +activephase=MAIN1 +humanhand=Dire Tactics;Malakir Blood-Priest;Shadowspear;Light of Hope +humanbattlefield=Angel of Destiny;Scourge of the Skyclaves;Thundering Chariot;Bastion of Remembrance;Plains;Plains;Plains;Swamp;Swamp;Swamp +aibattlefield=Loch Dragon;Expedition Diviner;Loch Dragon diff --git a/forge-gui/res/skins/darkforge/sprite_avatars.png b/forge-gui/res/skins/darkforge/sprite_avatars.png new file mode 100644 index 00000000000..12dbcbb61ed Binary files /dev/null and b/forge-gui/res/skins/darkforge/sprite_avatars.png differ diff --git a/forge-gui/res/skins/default/sprite_deckbox.png b/forge-gui/res/skins/default/sprite_deckbox.png new file mode 100644 index 00000000000..104d2018f0e Binary files /dev/null and b/forge-gui/res/skins/default/sprite_deckbox.png differ diff --git a/forge-gui/res/tokenscripts/u_4_3_salamander_warrior.txt b/forge-gui/res/tokenscripts/u_4_3_salamander_warrior.txt new file mode 100644 index 00000000000..df0586f6a6d --- /dev/null +++ b/forge-gui/res/tokenscripts/u_4_3_salamander_warrior.txt @@ -0,0 +1,6 @@ +Name:Salamander Warrior +ManaCost:no cost +Types:Creature Salamander Warrior +Colors:blue +PT:4/3 +Oracle: diff --git a/forge-gui/src/main/java/forge/deck/DeckProxy.java b/forge-gui/src/main/java/forge/deck/DeckProxy.java index 01e46db5ecf..85941f113f3 100644 --- a/forge-gui/src/main/java/forge/deck/DeckProxy.java +++ b/forge-gui/src/main/java/forge/deck/DeckProxy.java @@ -1,11 +1,15 @@ package forge.deck; import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.Map.Entry; +import forge.card.CardSplitType; import org.apache.commons.lang3.StringUtils; import com.google.common.base.Function; @@ -260,6 +264,29 @@ public class DeckProxy implements InventoryItem { return highestRarity; } + public PaperCard getHighestCMCCard() { + PaperCard key = null; + Map keyCMC = new HashMap<>(64); + + for (final Entry pc : getDeck().getAllCardsInASinglePool()) { + if (pc.getKey().getRules().getManaCost() != null) { + if (pc.getKey().getRules().getSplitType() != CardSplitType.Split) + keyCMC.put(pc.getKey(),pc.getKey().getRules().getManaCost().getCMC()); + } + } + + if (!keyCMC.isEmpty()) { + int max = Collections.max(keyCMC.values()); + //get any max cmc + for (Entry entry : keyCMC.entrySet()) { + if (entry.getValue()==max) { + return entry.getKey(); + } + } + } + return key; + } + public Set getFormats() { if (formats == null) { formats = FModel.getFormats().getAllFormatsOfDeck(getDeck()); diff --git a/forge-gui/src/main/java/forge/limited/BoosterDraft.java b/forge-gui/src/main/java/forge/limited/BoosterDraft.java index a3ffdf73ebe..78af6def2b4 100644 --- a/forge-gui/src/main/java/forge/limited/BoosterDraft.java +++ b/forge-gui/src/main/java/forge/limited/BoosterDraft.java @@ -20,7 +20,6 @@ package forge.limited; import com.google.common.base.Predicate; import com.google.common.base.Supplier; import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; import forge.StaticData; import forge.card.CardEdition; import forge.deck.CardPool; @@ -41,7 +40,6 @@ import forge.util.gui.SGuiChoose; import forge.util.gui.SOptionPane; import forge.util.storage.IStorage; import forge.util.Localizer; -import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.ArrayUtils; import java.io.File; @@ -181,34 +179,40 @@ public class BoosterDraft implements IBoosterDraft { break; case Chaos: + /** + * A chaos draft consists of boosters from many different sets. + * Default settings are boosters from all sets with a booster size of 15 cards. + * Alternatively, the sets can be restricted to a format like Modern or to a theme. + * Examples for themes: sets that take place on a certain plane, core sets, masters sets, + * or sets that share a mechanic. + */ + // Get chaos draft themes + final List themes = new ArrayList<>(); + final IStorage themeStorage = FModel.getThemedChaosDrafts(); + for (final ThemedChaosDraft theme : themeStorage) { + themes.add(theme); + } + Collections.sort(themes); // sort for user interface + // Ask user to select theme + final String dialogQuestion = Localizer.getInstance().getMessage("lblChooseChaosTheme"); + final ThemedChaosDraft theme = SGuiChoose.oneOrNone(dialogQuestion, themes); + if (theme == null) { + return false; // abort if no theme is selected + } + // Filter all sets by theme restrictions + final Predicate themeFilter = theme.getEditionFilter(); final CardEdition.Collection allEditions = StaticData.instance().getEditions(); - final Iterable chaosDraftEditions = Iterables.filter(allEditions.getOrderedEditions(), new Predicate() { - @Override - public boolean apply(final CardEdition cardEdition) { - boolean isExpansion = cardEdition.getType().equals(CardEdition.Type.EXPANSION); - boolean isCoreSet = cardEdition.getType().equals(CardEdition.Type.CORE); - boolean isReprintSet = cardEdition.getType().equals(CardEdition.Type.REPRINT); - if (isExpansion || isCoreSet || isReprintSet) { - // Only allow sets with 15 cards in booster packs - if (cardEdition.hasBoosterTemplate()) { - final List> slots = cardEdition.getBoosterTemplate().getSlots(); - int boosterSize = 0; - for (Pair slot : slots) { - boosterSize += slot.getRight(); - } - return boosterSize == 15; - } - } - return false; - } - }); - - // Randomize order of sets - List shuffled = Lists.newArrayList(chaosDraftEditions); - Collections.shuffle(shuffled); - - final Supplier> ChaosDraftSupplier = new ChaosBoosterSupplier(shuffled); - + final Iterable chaosDraftEditions = Iterables.filter( + allEditions.getOrderedEditions(), + themeFilter); + // Add chaos "boosters" as special suppliers + final Supplier> ChaosDraftSupplier; + try { + ChaosDraftSupplier = new ChaosBoosterSupplier(chaosDraftEditions); + } catch(IllegalArgumentException e) { + System.out.println(e.getMessage()); + return false; + } for (int i = 0; i < 3; i++) { this.product.add(ChaosDraftSupplier); } diff --git a/forge-gui/src/main/java/forge/limited/ThemedChaosDraft.java b/forge-gui/src/main/java/forge/limited/ThemedChaosDraft.java new file mode 100644 index 00000000000..1b207167087 --- /dev/null +++ b/forge-gui/src/main/java/forge/limited/ThemedChaosDraft.java @@ -0,0 +1,218 @@ +package forge.limited; + +import com.google.common.base.Function; +import com.google.common.base.Predicate; + +import forge.card.CardEdition; +import forge.game.GameFormat; +import forge.model.FModel; +import forge.util.TextUtil; +import forge.util.storage.StorageReaderFile; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.List; + +/** + * Themed chaos draft allows limiting the pool of available random boosters for a draft to a certain theme. + */ +public class ThemedChaosDraft implements Comparable { + private final String tag; + private final String label; + private final int orderNumber; + + /** + * @param tag Tag name used in edition files. + * @param label Label used in user interface. + * @param orderNumber Number used to order entries in user interface. + */ + public ThemedChaosDraft(String tag, String label, int orderNumber) { + this.tag = tag; + this.label = label; + this.orderNumber = orderNumber; + } + + /** + * @return theme tag + */ + public String getTag() { return tag; } + + /** + * @return theme label + */ + public String getLabel() { return label; } + + /** + * @return theme order number + */ + public int getOrderNumber() { return orderNumber; } + + /** + * @return Predicate to sort out editions not belonging to the chaos draft theme + */ + public Predicate getEditionFilter() { + Predicate filter; + switch(tag) { + case "DEFAULT": + filter = DEFAULT_FILTER; + break; + case "MODERN": + case "PIONEER": + case "STANDARD": + filter = getFormatFilter(tag); + break; + default: + filter = themedFilter; + } + return filter; + } + + /** + * Filter to select editions by ChaosDraftThemes tag defined in edition files. + * Tag must be defined in res/blockdata/chaosdraftthemes.txt + */ + private final Predicate themedFilter = new Predicate() { + @Override + public boolean apply(final CardEdition cardEdition) { + String[] themes = cardEdition.getChaosDraftThemes(); + for (String theme : themes) { + if (tag.equals(theme)) return true; + } + return false; + } + }; + + /** + * @param formatName format to filter by, currently supported: MODERN, PIONEER, STANDARD + * @return Filter to select editions belonging to a certain constructed format. + */ + private Predicate getFormatFilter(String formatName) { + GameFormat.Collection formats = FModel.getFormats(); + GameFormat format; + switch(formatName) { + case "MODERN": + format = formats.getModern(); + break; + case "PIONEER": + format = formats.getPioneer(); + break; + case "STANDARD": + default: + format = formats.getStandard(); + } + return new Predicate() { + @Override + public boolean apply(final CardEdition cardEdition){ + return DEFAULT_FILTER.apply(cardEdition) && format.isSetLegal(cardEdition.getCode()); + } + }; + } + + /** + * Default filter that only allows actual sets that were printed as 15-card boosters + */ + private static final Predicate DEFAULT_FILTER = new Predicate() { + @Override + public boolean apply(final CardEdition cardEdition) { + boolean isExpansion = cardEdition.getType().equals(CardEdition.Type.EXPANSION); + boolean isCoreSet = cardEdition.getType().equals(CardEdition.Type.CORE); + boolean isReprintSet = cardEdition.getType().equals(CardEdition.Type.REPRINT); + if (isExpansion || isCoreSet || isReprintSet) { + // Only allow sets with 15 cards in booster packs + if (cardEdition.hasBoosterTemplate()) { + final List> slots = cardEdition.getBoosterTemplate().getSlots(); + int boosterSize = 0; + for (Pair slot : slots) { + boosterSize += slot.getRight(); + } + return boosterSize == 15; + } + } + return false; + } + }; + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return this.label; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = (prime * result) + ((this.tag == null) ? 0 : this.tag.hashCode()); + result = (prime * result) + ((this.label == null) ? 0 : this.label.hashCode()); + return result; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + @Override + public int compareTo(ThemedChaosDraft other) { + return (this.orderNumber != other.orderNumber) + ? this.orderNumber - other.orderNumber + : this.label.compareTo(other.label); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (this.getClass() != obj.getClass()) { + return false; + } + + final ThemedChaosDraft other = (ThemedChaosDraft) obj; + if (!this.label.equals(other.label)) { + return false; + } + if (!this.tag.equals(other.tag)) { + return false; + } + return true; + } + + public static final Function FN_GET_TAG = new Function() { + @Override + public String apply(ThemedChaosDraft themedChaosBooster) { + return themedChaosBooster.getTag(); + } + }; + + public static class Reader extends StorageReaderFile { + public Reader(String pathname) { + super(pathname, ThemedChaosDraft.FN_GET_TAG); + } + + @Override + protected ThemedChaosDraft read(String line, int idx) { + final String[] sParts = TextUtil.splitWithParenthesis(line, ',', 3); + int orderNumber = Integer.parseInt(sParts[0].trim(), 10); + String tag = sParts[1].trim(); + String label = sParts[2].trim(); + return new ThemedChaosDraft(tag, label, orderNumber); + } + } +} diff --git a/forge-gui/src/main/java/forge/match/input/InputLondonMulligan.java b/forge-gui/src/main/java/forge/match/input/InputLondonMulligan.java index d227c20fce2..4cfdb546e99 100644 --- a/forge-gui/src/main/java/forge/match/input/InputLondonMulligan.java +++ b/forge-gui/src/main/java/forge/match/input/InputLondonMulligan.java @@ -54,6 +54,7 @@ public class InputLondonMulligan extends InputSyncronizedBase { public final void showMessage() { final Localizer localizer = Localizer.getInstance(); final Game game = player.getGame(); + game.getView().updateIsMulligan(true); int cardsLeft = toReturn - selected.size(); StringBuilder sb = new StringBuilder(); @@ -79,6 +80,7 @@ public class InputLondonMulligan extends InputSyncronizedBase { private void done() { resetCardHighlights(); + getController().getGame().getView().updateIsMulligan(false); stop(); } diff --git a/forge-gui/src/main/java/forge/model/FModel.java b/forge-gui/src/main/java/forge/model/FModel.java index fe3dc41129f..1c1a621b8c1 100644 --- a/forge-gui/src/main/java/forge/model/FModel.java +++ b/forge-gui/src/main/java/forge/model/FModel.java @@ -37,6 +37,7 @@ import forge.gauntlet.GauntletData; import forge.interfaces.IProgressBar; import forge.itemmanager.ItemManagerConfig; import forge.limited.GauntletMini; +import forge.limited.ThemedChaosDraft; import forge.planarconquest.ConquestController; import forge.planarconquest.ConquestPlane; import forge.planarconquest.ConquestPreferences; @@ -91,6 +92,7 @@ public final class FModel { private static IStorage blocks; private static IStorage fantasyBlocks; + private static IStorage themedChaosDrafts; private static IStorage planes; private static IStorage worlds; private static GameFormat.Collection formats; @@ -187,6 +189,7 @@ public final class FModel { questPreferences = new QuestPreferences(); conquestPreferences = new ConquestPreferences(); fantasyBlocks = new StorageBase<>("Custom blocks", new CardBlock.Reader(ForgeConstants.BLOCK_DATA_DIR + "fantasyblocks.txt", magicDb.getEditions())); + themedChaosDrafts = new StorageBase<>("Themed Chaos Drafts", new ThemedChaosDraft.Reader(ForgeConstants.BLOCK_DATA_DIR + "chaosdraftthemes.txt")); planes = new StorageBase<>("Conquest planes", new ConquestPlane.Reader(ForgeConstants.CONQUEST_PLANES_DIR + "planes.txt")); Map standardWorlds = new QuestWorld.Reader(ForgeConstants.QUEST_WORLD_DIR + "worlds.txt").readAll(); Map customWorlds = new QuestWorld.Reader(ForgeConstants.USER_QUEST_WORLD_DIR + "customworlds.txt").readAll(); @@ -383,6 +386,10 @@ public final class FModel { return fantasyBlocks; } + public static IStorage getThemedChaosDrafts() { + return themedChaosDrafts; + } + public static TournamentData getTournamentData() { return tournamentData; } public static void setTournamentData(TournamentData tournamentData) { FModel.tournamentData = tournamentData; } diff --git a/forge-gui/src/main/java/forge/properties/ForgeConstants.java b/forge-gui/src/main/java/forge/properties/ForgeConstants.java index bf1de97acb9..7834cdb58cf 100644 --- a/forge-gui/src/main/java/forge/properties/ForgeConstants.java +++ b/forge-gui/src/main/java/forge/properties/ForgeConstants.java @@ -100,6 +100,7 @@ public final class ForgeConstants { public static final String SPRITE_ABILITY_FILE = "sprite_ability.png"; public static final String SPRITE_BORDER_FILE = "sprite_border.png"; public static final String SPRITE_BUTTONS_FILE = "sprite_buttons.png"; + public static final String SPRITE_DECKBOX_FILE = "sprite_deckbox.png"; public static final String SPRITE_START_FILE = "sprite_start.png"; public static final String SPRITE_MANAICONS_FILE = "sprite_manaicons.png"; public static final String SPRITE_AVATARS_FILE = "sprite_avatars.png"; diff --git a/forge-gui/src/main/java/forge/properties/ForgePreferences.java b/forge-gui/src/main/java/forge/properties/ForgePreferences.java index 679b2922e96..8526e1ace69 100644 --- a/forge-gui/src/main/java/forge/properties/ForgePreferences.java +++ b/forge-gui/src/main/java/forge/properties/ForgePreferences.java @@ -127,6 +127,7 @@ public class ForgePreferences extends PreferencesStore { UI_DISPLAY_CURRENT_COLORS(ForgeConstants.DISP_CURRENT_COLORS_NEVER), UI_FILTER_LANDS_BY_COLOR_IDENTITY("true"), UI_ALLOW_ESC_TO_END_TURN ("false"), + UI_ALT_PLAYERINFOLAYOUT ("false"), UI_PRESELECT_PREVIOUS_ABILITY_ORDER ("false"), UI_AUTO_YIELD_MODE (ForgeConstants.AUTO_YIELD_PER_ABILITY), UI_SHOW_STORM_COUNT_IN_PROMPT ("false"), diff --git a/forge-gui/src/main/java/forge/quest/io/MainWorldDuelReader.java b/forge-gui/src/main/java/forge/quest/io/MainWorldDuelReader.java index 633d4d602ee..22fe331d71a 100644 --- a/forge-gui/src/main/java/forge/quest/io/MainWorldDuelReader.java +++ b/forge-gui/src/main/java/forge/quest/io/MainWorldDuelReader.java @@ -18,16 +18,15 @@ import org.apache.commons.lang3.StringUtils; import forge.ImageKeys; import forge.deck.Deck; +import forge.deck.DeckProxy; import forge.deck.io.DeckSerializer; import forge.deck.io.DeckStorage; -import forge.model.FModel; import forge.quest.QuestEvent; import forge.quest.QuestEventDifficulty; import forge.quest.QuestEventDuel; import forge.util.FileSection; import forge.util.FileUtil; import forge.util.TextUtil; -import forge.util.storage.IStorage; import forge.util.storage.StorageReaderFolder; public class MainWorldDuelReader extends StorageReaderFolder { @@ -77,10 +76,11 @@ public class MainWorldDuelReader extends StorageReaderFolder { } // then I add wild decks in constructed directory - IStorage constructedDecks = FModel.getDecks().getConstructed(); - Iterator it = constructedDecks.iterator(); + Iterable constructedDecks = DeckProxy.getAllConstructedDecks(); + Iterator it = constructedDecks.iterator(); + while(it.hasNext()) { - Deck currDeck = (Deck) it.next(); + Deck currDeck = it.next().getDeck(); final QuestEventDuel newDeck = read(currDeck); String newKey = keySelector.apply(newDeck); if (result.containsKey(newKey)) { diff --git a/forge-gui/src/main/java/forge/sound/EventVisualizer.java b/forge-gui/src/main/java/forge/sound/EventVisualizer.java index 734fd807df2..dc4e848b4f4 100644 --- a/forge-gui/src/main/java/forge/sound/EventVisualizer.java +++ b/forge-gui/src/main/java/forge/sound/EventVisualizer.java @@ -35,6 +35,7 @@ import forge.game.event.GameEventZone; import forge.game.event.IGameEventVisitor; import forge.game.spellability.SpellAbility; import forge.game.zone.ZoneType; +import forge.util.TextUtil; import forge.util.maps.MapOfLists; /** @@ -213,7 +214,7 @@ public class EventVisualizer extends IGameEventVisitor.Base imp } } // No interest if "colors together" or "alternative colors" - only interested in colors themselves - fullManaColors = new StringBuilder(fullManaColors.toString().replaceAll("\\s", "")); + fullManaColors = new StringBuilder(TextUtil.fastReplace(fullManaColors.toString()," ", "")); int fullManaColorsLength = fullManaColors.length(); diff --git a/forge-gui/src/main/java/forge/sound/SoundSystem.java b/forge-gui/src/main/java/forge/sound/SoundSystem.java index 8e69ef87e0b..3561456c7d9 100644 --- a/forge-gui/src/main/java/forge/sound/SoundSystem.java +++ b/forge-gui/src/main/java/forge/sound/SoundSystem.java @@ -32,7 +32,7 @@ public class SoundSystem { this.visualizer = new EventVisualizer(GamePlayerUtil.getGuiPlayer()); } private static boolean isUsingAltSystem() { - return FModel.getPreferences().getPrefBoolean(FPref.UI_ALT_SOUND_SYSTEM); + return !GuiBase.getInterface().isLibgdxPort() && FModel.getPreferences().getPrefBoolean(FPref.UI_ALT_SOUND_SYSTEM); } /**