diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtil.java b/forge-ai/src/main/java/forge/ai/ComputerUtil.java
index ff73d875785..c9eb6634f57 100644
--- a/forge-ai/src/main/java/forge/ai/ComputerUtil.java
+++ b/forge-ai/src/main/java/forge/ai/ComputerUtil.java
@@ -91,9 +91,6 @@ public class ComputerUtil {
}
}
- source.setCastSA(sa);
- sa.setLastStateBattlefield(game.getLastStateBattlefield());
- sa.setLastStateGraveyard(game.getLastStateGraveyard());
sa.setHostCard(game.getAction().moveToStack(source, sa));
}
@@ -219,9 +216,6 @@ public class ComputerUtil {
final Card source = sa.getHostCard();
if (sa.isSpell() && !source.isCopiedSpell()) {
- source.setCastSA(sa);
- sa.setLastStateBattlefield(game.getLastStateBattlefield());
- sa.setLastStateGraveyard(game.getLastStateGraveyard());
sa.setHostCard(game.getAction().moveToStack(source, sa));
}
@@ -246,9 +240,6 @@ public class ComputerUtil {
final Card source = sa.getHostCard();
if (sa.isSpell() && !source.isCopiedSpell()) {
- source.setCastSA(sa);
- sa.setLastStateBattlefield(game.getLastStateBattlefield());
- sa.setLastStateGraveyard(game.getLastStateGraveyard());
sa.setHostCard(game.getAction().moveToStack(source, sa));
}
@@ -267,9 +258,6 @@ public class ComputerUtil {
final Card source = newSA.getHostCard();
if (newSA.isSpell() && !source.isCopiedSpell()) {
- source.setCastSA(newSA);
- sa.setLastStateBattlefield(game.getLastStateBattlefield());
- sa.setLastStateGraveyard(game.getLastStateGraveyard());
newSA.setHostCard(game.getAction().moveToStack(source, sa));
if (newSA.getApi() == ApiType.Charm && !newSA.isWrapper()) {
@@ -290,9 +278,6 @@ public class ComputerUtil {
if (ComputerUtilCost.canPayCost(sa, ai)) {
final Card source = sa.getHostCard();
if (sa.isSpell() && !source.isCopiedSpell()) {
- source.setCastSA(sa);
- sa.setLastStateBattlefield(game.getLastStateBattlefield());
- sa.setLastStateGraveyard(game.getLastStateGraveyard());
sa.setHostCard(game.getAction().moveToStack(source, sa));
}
diff --git a/forge-ai/src/main/java/forge/ai/GameState.java b/forge-ai/src/main/java/forge/ai/GameState.java
index 9d71da36c6a..e07b65d95c4 100644
--- a/forge-ai/src/main/java/forge/ai/GameState.java
+++ b/forge-ai/src/main/java/forge/ai/GameState.java
@@ -981,14 +981,27 @@ public abstract class GameState {
spellDef = spellDef.substring(0, spellDef.indexOf("->")).trim();
}
- PaperCard pc = StaticData.instance().getCommonCards().getCard(spellDef);
+ Card c = null;
- if (pc == null) {
- System.err.println("ERROR: Could not find a card with name " + spellDef + " to precast!");
- return;
+ if (StringUtils.isNumeric(spellDef)) {
+ // Precast from a specific host
+ c = idToCard.get(Integer.parseInt(spellDef));
+ if (c == null) {
+ System.err.println("ERROR: Could not find a card with ID " + spellDef + " to precast!");
+ return;
+ }
+ } else {
+ // Precast from a card by name
+ PaperCard pc = StaticData.instance().getCommonCards().getCard(spellDef);
+
+ if (pc == null) {
+ System.err.println("ERROR: Could not find a card with name " + spellDef + " to precast!");
+ return;
+ }
+
+ c = Card.fromPaperCard(pc, activator);
}
- Card c = Card.fromPaperCard(pc, activator);
SpellAbility sa = null;
if (!scriptID.isEmpty()) {
diff --git a/forge-core/src/main/java/forge/ImageKeys.java b/forge-core/src/main/java/forge/ImageKeys.java
index e07f836566d..f2b976f3008 100644
--- a/forge-core/src/main/java/forge/ImageKeys.java
+++ b/forge-core/src/main/java/forge/ImageKeys.java
@@ -113,7 +113,11 @@ public final class ImageKeys {
}
//try fullborder...
if (filename.contains(".full")) {
- file = findFile(dir, TextUtil.fastReplace(filename, ".full", ".fullborder"));
+ String fullborderFile = TextUtil.fastReplace(filename, ".full", ".fullborder");
+ file = findFile(dir, fullborderFile);
+ if (file != null) { return file; }
+ // if there's an art variant try without it
+ file = findFile(dir, TextUtil.fastReplace(fullborderFile, "1.fullborder", ".fullborder"));
if (file != null) { return file; }
}
//if an image, like phenomenon or planes is missing .full in their filenames but you have an existing images that have .full/.fullborder
diff --git a/forge-core/src/main/java/forge/card/CardDb.java b/forge-core/src/main/java/forge/card/CardDb.java
index 2c4e54ad21a..7fcfbfd2a49 100644
--- a/forge-core/src/main/java/forge/card/CardDb.java
+++ b/forge-core/src/main/java/forge/card/CardDb.java
@@ -312,17 +312,21 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
return tryGetCard(request);
}
- public int getCardCollectorNumber(String cardName, String reqEdition) {
+ public String getCardCollectorNumber(String cardName, String reqEdition, int artIndex) {
cardName = getName(cardName);
CardEdition edition = editions.get(reqEdition);
if (edition == null)
- return -1;
+ return null;
+ int numMatches = 0;
for (CardInSet card : edition.getCards()) {
if (card.name.equalsIgnoreCase(cardName)) {
- return card.collectorNumber;
+ numMatches += 1;
+ if (numMatches == artIndex) {
+ return card.collectorNumber;
+ }
}
}
- return -1;
+ return null;
}
private PaperCard tryGetCard(CardRequest request) {
diff --git a/forge-core/src/main/java/forge/card/CardEdition.java b/forge-core/src/main/java/forge/card/CardEdition.java
index e2b786c0322..ce6289bb5f5 100644
--- a/forge-core/src/main/java/forge/card/CardEdition.java
+++ b/forge-core/src/main/java/forge/card/CardEdition.java
@@ -38,6 +38,8 @@ import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Map.Entry;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
@@ -75,10 +77,10 @@ public final class CardEdition implements Comparable { // immutable
public static class CardInSet {
public final CardRarity rarity;
- public final int collectorNumber;
+ public final String collectorNumber;
public final String name;
- public CardInSet(final String name, final int collectorNumber, final CardRarity rarity) {
+ public CardInSet(final String name, final String collectorNumber, final CardRarity rarity) {
this.name = name;
this.collectorNumber = collectorNumber;
this.rarity = rarity;
@@ -86,7 +88,7 @@ public final class CardEdition implements Comparable { // immutable
public String toString() {
StringBuilder sb = new StringBuilder();
- if (collectorNumber != -1) {
+ if (collectorNumber != null) {
sb.append(collectorNumber);
sb.append(' ');
}
@@ -190,6 +192,7 @@ public final class CardEdition implements Comparable { // immutable
public boolean getSmallSetOverride() { return smallSetOverride; }
public String getBoosterMustContain() { return boosterMustContain; }
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
public Map getTokens() { return tokenNormalized; }
@@ -266,24 +269,33 @@ public final class CardEdition implements Comparable { // immutable
Map tokenNormalized = new HashMap<>();
List processedCards = new ArrayList<>();
if (contents.containsKey("cards")) {
+ final Pattern pattern = Pattern.compile(
+ /*
+ The following pattern will match the WAR Japanese art entries,
+ it should also match the Un-set and older alternate art cards
+ like Merseine from FEM (should the editions files ever be updated)
+ */
+ //"(^(?[0-9]+.?) )?((?[SCURML]) )?(?.*)$"
+ /* Ideally we'd use the named group above, but Android 6 and
+ earlier don't appear to support named groups.
+ So, untill support for those devices is officially dropped,
+ we'll have to suffice with numbered groups.
+ We are looking for:
+ * cnum - grouping #2
+ * rarity - grouping #4
+ * name - grouping #5
+ */
+ "(^([0-9]+.?) )?(([SCURML]) )?(.*)$"
+ );
for(String line : contents.get("cards")) {
- if (StringUtils.isBlank(line))
- continue;
-
- // Optional collector number at the start.
- String[] split = line.split(" ", 2);
- int collectorNumber = -1;
- if (split.length >= 2 && StringUtils.isNumeric(split[0])) {
- collectorNumber = Integer.parseInt(split[0]);
- line = split[1];
+ Matcher matcher = pattern.matcher(line);
+ if (matcher.matches()) {
+ String collectorNumber = matcher.group(2);
+ CardRarity r = CardRarity.smartValueOf(matcher.group(4));
+ String cardName = matcher.group(5);
+ CardInSet cis = new CardInSet(cardName, collectorNumber, r);
+ processedCards.add(cis);
}
-
- // You may omit rarity for early development
- CardRarity r = CardRarity.smartValueOf(line.substring(0, 1));
- boolean hadRarity = r != CardRarity.Unknown && line.charAt(1) == ' ';
- String cardName = hadRarity ? line.substring(2) : line;
- CardInSet cis = new CardInSet(cardName, collectorNumber, r);
- processedCards.add(cis);
}
}
diff --git a/forge-core/src/main/java/forge/card/CardRules.java b/forge-core/src/main/java/forge/card/CardRules.java
index 322c003b6f2..a27b60adf2c 100644
--- a/forge-core/src/main/java/forge/card/CardRules.java
+++ b/forge-core/src/main/java/forge/card/CardRules.java
@@ -222,7 +222,12 @@ public final class CardRules implements ICardCharacteristics {
public boolean canBeBrawlCommander() {
CardType type = mainPart.getType();
- return (type.isLegendary() && type.isCreature()) || type.isPlaneswalker();
+ return type.isLegendary() && (type.isCreature() || type.isPlaneswalker());
+ }
+
+ public boolean canBeTinyLeadersCommander() {
+ CardType type = mainPart.getType();
+ return type.isLegendary() && (type.isCreature() || type.isPlaneswalker());
}
public String getMeldWith() {
diff --git a/forge-core/src/main/java/forge/card/CardRulesPredicates.java b/forge-core/src/main/java/forge/card/CardRulesPredicates.java
index 6679b3ad673..66dca47b592 100644
--- a/forge-core/src/main/java/forge/card/CardRulesPredicates.java
+++ b/forge-core/src/main/java/forge/card/CardRulesPredicates.java
@@ -594,8 +594,10 @@ public final class CardRulesPredicates {
public static final Predicate IS_VANGUARD = CardRulesPredicates.coreType(true, CardType.CoreType.Vanguard);
public static final Predicate IS_CONSPIRACY = CardRulesPredicates.coreType(true, CardType.CoreType.Conspiracy);
public static final Predicate IS_NON_LAND = CardRulesPredicates.coreType(false, CardType.CoreType.Land);
- public static final Predicate CAN_BE_BRAWL_COMMANDER = Predicates.or(Presets.IS_PLANESWALKER,
- Predicates.and(Presets.IS_CREATURE, Presets.IS_LEGENDARY));
+ public static final Predicate CAN_BE_BRAWL_COMMANDER = Predicates.and(Presets.IS_LEGENDARY,
+ Predicates.or(Presets.IS_CREATURE, Presets.IS_PLANESWALKER));
+ public static final Predicate CAN_BE_TINY_LEADERS_COMMANDER = Predicates.and(Presets.IS_LEGENDARY,
+ Predicates.or(Presets.IS_CREATURE, Presets.IS_PLANESWALKER));
/** The Constant IS_NON_CREATURE_SPELL. **/
public static final Predicate IS_NON_CREATURE_SPELL = com.google.common.base.Predicates
diff --git a/forge-core/src/main/java/forge/deck/DeckFormat.java b/forge-core/src/main/java/forge/deck/DeckFormat.java
index 3ea356c6a6d..e369fccc075 100644
--- a/forge-core/src/main/java/forge/deck/DeckFormat.java
+++ b/forge-core/src/main/java/forge/deck/DeckFormat.java
@@ -463,6 +463,9 @@ public enum DeckFormat {
if (this.equals(DeckFormat.Brawl)) {
return rules.canBeBrawlCommander();
}
+ if (this.equals(DeckFormat.TinyLeaders)) {
+ return rules.canBeTinyLeadersCommander();
+ }
return rules.canBeCommander();
}
diff --git a/forge-core/src/main/java/forge/util/TextUtil.java b/forge-core/src/main/java/forge/util/TextUtil.java
index 4974a8e087f..06a706b20f0 100644
--- a/forge-core/src/main/java/forge/util/TextUtil.java
+++ b/forge-core/src/main/java/forge/util/TextUtil.java
@@ -5,6 +5,8 @@ import forge.item.PaperCard;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
+import com.google.common.collect.ImmutableSortedMap;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@@ -17,6 +19,22 @@ import java.util.Map.Entry;
*/
public class TextUtil {
+ static ImmutableSortedMap romanMap = ImmutableSortedMap.naturalOrder()
+ .put(1000, "M").put(900, "CM")
+ .put(500, "D").put(400, "CD")
+ .put(100, "C").put(90, "XC")
+ .put(50, "L").put(40, "XL")
+ .put(10, "X").put(9, "IX")
+ .put(5, "V").put(4, "IV").put(1, "I").build();
+
+ public final static String toRoman(int number) {
+ if (number <= 0) {
+ return "";
+ }
+ int l = romanMap.floorKey(number);
+ return romanMap.get(l) + toRoman(number-l);
+ }
+
/**
* Safely converts an object to a String.
*
diff --git a/forge-game/src/main/java/forge/game/GameAction.java b/forge-game/src/main/java/forge/game/GameAction.java
index 16b67a2d4e7..16ec6662f0d 100644
--- a/forge-game/src/main/java/forge/game/GameAction.java
+++ b/forge-game/src/main/java/forge/game/GameAction.java
@@ -547,6 +547,13 @@ public class GameAction {
c.setCastSA(null);
} else if (zoneTo.is(ZoneType.Stack)) {
c.setCastFrom(zoneFrom.getZoneType());
+ if (cause != null && cause.isSpell() && c.equals(cause.getHostCard()) && !c.isCopiedSpell()) {
+ cause.setLastStateBattlefield(game.getLastStateBattlefield());
+ cause.setLastStateGraveyard(game.getLastStateGraveyard());
+ c.setCastSA(cause);
+ } else {
+ c.setCastSA(null);
+ }
} else if (!(zoneTo.is(ZoneType.Battlefield) && zoneFrom.is(ZoneType.Stack))) {
c.setCastFrom(null);
c.setCastSA(null);
diff --git a/forge-game/src/main/java/forge/game/GameActionUtil.java b/forge-game/src/main/java/forge/game/GameActionUtil.java
index b54c727370f..6d9ed807964 100644
--- a/forge-game/src/main/java/forge/game/GameActionUtil.java
+++ b/forge-game/src/main/java/forge/game/GameActionUtil.java
@@ -22,8 +22,10 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
+import forge.card.MagicColor;
import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostParser;
+import forge.game.ability.AbilityFactory;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.card.*;
@@ -32,9 +34,15 @@ import forge.game.cost.Cost;
import forge.game.keyword.KeywordInterface;
import forge.game.player.Player;
import forge.game.player.PlayerController;
+import forge.game.replacement.ReplacementEffect;
+import forge.game.replacement.ReplacementHandler;
+import forge.game.replacement.ReplacementLayer;
import forge.game.spellability.*;
import forge.game.trigger.Trigger;
+import forge.game.trigger.TriggerHandler;
+import forge.game.trigger.TriggerType;
import forge.game.zone.ZoneType;
+import forge.util.Lang;
import forge.util.TextUtil;
import org.apache.commons.lang3.StringUtils;
@@ -363,10 +371,11 @@ public final class GameActionUtil {
}
SpellAbility result = null;
final Card host = sa.getHostCard();
+ final Game game = host.getGame();
final Player activator = sa.getActivatingPlayer();
final PlayerController pc = activator.getController();
- host.getGame().getAction().checkStaticAbilities(false);
+ game.getAction().checkStaticAbilities(false);
boolean reset = false;
@@ -429,7 +438,60 @@ public final class GameActionUtil {
int v = pc.chooseNumberForKeywordCost(sa, cost, ki, str, Integer.MAX_VALUE);
if (v > 0) {
- host.addReplacementEffect(CardFactoryUtil.makeEtbCounter("etbCounter:P1P1:" + v, host, false));
+
+ final Card eff = new Card(game.nextCardId(), game);
+ eff.setTimestamp(game.getNextTimestamp());
+ eff.setName(c.getName() + "'s Effect");
+ eff.addType("Effect");
+ eff.setToken(true); // Set token to true, so when leaving play it gets nuked
+ eff.setOwner(activator);
+
+ eff.setImageKey(c.getImageKey());
+ eff.setColor(MagicColor.COLORLESS);
+ eff.setImmutable(true);
+ // try to get the SpellAbility from the mana ability
+ //eff.setEffectSource((SpellAbility)null);
+
+ eff.addRemembered(host);
+
+ String abStr = "DB$ PutCounter | Defined$ ReplacedCard | CounterType$ P1P1 | ETB$ True | CounterNum$ " + v;
+
+ SpellAbility saAb = AbilityFactory.getAbility(abStr, c);
+
+ CardFactoryUtil.setupETBReplacementAbility(saAb);
+
+ String desc = "It enters the battlefield with ";
+ desc += Lang.nounWithNumeral(v, CounterType.P1P1.getName() + " counter");
+ desc += " on it.";
+
+ String repeffstr = "Event$ Moved | ValidCard$ Card.IsRemembered | Destination$ Battlefield | Description$ " + desc;
+
+ ReplacementEffect re = ReplacementHandler.parseReplacement(repeffstr, eff, true);
+ re.setLayer(ReplacementLayer.Other);
+ re.setOverridingAbility(saAb);
+
+ eff.addReplacementEffect(re);
+
+ // Forgot Trigger
+ String trig = "Mode$ ChangesZone | ValidCard$ Card.IsRemembered | Origin$ Stack | Destination$ Any | TriggerZones$ Command | Static$ True";
+ String forgetEffect = "DB$ Pump | ForgetObjects$ TriggeredCard";
+ String exileEffect = "DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile"
+ + " | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ EQ0";
+
+ SpellAbility saForget = AbilityFactory.getAbility(forgetEffect, eff);
+ AbilitySub saExile = (AbilitySub) AbilityFactory.getAbility(exileEffect, eff);
+ saForget.setSubAbility(saExile);
+
+ final Trigger parsedTrigger = TriggerHandler.parseTrigger(trig, eff, true);
+ parsedTrigger.setOverridingAbility(saForget);
+ eff.addTrigger(parsedTrigger);
+ eff.updateStateForView();
+
+ // TODO: Add targeting to the effect so it knows who it's dealing with
+ game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
+ game.getAction().moveTo(ZoneType.Command, eff, null);
+ game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
+
if (result == null) {
result = sa.copy();
}
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 0be3279d3e4..1d278409976 100644
--- a/forge-game/src/main/java/forge/game/card/Card.java
+++ b/forge-game/src/main/java/forge/game/card/Card.java
@@ -6353,6 +6353,10 @@ public class Card extends GameEntity implements Comparable {
removeSVar("PayX"); // Temporary AI X announcement variable
removeSVar("IsCastFromPlayEffect"); // Temporary SVar indicating that the spell is cast indirectly via AF Play
setSunburstValue(0); // Sunburst
+ setXManaCostPaid(0);
+ setXManaCostPaidByColor(null);
+ setKickerMagnitude(0);
+ setPseudoMultiKickerMagnitude(0);
}
public final int getFinalChapterNr() {
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 e60f3e16bd1..88307959cdb 100644
--- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java
+++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java
@@ -20,7 +20,6 @@ package forge.game.card;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
-import com.google.common.base.Strings;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@@ -3010,24 +3009,43 @@ public class CardFactoryUtil {
inst.addTrigger(parsedTrigger);
} else if (keyword.startsWith("Saga")) {
- // Saga there doesn't need Max value anymore?
final String[] k = keyword.split(":");
- final String[] abs = k[2].split(",");
+ final List abs = Arrays.asList(k[2].split(","));
+ if (abs.size() != Integer.valueOf(k[1])) {
+ throw new RuntimeException("Saga max differ from Ability amount");
+ }
- int i = 1;
- for (String ab : abs) {
- SpellAbility sa = AbilityFactory.getAbility(card, ab);
- sa.setChapter(i);
+ int idx = 0;
+ int skipId = 0;
+ for(String ab : abs) {
+ idx += 1;
+ if (idx <= skipId) {
+ continue;
+ }
- // TODO better logic for Roman numbers
- // In the Description try to merge Chapter trigger with the Same Effect
- String trigStr = "Mode$ CounterAdded | ValidCard$ Card.Self | TriggerZones$ Battlefield"
- + "| CounterType$ LORE | CounterAmount$ EQ" + i
- + "| TriggerDescription$ " + Strings.repeat("I", i) + " - " + sa.getDescription();
- final Trigger t = TriggerHandler.parseTrigger(trigStr, card, intrinsic);
- t.setOverridingAbility(sa);
- inst.addTrigger(t);
- ++i;
+ skipId = idx + abs.subList(idx - 1, abs.size()).lastIndexOf(ab);
+ StringBuilder desc = new StringBuilder();
+ for (int i = idx; i <= skipId; i++) {
+ if (i != idx) {
+ desc.append(", ");
+ }
+ desc.append(TextUtil.toRoman(i));
+ }
+
+ for (int i = idx; i <= skipId; i++) {
+ SpellAbility sa = AbilityFactory.getAbility(card, ab);
+ sa.setChapter(i);
+
+ StringBuilder trigStr = new StringBuilder("Mode$ CounterAdded | ValidCard$ Card.Self | TriggerZones$ Battlefield");
+ trigStr.append("| CounterType$ LORE | CounterAmount$ EQ").append(i);
+ if (i != idx) {
+ trigStr.append(" | Secondary$ True");
+ }
+ trigStr.append("| TriggerDescription$ ").append(desc).append(" — ").append(sa.getDescription());
+ final Trigger t = TriggerHandler.parseTrigger(trigStr.toString(), card, intrinsic);
+ t.setOverridingAbility(sa);
+ inst.addTrigger(t);
+ }
}
} else if (keyword.equals("Soulbond")) {
// Setup ETB trigger for card with Soulbond keyword
diff --git a/forge-game/src/main/java/forge/game/combat/Combat.java b/forge-game/src/main/java/forge/game/combat/Combat.java
index 4fc83734d74..4c85ccd5cac 100644
--- a/forge-game/src/main/java/forge/game/combat/Combat.java
+++ b/forge-game/src/main/java/forge/game/combat/Combat.java
@@ -882,6 +882,10 @@ public class Combat {
return true; // is blocking something at the moment
}
+ if (!blocker.isLKI()) {
+ return false;
+ }
+
CombatLki lki = lkiCache.get(blocker);
return null != lki && !lki.isAttacker; // was blocking something anyway
}
@@ -892,7 +896,11 @@ public class Combat {
if (blockers != null && blockers.contains(blocker)) {
return true; // is blocking the attacker's band at the moment
}
-
+
+ if (!blocker.isLKI()) {
+ return false;
+ }
+
CombatLki lki = lkiCache.get(blocker);
return null != lki && !lki.isAttacker && lki.relatedBands.contains(ab); // was blocking that very band
}
diff --git a/forge-game/src/main/java/forge/game/mana/ManaPool.java b/forge-game/src/main/java/forge/game/mana/ManaPool.java
index e90e6eb9b50..d11afbe776c 100644
--- a/forge-game/src/main/java/forge/game/mana/ManaPool.java
+++ b/forge-game/src/main/java/forge/game/mana/ManaPool.java
@@ -254,7 +254,7 @@ public class ManaPool extends ManaConversionMatrix implements Iterable {
}
}
if (mana.addsCounters(sa)) {
- mana.getManaAbility().createETBCounters(host);
+ mana.getManaAbility().createETBCounters(host, this.owner);
}
if (mana.triggersWhenSpent()) {
mana.getManaAbility().addTriggersWhenSpent(sa, host);
diff --git a/forge-game/src/main/java/forge/game/spellability/AbilityManaPart.java b/forge-game/src/main/java/forge/game/spellability/AbilityManaPart.java
index da064a4cbd6..510458a6189 100644
--- a/forge-game/src/main/java/forge/game/spellability/AbilityManaPart.java
+++ b/forge-game/src/main/java/forge/game/spellability/AbilityManaPart.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 .
*/
@@ -19,9 +19,11 @@ package forge.game.spellability;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
+
import forge.card.ColorSet;
import forge.card.MagicColor;
import forge.card.mana.ManaAtom;
+import forge.game.Game;
import forge.game.ability.AbilityFactory;
import forge.game.ability.AbilityKey;
import forge.game.card.Card;
@@ -34,6 +36,8 @@ import forge.game.replacement.*;
import forge.game.trigger.Trigger;
import forge.game.trigger.TriggerHandler;
import forge.game.trigger.TriggerType;
+import forge.game.zone.ZoneType;
+import forge.util.Lang;
import forge.util.TextUtil;
import org.apache.commons.lang3.StringUtils;
@@ -46,7 +50,7 @@ import java.util.regex.Pattern;
*
* Abstract AbilityMana class.
*
- *
+ *
* @author Forge
* @version $Id$
*/
@@ -78,7 +82,7 @@ public class AbilityManaPart implements java.io.Serializable {
*
* Constructor for AbilityMana.
*
- *
+ *
* @param sourceCard
* a {@link forge.game.card.Card} object.
*/
@@ -111,7 +115,7 @@ public class AbilityManaPart implements java.io.Serializable {
*
* produceMana.
*
- *
+ *
* @param produced
* a {@link java.lang.String} object.
* @param player
@@ -169,7 +173,7 @@ public class AbilityManaPart implements java.io.Serializable {
* cannotCounterPaidWith.
*
* @param saBeingPaid
- *
+ *
* @return a {@link java.lang.String} object.
*/
public boolean cannotCounterPaidWith(SpellAbility saBeingPaid) {
@@ -186,7 +190,7 @@ public class AbilityManaPart implements java.io.Serializable {
* addKeywords.
*
* @param saBeingPaid
- *
+ *
* @return a {@link java.lang.String} object.
*/
public boolean addKeywords(SpellAbility saBeingPaid) {
@@ -205,7 +209,7 @@ public class AbilityManaPart implements java.io.Serializable {
*
* getKeywords.
*
- *
+ *
* @return a {@link java.lang.String} object.
*/
public String getKeywords() {
@@ -217,7 +221,7 @@ public class AbilityManaPart implements java.io.Serializable {
* addsCounters.
*
* @param saBeingPaid
- *
+ *
* @return a {@link java.lang.String} object.
*/
public boolean addsCounters(SpellAbility saBeingPaid) {
@@ -227,10 +231,26 @@ public class AbilityManaPart implements java.io.Serializable {
/**
* createETBCounters
*/
- public void createETBCounters(Card c) {
+ public void createETBCounters(Card c, Player controller) {
String[] parse = this.addsCounters.split("_");
// Convert random SVars if there are other cards with this effect
if (c.isValid(parse[0], c.getController(), c, null)) {
+ final Game game = this.sourceCard.getGame();
+ final Card eff = new Card(game.nextCardId(), game);
+ eff.setTimestamp(game.getNextTimestamp());
+ eff.setName(sourceCard.getName() + "'s Effect");
+ eff.addType("Effect");
+ eff.setToken(true); // Set token to true, so when leaving play it gets nuked
+ eff.setOwner(controller);
+
+ eff.setImageKey(sourceCard.getImageKey());
+ eff.setColor(MagicColor.COLORLESS);
+ eff.setImmutable(true);
+ // try to get the SpellAbility from the mana ability
+ //eff.setEffectSource((SpellAbility)null);
+
+ eff.addRemembered(c);
+
String abStr = "DB$ PutCounter | Defined$ ReplacedCard | CounterType$ " + parse[1]
+ " | ETB$ True | CounterNum$ " + parse[2];
@@ -240,15 +260,37 @@ public class AbilityManaPart implements java.io.Serializable {
}
CardFactoryUtil.setupETBReplacementAbility(sa);
- String repeffstr = "Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield "
- + " | Secondary$ True | Description$ CARDNAME"
- + " enters the battlefield with " + CounterType.valueOf(parse[1]).getName() + " counters.";
+ String desc = "It enters the battlefield with ";
+ desc += Lang.nounWithNumeral(parse[2], CounterType.valueOf(parse[1]).getName() + " counter");
+ desc += " on it.";
- ReplacementEffect re = ReplacementHandler.parseReplacement(repeffstr, c, false);
+ String repeffstr = "Event$ Moved | ValidCard$ Card.IsRemembered | Destination$ Battlefield | Description$ " + desc;
+
+ ReplacementEffect re = ReplacementHandler.parseReplacement(repeffstr, eff, true);
re.setLayer(ReplacementLayer.Other);
re.setOverridingAbility(sa);
- c.addReplacementEffect(re);
+ eff.addReplacementEffect(re);
+
+ // Forgot Trigger
+ String trig = "Mode$ ChangesZone | ValidCard$ Card.IsRemembered | Origin$ Stack | Destination$ Any | TriggerZones$ Command | Static$ True";
+ String forgetEffect = "DB$ Pump | ForgetObjects$ TriggeredCard";
+ String exileEffect = "DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile"
+ + " | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ EQ0";
+
+ SpellAbility saForget = AbilityFactory.getAbility(forgetEffect, eff);
+ AbilitySub saExile = (AbilitySub) AbilityFactory.getAbility(exileEffect, eff);
+ saForget.setSubAbility(saExile);
+
+ final Trigger parsedTrigger = TriggerHandler.parseTrigger(trig, eff, true);
+ parsedTrigger.setOverridingAbility(saForget);
+ eff.addTrigger(parsedTrigger);
+ eff.updateStateForView();
+
+ // TODO: Add targeting to the effect so it knows who it's dealing with
+ game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
+ game.getAction().moveTo(ZoneType.Command, eff, null);
+ game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
}
}
@@ -269,7 +311,7 @@ public class AbilityManaPart implements java.io.Serializable {
*
* getManaRestrictions.
*
- *
+ *
* @return a {@link java.lang.String} object.
*/
public String getManaRestrictions() {
@@ -280,7 +322,7 @@ public class AbilityManaPart implements java.io.Serializable {
*
* meetsManaRestrictions.
*
- *
+ *
* @param sa
* a {@link forge.game.spellability.SpellAbility} object.
* @return a boolean.
@@ -296,7 +338,7 @@ public class AbilityManaPart implements java.io.Serializable {
if (restriction.equals("nonSpell")) {
return !sa.isSpell();
}
-
+
if (restriction.equals("CumulativeUpkeep")) {
if (sa.isCumulativeupkeep()) {
return true;
@@ -349,7 +391,7 @@ public class AbilityManaPart implements java.io.Serializable {
*
* mana.
*
- *
+ *
* @return a {@link java.lang.String} object.
*/
public final String mana() {
@@ -438,7 +480,7 @@ public class AbilityManaPart implements java.io.Serializable {
*
* canProduce.
*
- *
+ *
* @param s
* a {@link java.lang.String} object.
* @return a boolean.
@@ -468,7 +510,7 @@ public class AbilityManaPart implements java.io.Serializable {
*
* isBasic.
*
- *
+ *
* @return a boolean.
*/
public final boolean isBasic() {
@@ -541,7 +583,7 @@ public class AbilityManaPart implements java.io.Serializable {
public Card getSourceCard() {
return sourceCard;
}
-
+
public void setSourceCard(final Card host) {
sourceCard = host;
}
diff --git a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java
index 75479eaadfc..2bfe8b388a4 100644
--- a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java
+++ b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java
@@ -1299,6 +1299,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
String announce = getParam("Announce");
if (StringUtils.isBlank(announce)) {
mapParams.put("Announce", variable);
+ originalMapParams.put("Announce", variable);
return;
}
String[] announcedOnes = TextUtil.split(announce, ',');
@@ -1308,6 +1309,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
}
}
mapParams.put("Announce", announce + ";" + variable);
+ originalMapParams.put("Announce", announce + ";" + variable);
}
public boolean isXCost() {
diff --git a/forge-game/src/main/java/forge/trackable/TrackableTypes.java b/forge-game/src/main/java/forge/trackable/TrackableTypes.java
index 6214563f8f7..0dce88f71e5 100644
--- a/forge-game/src/main/java/forge/trackable/TrackableTypes.java
+++ b/forge-game/src/main/java/forge/trackable/TrackableTypes.java
@@ -100,17 +100,21 @@ public class TrackableTypes {
if (newCollection != null) {
//swap in objects in old collection for objects in new collection
for (int i = 0; i < newCollection.size(); i++) {
- T newObj = newCollection.get(i);
- if (newObj != null) {
- T existingObj = from.getTracker().getObj(itemType, newObj.getId());
- if (existingObj != null) { //if object exists already, update its changed properties
- existingObj.copyChangedProps(newObj);
- newCollection.remove(i);
- newCollection.add(i, existingObj);
- }
- else { //if object is new, cache in object lookup
- from.getTracker().putObj(itemType, newObj.getId(), newObj);
+ try {
+ T newObj = newCollection.get(i);
+ if (newObj != null) {
+ T existingObj = from.getTracker().getObj(itemType, newObj.getId());
+ if (existingObj != null) { //if object exists already, update its changed properties
+ existingObj.copyChangedProps(newObj);
+ newCollection.remove(i);
+ newCollection.add(i, existingObj);
+ }
+ else { //if object is new, cache in object lookup
+ from.getTracker().putObj(itemType, newObj.getId(), newObj);
+ }
}
+ } catch (IndexOutOfBoundsException e) {
+ System.err.println("got an IndexOutOfBoundsException, trying to continue ...");
}
}
}
diff --git a/forge-gui-android/AndroidManifest.xml b/forge-gui-android/AndroidManifest.xml
index 5edbcfad66e..9a984611ed7 100644
--- a/forge-gui-android/AndroidManifest.xml
+++ b/forge-gui-android/AndroidManifest.xml
@@ -6,7 +6,7 @@
+ android:targetSdkVersion="26" />
diff --git a/forge-gui-android/pom.xml b/forge-gui-android/pom.xml
index 76158aee896..9afc4dcc9ab 100644
--- a/forge-gui-android/pom.xml
+++ b/forge-gui-android/pom.xml
@@ -142,7 +142,7 @@
true
- 25
+ 26
true
${project.basedir}/AndroidManifest.xml
@@ -183,7 +183,7 @@
false
- 25
+ 26
false
diff --git a/forge-gui-android/project.properties b/forge-gui-android/project.properties
index 735ea3db305..94206b9059a 100644
--- a/forge-gui-android/project.properties
+++ b/forge-gui-android/project.properties
@@ -9,4 +9,4 @@
# Project target.
project.type=0
-target=android-20
+target=android-26
diff --git a/forge-gui-android/res/mipmap-hdpi/ic_launcher.png b/forge-gui-android/res/mipmap-hdpi/ic_launcher.png
index 13ac6220632..4271e4c73a0 100644
Binary files a/forge-gui-android/res/mipmap-hdpi/ic_launcher.png and b/forge-gui-android/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/forge-gui-android/res/mipmap-hdpi/ic_launcher_foreground.png b/forge-gui-android/res/mipmap-hdpi/ic_launcher_foreground.png
index a29e46aa510..a749b470515 100644
Binary files a/forge-gui-android/res/mipmap-hdpi/ic_launcher_foreground.png and b/forge-gui-android/res/mipmap-hdpi/ic_launcher_foreground.png differ
diff --git a/forge-gui-android/res/mipmap-hdpi/ic_launcher_round.png b/forge-gui-android/res/mipmap-hdpi/ic_launcher_round.png
index 07a75d76bfa..23880358c4f 100644
Binary files a/forge-gui-android/res/mipmap-hdpi/ic_launcher_round.png and b/forge-gui-android/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/forge-gui-android/res/mipmap-ldpi/ic_launcher.png b/forge-gui-android/res/mipmap-ldpi/ic_launcher.png
index ee25ac432d9..ae40d73a33c 100644
Binary files a/forge-gui-android/res/mipmap-ldpi/ic_launcher.png and b/forge-gui-android/res/mipmap-ldpi/ic_launcher.png differ
diff --git a/forge-gui-android/res/mipmap-mdpi/ic_launcher.png b/forge-gui-android/res/mipmap-mdpi/ic_launcher.png
index 5fdd9db84cf..75cac9e8a25 100644
Binary files a/forge-gui-android/res/mipmap-mdpi/ic_launcher.png and b/forge-gui-android/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/forge-gui-android/res/mipmap-mdpi/ic_launcher_foreground.png b/forge-gui-android/res/mipmap-mdpi/ic_launcher_foreground.png
index 524a6232021..bcb5f32aa66 100644
Binary files a/forge-gui-android/res/mipmap-mdpi/ic_launcher_foreground.png and b/forge-gui-android/res/mipmap-mdpi/ic_launcher_foreground.png differ
diff --git a/forge-gui-android/res/mipmap-mdpi/ic_launcher_round.png b/forge-gui-android/res/mipmap-mdpi/ic_launcher_round.png
index bb574ba21ae..fa0400329c5 100644
Binary files a/forge-gui-android/res/mipmap-mdpi/ic_launcher_round.png and b/forge-gui-android/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/forge-gui-android/res/mipmap-xhdpi/ic_launcher.png b/forge-gui-android/res/mipmap-xhdpi/ic_launcher.png
index 5d5de8a444f..ad7c6ed96bb 100644
Binary files a/forge-gui-android/res/mipmap-xhdpi/ic_launcher.png and b/forge-gui-android/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/forge-gui-android/res/mipmap-xhdpi/ic_launcher_foreground.png b/forge-gui-android/res/mipmap-xhdpi/ic_launcher_foreground.png
index 0e93289f2d1..25275afddb0 100644
Binary files a/forge-gui-android/res/mipmap-xhdpi/ic_launcher_foreground.png and b/forge-gui-android/res/mipmap-xhdpi/ic_launcher_foreground.png differ
diff --git a/forge-gui-android/res/mipmap-xhdpi/ic_launcher_round.png b/forge-gui-android/res/mipmap-xhdpi/ic_launcher_round.png
index 96328be12a9..42f78d72996 100644
Binary files a/forge-gui-android/res/mipmap-xhdpi/ic_launcher_round.png and b/forge-gui-android/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/forge-gui-android/res/mipmap-xxhdpi/ic_launcher.png b/forge-gui-android/res/mipmap-xxhdpi/ic_launcher.png
index e6ea9ce1897..3f9d487ce92 100644
Binary files a/forge-gui-android/res/mipmap-xxhdpi/ic_launcher.png and b/forge-gui-android/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/forge-gui-android/res/mipmap-xxhdpi/ic_launcher_foreground.png b/forge-gui-android/res/mipmap-xxhdpi/ic_launcher_foreground.png
index a01a5036f4f..a01aaa6e9df 100644
Binary files a/forge-gui-android/res/mipmap-xxhdpi/ic_launcher_foreground.png and b/forge-gui-android/res/mipmap-xxhdpi/ic_launcher_foreground.png differ
diff --git a/forge-gui-android/res/mipmap-xxhdpi/ic_launcher_round.png b/forge-gui-android/res/mipmap-xxhdpi/ic_launcher_round.png
index e4d1b24e68e..c1f4153cef3 100644
Binary files a/forge-gui-android/res/mipmap-xxhdpi/ic_launcher_round.png and b/forge-gui-android/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/forge-gui-android/res/mipmap-xxxhdpi/ic_launcher.png b/forge-gui-android/res/mipmap-xxxhdpi/ic_launcher.png
index 3380a1063bb..6d186851cd6 100644
Binary files a/forge-gui-android/res/mipmap-xxxhdpi/ic_launcher.png and b/forge-gui-android/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/forge-gui-android/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/forge-gui-android/res/mipmap-xxxhdpi/ic_launcher_foreground.png
index e8ccb890b9e..aaa2395dcb9 100644
Binary files a/forge-gui-android/res/mipmap-xxxhdpi/ic_launcher_foreground.png and b/forge-gui-android/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ
diff --git a/forge-gui-android/res/mipmap-xxxhdpi/ic_launcher_round.png b/forge-gui-android/res/mipmap-xxxhdpi/ic_launcher_round.png
index 68aca8009d4..8ad3506407f 100644
Binary files a/forge-gui-android/res/mipmap-xxxhdpi/ic_launcher_round.png and b/forge-gui-android/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/forge-gui-android/res/values/ic_launcher_background.xml b/forge-gui-android/res/values/ic_launcher_background.xml
index 7f8bb682c03..ab983282473 100644
--- a/forge-gui-android/res/values/ic_launcher_background.xml
+++ b/forge-gui-android/res/values/ic_launcher_background.xml
@@ -1,4 +1,4 @@
- #f0f0f0
+ #ffffff
\ No newline at end of file
diff --git a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorConstructed.java b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorConstructed.java
index eec8c20c98a..0d72be9a4e5 100644
--- a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorConstructed.java
+++ b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorConstructed.java
@@ -103,7 +103,7 @@ public final class CEditorConstructed extends CDeckEditor {
case TinyLeaders:
allSections.add(DeckSection.Commander);
- commanderFilter = CardRulesPredicates.Presets.CAN_BE_COMMANDER;
+ commanderFilter = CardRulesPredicates.Presets.CAN_BE_TINY_LEADERS_COMMANDER;
commanderPool = ItemPool.createFrom(FModel.getMagicDb().getCommonCards().getAllCards(Predicates.compose(commanderFilter, PaperCard.FN_GET_RULES)), PaperCard.class);
normalPool = ItemPool.createFrom(FModel.getMagicDb().getCommonCards().getAllCards(), PaperCard.class);
diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuDownloaders.java b/forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuDownloaders.java
index 53a0814f8c3..b3fd57d9a7f 100644
--- a/forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuDownloaders.java
+++ b/forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuDownloaders.java
@@ -23,6 +23,13 @@ public enum CSubmenuDownloaders implements ICDoc {
VSubmenuDownloaders.SINGLETON_INSTANCE.showLicensing();
}
};
+ private final UiCommand cmdCheckForUpdates = new UiCommand() {
+ @Override
+ public void run() {
+ new AutoUpdater(false).attemptToUpdate();
+ }
+ };
+
private final UiCommand cmdPicDownload = new UiCommand() {
@Override public void run() {
new GuiDownloader(new GuiDownloadPicturesLQ()).show();
@@ -84,6 +91,7 @@ public enum CSubmenuDownloaders implements ICDoc {
@Override
public void initialize() {
final VSubmenuDownloaders view = VSubmenuDownloaders.SINGLETON_INSTANCE;
+ view.setCheckForUpdatesCommand(cmdCheckForUpdates);
view.setDownloadPicsCommand(cmdPicDownload);
view.setDownloadPicsHQCommand(cmdPicDownloadHQ);
view.setDownloadSetPicsCommand(cmdSetDownload);
diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuPreferences.java b/forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuPreferences.java
index 96080f2a500..3e26afdf007 100644
--- a/forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuPreferences.java
+++ b/forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuPreferences.java
@@ -3,6 +3,7 @@ package forge.screens.home.settings;
import forge.*;
import forge.ai.AiProfileUtil;
import forge.control.FControl.CloseAction;
+import forge.download.AutoUpdater;
import forge.game.GameLogEntryType;
import forge.gui.framework.FScreen;
import forge.gui.framework.ICDoc;
@@ -225,6 +226,7 @@ public enum CSubmenuPreferences implements ICDoc {
initializeGameLogVerbosityComboBox();
initializeCloseActionComboBox();
initializeDefaultFontSizeComboBox();
+ initializeAutoUpdaterComboBox();
initializeMulliganRuleComboBox();
initializeAiProfilesComboBox();
initializeStackAdditionsComboBox();
@@ -378,6 +380,16 @@ public enum CSubmenuPreferences implements ICDoc {
panel.setComboBox(comboBox, selectedItem);
}
+ private void initializeAutoUpdaterComboBox() {
+ // TODO: Ideally we would filter out update paths based on the type of Forge people have
+ final String[] updatePaths = AutoUpdater.updateChannels;
+ final FPref updatePreference = FPref.AUTO_UPDATE;
+ final FComboBoxPanel panel = this.view.getCbpAutoUpdater();
+ final FComboBox comboBox = createComboBox(updatePaths, updatePreference);
+ final String selectedItem = this.prefs.getPref(updatePreference);
+ panel.setComboBox(comboBox, selectedItem);
+ }
+
private void initializeMulliganRuleComboBox() {
final String [] choices = MulliganDefs.getMulliganRuleNames();
final FPref userSetting = FPref.MULLIGAN_RULE;
diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/settings/VSubmenuDownloaders.java b/forge-gui-desktop/src/main/java/forge/screens/home/settings/VSubmenuDownloaders.java
index 6e1354a6727..2f48c1841ef 100644
--- a/forge-gui-desktop/src/main/java/forge/screens/home/settings/VSubmenuDownloaders.java
+++ b/forge-gui-desktop/src/main/java/forge/screens/home/settings/VSubmenuDownloaders.java
@@ -55,6 +55,7 @@ public enum VSubmenuDownloaders implements IVSubmenu {
private final JPanel pnlContent = new JPanel(new MigLayout("insets 0, gap 0, wrap, ay center"));
private final FScrollPane scrContent = new FScrollPane(pnlContent, false);
+ private final FLabel btnCheckForUpdates = _makeButton(localizer.getMessage("btnCheckForUpdates"));
private final FLabel btnDownloadSetPics = _makeButton(localizer.getMessage("btnDownloadSetPics"));
private final FLabel btnDownloadPics = _makeButton(localizer.getMessage("btnDownloadPics"));
private final FLabel btnDownloadPicsHQ = _makeButton(localizer.getMessage("btnDownloadPicsHQ"));
@@ -80,6 +81,9 @@ public enum VSubmenuDownloaders implements IVSubmenu {
if (javaRecentEnough()) {
+ pnlContent.add(btnCheckForUpdates, constraintsBTN);
+ pnlContent.add(_makeLabel(localizer.getMessage("lblCheckForUpdates")), constraintsLBL);
+
pnlContent.add(btnDownloadPics, constraintsBTN);
pnlContent.add(_makeLabel(localizer.getMessage("lblDownloadPics")), constraintsLBL);
@@ -162,6 +166,7 @@ public enum VSubmenuDownloaders implements IVSubmenu {
return EMenuGroup.SETTINGS;
}
+ public void setCheckForUpdatesCommand(UiCommand command) { btnCheckForUpdates.setCommand(command); }
public void setDownloadPicsCommand(UiCommand command) { btnDownloadPics.setCommand(command); }
public void setDownloadPicsHQCommand(UiCommand command) { btnDownloadPicsHQ.setCommand(command); }
public void setDownloadSetPicsCommand(UiCommand command) { btnDownloadSetPics.setCommand(command); }
diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/settings/VSubmenuPreferences.java b/forge-gui-desktop/src/main/java/forge/screens/home/settings/VSubmenuPreferences.java
index e5d6c8658cf..567a017c0e1 100644
--- a/forge-gui-desktop/src/main/java/forge/screens/home/settings/VSubmenuPreferences.java
+++ b/forge-gui-desktop/src/main/java/forge/screens/home/settings/VSubmenuPreferences.java
@@ -25,8 +25,8 @@ import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
-import java.util.*;
import java.util.List;
+import java.util.*;
/**
@@ -123,6 +123,7 @@ public enum VSubmenuPreferences implements IVSubmenu {
private final FComboBoxPanel cbpCounterDisplayLocation =new FComboBoxPanel<>(localizer.getMessage("cbpCounterDisplayLocation")+":");
private final FComboBoxPanel cbpGraveyardOrdering = new FComboBoxPanel<>(localizer.getMessage("cbpGraveyardOrdering")+":");
private final FComboBoxPanel cbpDefaultLanguage = new FComboBoxPanel<>(localizer.getMessage("cbpSelectLanguage")+":");
+ private final FComboBoxPanel cbpAutoUpdater = new FComboBoxPanel<>(localizer.getMessage("cbpAutoUpdater")+":");
/**
* Constructor.
@@ -157,6 +158,10 @@ public enum VSubmenuPreferences implements IVSubmenu {
pnlPrefs.add(new SectionLabel(localizer.getMessage("GeneralConfiguration")), sectionConstraints);
// language
+
+ pnlPrefs.add(cbpAutoUpdater, comboBoxConstraints);
+ pnlPrefs.add(new NoteLabel(localizer.getMessage("nlAutoUpdater")), descriptionConstraints);
+
pnlPrefs.add(cbpDefaultLanguage, comboBoxConstraints);
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlSelectLanguage")), descriptionConstraints);
@@ -531,6 +536,10 @@ public enum VSubmenuPreferences implements IVSubmenu {
}
}
+ public final FComboBoxPanel getCbpAutoUpdater() {
+ return cbpAutoUpdater;
+ }
+
/** @return {@link javax.swing.JCheckBox} */
public final JCheckBox getCbCompactMainMenu() {
return cbCompactMainMenu;
diff --git a/forge-gui-desktop/src/main/java/forge/view/Main.java b/forge-gui-desktop/src/main/java/forge/view/Main.java
index 05675d2225d..de1bc65aafa 100644
--- a/forge-gui-desktop/src/main/java/forge/view/Main.java
+++ b/forge-gui-desktop/src/main/java/forge/view/Main.java
@@ -81,7 +81,7 @@ public final class Main {
break;
default:
- System.out.println("Unknown mode.\nKnown mode is 'sim' ");
+ System.out.println("Unknown mode.\nKnown mode is 'sim', 'parse' ");
break;
}
diff --git a/forge-gui-mobile/src/forge/assets/FSkin.java b/forge-gui-mobile/src/forge/assets/FSkin.java
index 3eea1009c25..520c5e6a05c 100644
--- a/forge-gui-mobile/src/forge/assets/FSkin.java
+++ b/forge-gui-mobile/src/forge/assets/FSkin.java
@@ -209,7 +209,7 @@ public class FSkin {
textures.put(f6.path(), textures.get(f3.path()));
}
if (f7.exists()){
- Texture t = new Texture(f7, false);
+ Texture t = new Texture(f7, true);
//t.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
textures.put(f7.path(), t);
}
diff --git a/forge-gui-mobile/src/forge/assets/FSkinImage.java b/forge-gui-mobile/src/forge/assets/FSkinImage.java
index 5ed5abe8b8f..38daeb2ced1 100644
--- a/forge-gui-mobile/src/forge/assets/FSkinImage.java
+++ b/forge-gui-mobile/src/forge/assets/FSkinImage.java
@@ -193,6 +193,15 @@ public enum FSkinImage implements FImage {
QUEST_BIG_SWORD (FSkinProp.ICO_QUEST_BIG_SWORD, SourceFile.ICONS),
QUEST_BIG_BAG (FSkinProp.ICO_QUEST_BIG_BAG, SourceFile.ICONS),
+ //menu icon
+ MENU_GALAXY (FSkinProp.ICO_MENU_GALAXY, SourceFile.ICONS),
+ MENU_STATS (FSkinProp.ICO_MENU_STATS, SourceFile.ICONS),
+ MENU_PUZZLE (FSkinProp.ICO_MENU_PUZZLE, SourceFile.ICONS),
+ MENU_GAUNTLET (FSkinProp.ICO_MENU_GAUNTLET, SourceFile.ICONS),
+ MENU_SEALED (FSkinProp.ICO_MENU_SEALED, SourceFile.ICONS),
+ MENU_DRAFT (FSkinProp.ICO_MENU_DRAFT, SourceFile.ICONS),
+ MENU_CONSTRUCTED (FSkinProp.ICO_MENU_CONSTRUCTED, SourceFile.ICONS),
+
//Interface icons
QUESTION (FSkinProp.ICO_QUESTION, SourceFile.ICONS),
INFORMATION (FSkinProp.ICO_INFORMATION, SourceFile.ICONS),
diff --git a/forge-gui-mobile/src/forge/card/CardImageRenderer.java b/forge-gui-mobile/src/forge/card/CardImageRenderer.java
index b2094fbaa15..8bedd01ae42 100644
--- a/forge-gui-mobile/src/forge/card/CardImageRenderer.java
+++ b/forge-gui-mobile/src/forge/card/CardImageRenderer.java
@@ -35,6 +35,9 @@ import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.List;
+import static forge.card.CardRenderer.CROP_MULTIPLIER;
+import static forge.card.CardRenderer.isModernFrame;
+
public class CardImageRenderer {
private static final float BASE_IMAGE_WIDTH = 360;
private static final float BASE_IMAGE_HEIGHT = 504;
@@ -357,13 +360,19 @@ public class CardImageRenderer {
float new_yRotate = (dispH - new_w) /2;
boolean rotateSplit = FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_ROTATE_SPLIT_CARDS);
boolean rotatePlane = FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_ROTATE_PLANE_OR_PHENOMENON);
+ float croppedArea = isModernFrame(card) ? CROP_MULTIPLIER : 0.97f;
+ float minusxy = isModernFrame(card) ? 0.0f : 0.13f*radius;
+ if (card.getCurrentState().getSetCode().equals("LEA")||card.getCurrentState().getSetCode().equals("LEB")) {
+ croppedArea = 0.975f;
+ minusxy = 0.135f*radius;
+ }
if (rotatePlane && (card.getCurrentState().isPhenomenon() || card.getCurrentState().isPlane())) {
if (Forge.enableUIMask){
if (ImageCache.isExtendedArt(card))
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90);
else {
g.drawRotatedImage(FSkin.getBorders().get(0), new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90);
- g.drawRotatedImage(ImageCache.croppedBorderImage(image, fullborder), new_x+radius/2, new_y+radius/2, new_w*0.96f, new_h*0.96f, (new_x+radius/2) + (new_w*0.96f) / 2, (new_y+radius/2) + (new_h*0.96f) / 2, -90);
+ g.drawRotatedImage(ImageCache.croppedBorderImage(image, fullborder), new_x+radius/2-minusxy, new_y+radius/2-minusxy, new_w*croppedArea, new_h*croppedArea, (new_x+radius/2-minusxy) + (new_w*croppedArea) / 2, (new_y+radius/2-minusxy) + (new_h*croppedArea) / 2, -90);
}
} else
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90);
@@ -374,7 +383,7 @@ public class CardImageRenderer {
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90);
else {
g.drawRotatedImage(FSkin.getBorders().get(ImageCache.getFSkinBorders(card)), new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90);
- g.drawRotatedImage(ImageCache.croppedBorderImage(image, fullborder), new_x + radius / 2, new_y + radius / 2, new_w * 0.96f, new_h * 0.96f, (new_x + radius / 2) + (new_w * 0.96f) / 2, (new_y + radius / 2) + (new_h * 0.96f) / 2, isAftermath ? 90 : -90);
+ g.drawRotatedImage(ImageCache.croppedBorderImage(image, fullborder), new_x + radius / 2-minusxy, new_y + radius / 2-minusxy, new_w * croppedArea, new_h * croppedArea, (new_x + radius / 2-minusxy) + (new_w * croppedArea) / 2, (new_y + radius / 2-minusxy) + (new_h * croppedArea) / 2, isAftermath ? 90 : -90);
}
} else
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90);
@@ -384,7 +393,7 @@ public class CardImageRenderer {
g.drawImage(image, x, y, w, h);
else {
g.drawImage(ImageCache.getBorderImage(card, canshow), x, y, w, h);
- g.drawImage(ImageCache.croppedBorderImage(image, fullborder), x + radius / 2.4f, y + radius / 2, w * 0.96f, h * 0.96f);
+ g.drawImage(ImageCache.croppedBorderImage(image, fullborder), x + radius / 2.4f-minusxy, y + radius / 2-minusxy, w * croppedArea, h * croppedArea);
}
} else {
if (canshow && !ImageKeys.getTokenKey(ImageKeys.MORPH_IMAGE).equals(card.getState(altState).getImageKey()))
diff --git a/forge-gui-mobile/src/forge/card/CardRenderer.java b/forge-gui-mobile/src/forge/card/CardRenderer.java
index 6dee11cb8cc..6dcc0c48681 100644
--- a/forge-gui-mobile/src/forge/card/CardRenderer.java
+++ b/forge-gui-mobile/src/forge/card/CardRenderer.java
@@ -105,6 +105,7 @@ public class CardRenderer {
private static final float NAME_COST_THRESHOLD = Utils.scale(200);
private static final float BORDER_THICKNESS = Utils.scale(1);
public static final float PADDING_MULTIPLIER = 0.021f;
+ public static final float CROP_MULTIPLIER = 0.96f;
private static Map counterFonts = new HashMap<>();
private static final Color counterBackgroundColor = new Color(0f, 0f, 0f, 0.9f);
@@ -142,6 +143,49 @@ public class CardRenderer {
}
}
+ public static boolean isModernFrame(IPaperCard c) {
+ if (c == null)
+ return false;
+
+ CardEdition ed = FModel.getMagicDb().getEditions().get(c.getEdition());
+ if (ed != null) {
+ switch (ed.getCode()) {
+ case "MED":
+ case "ME2":
+ case "ME3":
+ case "ME4":
+ case "TSB":
+ return false;
+ default:
+ return ed.isModern();
+ }
+ }
+
+ return false;
+ }
+
+ public static boolean isModernFrame(CardView c) {
+ if (c == null)
+ return false;
+
+ CardView.CardStateView state = c.getCurrentState();
+ CardEdition ed = FModel.getMagicDb().getEditions().get(state.getSetCode());
+ if (ed != null) {
+ switch (ed.getCode()) {
+ case "MED":
+ case "ME2":
+ case "ME3":
+ case "ME4":
+ case "TSB":
+ return false;
+ default:
+ return ed.isModern();
+ }
+ }
+
+ return false;
+ }
+
public static float getCardListItemHeight(boolean compactMode) {
if (compactMode) {
return MANA_SYMBOL_SIZE + 2 * FList.PADDING;
@@ -402,7 +446,12 @@ public class CardRenderer {
public static void drawCard(Graphics g, IPaperCard pc, float x, float y, float w, float h, CardStackPosition pos) {
Texture image = new RendererCachedCardImage(pc, false).getImage();
float radius = (h - w)/8;
-
+ float croppedArea = isModernFrame(pc) ? CROP_MULTIPLIER : 0.97f;
+ float minusxy = isModernFrame(pc) ? 0.0f : 0.13f*radius;
+ if (pc.getEdition().equals("LEA")||pc.getEdition().equals("LEB")) {
+ croppedArea = 0.975f;
+ minusxy = 0.135f*radius;
+ }
if (image != null) {
if (image == ImageCache.defaultImage) {
CardImageRenderer.drawCardImage(g, CardView.getCardForUi(pc), false, x, y, w, h, pos);
@@ -413,7 +462,7 @@ public class CardRenderer {
g.drawImage(image, x, y, w, h);
else {
g.drawImage(ImageCache.getBorderImage(pc), x, y, w, h);
- g.drawImage(ImageCache.croppedBorderImage(image, fullborder), x + radius / 2.4f, y + radius / 2, w * 0.96f, h * 0.96f);
+ g.drawImage(ImageCache.croppedBorderImage(image, fullborder), x + radius / 2.4f-minusxy, y + radius / 2-minusxy, w * croppedArea, h * croppedArea);
}
} else
g.drawImage(image, x, y, w, h);
@@ -437,7 +486,12 @@ public class CardRenderer {
Texture image = new RendererCachedCardImage(card, false).getImage();
FImage sleeves = MatchController.getPlayerSleeve(card.getOwner());
float radius = (h - w)/8;
-
+ float croppedArea = isModernFrame(card) ? CROP_MULTIPLIER : 0.97f;
+ float minusxy = isModernFrame(card) ? 0.0f : 0.13f*radius;
+ if (card.getCurrentState().getSetCode().equals("LEA")||card.getCurrentState().getSetCode().equals("LEB")) {
+ croppedArea = 0.975f;
+ minusxy = 0.135f*radius;
+ }
if (image != null) {
if (image == ImageCache.defaultImage) {
CardImageRenderer.drawCardImage(g, card, false, x, y, w, h, pos);
@@ -450,7 +504,7 @@ public class CardRenderer {
g.drawRotatedImage(image, x, y, w, h, x + w / 2, y + h / 2, -90);
else {
g.drawRotatedImage(FSkin.getBorders().get(0), x, y, w, h, x + w / 2, y + h / 2, -90);
- g.drawRotatedImage(ImageCache.croppedBorderImage(image, fullborder), x+radius/2.3f, y+radius/2, w*0.96f, h*0.96f, (x+radius/2.3f) + (w*0.96f) / 2, (y+radius/2) + (h*0.96f) / 2, -90);
+ g.drawRotatedImage(ImageCache.croppedBorderImage(image, fullborder), x+radius/2.3f-minusxy, y+radius/2-minusxy, w*croppedArea, h*croppedArea, (x+radius/2.3f-minusxy) + (w*croppedArea) / 2, (y+radius/2-minusxy) + (h*croppedArea) / 2, -90);
}
} else
g.drawRotatedImage(image, x, y, w, h, x + w / 2, y + h / 2, -90);
@@ -461,7 +515,7 @@ public class CardRenderer {
else {
boolean t = (card.getCurrentState().getOriginalColors() != card.getCurrentState().getColors()) || card.getCurrentState().hasChangeColors();
g.drawBorderImage(ImageCache.getBorderImage(card, canshow), ImageCache.getTint(card), x, y, w, h, t); //tint check for changed colors
- g.drawImage(ImageCache.croppedBorderImage(image, fullborder), x + radius / 2.4f, y + radius / 2, w * 0.96f, h * 0.96f);
+ g.drawImage(ImageCache.croppedBorderImage(image, fullborder), x + radius / 2.4f-minusxy, y + radius / 2-minusxy, w * croppedArea, h * croppedArea);
}
} else {
if (canshow)
@@ -1119,8 +1173,14 @@ public class CardRenderer {
public static void drawFoilEffect(Graphics g, CardView card, float x, float y, float w, float h, boolean inZoomer) {
float new_x = x; float new_y = y; float new_w = w; float new_h = h; float radius = (h - w)/8;
+ float croppedArea = isModernFrame(card) ? CROP_MULTIPLIER : 0.97f;
+ float minusxy = isModernFrame(card) ? 0.0f : 0.13f*radius;
+ if (card.getCurrentState().getSetCode().equals("LEA")||card.getCurrentState().getSetCode().equals("LEB")) {
+ croppedArea = 0.975f;
+ minusxy = 0.135f*radius;
+ }
if (Forge.enableUIMask) {
- new_x += radius/2.4f; new_y += radius/2; new_w = w * 0.96f; new_h = h * 0.96f;
+ new_x += radius/2.4f-minusxy; new_y += radius/2-minusxy; new_w = w * croppedArea; new_h = h * croppedArea;
}
if (isPreferenceEnabled(FPref.UI_OVERLAY_FOIL_EFFECT) && MatchController.instance.mayView(card)) {
boolean rotateSplit = isPreferenceEnabled(FPref.UI_ROTATE_SPLIT_CARDS) && card.isSplitCard() && inZoomer;
diff --git a/forge-gui-mobile/src/forge/card/CardZoom.java b/forge-gui-mobile/src/forge/card/CardZoom.java
index 8608cbbc82f..72d7d7c978f 100644
--- a/forge-gui-mobile/src/forge/card/CardZoom.java
+++ b/forge-gui-mobile/src/forge/card/CardZoom.java
@@ -219,7 +219,22 @@ public class CardZoom extends FOverlay {
float w = getWidth();
float h = getHeight();
float messageHeight = FDialog.MSG_HEIGHT;
- float maxCardHeight = h - 2 * messageHeight;
+ float AspectRatioMultiplier = 2;
+ switch (Forge.extrawide) {
+ case "default":
+ AspectRatioMultiplier = 3; //good for tablets with 16:10 or similar
+ break;
+ case "wide":
+ AspectRatioMultiplier = 2.5f;
+ break;
+ case "extrawide":
+ AspectRatioMultiplier = 2; //good for tall phones with 21:9 or similar
+ break;
+ default:
+ AspectRatioMultiplier = 3;
+ break;
+ }
+ float maxCardHeight = h - AspectRatioMultiplier * messageHeight; //maxheight of currently zoomed card
float cardWidth, cardHeight, y;
diff --git a/forge-gui-mobile/src/forge/deck/FDeckEditor.java b/forge-gui-mobile/src/forge/deck/FDeckEditor.java
index 2f74d266722..ac553fb40ab 100644
--- a/forge-gui-mobile/src/forge/deck/FDeckEditor.java
+++ b/forge-gui-mobile/src/forge/deck/FDeckEditor.java
@@ -856,6 +856,9 @@ public class FDeckEditor extends TabPageScreen {
case Brawl:
isLegalCommander = card.getRules().canBeBrawlCommander();
break;
+ case TinyLeaders:
+ isLegalCommander = card.getRules().canBeTinyLeadersCommander();
+ break;
case Oathbreaker:
isLegalCommander = card.getRules().canBeOathbreaker();
captionSuffix = localizer.getMessage("lblOathbreaker");
diff --git a/forge-gui-mobile/src/forge/screens/home/LoadGameMenu.java b/forge-gui-mobile/src/forge/screens/home/LoadGameMenu.java
index 47f4707f310..a875ea6c3ec 100644
--- a/forge-gui-mobile/src/forge/screens/home/LoadGameMenu.java
+++ b/forge-gui-mobile/src/forge/screens/home/LoadGameMenu.java
@@ -20,11 +20,11 @@ import forge.util.Localizer;
public class LoadGameMenu extends FPopupMenu {
public enum LoadGameScreen {
- BoosterDraft("lblBoosterDraft", FSkinImage.HAND, LoadDraftScreen.class),
- SealedDeck("lblSealedDeck", FSkinImage.PACK, LoadSealedScreen.class),
+ BoosterDraft("lblBoosterDraft", FSkinImage.MENU_DRAFT, LoadDraftScreen.class),
+ SealedDeck("lblSealedDeck", FSkinImage.MENU_SEALED, LoadSealedScreen.class),
QuestMode("lblQuestMode", FSkinImage.QUEST_ZEP, LoadQuestScreen.class),
- PlanarConquest("lblPlanarConquest", FSkinImage.MULTIVERSE, LoadConquestScreen.class),
- Gauntlet("lblGauntlet", FSkinImage.ALPHASTRIKE, LoadGauntletScreen.class);
+ PlanarConquest("lblPlanarConquest", FSkinImage.MENU_GALAXY, LoadConquestScreen.class),
+ Gauntlet("lblGauntlet", FSkinImage.MENU_GAUNTLET, LoadGauntletScreen.class);
private final FMenuItem item;
private final Class extends FScreen> screenClass;
diff --git a/forge-gui-mobile/src/forge/screens/home/NewGameMenu.java b/forge-gui-mobile/src/forge/screens/home/NewGameMenu.java
index 0bd6829888b..af3cb2e1b74 100644
--- a/forge-gui-mobile/src/forge/screens/home/NewGameMenu.java
+++ b/forge-gui-mobile/src/forge/screens/home/NewGameMenu.java
@@ -24,13 +24,13 @@ public class NewGameMenu extends FPopupMenu {
final static Localizer localizer = Localizer.getInstance();
public enum NewGameScreen {
- Constructed(localizer.getMessage("lblConstructed"), FSkinImage.DECKLIST, ConstructedScreen.class),
- BoosterDraft(localizer.getMessage("lblBoosterDraft"), FSkinImage.HAND, NewDraftScreen.class),
- SealedDeck(localizer.getMessage("lblSealedDeck"), FSkinImage.PACK, NewSealedScreen.class),
+ Constructed(localizer.getMessage("lblConstructed"), FSkinImage.MENU_CONSTRUCTED, ConstructedScreen.class),
+ BoosterDraft(localizer.getMessage("lblBoosterDraft"), FSkinImage.MENU_DRAFT, NewDraftScreen.class),
+ SealedDeck(localizer.getMessage("lblSealedDeck"), FSkinImage.MENU_SEALED, NewSealedScreen.class),
QuestMode(localizer.getMessage("lblQuestMode"), FSkinImage.QUEST_ZEP, NewQuestScreen.class),
- PuzzleMode(localizer.getMessage("lblPuzzleMode"), FSkinImage.QUEST_BOOK, PuzzleScreen.class),
- PlanarConquest(localizer.getMessage("lblPlanarConquest"), FSkinImage.MULTIVERSE, NewConquestScreen.class),
- Gauntlet(localizer.getMessage("lblGauntlet"), FSkinImage.ALPHASTRIKE, NewGauntletScreen.class);
+ PuzzleMode(localizer.getMessage("lblPuzzleMode"), FSkinImage.MENU_PUZZLE, PuzzleScreen.class),
+ PlanarConquest(localizer.getMessage("lblPlanarConquest"), FSkinImage.MENU_GALAXY, NewConquestScreen.class),
+ Gauntlet(localizer.getMessage("lblGauntlet"), FSkinImage.MENU_GAUNTLET, NewGauntletScreen.class);
private final FMenuItem item;
private final Class extends FScreen> screenClass;
diff --git a/forge-gui-mobile/src/forge/screens/home/puzzle/PuzzleScreen.java b/forge-gui-mobile/src/forge/screens/home/puzzle/PuzzleScreen.java
index a740859f49b..0011ed4a6dc 100644
--- a/forge-gui-mobile/src/forge/screens/home/puzzle/PuzzleScreen.java
+++ b/forge-gui-mobile/src/forge/screens/home/puzzle/PuzzleScreen.java
@@ -54,36 +54,45 @@ public class PuzzleScreen extends LaunchScreen {
final ArrayList puzzles = PuzzleIO.loadPuzzles();
Collections.sort(puzzles);
- GuiChoose.one(Localizer.getInstance().getMessage("lblChooseAPuzzle"), puzzles, new Callback() {
+ GuiChoose.oneOrNone(Localizer.getInstance().getMessage("lblChooseAPuzzle"), puzzles, new Callback() {
@Override
public void run(final Puzzle chosen) {
- LoadingOverlay.show(Localizer.getInstance().getMessage("lblLoadingThePuzzle"), new Runnable() {
- @Override
- public void run() {
- // Load selected puzzle
- final HostedMatch hostedMatch = GuiBase.getInterface().hostMatch();
- hostedMatch.setStartGameHook(new Runnable() {
- @Override
- public final void run() {
- chosen.applyToGame(hostedMatch.getGame());
- }
- });
+ if (chosen != null) {
+ LoadingOverlay.show(Localizer.getInstance().getMessage("lblLoadingThePuzzle"), new Runnable() {
+ @Override
+ public void run() {
+ // Load selected puzzle
+ final HostedMatch hostedMatch = GuiBase.getInterface().hostMatch();
+ hostedMatch.setStartGameHook(new Runnable() {
+ @Override
+ public final void run() {
+ chosen.applyToGame(hostedMatch.getGame());
+ }
+ });
- final List players = new ArrayList<>();
- final RegisteredPlayer human = new RegisteredPlayer(new Deck()).setPlayer(GamePlayerUtil.getGuiPlayer());
- human.setStartingHand(0);
- players.add(human);
+ hostedMatch.setEndGameHook((new Runnable() {
+ @Override
+ public void run() {
+ chosen.savePuzzleSolve(hostedMatch.getGame().getOutcome().isWinner(GamePlayerUtil.getGuiPlayer()));
+ }
+ }));
- final RegisteredPlayer ai = new RegisteredPlayer(new Deck()).setPlayer(GamePlayerUtil.createAiPlayer());
- ai.setStartingHand(0);
- players.add(ai);
+ final List players = new ArrayList<>();
+ final RegisteredPlayer human = new RegisteredPlayer(new Deck()).setPlayer(GamePlayerUtil.getGuiPlayer());
+ human.setStartingHand(0);
+ players.add(human);
- GameRules rules = new GameRules(GameType.Puzzle);
- rules.setGamesPerMatch(1);
- hostedMatch.startMatch(rules, null, players, human, GuiBase.getInterface().getNewGuiGame());
- FOptionPane.showMessageDialog(chosen.getGoalDescription(), chosen.getName());
- }
- });
+ final RegisteredPlayer ai = new RegisteredPlayer(new Deck()).setPlayer(GamePlayerUtil.createAiPlayer());
+ ai.setStartingHand(0);
+ players.add(ai);
+
+ GameRules rules = new GameRules(GameType.Puzzle);
+ rules.setGamesPerMatch(1);
+ hostedMatch.startMatch(rules, null, players, human, GuiBase.getInterface().getNewGuiGame());
+ FOptionPane.showMessageDialog(chosen.getGoalDescription(), chosen.getName());
+ }
+ });
+ }
}
});
diff --git a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestMenu.java b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestMenu.java
index cffbd132a52..80ee1a8ff28 100644
--- a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestMenu.java
+++ b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestMenu.java
@@ -56,7 +56,7 @@ public class ConquestMenu extends FPopupMenu {
setCurrentScreen(collectionScreen);
}
});
- private static final FMenuItem statsItem = new FMenuItem(Localizer.getInstance().getMessage("lblStatistics"), FSkinImage.HDMULTI, new FEventHandler() {
+ private static final FMenuItem statsItem = new FMenuItem(Localizer.getInstance().getMessage("lblStatistics"), FSkinImage.MENU_STATS, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
setCurrentScreen(statsScreen);
diff --git a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestRewardDialog.java b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestRewardDialog.java
index e5086c2138c..239baa355d3 100644
--- a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestRewardDialog.java
+++ b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestRewardDialog.java
@@ -244,10 +244,7 @@ public class ConquestRewardDialog extends FScrollPane {
//ensure current card in view
if (getScrollHeight() > getHeight() && index < cardCount) {
CardRevealer currentCard = cardRevealers.get(index);
- if (!Forge.extrawide.equals("default"))
- scrollIntoView(currentCard, currentCard.getHeight() / (columnCount * PADDING) / 2);
- else
- scrollIntoView(currentCard, currentCard.getHeight() / 2 + PADDING); //show half of the card below
+ scrollIntoView(currentCard, currentCard.getHeight() / (columnCount * PADDING) / 2);
}
}
diff --git a/forge-gui-mobile/src/forge/screens/quest/QuestMenu.java b/forge-gui-mobile/src/forge/screens/quest/QuestMenu.java
index 401852ee2e6..3cff3b41e84 100644
--- a/forge-gui-mobile/src/forge/screens/quest/QuestMenu.java
+++ b/forge-gui-mobile/src/forge/screens/quest/QuestMenu.java
@@ -79,7 +79,7 @@ public class QuestMenu extends FPopupMenu implements IVQuestStats {
setCurrentScreen(bazaarScreen);
}
});
- private static final FMenuItem statsItem = new FMenuItem(Localizer.getInstance().getMessage("lblStatistics"), FSkinImage.HDMULTI, new FEventHandler() {
+ private static final FMenuItem statsItem = new FMenuItem(Localizer.getInstance().getMessage("lblStatistics"), FSkinImage.MENU_STATS, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
setCurrentScreen(statsScreen);
diff --git a/forge-gui/res/blockdata/blocks.txt b/forge-gui/res/blockdata/blocks.txt
index 3db02878fcb..67d158df0af 100644
--- a/forge-gui/res/blockdata/blocks.txt
+++ b/forge-gui/res/blockdata/blocks.txt
@@ -83,4 +83,5 @@ War of the Spark, 3/6/WAR, WAR
Modern Horizons, 3/6/WAR, MH1
Core Set 2020, 3/6/M20, M20
Throne of Eldraine, 3/6/ELD, ELD
-Theros Beyond Death, 3/6/THB, THB
\ No newline at end of file
+Theros Beyond Death, 3/6/THB, THB
+Mystery Booster, 3/6/THB, MB1
\ No newline at end of file
diff --git a/forge-gui/res/blockdata/printsheets.txt b/forge-gui/res/blockdata/printsheets.txt
index fbb6d083c2b..3dc9401f5dd 100644
--- a/forge-gui/res/blockdata/printsheets.txt
+++ b/forge-gui/res/blockdata/printsheets.txt
@@ -1657,7 +1657,7 @@ Torbran, Thane of Red Fell|ELD|2
Feasting Troll King|ELD|2
Gilded Goose|ELD|2
The Great Henge|ELD|2
-Once Upon A Time|ELD|2
+Once Upon a Time|ELD|2
Questing Beast|ELD|2
Return of the Wildspeaker|ELD|2
Wicked Wolf|ELD|2
@@ -1778,4 +1778,1857 @@ Alseid of Life's Bounty|THB|2
Thirst for Meaning|THB|2
Gray Merchant of Asphodel|THB|2
Thrill of Possibility|THB|2
-Wolfwillow Haven|THB|2
\ No newline at end of file
+Wolfwillow Haven|THB|2
+
+[MB1 White CommonUncommon]
+Abzan Falconer
+Abzan Runemark
+Acrobatic Maneuver
+Adanto Vanguard
+Affa Protector
+Ainok Bond-Kin
+Ajani's Pridemate
+Alley Evasion
+Angelic Gift
+Angelic Purge
+Angel of Mercy
+Angel of Renewal
+Angelsong
+Apostle's Blessing
+Arrest
+Arrester's Zeal
+Artful Maneuver
+Aura of Silence
+Aven Battle Priest
+Aven Sentry
+Ballynock Cohort
+Bartered Cow
+Battle Mastery
+Benevolent Ancestor
+Blade Instructor
+Blessed Spirits
+Bonds of Faith
+Borrowed Grace
+Built to Last
+Bulwark Giant
+Candlelight Vigil
+Caravan Escort
+Cartouche of Solidarity
+Cast Out
+Cathar's Companion
+Caught in the Brights
+Celestial Crusader
+Celestial Flare
+Center Soul
+Champion of Arashin
+Charge
+Cliffside Lookout
+Cloudshift
+#Coalition Honor Guard
+Collar the Culprit
+Congregate
+Conviction
+Countless Gears Renegade
+Court Homunculus
+Court Street Denizen
+Crib Swap
+Danitha Capashen, Paragon
+Daring Skyjek
+Darksteel Mutation
+Dauntless Cathar
+Dawnglare Invoker
+Decommission
+Defiant Strike
+Desperate Sentry
+Devilthorn Fox
+Disenchant
+Dismantling Blow
+Disposal Mummy
+Divine Favor
+Djeru's Renunciation
+Djeru's Resolve
+Doomed Traveler
+Dragon Bell Monk
+Dragon's Eye Sentry
+Dragon's Presence
+Eddytrail Hawk
+Emerge Unscathed
+Encampment Keeper
+Encircling Fissure
+Enduring Victory
+Enlightened Ascetic
+Ephemeral Shields
+Ephemerate
+Excavation Elephant
+Excoriate
+Expedition Raptor
+Expose Evil
+Exultant Skymarcher
+Eyes in the Skies
+Faithbearer Paladin
+Faith's Fetters
+Feat of Resistance
+Felidar Guardian
+Felidar Umbra
+Fencing Ace
+Fiend Hunter
+Firehoof Cavalry
+Forsake the Worldly
+Fortify
+Fragmentize
+Geist of the Moors
+Ghostblade Eidolon
+Gideon's Lawkeeper
+Gift of Estates
+Glaring Aegis
+Gleam of Resistance
+Glint-Sleeve Artisan
+God-Pharaoh's Faithful
+Gods Willing
+Grasp of the Hieromancer
+Great-Horn Krushok
+Guided Strike
+Gustcloak Skirmisher
+Gust Walker
+Healer's Hawk
+Healing Grace
+Healing Hands
+Heavy Infantry
+Humble
+Hyena Umbra
+Infantry Veteran
+Inquisitor's Ox
+Inspired Charge
+Intrusive Packbeast
+Iona's Judgment
+Isolation Zone
+Jubilant Mascot
+Knight of Cliffhaven
+Knight of Old Benalia
+Knight of Sorrows
+Knight of the Skyward Eye
+Knight of the Tusk
+Kor Bladewhirl
+Kor Firewalker
+Kor Hookmaster
+Kor Sky Climber
+Kor Skyfisher
+Leonin Relic-Warder
+Lieutenants of the Guard
+Lightform
+Lightwalker
+Lingering Souls
+Lone Missionary
+Lonesome Unicorn
+Looming Altisaur
+Lotus-Eye Mystics
+Loxodon Partisan
+Loyal Sentry
+Lunarch Mantle
+Mardu Hordechief
+Marked by Honor
+Meditation Puzzle
+Midnight Guard
+Momentary Blink
+Moonlit Strider
+Mortal's Ardor
+Mother of Runes
+Ninth Bridge Patrol
+Nyx-Fleece Ram
+Ondu Greathorn
+Ondu War Cleric
+Oreskos Swiftclaw
+Oust
+Pacifism
+Palace Jailer
+Palace Sentinels
+Paladin of the Bloodstained
+Path of Peace
+Path to Exile
+Peace of Mind
+Pegasus Courser
+Pentarch Ward
+Pitfall Trap
+Pressure Point
+Promise of Bunrei
+Prowling Caracal
+Rally the Peasants
+Raptor Companion
+Refurbish
+Renewed Faith
+Resurrection
+Retreat to Emeria
+Reviving Dose
+Rhet-Crop Spearmaster
+Righteous Cause
+Rootborn Defenses
+Sacred Cat
+Sanctum Gargoyle
+Sandstorm Charger
+Savannah Lions
+Seal of Cleansing
+Searing Light
+Seeker of the Way
+Sensor Splicer
+Seraph of the Suns
+Serra Disciple
+Serra's Embrace
+Sheer Drop
+Shining Aerosaur
+Shining Armor
+Shoulder to Shoulder
+Siegecraft
+Silverchase Fox
+Skyhunter Skirmisher
+Skymarcher Aspirant
+Skyspear Cavalry
+Slash of Talons
+Snubhorn Sentry
+Soulmender
+Soul Parry
+Soul-Strike Technique
+Soul Summons
+Soul Warden
+Sparring Mummy
+Spectral Gateguards
+Stalwart Aven
+Star-Crowned Stag
+Stave Off
+Steadfast Sentinel
+Stone Haven Medic
+Sunlance
+Sunrise Seeker
+Suppression Bonds
+Survive the Night
+Swords to Plowshares
+Take Vengeance
+Tandem Tactics
+Terashi's Grasp
+Territorial Hammerskull
+Thraben Inspector
+Thraben Standard Bearer
+Topan Freeblade
+Unwavering Initiate
+Veteran Swordsmith
+Village Bell-Ringer
+Voice of the Provinces
+Wake the Reflections
+Wall of Omens
+Wall of One Thousand Cuts
+Wandering Champion
+War Behemoth
+Wild Griffin
+Windborne Charge
+Winged Shepherd
+Wing Shards
+Youthful Knight
+Zealous Strike
+
+[MB1 Blue CommonUncommon]
+Academy Journeymage
+Aethersnipe
+Aether Spellbomb
+Aether Tradewinds
+Amass the Components
+Amphin Pathmage
+Anticipate
+Arcane Denial
+Archaeomancer
+Archetype of Imagination
+Artificer's Assistant
+Augur of Bolas
+Augury Owl
+Bastion Inventor
+Befuddle
+Benthic Giant
+Bewilder
+Blue Elemental Blast
+Borrowing 100,000 Arrows
+Brainstorm
+Brilliant Spectrum
+Brine Elemental
+Calculated Dismissal
+Caller of Gales
+Call to Heel
+Cancel
+Capture Sphere
+Cartouche of Knowledge
+Castaway's Despair
+Catalog
+Chart a Course
+Chillbringer
+Choking Tethers
+Chronostutter
+Circular Logic
+Citywatch Sphinx
+Claustrophobia
+Clear the Mind
+Cloak of Mists
+Cloud Elemental
+Cloudkin Seer
+Cloudreader Sphinx
+Clutch of Currents
+Compelling Argument
+Concentrate
+Condescend
+Containment Membrane
+Contingency Plan
+Contradict
+Convolute
+Coralhelm Guide
+Coral Trickster
+Counterspell
+Court Hussar
+Crashing Tide
+Crush Dissent
+Curiosity
+Curio Vendor
+Daze
+Dazzling Lights
+Decision Paralysis
+Deep Analysis
+Deep Freeze
+Diminish
+Dirgur Nemesis
+Dispel
+Displace
+Distortion Strike
+Divination
+Doorkeeper
+Dragon's Eye Savants
+Drag Under
+Dreadwaters
+Dream Cache
+Dream Twist
+Eel Umbra
+Embodiment of Spring
+Enlightened Maniac
+Ensoul Artifact
+Errant Ephemeron
+Essence Scatter
+Everdream
+Exclude
+Fact or Fiction
+Faerie Invaders
+Faerie Mechanist
+Failed Inspection
+Fascination
+Fathom Seer
+Flashfreeze
+Fledgling Mawcor
+Fleeting Distraction
+Fog Bank
+Fogwalker
+Foil
+Forbidden Alchemy
+Frantic Search
+Frilled Sea Serpent
+Frost Lynx
+Gaseous Form
+Ghost Ship
+Glacial Crasher
+Glint
+Gone Missing
+Grasp of Phantoms
+Guard Gomazoa
+Gurmag Drowner
+Gush
+Hieroglyphic Illumination
+Hightide Hermit
+Hinterland Drake
+Horseshoe Crab
+Humongulus
+Impulse
+Inkfathom Divers
+Invisibility
+Ior Ruin Expedition
+Jace's Phantasm
+Jeering Homunculus
+Jeskai Sage
+Jwar Isle Avenger
+Kiora's Dambreaker
+Laboratory Brute
+Laboratory Maniac
+Labyrinth Guardian
+Lay Claim
+Leapfrog
+Mahamoti Djinn
+Mana Leak
+Man-o'-War
+Maximize Altitude
+Memory Lapse
+Merfolk Looter
+Messenger Jays
+Metallic Rebuke
+Mind Sculpt
+Mist Raven
+Mnemonic Wall
+Monastery Loremaster
+Mulldrifter
+Murder of Crows
+Mystical Teachings
+Mystic of the Hidden Way
+Nagging Thoughts
+Negate
+Niblis of Dusk
+Nine-Tail White Fox
+Ninja of the Deep Hours
+Ojutai Interceptor
+Ojutai's Breath
+Omenspeaker
+Opportunity
+Opt
+Peel from Reality
+Phantasmal Bear
+Phyrexian Ingester
+Pondering Mage
+Portent
+Predict
+Preordain
+Prodigal Sorcerer
+Propaganda
+Prosperous Pirates
+Purple-Crystal Crab
+Refocus
+Repulse
+Retraction Helix
+Riftwing Cloudskate
+Ringwarden Owl
+River Darter
+River Serpent
+Riverwheel Aerialists
+Sage of Lat-Nam
+Sailor of Means
+Scroll Thief
+Sea Gate Oracle
+Sealock Monster
+Secrets of the Golden City
+Send to Sleep
+Shaper Parasite
+Shimmerscale Drake
+Shipwreck Looter
+Sigiled Starfish
+Silent Observer
+Silvergill Adept
+Singing Bell Strike
+Skaab Goliath
+Skitter Eel
+Skittering Crustacean
+Sleep
+Slipstream Eel
+Slither Blade
+Snap
+Snapping Drake
+Somber Hoverguard
+Sphinx's Tutelage
+Spire Monitor
+Steady Progress
+Stitched Drake
+Storm Sculptor
+Strategic Planning
+Stream of Thought
+Surrakar Banisher
+Syncopate
+Syr Elenora, the Discerning
+Tandem Lookout
+Temporal Fissure
+Thornwind Faeries
+Thoughtcast
+Thought Collapse
+Thought Scour
+Thrummingbird
+Thunder Drake
+Tidal Warrior
+Tidal Wave
+Totally Lost
+Trail of Evidence
+Treasure Cruise
+Treasure Hunt
+Treasure Mage
+Trinket Mage
+Triton Tactics
+Turn Aside
+Uncomfortable Chill
+Vapor Snag
+Vigean Graftmage
+Wall of Frost
+Warden of Evos Isle
+Watercourser
+Wave-Wing Elemental
+Weldfast Wingsmith
+Welkin Tern
+Whiplash Trap
+Windcaller Aven
+Wind Drake
+Wind-Kin Raiders
+Windrider Eel
+Wind Strider
+Wishcoin Crab
+Wishful Merfolk
+Write into Being
+Youthful Scholar
+
+[MB1 Black CommonUncommon]
+Absorb Vis
+Accursed Spirit
+Aid the Fallen
+Alesha's Vanguard
+Alley Strangler
+Altar's Reap
+Ambitious Aetherborn
+Ancestral Vengeance
+Animate Dead
+Annihilate
+Bala Ged Scorpion
+Baleful Ammit
+Balustrade Spy
+Bartizan Bats
+Bitter Revelation
+Black Cat
+Bladebrand
+Blessing of Belzenlok
+Blighted Bat
+Blightsoil Druid
+Blistergrub
+Blood Artist
+Bloodrite Invoker
+Bone Splinters
+Boon of Emrakul
+Breeding Pit
+Butcher's Glee
+Cabal Therapy
+Cackling Imp
+Cadaver Imp
+Caligo Skin-Witch
+Carrion Feeder
+Carrion Imp
+Catacomb Crocodile
+Catacomb Slug
+Caustic Tar
+Certain Death
+Child of Night
+Coat with Venom
+Corpsehatch
+Costly Plunder
+Covenant of Blood
+Cower in Fear
+Crippling Blight
+Crow of Dark Tidings
+Cursed Minotaur
+Daring Demolition
+Darkblast
+Dark Dabbling
+Dark Ritual
+Dark Withering
+Deadbridge Shaman
+Deadeye Tormentor
+Dead Reveler
+Death Denied
+Defeat
+Demonic Tutor
+Demonic Vigor
+Demon's Grasp
+Desperate Castaways
+Diabolic Edict
+Die Young
+Dinosaur Hunter
+Dirge of Dread
+Dismember
+Disowned Ancestor
+Doomed Dissenter
+Douse in Gloom
+Dreadbringer Lampads
+Dread Drone
+Dread Return
+Dregscape Zombie
+Driver of the Dead
+Drudge Sentinel
+Dukhara Scavenger
+Dune Beetle
+Duress
+Dusk Charger
+Dusk Legion Zealot
+Epicure of Blood
+Erg Raiders
+Eternal Thirst
+Evincar's Justice
+Executioner's Capsule
+Eyeblight's Ending
+Fallen Angel
+Farbog Revenant
+Fatal Push
+Fen Hauler
+Feral Abomination
+Festercreep
+Festering Newt
+Fetid Imp
+Fill with Fright
+First-Sphere Gargantua
+Flesh to Dust
+Fretwork Colony
+Fungal Infection
+Genju of the Fens
+Ghostly Changeling
+Ghoulcaller's Accomplice
+Gifted Aetherborn
+Go for the Throat
+Grasping Scoundrel
+Gravedigger
+Gravepurge
+Gray Merchant of Asphodel
+Grim Affliction
+Grim Discovery
+Grixis Slavedriver
+Grotesque Mutation
+Gruesome Fate
+Gurmag Angler
+Hideous End
+Hired Blade
+Hound of the Farbogs
+Induce Despair
+Infernal Scarring
+Infest
+Innocent Blood
+Inquisition of Kozilek
+Instill Infection
+Kalastria Nightwatch
+Krumar Bond-Kin
+Lawless Broker
+Lazotep Behemoth
+Lethal Sting
+Lord of the Accursed
+Macabre Waltz
+Marauding Boneslasher
+March of the Drowned
+Mark of the Vampire
+Marsh Hulk
+Mephitic Vapors
+Merciless Resolve
+Miasmic Mummy
+Mind Rake
+Mind Rot
+Mire's Malice
+Moment of Craving
+Murder
+Murderous Compulsion
+Nameless Inversion
+Nantuko Husk
+Never Happened
+Night's Whisper
+Nirkana Assassin
+Noxious Dragon
+Okiba-Gang Shinobi
+Painful Lesson
+Phyrexian Rager
+Phyrexian Reclamation
+Pit Keeper
+Plaguecrafter
+Plagued Rusalka
+Plague Wight
+Prakhata Club Security
+Prowling Pangolin
+Queen's Agent
+Quest for the Gravelord
+Rabid Bloodsucker
+Rakdos Drake
+Rakshasa's Secret
+Ravenous Chupacabra
+Read the Bones
+Reaper of Night
+Reassembling Skeleton
+Reckless Imp
+Reckless Spite
+Recover
+Renegade Demon
+Renegade's Getaway
+Returned Centaur
+Revenant
+Rite of the Serpent
+Rotfeaster Maggot
+Ruin Rat
+Scarab Feast
+Scrounger of Souls
+Scuttling Death
+Seal of Doom
+Sengir Vampire
+Shadowcloak Vampire
+Shambling Attendants
+Shambling Goblin
+Shriekmaw
+Silumgar Butcher
+Skeletal Scrying
+Skeleton Archer
+Skulking Ghost
+Smiting Helix
+Spreading Rot
+Stab Wound
+Stallion of Ashmouth
+Stinkweed Imp
+Street Wraith
+Stromkirk Patrol
+Subtle Strike
+Sultai Runemark
+Tar Snare
+Tavern Swindler
+Tendrils of Corruption
+Thallid Omnivore
+The Eldest Reborn
+Thornbow Archer
+Thorn of the Black Rose
+Thraben Foulbloods
+Tidy Conclusion
+Torment of Venom
+Touch of Moonglove
+Tragic Slip
+Trespasser's Curse
+Trial of Ambition
+Twins of Maurer Estate
+Typhoid Rats
+Unburden
+Undercity's Embrace
+Untamed Hunger
+Unyielding Krumar
+Urborg Uprising
+Vampire Champion
+Vampire Envoy
+Vampire Hexmage
+Vampire Lacerator
+Vampire Nighthawk
+Vessel of Malignity
+Virulent Swipe
+Voracious Null
+Vraska's Finisher
+Wake of Vultures
+Walking Corpse
+Walk the Plank
+Wander in Death
+Warteye Witch
+Weight of the Underworld
+Weirded Vampire
+Wight of Precinct Six
+Will-o'-the-Wisp
+Windgrace Acolyte
+Wrench Mind
+Yargle, Glutton of Urborg
+Zulaport Chainmage
+
+[MB1 Red CommonUncommon]
+Act of Treason
+Act on Impulse
+Ahn-Crop Crasher
+Ainok Tracker
+Akroan Sergeant
+Alchemist's Greeting
+Ancient Grudge
+Anger
+Arc Trail
+Arrow Storm
+Atarka Efreet
+Avarax
+Azra Bladeseeker
+Balduvian Horde
+Barging Sergeant
+Barrage of Boulders
+Battle Rampart
+Battle-Rattle Shaman
+Beetleback Chief
+Bellows Lizard
+Blades of Velis Vel
+Blastfire Bolt
+Blazing Volley
+Blindblast
+Bloodfire Expert
+Bloodlust Inciter
+Bloodmad Vampire
+Blood Ogre
+Bloodstone Goblin
+Blow Your House Down
+Blur of Blades
+Boggart Brute
+Boiling Earth
+Bombard
+Bomber Corps
+Borrowed Hostility
+Boulder Salvo
+Brazen Buccaneers
+Brazen Wolves
+Bring Low
+Browbeat
+Brute Strength
+Built to Smash
+Burst Lightning
+Canyon Lurkers
+Cartouche of Zeal
+Cathartic Reunion
+Chandra's Pyrohelix
+Chandra's Revolution
+Charging Monstrosaur
+Chartooth Cougar
+Cinder Hellion
+Cleansing Screech
+Cobblebrute
+Cosmotronic Wave
+Crash Through
+Crowd's Favor
+Crown-Hunter Hireling
+Curse of Opulence
+Curse of the Nightly Hunt
+Death by Dragons
+Defiant Ogre
+Demolish
+Desert Cerodon
+Desperate Ravings
+Destructive Tampering
+Direct Current
+Distemper of the Blood
+Dragon Breath
+Dragon Egg
+Dragon Fodder
+Dragonsoul Knight
+Dragon Whelp
+Dual Shot
+Dynacharge
+Earth Elemental
+Emrakul's Hatcher
+Enthralling Victor
+Erratic Explosion
+Expedite
+Faithless Looting
+Falkenrath Reaver
+Fall of the Hammer
+Fervent Strike
+Fierce Invocation
+Fiery Hellhound
+Fiery Temper
+Fireball
+Firebolt
+Firebrand Archer
+Fire Elemental
+Flame Jab
+Flametongue Kavu
+Flamewave Invoker
+Fling
+Forge Devil
+Foundry Street Denizen
+Frenzied Raptor
+Frilled Deathspitter
+Frontline Devastator
+Frontline Rebel
+Furnace Whelp
+Fury Charm
+Galvanic Blast
+Generator Servant
+Genju of the Spires
+Geomancer's Gambit
+Ghitu Lavarunner
+Giant Spectacle
+Goblin Assault
+Goblin Balloon Brigade
+Goblin Bombardment
+Goblin Fireslinger
+Goblin Locksmith
+Goblin Matron
+Goblin Motivator
+Goblin Oriflamme
+Goblin Roughrider
+Goblin Warchief
+Goblin War Paint
+Gorehorn Minotaurs
+Gore Swine
+Granitic Titan
+Grapeshot
+Gravitic Punch
+Gut Shot
+Guttersnipe
+Hammerhand
+Hanweir Lancer
+Hardened Berserker
+Hijack
+Hulking Devil
+Hyena Pack
+Ill-Tempered Cyclops
+Impact Tremors
+Incorrigible Youths
+Inferno Fist
+Inferno Jet
+Ingot Chewer
+Insolent Neonate
+Jackal Pup
+Keldon Halberdier
+Keldon Overseer
+Khenra Scrapper
+Kiln Fiend
+Kird Ape
+Kolaghan Stormsinger
+Krenko's Command
+Krenko's Enforcer
+Leaping Master
+Leopard-Spotted Jiao
+Lightning Bolt
+Lightning Javelin
+Lightning Shrieker
+Lightning Talons
+Madcap Skills
+Magma Spray
+Makindi Sliderunner
+Mardu Warshrieker
+Mark of Mutiny
+Maximize Velocity
+Miner's Bane
+Mogg Fanatic
+Mogg Flunkies
+Mogg War Marshal
+Molten Rain
+Monastery Swiftspear
+Mutiny
+Nimble-Blade Khenra
+Ondu Champion
+Orcish Cannonade
+Orcish Oriflamme
+Outnumber
+Pillage
+Price of Progress
+Prickleboar
+Prophetic Ravings
+Pyrotechnics
+Quakefoot Cyclops
+Rampaging Cyclops
+Reckless Fireweaver
+Reckless Wurm
+Renegade Tactics
+Rivals' Duel
+Roast
+Rolling Thunder
+Rubblebelt Maaka
+Ruinous Gremlin
+Rummaging Goblin
+Run Amok
+Rush of Adrenaline
+Salivating Gremlins
+Samut's Sprint
+Sarkhan's Rage
+Screamreach Brawler
+Seismic Shift
+Seismic Stomp
+Shatter
+Shattering Spree
+Shenanigans
+Shock
+Skirk Commando
+Skirk Prospector
+Smash to Smithereens
+Smelt
+Sparkmage Apprentice
+Sparkspitter
+Sparktongue Dragon
+Spikeshot Goblin
+Staggershock
+Stormblood Berserker
+Sulfurous Blast
+Summit Prowler
+Sun-Crowned Hunters
+Swashbuckling
+Sweatworks Brawler
+Swift Kick
+Tarfire
+Tectonic Rift
+Temur Battle Rage
+Thresher Lizard
+Thrill of Possibility
+Tibalt's Rager
+Torch Courier
+Uncaged Fury
+Undying Rage
+Valakut Invoker
+Valakut Predator
+Valley Dasher
+Vandalize
+Vent Sentinel
+Vessel of Volatility
+Volcanic Dragon
+Volcanic Rush
+Voldaren Duelist
+Wall of Fire
+Wayward Giant
+Wildfire Emissary
+Wojek Bodyguard
+Young Pyromancer
+Zada's Commando
+Zealot of the God-Pharaoh
+
+[MB1 Green CommonUncommon]
+Abundant Growth
+Acidic Slime
+Adventurous Impulse
+Aerie Bowmasters
+Affectionate Indrik
+Aggressive Instinct
+Aggressive Urge
+Ainok Survivalist
+Alpine Grizzly
+Ambassador Oak
+Ancestral Mask
+Ancient Brontodon
+Ancient Stirrings
+Arachnus Web
+Arbor Armament
+Arbor Elf
+Aura Gnarlid
+Avacyn's Pilgrim
+Backwoods Survivalists
+Baloth Gorger
+Basking Rootwalla
+Beastbreaker of Bala Ged
+Beast Within
+Become Immense
+Beneath the Sands
+Bestial Menace
+Bitterblade Warrior
+Bitterbow Sharpshooters
+Blanchwood Armor
+Blastoderm
+Blossom Dryad
+Borderland Explorer
+Borderland Ranger
+Briarhorn
+Bristling Boar
+Broken Bond
+Broodhunter Wurm
+Byway Courier
+Canopy Spider
+Carnivorous Moss-Beast
+Caustic Caterpillar
+Centaur Courser
+Charging Rhino
+Citanul Woodreaders
+Clip Wings
+Colossal Dreadmaw
+Combo Attack
+Commune with Nature
+Commune with the Gods
+Conifer Strider
+Creeping Mold
+Crop Rotation
+Crossroads Consecrator
+Crowned Ceratok
+Crushing Canopy
+Cultivate
+Daggerback Basilisk
+Dawn's Reflection
+Death-Hood Cobra
+Desert Twister
+Destructor Dragon
+Dissenter's Deliverance
+Domesticated Hydra
+Dragonscale Boon
+Dragon-Scarred Bear
+Durkwood Baloth
+Earthen Arms
+Elemental Uprising
+Elephant Guide
+Elves of Deep Shadow
+Elvish Fury
+Elvish Visionary
+Elvish Warrior
+Ember Weaver
+Epic Confrontation
+Essence Warden
+Eternal Witness
+Experiment One
+Explore
+Explosive Vegetation
+Ezuri's Archers
+Fade into Antiquity
+Farseek
+Feed the Clan
+Feral Krushok
+Feral Prowler
+Ferocious Zheng
+Fertile Ground
+Fierce Empath
+Fog
+Formless Nurturing
+Frontier Mastodon
+Gaea's Blessing
+Gaea's Protector
+Giant Growth
+Giant Spider
+Gift of Growth
+Gift of Paradise
+Glade Watcher
+Gnarlid Pack
+Grapple with the Past
+Grazing Gladehart
+Greater Basilisk
+Greater Sandwurm
+Greenwood Sentinel
+Groundswell
+Guardian Shield-Bearer
+Hamlet Captain
+Hardy Veteran
+Harmonize
+Harrow
+Hooded Brawler
+Hooting Mandrills
+Hunter's Ambush
+Hunt the Weak
+Imperious Perfect
+Invigorate
+Ivy Lane Denizen
+Jungle Delver
+Jungle Wayfinder
+Kavu Climber
+Kavu Primarch
+Khalni Heart Expedition
+Kin-Tree Warden
+Kozilek's Predator
+Kraul Foragers
+Kraul Warrior
+Krosan Druid
+Krosan Tusker
+Larger Than Life
+Lay of the Land
+Lead by Example
+Lead the Stampede
+Lifespring Druid
+Lignify
+Llanowar Elves
+Llanowar Empath
+Longshot Squad
+Lure
+Manglehorn
+Mantle of Webs
+Map the Wastes
+Might of the Masses
+Mulch
+Natural Connection
+Naturalize
+Nature's Claim
+Nature's Lore
+Nest Invader
+Nettle Sentinel
+New Horizons
+Nimble Mongoose
+Oakgnarl Warrior
+Ondu Giant
+Oran-Rief Invoker
+Overgrown Armasaur
+Overgrown Battlement
+Overrun
+Pack's Favor
+Peema Outrider
+Pelakka Wurm
+Penumbra Spider
+Pierce the Sky
+Pinion Feast
+Plummet
+Pouncing Cheetah
+Prey's Vengeance
+Prey Upon
+Priest of Titania
+Pulse of Murasa
+Quiet Disrepair
+Rain of Thorns
+Rampant Growth
+Rancor
+Ranger's Guile
+Ravenous Leucrocota
+Reclaim
+Reclaiming Vines
+Regrowth
+Relic Crush
+Return to the Earth
+Revive
+Rhox Maulers
+Riparian Tiger
+Roar of the Wurm
+Root Out
+Roots
+Rosethorn Halberd
+Runeclaw Bear
+Sagu Archer
+Sakura-Tribe Elder
+Saproling Migration
+Savage Punch
+Scatter the Seeds
+Seal of Strength
+Search for Tomorrow
+Seek the Horizon
+Seek the Wilds
+Shape the Sands
+Siege Wurm
+Silhana Ledgewalker
+Silkweaver Elite
+Snake Umbra
+Snapping Sailback
+Spider Spawning
+Stalking Tiger
+Stoic Builder
+Strength in Numbers
+Sylvan Bounty
+Sylvan Scrying
+Tajuru Pathwarden
+Tajuru Warcaller
+Take Down
+Talons of Wildwood
+Terrain Elemental
+Territorial Baloth
+#The Crowd Goes Wild
+Thornhide Wolves
+Thornscape Battlemage
+Thornweald Archer
+Thrashing Brontodon
+Thrive
+Timberwatch Elf
+Time to Feed
+Titanic Growth
+Tukatongue Thallid
+Turntimber Basilisk
+Vastwood Gorger
+Venom Sliver
+Watcher in the Web
+Wellwisher
+Wild Growth
+Wild Mongrel
+Wildsize
+Wolfkin Bond
+Woodborn Behemoth
+Woolly Loxodon
+Wren's Run Vanquisher
+Yavimaya Elder
+Yavimaya Sapherd
+Yeva's Forcemage
+Zendikar's Roil
+
+[MB1 Multi CommonUncommon]
+Azorius Charm
+Cunning Breezedancer
+Ethercaste Knight
+Kiss of the Amesha
+Lawmage's Binding
+Migratory Route
+Mistmeadow Witch
+Raff Capashen, Ship's Mage
+Reflector Mage
+Riptide Crab
+Agony Warp
+Baleful Strix
+Call of the Nightwing
+Contraband Kingpin
+Deny Reality
+Extract from Darkness
+Kathari Remnant
+Shipwreck Singer
+Soul Manipulation
+Thought Erasure
+Azra Oddsmaker
+Bituminous Blast
+Bladewing the Risen
+Blightning
+Cauldron Dance
+Claim // Fame
+Goblin Deathraiders
+Shambling Remains
+Terminate
+Unlicensed Disintegration
+Bloodbraid Elf
+Draconic Disciple
+Fires of Yavimaya
+Ghor-Clan Rampager
+Giantbaiting
+Raging Swordtooth
+Rosheen Meanderer
+Savage Twister
+Treacherous Terrain
+Vengeful Rebirth
+Zhur-Taa Druid
+Armadillo Cloak
+Belligerent Brontodon
+Citadel Castellan
+Engineered Might
+Join Shields
+Pollenbright Wings
+Qasali Pridemage
+Rosemane Centaur
+Satyr Enchanter
+Selesnya Guildmage
+Unflinching Courage
+Wayfaring Temple
+Campaign of Vengeance
+Drana's Emissary
+Gift of Orzhova
+Gwyllion Hedge-Mage
+Hidden Stockpile
+Mortify
+Pillory of the Sleepless
+Tithe Drinker
+Underworld Coinsmith
+Zealous Persecution
+Fire // Ice
+Gelectrode
+Hypothesizzle
+Maverick Thopterist
+Mercurial Geists
+Nucklavee
+Reclusive Artificer
+Shrewd Hatchling
+Stormchaser Chimera
+Wee Dragonauts
+Baloth Null
+Corpsejack Menace
+Deathreap Ritual
+Grim Contest
+Kin-Tree Invocation
+Obelisk Spider
+Ochran Assassin
+Putrefy
+Winding Constrictor
+Akroan Hoplite
+Boros Challenger
+Flame-Kin Zealot
+Hammer Dropper
+Highspire Mantis
+Iroas's Champion
+Lightning Helix
+Martial Glory
+Weapons Trainer
+Bounding Krasis
+Coiling Oracle
+Ethereal Ambush
+Jungle Barrier
+Kiora's Follower
+Plaxcaster Frogling
+River Hoopoe
+Shardless Agent
+Tatyova, Benthic Druid
+Urban Evolution
+Esper Charm
+Thopter Foundry
+Tower Gargoyle
+Crosis's Charm
+Sedraxis Specter
+Slave of Bolas
+Sprouting Thrinax
+Naya Charm
+Woolly Thoctar
+Rhox War Monk
+Skyward Eye Prophets
+Mardu Roughrider
+Bear's Companion
+Abzan Charm
+Abzan Guide
+Armament Corps
+Warden of the Eye
+Sultai Charm
+Sultai Soothsayer
+Fusion Elemental
+
+[MB1 Artifact Land CommonUncommon]
+Blinding Souleater
+Benthic Infiltrator
+Wretched Gryff
+Implement of Malice
+Call the Scions
+Gruul Signet
+Simic Locket
+Alchemist's Vial
+Alloy Myr
+Armillary Sphere
+Artisan of Kozilek
+Ashnod's Altar
+Bomat Bazaar Barge
+Bone Saw
+Bottle Gnomes
+Breaker of Armies
+Burnished Hart
+Cathodion
+Coldsteel Heart
+Consulate Dreadnought
+Copper Carapace
+Crystal Ball
+Crystal Chimes
+Diamond Mare
+Eldrazi Devastator
+Emmessi Tome
+Etched Oracle
+Farmstead Gleaner
+Filigree Familiar
+Flayer Husk
+Foundry Inspector
+Fountain of Renewal
+Frogmite
+Guardians of Meletis
+Heavy Arbalest
+Herald's Horn
+Hexplate Golem
+Hot Soup
+Icy Manipulator
+Irontread Crusher
+Juggernaut
+Lightning Greaves
+Loxodon Warhammer
+Mask of Memory
+Meteorite
+Millikin
+Millstone
+Mind Stone
+Mishra's Bauble
+Moonglove Extract
+Mortarpod
+Myr Retriever
+Myr Sire
+Ornithopter
+Palladium Myr
+Peace Strider
+Perilous Myr
+Pilgrim's Eye
+Prophetic Prism
+Renegade Map
+Rhonas's Monument
+Sandstone Oracle
+Serrated Arrows
+Short Sword
+Sigil of Valor
+Skullclamp
+Skyscanner
+Sol Ring
+Sorcerer's Broom
+Spy Kit
+Sunset Pyramid
+Suspicious Bookcase
+Thought Vessel
+Thran Dynamo
+Thran Golem
+Tormod's Crypt
+Trepanation Blade
+Universal Automaton
+Universal Solvent
+Whispersilk Cloak
+New Benalia
+Faerie Conclave
+Blighted Fen
+Bojuka Bog
+Forgotten Cave
+Goblin Burrows
+Great Furnace
+Wirewood Lodge
+Sejiri Refuge
+Dismal Backwater
+Dreadship Reef
+Akoum Refuge
+Kazandu Refuge
+Skarrg, the Rage Pits
+Blossoming Sands
+Graypelt Refuge
+Orzhov Basilica
+Scoured Barrens
+Swiftwater Cliffs
+Jungle Hollow
+Thornwood Falls
+Arcane Sanctum
+Crumbling Necropolis
+Jungle Shrine
+Frontier Bivouac
+Sandsteppe Citadel
+Aether Hub
+Ash Barrens
+Blasted Landscape
+Darksteel Citadel
+Evolving Wilds
+Field of Ruin
+Gateway Plaza
+Ghost Quarter
+Krosan Verge
+Mishra's Factory
+Reliquary Tower
+Rogue's Passage
+Tectonic Edge
+Temple of the False God
+Unclaimed Territory
+
+[MB1 Pre M15]
+Ana Sanctuary
+Ancient Den
+Ancient Ziggurat
+Angelic Destiny
+Archangel
+Asceticism
+Assemble the Legion
+Athreos, God of Passage
+Aura Shards
+Avalanche Riders
+Bear Cub
+Belbe's Portal
+Black Knight
+Bloom Tender
+Bonesplitter
+Bow of Nylea
+Brimstone Dragon
+Brimstone Mage
+Cairn Wanderer
+Carpet of Flowers
+Centaur Glade
+Chancellor of the Annex
+Chatter of the Squirrel
+Chromatic Star
+Contagion Clasp
+Corrupted Conscience
+Cragganwick Cremator
+Crenellated Wall
+Crystal Shard
+Darksteel Garrison
+Dauthi Mindripper
+Defense of the Heart
+Dictate of Erebos
+Dolmen Gate
+Dominus of Fealty
+Doomgape
+Draco
+Dragon Broodmother
+Dragon Mask
+Dungrove Elder
+Eater of Days
+Elixir of Immortality
+Empyrial Armor
+Enchanted Evening
+Energy Field
+Exsanguinate
+Flameshot
+Floodgate
+Font of Mythos
+Ghitu War Cry
+Gilt-Leaf Palace
+Goblin Game
+Greater Gargadon
+Guided Passage
+Haakon, Stromgald Scourge
+Hedron Crab
+Helm of Awakening
+Hunter of Eyeblights
+Hurricane
+Hypnotic Specter
+Impending Disaster
+Jushi Apprentice
+Kaervek's Torch
+Kargan Dragonlord
+Knight of Dawn
+Knollspine Dragon
+Kor Chant
+Kruphix, God of Horizons
+Lashknife Barrier
+Lotus Petal
+Maelstrom Archangel
+Magus of the Moat
+Mana Tithe
+Manamorphose
+Martyr's Bond
+Martyr's Cause
+Master Transmuter
+Meddling Mage
+Mistform Shrieker
+Nemesis of Reason
+Oracle of Nectars
+Pathrazer of Ulamog
+Perish
+Pestilence
+Phantasmal Dragon
+Phantom Centaur
+Phyrexian Metamorph
+Phyrexian Soulgorger
+Purphoros, God of the Forge
+Questing Phelddagrif
+Rage Reflection
+Recoup
+Release the Ants
+Rhys the Redeemed
+Rhystic Study
+Rishadan Footpad
+Rith, the Awakener
+River Boa
+Sadistic Hypnotist
+Sakashima the Impostor
+Sapphire Charm
+Shrouded Lore
+Soothsaying
+Sorin Markov
+Squirrel Wrangler
+Thieving Magpie
+Thrun, the Last Troll
+Time Sieve
+Timely Reinforcements
+Tinker
+Tower of Eons
+Toxin Sliver
+Triumph of the Hordes
+Umbral Mantle
+Viashino Sandstalker
+Violent Ultimatum
+Volunteer Reserves
+Wargate
+Weathered Wayfarer
+Wild Nacatl
+Yavimaya's Embrace
+
+[MB1 Post M15 RareMythic]
+Adorned Pouncer
+Aetherflux Reservoir
+Akroan Horse
+Alesha, Who Smiles at Death
+Alhammarret's Archive
+All Is Dust
+Aminatou's Augury
+Angel of the Dire Hour
+Anger of the Gods
+Animar, Soul of Elements
+Approach of the Second Sun
+Arch of Orazca
+Basilisk Collar
+Beacon of Immortality
+Beastmaster Ascension
+Birds of Paradise
+Black Market
+Boompile
+Boros Reckoner
+Caged Sun
+Cauldron of Souls
+Champion of the Parish
+Chaos Warp
+Chasm Skulker
+Chromatic Lantern
+Coat of Arms
+Collective Brutality
+Commit // Memory
+Courser of Kruphix
+Coveted Jewel
+Daretti, Scrap Savant
+Deadly Tempest
+Debtors' Knell
+Decree of Justice
+Deepglow Skate
+Desolation Twin
+Dictate of Heliod
+Djinn of Wishes
+Dragonlord Ojutai
+Drana, Kalastria Bloodchief
+Eldrazi Monument
+Eldritch Evolution
+Elesh Norn, Grand Cenobite
+Evra, Halcyon Witness
+#Expropriate
+Fblthp, the Lost
+Felidar Sovereign
+Gideon Jura
+Goblin Charbelcher
+Goblin Piledriver
+Gonti, Lord of Luxury
+Grasp of Fate
+Grave Titan
+Gravecrawler
+Greenbelt Rampager
+Hornet Nest
+Kiki-Jiki, Mirror Breaker
+Kolaghan's Command
+Krenko, Mob Boss
+Liliana, Death's Majesty
+Living Death
+Mana Crypt
+Meandering Towershell
+Memory Erosion
+Meren of Clan Nel Toth
+Mimic Vat
+Mind Shatter
+Mind Spring
+Mirran Crusader
+Mirror Entity
+Misdirection
+Mizzix's Mastery
+Mycoloth
+Mystic Confluence
+Nighthowler
+Nin, the Pain Artist
+Nissa, Voice of Zendikar
+Odric, Lunarch Marshal
+Phyrexian Arena
+Phyrexian Plaguelord
+Precursor Golem
+Preyseizer Dragon
+Queen Marchesa
+Reality Scramble
+Recruiter of the Guard
+Release the Gremlins
+Revel in Riches
+Rune-Scarred Demon
+Savage Knuckleblade
+Selvala, Heart of the Wilds
+Serendib Efreet
+Sewer Nemesis
+Shamanic Revelation
+Sliver Hivelord
+Solemn Simulacrum
+Spawning Grounds
+Star of Extinction
+Steamflogger Boss
+Stunt Double
+Sudden Demise
+Supreme Verdict
+Sword of the Animist
+Talrand, Sky Summoner
+Taurean Mauler
+Teferi's Protection
+Teferi, Temporal Archmage
+Temporal Mastery
+Tempt with Discovery
+Thalia's Lancers
+The Gitrog Monster
+The Mirari Conjecture
+Tireless Tracker
+Torment of Hailfire
+Trading Post
+Two-Headed Giant
+Urza's Rage
+Vigor
+Wheel of Fate
+Whelming Wave
+Whir of Invention
+Yuriko, the Tiger's Shadow
+
+[FMB1 Foils]
+Not of This World+|FMB1
+Celestial Dawn+|FMB1
+Celestial Kirin+|FMB1
+Changeling Hero+|FMB1
+Council Guardian+|FMB1
+Eidolon of Rhetoric+|FMB1
+Isamaru, Hound of Konda+|FMB1
+Lapse of Certainty+|FMB1
+Lumithread Field+|FMB1
+Norn's Annex+|FMB1
+Proclamation of Rebirth+|FMB1
+Pull from Eternity+|FMB1
+Rune-Tail, Kitsune Ascendant+|FMB1
+Sinew Sliver+|FMB1
+Soul's Attendant+|FMB1
+Spelltithe Enforcer+|FMB1
+Springjack Shepherd+|FMB1
+Wall of Shards+|FMB1
+White Knight+|FMB1
+Blighted Agent+|FMB1
+Delay+|FMB1
+Fatespinner+|FMB1
+Frozen Aether+|FMB1
+Grand Architect+|FMB1
+Intruder Alarm+|FMB1
+Misthollow Griffin+|FMB1
+Paradox Haze+|FMB1
+Patron of the Moon+|FMB1
+Puca's Mischief+|FMB1
+Spellweaver Volute+|FMB1
+Storm Crow+|FMB1
+Zur's Weirding+|FMB1
+Bringer of the Black Dawn+|FMB1
+Chimney Imp+|FMB1
+Conspiracy+|FMB1
+Echoing Decay+|FMB1
+Funeral Charm+|FMB1
+Herald of Leshrac+|FMB1
+Marrow-Gnawer+|FMB1
+Nezumi Shortfang+|FMB1
+One with Nothing+|FMB1
+Ravenous Trap+|FMB1
+Rescue from the Underworld+|FMB1
+Undead Warchief+|FMB1
+Viscera Seer+|FMB1
+Balduvian Rage+|FMB1
+Braid of Fire+|FMB1
+Burning Inquiry+|FMB1
+Fiery Gambit+|FMB1
+Flamekin Harbinger+|FMB1
+Form of the Dragon+|FMB1
+Goblin Bushwhacker+|FMB1
+Guerrilla Tactics+|FMB1
+Lightning Storm+|FMB1
+Norin the Wary+|FMB1
+Ogre Gatecrasher+|FMB1
+Pyretic Ritual+|FMB1
+Scourge of the Throne+|FMB1
+Stigma Lasher+|FMB1
+Treasonous Ogre+|FMB1
+Allosaurus Rider+|FMB1
+Archetype of Endurance+|FMB1
+Boreal Druid+|FMB1
+Boundless Realms+|FMB1
+Bramblewood Paragon+|FMB1
+Fungusaur+|FMB1
+Game-Trail Changeling+|FMB1
+Gleeful Sabotage+|FMB1
+Greater Mossdog+|FMB1
+Helix Pinnacle+|FMB1
+Hornet Sting+|FMB1
+Manaweft Sliver+|FMB1
+Maro+|FMB1
+Myojin of Life's Web+|FMB1
+Panglacial Wurm+|FMB1
+Reki, the History of Kamigawa+|FMB1
+Rhox+|FMB1
+Sakura-Tribe Scout+|FMB1
+Scryb Ranger+|FMB1
+Sheltering Ancient+|FMB1
+Sosuke, Son of Seshiro+|FMB1
+Spike Feeder+|FMB1
+Aurelia's Fury+|FMB1
+Drogskol Captain+|FMB1
+Glittering Wish+|FMB1
+Harmonic Sliver+|FMB1
+Karrthus, Tyrant of Jund+|FMB1
+Maelstrom Nexus+|FMB1
+Mind Funeral+|FMB1
+Sarkhan the Mad+|FMB1
+Sen Triplets+|FMB1
+Yore-Tiller Nephilim+|FMB1
+Balefire Liege+|FMB1
+Gilder Bairn+|FMB1
+Kulrath Knight+|FMB1
+Noggle Bandit+|FMB1
+Wear // Tear+|FMB1
+Amulet of Vigor+|FMB1
+Blasting Station+|FMB1
+Codex Shredder+|FMB1
+Geth's Grimoire+|FMB1
+Iron Myr+|FMB1
+Knowledge Pool+|FMB1
+Lantern of Insight+|FMB1
+Leveler+|FMB1
+Lich's Mirror+|FMB1
+Magewright's Stone+|FMB1
+Memnite+|FMB1
+Mindslaver+|FMB1
+Pili-Pala+|FMB1
+Reaper King+|FMB1
+Sundial of the Infinite+|FMB1
+Teferi's Puzzle Box+|FMB1
+Trailblazer's Boots+|FMB1
+Triskelion+|FMB1
+Witchbane Orb+|FMB1
+Alchemist's Refuge+|FMB1
+Minamo, School at Water's Edge+|FMB1
+Mirrodin's Core+|FMB1
+Shizo, Death's Storehouse+|FMB1
+Stalking Stones+|FMB1
+
+[CN2 Not In Normal Slots]
+Adriana's Valor
+#Assemble the Rank and Vile
+Echoing Boon
+#Emissary's Ploy
+Hired Heist
+#Hold the Permiter
+Hymn of the Wilds
+Incendiary Dissent
+Natural Unity
+#Sovereign's Realm
+#Summoner's Bond
+Weight Advantage
+Kaya, Ghost Assassin|CN2|2
+
+[CN2 Foil Kaya]
+Kaya, Ghost Assassin|CN2|2
diff --git a/forge-gui/res/cardsfolder/c/cavalier_of_dawn.txt b/forge-gui/res/cardsfolder/c/cavalier_of_dawn.txt
index 513fd7f037c..601d7d96ee4 100644
--- a/forge-gui/res/cardsfolder/c/cavalier_of_dawn.txt
+++ b/forge-gui/res/cardsfolder/c/cavalier_of_dawn.txt
@@ -4,8 +4,9 @@ Types:Creature Elemental Knight
PT:4/6
K:Vigilance
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDestroy | TriggerDescription$ When CARDNAME enters the battlefield, destroy up to one target nonland permanent. Its controller creates a 3/3 colorless Golem artifact creature token.
-SVar:TrigDestroy:DB$ Destroy | TargetMin$ 0 | TargetMax$ 1 | ValidTgts$ Permanent.nonLand | TgtPrompt$ Select target nonland permanent | SubAbility$ DBToken
-SVar:DBToken:DB$ Token | TokenAmount$ 1 | TokenScript$ c_3_3_a_golem | TokenOwner$ TargetedController | LegacyImage$ c 3 3 a golem m20
+SVar:TrigDestroy:DB$ Destroy | TargetMin$ 0 | TargetMax$ 1 | ValidTgts$ Permanent.nonLand | TgtPrompt$ Select target nonland permanent | RememberLKI$ True | SubAbility$ DBToken
+SVar:DBToken:DB$ Token | TokenAmount$ 1 | TokenScript$ c_3_3_a_golem | TokenOwner$ RememberedController | LegacyImage$ c 3 3 a golem m20 | SubAbility$ DBCleanup
+SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigChangeZone | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME dies, return target artifact or enchantment card from your graveyard to your hand.
SVar:TrigChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Hand | ValidTgts$ Artifact.YouCtrl,Enchantment.YouCtrl
Oracle:Vigilance\nWhen Cavalier of Dawn enters the battlefield, destroy up to one target nonland permanent. Its controller creates a 3/3 colorless Golem artifact creature token.\nWhen Cavalier of Dawn dies, return target artifact or enchantment card from your graveyard to your hand.
diff --git a/forge-gui/res/cardsfolder/d/dissenters_delivery.txt b/forge-gui/res/cardsfolder/d/dissenters_deliverance.txt
similarity index 100%
rename from forge-gui/res/cardsfolder/d/dissenters_delivery.txt
rename to forge-gui/res/cardsfolder/d/dissenters_deliverance.txt
diff --git a/forge-gui/res/cardsfolder/g/ghastly_demise.txt b/forge-gui/res/cardsfolder/g/ghastly_demise.txt
index 78ced7746b3..f04b0f2ac15 100644
--- a/forge-gui/res/cardsfolder/g/ghastly_demise.txt
+++ b/forge-gui/res/cardsfolder/g/ghastly_demise.txt
@@ -1,7 +1,7 @@
Name:Ghastly Demise
ManaCost:B
Types:Instant
-A:SP$ Destroy | Cost$ B | ValidTgts$ Creature.nonBlack+toughnessLEX | TgtPrompt$ Select target nonblack creature with toughness less than or equal to the number of cards in your graveyard. | References$ X | SpellDescription$ Destroy target nonblack creature if its toughness is less than or equal to the number of cards in your graveyard.
+A:SP$ Destroy | Cost$ B | ValidTgts$ Creature.nonBlack | TgtPrompt$ Select target nonblack creature | ConditionCheckSVar$ Y | ConditionSVarCompare$ LEX | References$ X,Y | StackDescription$ SpellDescription | SpellDescription$ Destroy target nonblack creature if its toughness is less than or equal to the number of cards in your graveyard.
+SVar:Y:Targeted$CardToughness
SVar:X:Count$InYourYard
-SVar:Picture:http://www.wizards.com/global/images/magic/general/ghastly_demise.jpg
Oracle:Destroy target nonblack creature if its toughness is less than or equal to the number of cards in your graveyard.
diff --git a/forge-gui/res/cardsfolder/j/joust.txt b/forge-gui/res/cardsfolder/j/joust.txt
index 9d4c5ba84f4..d68d4eeb6f6 100644
--- a/forge-gui/res/cardsfolder/j/joust.txt
+++ b/forge-gui/res/cardsfolder/j/joust.txt
@@ -1,7 +1,7 @@
Name:Joust
ManaCost:1 R
Types:Sorcery
-A:SP$ Pump | Cost$ 1 R | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | NumAtt$ +2 | NumDef$ +1 | ConditionDefined$ ThisTargetedCard | ConditionPresent$ Knight | SubAbility$ DBFight | SpellDescription$ Choose target creature you control and target creature you don't control. The creature you control gets +2/+1 until end of turn if it's a Knight. Then those creatures fight each other. (Each deals damage equal to its power to the other.)
+A:SP$ Pump | Cost$ 1 R | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | NumAtt$ +2 | NumDef$ +1 | AILogic$ Fight | ConditionDefined$ ThisTargetedCard | ConditionPresent$ Knight | SubAbility$ DBFight | SpellDescription$ Choose target creature you control and target creature you don't control. The creature you control gets +2/+1 until end of turn if it's a Knight. Then those creatures fight each other. (Each deals damage equal to its power to the other.)
SVar:DBFight:DB$ Fight | Defined$ ParentTarget | ValidTgts$ Creature.YouDontCtrl | AILogic$ Always | TgtPrompt$ Choose target creature you don't control
DeckHints:Type$Knight
Oracle:Choose target creature you control and target creature you don't control. The creature you control gets +2/+1 until end of turn if it's a Knight. Then those creatures fight each other. (Each deals damage equal to its power to the other.)
diff --git a/forge-gui/res/cardsfolder/n/nissas_pilgrimage.txt b/forge-gui/res/cardsfolder/n/nissas_pilgrimage.txt
index 3ad0c877919..f89143a06a0 100644
--- a/forge-gui/res/cardsfolder/n/nissas_pilgrimage.txt
+++ b/forge-gui/res/cardsfolder/n/nissas_pilgrimage.txt
@@ -1,9 +1,10 @@
Name:Nissa's Pilgrimage
ManaCost:2 G
Types:Sorcery
-A:SP$ ChangeZone | Cost$ 2 G | Origin$ Library | Destination$ Battlefield | Tapped$ True | ChangeType$ Land.Basic+Forest | ChangeNum$ 1 | SubAbility$ DBChangeZone1 | NoShuffle$ True | SpellDescription$ Search your library for up to two basic Forest cards, reveal those cards, and put one onto the battlefield tapped and the rest into your hand. Then shuffle your library. Spell mastery — If there are two or more instant or sorcery cards in your graveyard, search your library for up to three basic Forest cards instead of two.
-SVar:DBChangeZone1:DB$ChangeZone | Origin$ Library | Destination$ Hand | SubAbility$ DBChangeZone2 | ChangeType$ Land.Basic+Forest | ChangeNum$ 1 | ConditionCheckSVar$ X | ConditionSVarCompare$ LT2 | References$ X
-SVar:DBChangeZone2:DB$ChangeZone | Origin$ Library | Destination$ Hand | ChangeType$ Land.Basic+Forest | ChangeNum$ 2 | ConditionCheckSVar$ X | ConditionSVarCompare$ GE2 | References$ X
-SVar:X:Count$ValidGraveyard Instant.YouOwn,Sorcery.YouOwn
-SVar:Picture:http://www.wizards.com/global/images/magic/general/nissas_pilgrimage.jpg
+A:SP$ ChangeZone | Cost$ 2 G | Origin$ Library | Destination$ Library | ChangeType$ Land.Basic+Forest | ChangeNum$ X | References$ X,Y | RememberChanged$ True | SubAbility$ DBBattlefield | Shuffle$ False | StackDescription$ SpellDescription | SpellDescription$ Search your library for up to two basic Forest cards, reveal those cards, and put one onto the battlefield tapped and the rest into your hand. Then shuffle your library. Spell mastery — If there are two or more instant or sorcery cards in your graveyard, search your library for up to three basic Forest cards instead of two.
+SVar:DBBattlefield:DB$ ChangeZone | Origin$ Library | Destination$ Battlefield | Tapped$ True | SubAbility$ DBHand | ChangeType$ Card.IsRemembered | ChangeNum$ 1 | Mandatory$ True | NoLooking$ True | SelectPrompt$ Select a card to go to the battlefield | Shuffle$ False | StackDescription$ None
+SVar:DBHand:DB$ ChangeZone | Origin$ Library | Destination$ Hand | Defined$ Remembered | NoLooking$ True | StackDescription$ None | SubAbility$ DBCleanup
+SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
+SVar:X:Count$Compare Y GE2.3.2
+SVar:Y:Count$ValidGraveyard Instant.YouOwn,Sorcery.YouOwn
Oracle:Search your library for up to two basic Forest cards, reveal those cards, and put one onto the battlefield tapped and the rest into your hand. Then shuffle your library.\nSpell mastery — If there are two or more instant or sorcery cards in your graveyard, search your library for up to three basic Forest cards instead of two.
diff --git a/forge-gui/res/cardsfolder/s/settle_the_wreckage.txt b/forge-gui/res/cardsfolder/s/settle_the_wreckage.txt
index 521f24cb11c..c136b03296f 100644
--- a/forge-gui/res/cardsfolder/s/settle_the_wreckage.txt
+++ b/forge-gui/res/cardsfolder/s/settle_the_wreckage.txt
@@ -2,7 +2,7 @@ Name:Settle the Wreckage
ManaCost:2 W W
Types:Instant
A:SP$ ChangeZoneAll | Cost$ 2 W W | ValidTgts$ Player | ChangeType$ Creature.attacking | TgtPrompt$ Select target player | Origin$ Battlefield | Destination$ Exile | RememberChanged$ True | SubAbility$ DBGetLands | SpellDescription$ Exile all attacking creatures target player controls. That player may search their library for that many basic lands, put those cards onto the battlefield tapped, then shuffle their library.
-SVar:DBGetLands:DB$ ChangeZone | Optional$ True | Origin$ Library | Destination$ Battlefield | Tapped$ True | ChangeType$ Land.Basic | ChangeNum$ X | References$ X | DefinedPlayer$ RememberedController | ShuffleNonMandatory$ True | SubAbility$ DBCleanup
+SVar:DBGetLands:DB$ ChangeZone | Optional$ True | Origin$ Library | Destination$ Battlefield | Tapped$ True | ChangeType$ Land.Basic | ChangeNum$ X | References$ X | DefinedPlayer$ TargetedPlayer | ShuffleNonMandatory$ True | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:X:Count$RememberedSize
SVar:Picture:http://www.wizards.com/global/images/magic/general/settle_the_wreckage.jpg
diff --git a/forge-gui/res/cardsfolder/t/the_birth_of_meletis.txt b/forge-gui/res/cardsfolder/t/the_birth_of_meletis.txt
index 349f1e790d9..27021aac864 100644
--- a/forge-gui/res/cardsfolder/t/the_birth_of_meletis.txt
+++ b/forge-gui/res/cardsfolder/t/the_birth_of_meletis.txt
@@ -3,7 +3,7 @@ ManaCost:1 W
Types:Enchantment Saga
K:Saga:3:TrigChange,TrigToken,TrigGainLife
SVar:TrigChange:DB$ ChangeZone | Origin$ Library | Destination$ Hand | ChangeType$ Land.Plains+Basic | ChangeNum$ 1 | SpellDescription$ Search your library for a basic Plains card, reveal it, put it into your hand, then shuffle your library.
-SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ c_0_4_wall_defender | TokenOwner$ You | LegacyImage$ c 0 4 wall defender thb | SpellDescription$ Create a 0/4 colorless Wall artifact creature token with defender.
+SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ c_0_4_a_wall_defender | TokenOwner$ You | LegacyImage$ c 0 4 wall defender thb | SpellDescription$ Create a 0/4 colorless Wall artifact creature token with defender.
SVar:TrigGainLife:DB$ GainLife | Defined$ You | LifeAmount$ 2 | SpellDescription$ You gain 2 life.
DeckHas:Ability$LifeGain & Ability$Token
Oracle:(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)\nI - Search your library for a basic Plains card, reveal it, put it into your hand, then shuffle your library.\nII - Create a 0/4 colorless Wall artifact creature token with defender.\nIII - You gain 2 life.
diff --git a/forge-gui/res/cardsfolder/t/the_triumph_of_anax.txt b/forge-gui/res/cardsfolder/t/the_triumph_of_anax.txt
index a7aacb3fd3c..6a6b9d25af5 100755
--- a/forge-gui/res/cardsfolder/t/the_triumph_of_anax.txt
+++ b/forge-gui/res/cardsfolder/t/the_triumph_of_anax.txt
@@ -1,7 +1,7 @@
Name:The Triumph of Anax
ManaCost:2 R
Types:Enchantment Saga
-K:Saga:3:DBPump,DBPump,DBPump,DBPick
+K:Saga:4:DBPump,DBPump,DBPump,DBPick
SVar:DBPump:DB$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ +X | References$ X | KW$ Trample | SpellDescription$ Until end of turn, target creature gains trample and gets +X/+0, where X is the number of lore counters on CARDNAME.
SVar:X:Count$CardCounters.LORE
SVar:PlayMain1:TRUE
diff --git a/forge-gui/res/editions/Aether Revolt.txt b/forge-gui/res/editions/Aether Revolt.txt
index e2fcffcce5c..8f3e2c7cfd7 100644
--- a/forge-gui/res/editions/Aether Revolt.txt
+++ b/forge-gui/res/editions/Aether Revolt.txt
@@ -195,15 +195,15 @@ AdditionalSetUnlockedInQuest=MPS_KLD
182 C Watchful Automaton
183 C Welder Automaton
184 R Spire of Industry
-185 M Ajani, Valiant Protector
-186 R Ajani's Aid
+185 M Ajani, Valiant Protector
+186 C Inspiring Roar
187 U Ajani's Comrade
-188 C Inspiring Roar
+188 R Ajani's Aid
189 C Tranquil Expanse
190 M Tezzeret, Master of Metal
191 R Tezzeret's Betrayal
-192 U Tezzeret's Simulacrum
-193 C Pendulum of Patterns
+192 C Pendulum of Patterns
+193 U Tezzeret's Simulacrum
194 C Submerged Boneyard
[tokens]
diff --git a/forge-gui/res/editions/Battle Royale.txt b/forge-gui/res/editions/Battle Royale.txt
index 76831b31973..13417672427 100644
--- a/forge-gui/res/editions/Battle Royale.txt
+++ b/forge-gui/res/editions/Battle Royale.txt
@@ -27,10 +27,10 @@ Foil=NotSupported
17 C Curfew
18 C Dark Ritual
19 R Dirtcowl Wurm
-20 U Disenchant
+20 C Disenchant
21 C Disruptive Student
22 C Drifting Meadow
-23 C Elvish Lyrist
+23 U Elvish Lyrist
24 C Exhume
25 U Fecundity
26 C Fertile Ground
@@ -40,16 +40,16 @@ Foil=NotSupported
30 C Gorilla Warrior
31 C Healing Salve
32 C Heat Ray
-33 R Hurricane
+33 U Hurricane
34 C Infantry Veteran
-35 R Land Tax
+35 U Land Tax
36 R Lhurgoyf
37 C Lightning Elemental
38 R Living Death
39 C Llanowar Elves
40 C Man-o'-War
41 C Mana Leak
-42 U Maniacal Rage
+42 C Maniacal Rage
43 C Manta Riders
44 C Master Decoy
45 U Mogg Hollows
@@ -59,7 +59,7 @@ Foil=NotSupported
49 U Pestilence
50 C Phyrexian Ghoul
51 C Pincher Beetles
-52 U Plated Rootwalla
+52 C Plated Rootwalla
53 C Polluted Mire
54 C Prodigal Sorcerer
55 C Raging Goblin
@@ -72,7 +72,7 @@ Foil=NotSupported
62 C Sanctum Custodian
63 U Sanctum Guardian
64 C Sandstorm
-65 U Scaled Wurm
+65 C Scaled Wurm
66 C Scryb Sprites
67 U Seasoned Marshal
68 C Seeker of Skybreak
@@ -83,7 +83,7 @@ Foil=NotSupported
73 C Slippery Karst
74 C Soltari Foot Soldier
75 U Songstitcher
-76 U Soul Warden
+76 C Soul Warden
77 C Spike Colony
78 U Spike Feeder
79 R Spike Weaver
diff --git a/forge-gui/res/editions/Battlebond.txt b/forge-gui/res/editions/Battlebond.txt
index 18524d0e6c0..83e830766f5 100644
--- a/forge-gui/res/editions/Battlebond.txt
+++ b/forge-gui/res/editions/Battlebond.txt
@@ -135,7 +135,7 @@ Booster=10 Common, 3 Uncommon, 1 fromSheet("BBD RareMythic"), 1 BasicLand
125 C Omenspeaker
126 U Opportunity
127 U Oracle's Insight
-128 C Peregrine Drake
+128 U Peregrine Drake
129 U Phantom Warrior
130 U Reckless Scholar
131 R Sower of Temptation
@@ -203,7 +203,7 @@ Booster=10 Common, 3 Uncommon, 1 fromSheet("BBD RareMythic"), 1 BasicLand
193 C Cowl Prowler
194 C Daggerback Basilisk
195 M Doubling Season
-196 U Elvish Visionary
+196 C Elvish Visionary
197 U Feral Hydra
198 C Fertile Ground
199 U Fertilid
diff --git a/forge-gui/res/editions/Beatdown.txt b/forge-gui/res/editions/Beatdown.txt
index b8244084ac0..1c32e2b20ee 100644
--- a/forge-gui/res/editions/Beatdown.txt
+++ b/forge-gui/res/editions/Beatdown.txt
@@ -76,7 +76,7 @@ Foil=NotSupported
66 C Yavimaya Wurm
67 U Diabolic Vision
68 U Segmented Wurm
-69 C Clockwork Avian
+69 R Clockwork Avian
70 R Clockwork Beast
71 U Dwarven Ruins
72 U Ebon Stronghold
@@ -97,4 +97,4 @@ Foil=NotSupported
87 L Mountain
88 L Forest
89 L Forest
-90 L Forest
+90 L Forest
\ No newline at end of file
diff --git a/forge-gui/res/editions/Conspiracy Take the Crown.txt b/forge-gui/res/editions/Conspiracy Take the Crown.txt
index c82c56ae90e..7d2d59cfc7d 100644
--- a/forge-gui/res/editions/Conspiracy Take the Crown.txt
+++ b/forge-gui/res/editions/Conspiracy Take the Crown.txt
@@ -6,7 +6,8 @@ Code2=CN2
MciCode=cn2
Type=Other
BoosterCovers=3
-Booster=10 Common:!fromSheet("CN2 Draft Matters"), 3 Uncommon:!fromSheet("CN2 Draft Matters"), 1 RareMythic:!fromSheet("CN2 Draft Matters"), 1 fromSheet("CN2 Draft Matters")
+Booster=10 Common:!fromSheet("CN2 Not In Normal Slots"), 3 Uncommon:!fromSheet("CN2 Not In Normal Slots"), 1 RareMythic:!fromSheet("CN2 Not In Normal Slots"), 1 fromSheet("CN2 Draft Matters")
+AdditionalSheetForFoils=fromSheet("CN2 Foil Kaya")
[cards]
1 C Adriana's Valor
@@ -230,6 +231,7 @@ Booster=10 Common:!fromSheet("CN2 Draft Matters"), 3 Uncommon:!fromSheet("CN2 Dr
219 R Exotic Orchard
220 U Rogue's Passage
221 U Shimmering Grotto
+222 M Kaya, Ghost Assassin
[tokens]
w_1_1_soldier
@@ -242,4 +244,4 @@ r_1_1_goblin_noblock
r_8_8_lizard
g_3_3_beast
g_1_1_insect
-c_1_1_a_construct_defender
\ No newline at end of file
+c_1_1_a_construct_defender
diff --git a/forge-gui/res/editions/Fate Reforged.txt b/forge-gui/res/editions/Fate Reforged.txt
index 02752ed7073..e3810f09b24 100644
--- a/forge-gui/res/editions/Fate Reforged.txt
+++ b/forge-gui/res/editions/Fate Reforged.txt
@@ -184,14 +184,14 @@ Booster=10 Common:!land, 3 Uncommon, 1 RareMythic, 1 fromSheet("FRF Lands"), 0 f
174 C Tranquil Cove
175 C Wind-Scarred Crag
176 L Plains
-176 L Plains
-179 L Island
+177 L Plains
+178 L Island
179 L Island
+180 L Swamp
181 L Swamp
-181 L Swamp
+182 L Mountain
183 L Mountain
-183 L Mountain
-185 L Forest
+184 L Forest
185 L Forest
[tokens]
diff --git a/forge-gui/res/editions/Khans of Tarkir.txt b/forge-gui/res/editions/Khans of Tarkir.txt
index eb1ab10a7df..b1b96ce023e 100644
--- a/forge-gui/res/editions/Khans of Tarkir.txt
+++ b/forge-gui/res/editions/Khans of Tarkir.txt
@@ -258,26 +258,26 @@ Booster=10 Common, 3 Uncommon, 1 RareMythic, 1 BasicLand KTK
247 C Wind-Scarred Crag
248 R Windswept Heath
249 R Wooded Foothills
-269 L Forest
-269 L Forest
-269 L Forest
-269 L Forest
-257 L Island
-257 L Island
-257 L Island
-257 L Island
-263 L Mountain
-263 L Mountain
-263 L Mountain
-263 L Mountain
-250 L Plains
-250 L Plains
-250 L Plains
250 L Plains
+251 L Plains
+252 L Plains
+253 L Plains
+254 L Island
+255 L Island
+256 L Island
+257 L Island
258 L Swamp
-258 L Swamp
-258 L Swamp
-258 L Swamp
+259 L Swamp
+260 L Swamp
+261 L Swamp
+262 L Mountain
+263 L Mountain
+264 L Mountain
+265 L Mountain
+266 L Forest
+267 L Forest
+268 L Forest
+269 L Forest
[tokens]
w_3_4_bird_flying
diff --git a/forge-gui/res/editions/Magic 2014.txt b/forge-gui/res/editions/Magic 2014.txt
index d4daec8d83b..0934c02e1ef 100644
--- a/forge-gui/res/editions/Magic 2014.txt
+++ b/forge-gui/res/editions/Magic 2014.txt
@@ -238,26 +238,26 @@ Booster=10 Common, 3 Uncommon, 1 RareMythic, 1 BasicLand
227 U Encroaching Wastes
228 R Mutavault
229 U Shimmering Grotto
+230 L Plains
231 L Plains
-231 L Plains
-231 L Plains
-231 L Plains
-234 L Island
-234 L Island
-234 L Island
+232 L Plains
+233 L Plains
234 L Island
+235 L Island
+236 L Island
+237 L Island
+238 L Swamp
+239 L Swamp
+240 L Swamp
241 L Swamp
-241 L Swamp
-241 L Swamp
-241 L Swamp
-244 L Mountain
-244 L Mountain
-244 L Mountain
+242 L Mountain
+243 L Mountain
244 L Mountain
+245 L Mountain
246 L Forest
-246 L Forest
-246 L Forest
-246 L Forest
+247 L Forest
+248 L Forest
+249 L Forest
[tokens]
c_1_1_sliver
diff --git a/forge-gui/res/editions/Magic 2015.txt b/forge-gui/res/editions/Magic 2015.txt
index 53ada72d465..8d560ecd154 100644
--- a/forge-gui/res/editions/Magic 2015.txt
+++ b/forge-gui/res/editions/Magic 2015.txt
@@ -258,26 +258,26 @@ Booster=10 Common:!fromSheet("M15 Sample Cards"), 3 Uncommon:!fromSheet("M15 Sam
247 R Sliver Hive
248 R Urborg, Tomb of Yawgmoth
249 R Yavimaya Coast
+250 L Plains
251 L Plains
-251 L Plains
-251 L Plains
-251 L Plains
-255 L Island
-255 L Island
-255 L Island
+252 L Plains
+253 L Plains
+254 L Island
255 L Island
+256 L Island
+257 L Island
258 L Swamp
-258 L Swamp
-258 L Swamp
-258 L Swamp
-263 L Mountain
-263 L Mountain
-263 L Mountain
+259 L Swamp
+260 L Swamp
+261 L Swamp
+262 L Mountain
263 L Mountain
+264 L Mountain
+265 L Mountain
266 L Forest
-266 L Forest
-266 L Forest
-266 L Forest
+267 L Forest
+268 L Forest
+269 L Forest
270 R Aegis Angel
271 C Divine Verdict
272 C Inspired Charge
diff --git a/forge-gui/res/editions/Mystery Booster Retail Edition Foils.txt b/forge-gui/res/editions/Mystery Booster Retail Edition Foils.txt
new file mode 100644
index 00000000000..86da737ae2b
--- /dev/null
+++ b/forge-gui/res/editions/Mystery Booster Retail Edition Foils.txt
@@ -0,0 +1,128 @@
+[metadata]
+Code=FMB1
+Date=2020-03-08
+Name=Mystery Booster Retail Edition Foils
+Type=Other
+
+[cards]
+1 U Not of This World
+2 R Celestial Dawn
+3 R Celestial Kirin
+4 U Changeling Hero
+5 U Council Guardian
+6 U Eidolon of Rhetoric
+7 R Isamaru, Hound of Konda
+8 C Lapse of Certainty
+9 C Lumithread Field
+10 R Norn's Annex
+11 R Proclamation of Rebirth
+12 U Pull from Eternity
+13 R Rune-Tail, Kitsune Ascendant
+14 C Sinew Sliver
+15 C Soul's Attendant
+16 R Spelltithe Enforcer
+17 U Springjack Shepherd
+18 U Wall of Shards
+19 U White Knight
+20 C Blighted Agent
+21 U Delay
+22 R Fatespinner
+23 U Frozen Aether
+24 R Grand Architect
+25 R Intruder Alarm
+26 M Misthollow Griffin
+27 U Paradox Haze
+28 R Patron of the Moon
+29 R Puca's Mischief
+30 R Spellweaver Volute
+31 C Storm Crow
+32 R Zur's Weirding
+33 R Bringer of the Black Dawn
+34 C Chimney Imp
+35 R Conspiracy
+36 C Echoing Decay
+37 R Funeral Charm
+38 R Herald of Leshrac
+39 R Marrow-Gnawer
+40 R Nezumi Shortfang
+41 R One with Nothing
+42 U Ravenous Trap
+43 U Rescue from the Underworld
+44 R Undead Warchief
+45 C Viscera Seer
+46 U Balduvian Rage
+47 R Braid of Fire
+48 C Burning Inquiry
+49 R Fiery Gambit
+50 U Flamekin Harbinger
+51 R Form of the Dragon
+52 C Goblin Bushwhacker
+53 U Guerrilla Tactics
+54 U Lightning Storm
+55 R Norin the Wary
+56 C Ogre Gatecrasher
+57 C Pyretic Ritual
+58 M Scourge of the Throne
+59 R Stigma Lasher
+60 U Treasonous Ogre
+61 R Allosaurus Rider
+62 U Archetype of Endurance
+63 C Boreal Druid
+64 R Boundless Realms
+65 U Bramblewood Paragon
+66 R Fungusaur
+67 C Game-Trail Changeling
+68 C Gleeful Sabotage
+69 C Greater Mossdog
+70 R Helix Pinnacle
+71 C Hornet Sting
+72 U Manaweft Sliver
+73 R Maro
+74 R Myojin of Life's Web
+75 R Panglacial Wurm
+76 R Reki, the History of Kamigawa
+77 R Rhox
+78 C Sakura-Tribe Scout
+79 U Scryb Ranger
+80 U Sheltering Ancient
+81 U Sosuke, Son of Seshiro
+82 R Spike Feeder
+83 M Aurelia's Fury
+84 U Drogskol Captain
+85 R Glittering Wish
+86 U Harmonic Sliver
+87 M Karrthus, Tyrant of Jund
+88 M Maelstrom Nexus
+89 U Mind Funeral
+90 M Sarkhan the Mad
+91 M Sen Triplets
+92 R Yore-Tiller Nephilim
+93 R Balefire Liege
+94 U Gilder Bairn
+95 U Kulrath Knight
+96 C Noggle Bandit
+97 U Wear // Tear
+98 R Amulet of Vigor
+99 U Blasting Station
+100 U Codex Shredder
+101 U Geth's Grimoire
+102 C Iron Myr
+103 R Knowledge Pool
+104 U Lantern of Insight
+105 R Leveler
+106 M Lich's Mirror
+107 U Magewright's Stone
+108 U Memnite
+109 R Mindslaver
+110 C Pili-Pala
+111 R Reaper King
+112 R Sundial of the Infinite
+113 R Teferi's Puzzle Box
+114 U Trailblazer's Boots
+115 R Triskelion
+116 R Witchbane Orb
+117 R Alchemist's Refuge
+118 R Minamo, School at Water's Edge
+119 U Mirrodin's Core
+120 R Shizo, Death's Storehouse
+121 U Stalking Stones
diff --git a/forge-gui/res/editions/Mystery Booster.txt b/forge-gui/res/editions/Mystery Booster.txt
new file mode 100644
index 00000000000..4ca8e07217f
--- /dev/null
+++ b/forge-gui/res/editions/Mystery Booster.txt
@@ -0,0 +1,1704 @@
+[metadata]
+Code=MB1
+Date=2019-11-07
+Name=Mystery Booster
+Type=Reprint
+BoosterCovers=1
+Booster=2 fromSheet("MB1 White CommonUncommon"), 2 fromSheet("MB1 Blue CommonUncommon"), 2 fromSheet("MB1 Black CommonUncommon"), 2 fromSheet("MB1 Green CommonUncommon"), 2 fromSheet("MB1 Red CommonUncommon"), 1 fromSheet("MB1 Multi CommonUncommon"), 1 fromSheet("MB1 Artifact Land CommonUncommon"), 1 fromSheet("MB1 Pre M15"), 1 fromSheet("MB1 Post M15 RareMythic"), 1 fromSheet("FMB1 Foils")
+Foil=NotSupported
+
+[cards]
+1 R All Is Dust
+2 U Artisan of Kozilek
+3 U Breaker of Armies
+4 R Desolation Twin
+5 C Eldrazi Devastator
+6 U Pathrazer of Ulamog
+7 U Abzan Falconer
+8 C Abzan Runemark
+9 C Acrobatic Maneuver
+10 U Adanto Vanguard
+11 R Adorned Pouncer
+12 C Affa Protector
+13 C Ainok Bond-Kin
+14 U Ajani's Pridemate
+15 C Alley Evasion
+16 M Angelic Destiny
+17 C Angelic Gift
+18 C Angelic Purge
+19 C Angel of Mercy
+20 U Angel of Renewal
+21 R Angel of the Dire Hour
+22 C Angelsong
+23 C Apostle's Blessing
+24 R Approach of the Second Sun
+25 U Archangel
+26 C Arrest
+27 C Arrester's Zeal
+28 C Artful Maneuver
+29 U Aura of Silence
+30 C Aven Battle Priest
+31 C Aven Sentry
+32 C Ballynock Cohort
+33 C Bartered Cow
+34 U Battle Mastery
+35 R Beacon of Immortality
+36 C Benevolent Ancestor
+37 C Blade Instructor
+38 U Blessed Spirits
+39 C Bonds of Faith
+40 C Borrowed Grace
+41 C Built to Last
+42 C Bulwark Giant
+43 C Candlelight Vigil
+44 C Caravan Escort
+45 C Cartouche of Solidarity
+46 U Cast Out
+47 C Cathar's Companion
+48 C Caught in the Brights
+49 U Celestial Crusader
+50 C Celestial Flare
+51 C Center Soul
+52 C Champion of Arashin
+53 R Champion of the Parish
+54 R Chancellor of the Annex
+55 C Charge
+56 C Cliffside Lookout
+57 C Cloudshift
+58 C Coalition Honor Guard
+59 C Collar the Culprit
+60 U Congregate
+61 C Conviction
+62 C Countless Gears Renegade
+63 C Court Homunculus
+64 C Court Street Denizen
+65 U Crib Swap
+66 U Danitha Capashen, Paragon
+67 C Daring Skyjek
+68 U Darksteel Mutation
+69 C Dauntless Cathar
+70 C Dawnglare Invoker
+71 C Decommission
+72 R Decree of Justice
+73 C Defiant Strike
+74 C Desperate Sentry
+75 C Devilthorn Fox
+76 R Dictate of Heliod
+77 C Disenchant
+78 U Dismantling Blow
+79 C Disposal Mummy
+80 C Divine Favor
+81 C Djeru's Renunciation
+82 C Djeru's Resolve
+83 C Doomed Traveler
+84 C Dragon Bell Monk
+85 C Dragon's Eye Sentry
+86 C Dragon's Presence
+87 C Eddytrail Hawk
+88 M Elesh Norn, Grand Cenobite
+89 C Emerge Unscathed
+90 C Empyrial Armor
+91 C Encampment Keeper
+92 U Encircling Fissure
+93 C Enduring Victory
+94 C Enlightened Ascetic
+95 C Ephemeral Shields
+96 C Ephemerate
+97 R Evra, Halcyon Witness
+98 C Excavation Elephant
+99 C Excoriate
+100 C Expedition Raptor
+101 C Expose Evil
+102 C Exultant Skymarcher
+103 C Eyes in the Skies
+104 C Faithbearer Paladin
+105 C Faith's Fetters
+106 C Feat of Resistance
+107 U Felidar Guardian
+108 R Felidar Sovereign
+109 U Felidar Umbra
+110 C Fencing Ace
+111 U Fiend Hunter
+112 C Firehoof Cavalry
+113 C Forsake the Worldly
+114 C Fortify
+115 C Fragmentize
+116 C Geist of the Moors
+117 U Ghostblade Eidolon
+118 M Gideon Jura
+119 C Gideon's Lawkeeper
+120 U Gift of Estates
+121 C Glaring Aegis
+122 C Gleam of Resistance
+123 C Glint-Sleeve Artisan
+124 C God-Pharaoh's Faithful
+125 C Gods Willing
+126 R Grasp of Fate
+127 C Grasp of the Hieromancer
+128 C Great-Horn Krushok
+129 C Guided Strike
+130 U Gustcloak Skirmisher
+131 C Gust Walker
+132 C Healer's Hawk
+133 C Healing Grace
+134 C Healing Hands
+135 C Heavy Infantry
+136 C Humble
+137 C Hyena Umbra
+138 C Infantry Veteran
+139 C Inquisitor's Ox
+140 C Inspired Charge
+141 C Intrusive Packbeast
+142 C Iona's Judgment
+143 C Isolation Zone
+144 U Jubilant Mascot
+145 C Knight of Cliffhaven
+146 U Knight of Dawn
+147 C Knight of Old Benalia
+148 C Knight of Sorrows
+149 C Knight of the Skyward Eye
+150 C Knight of the Tusk
+151 U Kor Bladewhirl
+152 C Kor Chant
+153 U Kor Firewalker
+154 C Kor Hookmaster
+155 C Kor Sky Climber
+156 C Kor Skyfisher
+157 U Lashknife Barrier
+158 U Leonin Relic-Warder
+159 C Lieutenants of the Guard
+160 U Lightform
+161 C Lightwalker
+162 U Lingering Souls
+163 C Lone Missionary
+164 C Lonesome Unicorn
+165 C Looming Altisaur
+166 C Lotus-Eye Mystics
+167 C Loxodon Partisan
+168 C Loyal Sentry
+169 C Lunarch Mantle
+170 R Magus of the Moat
+171 C Mana Tithe
+172 C Mardu Hordechief
+173 C Marked by Honor
+174 R Martyr's Bond
+175 U Martyr's Cause
+176 C Meditation Puzzle
+177 C Midnight Guard
+178 R Mirran Crusader
+179 R Mirror Entity
+180 C Momentary Blink
+181 C Moonlit Strider
+182 C Mortal's Ardor
+183 U Mother of Runes
+184 C Ninth Bridge Patrol
+185 U Nyx-Fleece Ram
+186 R Odric, Lunarch Marshal
+187 C Ondu Greathorn
+188 C Ondu War Cleric
+189 C Oreskos Swiftclaw
+190 U Oust
+191 C Pacifism
+192 U Palace Jailer
+193 C Palace Sentinels
+194 C Paladin of the Bloodstained
+195 C Path of Peace
+196 U Path to Exile
+197 U Peace of Mind
+198 C Pegasus Courser
+199 C Pentarch Ward
+200 C Pitfall Trap
+201 C Pressure Point
+202 U Promise of Bunrei
+203 C Prowling Caracal
+204 C Rally the Peasants
+205 C Raptor Companion
+206 R Recruiter of the Guard
+207 U Refurbish
+208 C Renewed Faith
+209 C Resurrection
+210 U Retreat to Emeria
+211 C Reviving Dose
+212 C Rhet-Crop Spearmaster
+213 U Righteous Cause
+214 C Rootborn Defenses
+215 C Sacred Cat
+216 C Sanctum Gargoyle
+217 C Sandstorm Charger
+218 C Savannah Lions
+219 C Seal of Cleansing
+220 C Searing Light
+221 U Seeker of the Way
+222 C Sensor Splicer
+223 U Seraph of the Suns
+224 C Serra Disciple
+225 U Serra's Embrace
+226 C Sheer Drop
+227 C Shining Aerosaur
+228 C Shining Armor
+229 C Shoulder to Shoulder
+230 C Siegecraft
+231 C Silverchase Fox
+232 C Skyhunter Skirmisher
+233 U Skymarcher Aspirant
+234 C Skyspear Cavalry
+235 C Slash of Talons
+236 C Snubhorn Sentry
+237 C Soulmender
+238 C Soul Parry
+239 C Soul-Strike Technique
+240 C Soul Summons
+241 C Soul Warden
+242 C Sparring Mummy
+243 C Spectral Gateguards
+244 C Stalwart Aven
+245 C Star-Crowned Stag
+246 C Stave Off
+247 C Steadfast Sentinel
+248 C Stone Haven Medic
+249 C Sunlance
+250 C Sunrise Seeker
+251 C Suppression Bonds
+252 C Survive the Night
+253 U Swords to Plowshares
+254 C Take Vengeance
+255 C Tandem Tactics
+256 R Teferi's Protection
+257 C Terashi's Grasp
+258 C Territorial Hammerskull
+259 R Thalia's Lancers
+260 C Thraben Inspector
+261 C Thraben Standard Bearer
+262 U Timely Reinforcements
+263 C Topan Freeblade
+264 C Unwavering Initiate
+265 C Veteran Swordsmith
+266 C Village Bell-Ringer
+267 C Voice of the Provinces
+268 U Volunteer Reserves
+269 C Wake the Reflections
+270 U Wall of Omens
+271 C Wall of One Thousand Cuts
+272 C Wandering Champion
+273 C War Behemoth
+274 R Weathered Wayfarer
+275 C Wild Griffin
+276 U Windborne Charge
+277 C Winged Shepherd
+278 U Wing Shards
+279 C Youthful Knight
+280 C Zealous Strike
+281 C Academy Journeymage
+282 C Aethersnipe
+283 C Aether Tradewinds
+284 C Amass the Components
+285 R Aminatou's Augury
+286 C Amphin Pathmage
+287 C Anticipate
+288 C Arcane Denial
+289 C Archaeomancer
+290 U Archetype of Imagination
+291 C Artificer's Assistant
+292 C Augur of Bolas
+293 C Augury Owl
+294 C Bastion Inventor
+295 C Befuddle
+296 C Benthic Giant
+297 C Benthic Infiltrator
+298 C Bewilder
+299 U Blue Elemental Blast
+300 C Borrowing 100,000 Arrows
+301 C Brainstorm
+302 C Brilliant Spectrum
+303 U Brine Elemental
+304 C Calculated Dismissal
+305 C Caller of Gales
+306 C Call to Heel
+307 C Cancel
+308 C Capture Sphere
+309 C Cartouche of Knowledge
+310 C Castaway's Despair
+311 C Catalog
+312 U Chart a Course
+313 R Chasm Skulker
+314 C Chillbringer
+315 C Choking Tethers
+316 C Chronostutter
+317 U Circular Logic
+318 U Citywatch Sphinx
+319 C Claustrophobia
+320 C Clear the Mind
+321 C Cloak of Mists
+322 C Cloud Elemental
+323 C Cloudkin Seer
+324 C Cloudreader Sphinx
+325 C Clutch of Currents
+326 C Compelling Argument
+327 U Concentrate
+328 U Condescend
+329 C Containment Membrane
+330 C Contingency Plan
+331 C Contradict
+332 C Convolute
+333 C Coralhelm Guide
+334 C Coral Trickster
+335 U Corrupted Conscience
+336 C Counterspell
+337 C Court Hussar
+338 C Crashing Tide
+339 C Crush Dissent
+340 U Curiosity
+341 C Curio Vendor
+342 C Daze
+343 C Dazzling Lights
+344 C Decision Paralysis
+345 C Deep Analysis
+346 C Deep Freeze
+347 R Deepglow Skate
+348 C Diminish
+349 C Dirgur Nemesis
+350 C Dispel
+351 C Displace
+352 U Distortion Strike
+353 C Divination
+354 R Djinn of Wishes
+355 C Doorkeeper
+356 U Dragon's Eye Savants
+357 C Drag Under
+358 C Dreadwaters
+359 C Dream Cache
+360 C Dream Twist
+361 C Eel Umbra
+362 C Embodiment of Spring
+363 R Energy Field
+364 C Enlightened Maniac
+365 U Ensoul Artifact
+366 C Errant Ephemeron
+367 C Essence Scatter
+368 U Everdream
+369 U Exclude
+370 M Expropriate
+371 U Fact or Fiction
+372 C Faerie Invaders
+373 C Faerie Mechanist
+374 C Failed Inspection
+375 U Fascination
+376 C Fathom Seer
+377 R Fblthp, the Lost
+378 U Flashfreeze
+379 U Fledgling Mawcor
+380 C Fleeting Distraction
+381 U Floodgate
+382 U Fog Bank
+383 C Fogwalker
+384 C Foil
+385 C Forbidden Alchemy
+386 C Frantic Search
+387 C Frilled Sea Serpent
+388 C Frost Lynx
+389 C Gaseous Form
+390 C Ghost Ship
+391 C Glacial Crasher
+392 C Glint
+393 C Gone Missing
+394 C Grasp of Phantoms
+395 U Guard Gomazoa
+396 C Gurmag Drowner
+397 C Gush
+398 U Hedron Crab
+399 C Hieroglyphic Illumination
+400 C Hightide Hermit
+401 C Hinterland Drake
+402 C Horseshoe Crab
+403 C Humongulus
+404 C Impulse
+405 C Inkfathom Divers
+406 C Invisibility
+407 C Ior Ruin Expedition
+408 C Jace's Phantasm
+409 C Jeering Homunculus
+410 C Jeskai Sage
+411 R Jushi Apprentice // Tomoya the Revealer
+412 C Jwar Isle Avenger
+413 C Kiora's Dambreaker
+414 C Laboratory Brute
+415 U Laboratory Maniac
+416 U Labyrinth Guardian
+417 U Lay Claim
+418 C Leapfrog
+419 U Mahamoti Djinn
+420 C Mana Leak
+421 C Man-o'-War
+422 R Master Transmuter
+423 C Maximize Altitude
+424 R Memory Erosion
+425 C Memory Lapse
+426 U Merfolk Looter
+427 C Messenger Jays
+428 C Metallic Rebuke
+429 C Mind Sculpt
+430 R Mind Spring
+431 R The Mirari Conjecture
+432 R Misdirection
+433 U Mistform Shrieker
+434 C Mist Raven
+435 C Mnemonic Wall
+436 C Monastery Loremaster
+437 C Mulldrifter
+438 U Murder of Crows
+439 C Mystical Teachings
+440 R Mystic Confluence
+441 C Mystic of the Hidden Way
+442 C Nagging Thoughts
+443 C Negate
+444 C Niblis of Dusk
+445 C Nine-Tail White Fox
+446 C Ninja of the Deep Hours
+447 C Ojutai Interceptor
+448 C Ojutai's Breath
+449 C Omenspeaker
+450 U Opportunity
+451 C Opt
+452 C Peel from Reality
+453 C Phantasmal Bear
+454 U Phantasmal Dragon
+455 U Phyrexian Ingester
+456 R Phyrexian Metamorph
+457 C Pondering Mage
+458 C Portent
+459 U Predict
+460 C Preordain
+461 U Prodigal Sorcerer
+462 U Propaganda
+463 C Prosperous Pirates
+464 C Purple-Crystal Crab
+465 C Refocus
+466 C Repulse
+467 C Retraction Helix
+468 C Rhystic Study
+469 U Riftwing Cloudskate
+470 C Ringwarden Owl
+471 U Rishadan Footpad
+472 C River Darter
+473 C River Serpent
+474 C Riverwheel Aerialists
+475 U Sage of Lat-Nam
+476 C Sailor of Means
+477 R Sakashima the Impostor
+478 C Sapphire Charm
+479 C Scroll Thief
+480 C Sea Gate Oracle
+481 U Sealock Monster
+482 C Secrets of the Golden City
+483 C Send to Sleep
+484 R Serendib Efreet
+485 C Shaper Parasite
+486 C Shimmerscale Drake
+487 C Shipwreck Looter
+488 U Sigiled Starfish
+489 C Silent Observer
+490 U Silvergill Adept
+491 C Singing Bell Strike
+492 U Skaab Goliath
+493 C Skitter Eel
+494 C Skittering Crustacean
+495 U Sleep
+496 C Slipstream Eel
+497 C Slither Blade
+498 C Snap
+499 C Snapping Drake
+500 C Somber Hoverguard
+501 U Soothsaying
+502 U Sphinx's Tutelage
+503 C Spire Monitor
+504 C Steady Progress
+505 C Stitched Drake
+506 C Storm Sculptor
+507 C Strategic Planning
+508 C Stream of Thought
+509 R Stunt Double
+510 C Surrakar Banisher
+511 C Syncopate
+512 U Syr Elenora, the Discerning
+513 R Talrand, Sky Summoner
+514 C Tandem Lookout
+515 M Teferi, Temporal Archmage
+516 C Temporal Fissure
+517 M Temporal Mastery
+518 U Thieving Magpie
+519 C Thornwind Faeries
+520 C Thoughtcast
+521 C Thought Collapse
+522 C Thought Scour
+523 U Thrummingbird
+524 C Thunder Drake
+525 C Tidal Warrior
+526 C Tidal Wave
+527 U Tinker
+528 C Totally Lost
+529 U Trail of Evidence
+530 C Treasure Cruise
+531 C Treasure Hunt
+532 U Treasure Mage
+533 C Trinket Mage
+534 U Triton Tactics
+535 C Turn Aside
+536 C Uncomfortable Chill
+537 C Vapor Snag
+538 C Vigean Graftmage
+539 U Wall of Frost
+540 C Warden of Evos Isle
+541 C Watercourser
+542 C Wave-Wing Elemental
+543 C Weldfast Wingsmith
+544 C Welkin Tern
+545 R Whelming Wave
+546 C Whiplash Trap
+547 R Whir of Invention
+548 C Windcaller Aven
+549 C Wind Drake
+550 U Wind-Kin Raiders
+551 C Windrider Eel
+552 C Wind Strider
+553 C Wishcoin Crab
+554 C Wishful Merfolk
+555 C Wretched Gryff
+556 C Write into Being
+557 U Youthful Scholar
+558 C Absorb Vis
+559 C Accursed Spirit
+560 C Aid the Fallen
+561 C Alesha's Vanguard
+562 C Alley Strangler
+563 C Altar's Reap
+564 C Ambitious Aetherborn
+565 C Ancestral Vengeance
+566 U Animate Dead
+567 U Annihilate
+568 C Bala Ged Scorpion
+569 U Baleful Ammit
+570 C Balustrade Spy
+571 C Bartizan Bats
+572 C Bitter Revelation
+573 C Black Cat
+574 U Black Knight
+575 R Black Market
+576 C Bladebrand
+577 C Blessing of Belzenlok
+578 C Blighted Bat
+579 C Blightsoil Druid
+580 C Blistergrub
+581 U Blood Artist
+582 C Bloodrite Invoker
+583 C Bone Splinters
+584 C Boon of Emrakul
+585 U Breeding Pit
+586 C Butcher's Glee
+587 U Cabal Therapy
+588 C Cackling Imp
+589 C Cadaver Imp
+590 R Cairn Wanderer
+591 C Caligo Skin-Witch
+592 U Carrion Feeder
+593 C Carrion Imp
+594 C Catacomb Crocodile
+595 C Catacomb Slug
+596 U Caustic Tar
+597 C Certain Death
+598 C Child of Night
+599 C Coat with Venom
+600 R Collective Brutality
+601 U Corpsehatch
+602 C Costly Plunder
+603 C Covenant of Blood
+604 C Cower in Fear
+605 C Crippling Blight
+606 C Crow of Dark Tidings
+607 C Cursed Minotaur
+608 C Daring Demolition
+609 U Darkblast
+610 C Dark Dabbling
+611 C Dark Ritual
+612 C Dark Withering
+613 U Dauthi Mindripper
+614 C Deadbridge Shaman
+615 C Deadeye Tormentor
+616 R Deadly Tempest
+617 C Dead Reveler
+618 C Death Denied
+619 C Defeat
+620 U Demonic Tutor
+621 C Demonic Vigor
+622 C Demon's Grasp
+623 C Desperate Castaways
+624 C Diabolic Edict
+625 R Dictate of Erebos
+626 C Die Young
+627 C Dinosaur Hunter
+628 C Dirge of Dread
+629 U Dismember
+630 C Disowned Ancestor
+631 C Doomed Dissenter
+632 C Douse in Gloom
+633 R Drana, Kalastria Bloodchief
+634 C Dreadbringer Lampads
+635 C Dread Drone
+636 U Dread Return
+637 C Dregscape Zombie
+638 C Driver of the Dead
+639 C Drudge Sentinel
+640 C Dukhara Scavenger
+641 C Dune Beetle
+642 C Duress
+643 C Dusk Charger
+644 C Dusk Legion Zealot
+645 U The Eldest Reborn
+646 C Epicure of Blood
+647 C Erg Raiders
+648 C Eternal Thirst
+649 C Evincar's Justice
+650 C Executioner's Capsule
+651 U Exsanguinate
+652 C Eyeblight's Ending
+653 U Fallen Angel
+654 C Farbog Revenant
+655 U Fatal Push
+656 C Fen Hauler
+657 C Feral Abomination
+658 C Festercreep
+659 C Festering Newt
+660 C Fetid Imp
+661 C Fill with Fright
+662 C First-Sphere Gargantua
+663 C Flesh to Dust
+664 U Fretwork Colony
+665 C Fungal Infection
+666 U Genju of the Fens
+667 C Ghostly Changeling
+668 C Ghoulcaller's Accomplice
+669 U Gifted Aetherborn
+670 U Go for the Throat
+671 R Gonti, Lord of Luxury
+672 C Grasping Scoundrel
+673 R Gravecrawler
+674 C Gravedigger
+675 C Gravepurge
+676 M Grave Titan
+677 C Gray Merchant of Asphodel
+678 C Grim Affliction
+679 C Grim Discovery
+680 C Grixis Slavedriver
+681 C Grotesque Mutation
+682 C Gruesome Fate
+683 C Gurmag Angler
+684 R Haakon, Stromgald Scourge
+685 C Hideous End
+686 C Hired Blade
+687 C Hound of the Farbogs
+688 U Hunter of Eyeblights
+689 R Hypnotic Specter
+690 C Induce Despair
+691 C Infernal Scarring
+692 U Infest
+693 C Innocent Blood
+694 U Inquisition of Kozilek
+695 C Instill Infection
+696 C Kalastria Nightwatch
+697 C Krumar Bond-Kin
+698 C Lawless Broker
+699 C Lazotep Behemoth
+700 C Lethal Sting
+701 M Liliana, Death's Majesty
+702 R Living Death
+703 U Lord of the Accursed
+704 C Macabre Waltz
+705 C Marauding Boneslasher
+706 C March of the Drowned
+707 C Mark of the Vampire
+708 C Marsh Hulk
+709 C Mephitic Vapors
+710 C Merciless Resolve
+711 C Miasmic Mummy
+712 C Mind Rake
+713 C Mind Rot
+714 R Mind Shatter
+715 C Mire's Malice
+716 C Moment of Craving
+717 C Murder
+718 C Murderous Compulsion
+719 C Nameless Inversion
+720 C Nantuko Husk
+721 C Never Happened
+722 R Nighthowler
+723 C Night's Whisper
+724 C Nirkana Assassin
+725 U Noxious Dragon
+726 C Okiba-Gang Shinobi
+727 C Painful Lesson
+728 U Perish
+729 C Pestilence
+730 R Phyrexian Arena
+731 R Phyrexian Plaguelord
+732 C Phyrexian Rager
+733 U Phyrexian Reclamation
+734 C Pit Keeper
+735 U Plaguecrafter
+736 C Plagued Rusalka
+737 C Plague Wight
+738 C Prakhata Club Security
+739 C Prowling Pangolin
+740 C Queen's Agent
+741 U Quest for the Gravelord
+742 C Rabid Bloodsucker
+743 C Rakdos Drake
+744 C Rakshasa's Secret
+745 U Ravenous Chupacabra
+746 C Read the Bones
+747 C Reaper of Night // Harvest Fear
+748 U Reassembling Skeleton
+749 C Reckless Imp
+750 U Reckless Spite
+751 C Recover
+752 C Renegade Demon
+753 C Renegade's Getaway
+754 C Returned Centaur
+755 R Revel in Riches
+756 U Revenant
+757 C Rite of the Serpent
+758 C Rotfeaster Maggot
+759 C Ruin Rat
+760 R Rune-Scarred Demon
+761 U Sadistic Hypnotist
+762 C Scarab Feast
+763 C Scrounger of Souls
+764 C Scuttling Death
+765 C Seal of Doom
+766 U Sengir Vampire
+767 R Sewer Nemesis
+768 C Shadowcloak Vampire
+769 C Shambling Attendants
+770 C Shambling Goblin
+771 U Shriekmaw
+772 U Shrouded Lore
+773 C Silumgar Butcher
+774 U Skeletal Scrying
+775 C Skeleton Archer
+776 C Skulking Ghost
+777 U Smiting Helix
+778 M Sorin Markov
+779 C Spreading Rot
+780 U Stab Wound
+781 C Stallion of Ashmouth
+782 C Stinkweed Imp
+783 U Street Wraith
+784 C Stromkirk Patrol
+785 C Subtle Strike
+786 C Sultai Runemark
+787 C Tar Snare
+788 U Tavern Swindler
+789 C Tendrils of Corruption
+790 C Thallid Omnivore
+791 C Thornbow Archer
+792 C Thorn of the Black Rose
+793 C Thraben Foulbloods
+794 C Tidy Conclusion
+795 R Torment of Hailfire
+796 C Torment of Venom
+797 C Touch of Moonglove
+798 R Toxin Sliver
+799 C Tragic Slip
+800 C Trespasser's Curse
+801 U Trial of Ambition
+802 C Twins of Maurer Estate
+803 C Typhoid Rats
+804 C Unburden
+805 C Undercity's Embrace
+806 C Untamed Hunger
+807 C Unyielding Krumar
+808 C Urborg Uprising
+809 C Vampire Champion
+810 C Vampire Envoy
+811 U Vampire Hexmage
+812 C Vampire Lacerator
+813 U Vampire Nighthawk
+814 C Vessel of Malignity
+815 C Virulent Swipe
+816 C Voracious Null
+817 C Vraska's Finisher
+818 C Wake of Vultures
+819 C Walking Corpse
+820 U Walk the Plank
+821 C Wander in Death
+822 C Warteye Witch
+823 C Weight of the Underworld
+824 C Weirded Vampire
+825 U Wight of Precinct Six
+826 U Will-o'-the-Wisp
+827 C Windgrace Acolyte
+828 C Wrench Mind
+829 U Yargle, Glutton of Urborg
+830 C Zulaport Chainmage
+831 C Act of Treason
+832 U Act on Impulse
+833 U Ahn-Crop Crasher
+834 C Ainok Tracker
+835 C Akroan Sergeant
+836 C Alchemist's Greeting
+837 R Alesha, Who Smiles at Death
+838 U Ancient Grudge
+839 U Anger
+840 R Anger of the Gods
+841 U Arc Trail
+842 C Arrow Storm
+843 C Atarka Efreet
+844 U Avalanche Riders
+845 C Avarax
+846 C Azra Bladeseeker
+847 C Balduvian Horde
+848 C Barging Sergeant
+849 C Barrage of Boulders
+850 C Battle Rampart
+851 C Battle-Rattle Shaman
+852 U Beetleback Chief
+853 C Bellows Lizard
+854 C Blades of Velis Vel
+855 C Blastfire Bolt
+856 C Blazing Volley
+857 C Blindblast
+858 C Bloodfire Expert
+859 C Bloodlust Inciter
+860 C Bloodmad Vampire
+861 C Blood Ogre
+862 C Bloodstone Goblin
+863 C Blow Your House Down
+864 C Blur of Blades
+865 C Boggart Brute
+866 C Boiling Earth
+867 C Bombard
+868 C Bomber Corps
+869 C Borrowed Hostility
+870 C Boulder Salvo
+871 C Brazen Buccaneers
+872 C Brazen Wolves
+873 R Brimstone Dragon
+874 U Brimstone Mage
+875 C Bring Low
+876 U Browbeat
+877 C Brute Strength
+878 C Built to Smash
+879 C Burst Lightning
+880 C Canyon Lurkers
+881 C Cartouche of Zeal
+882 C Cathartic Reunion
+883 C Chandra's Pyrohelix
+884 C Chandra's Revolution
+885 R Chaos Warp
+886 U Charging Monstrosaur
+887 C Chartooth Cougar
+888 C Cinder Hellion
+889 C Cleansing Screech
+890 C Cobblebrute
+891 C Cosmotronic Wave
+892 R Cragganwick Cremator
+893 C Crash Through
+894 C Crowd's Favor
+895 C Crown-Hunter Hireling
+896 U Curse of Opulence
+897 U Curse of the Nightly Hunt
+898 M Daretti, Scrap Savant
+899 U Death by Dragons
+900 C Defiant Ogre
+901 C Demolish
+902 C Desert Cerodon
+903 U Desperate Ravings
+904 C Destructive Tampering
+905 C Direct Current
+906 C Distemper of the Blood
+907 U Dragon Breath
+908 C Dragon Egg
+909 C Dragon Fodder
+910 C Dragonsoul Knight
+911 U Dragon Whelp
+912 C Dual Shot
+913 C Dynacharge
+914 C Earth Elemental
+915 C Emrakul's Hatcher
+916 U Enthralling Victor
+917 C Erratic Explosion
+918 C Expedite
+919 C Faithless Looting
+920 C Falkenrath Reaver
+921 C Fall of the Hammer
+922 C Fervent Strike
+923 C Fierce Invocation
+924 C Fiery Hellhound
+925 C Fiery Temper
+926 U Fireball
+927 C Firebolt
+928 C Firebrand Archer
+929 C Fire Elemental
+930 U Flame Jab
+931 U Flameshot
+932 U Flametongue Kavu
+933 U Flamewave Invoker
+934 C Fling
+935 C Forge Devil
+936 C Foundry Street Denizen
+937 C Frenzied Raptor
+938 C Frilled Deathspitter
+939 C Frontline Devastator
+940 C Frontline Rebel
+941 C Furnace Whelp
+942 C Fury Charm
+943 C Galvanic Blast
+944 C Generator Servant
+945 U Genju of the Spires
+946 C Geomancer's Gambit
+947 C Ghitu Lavarunner
+948 U Ghitu War Cry
+949 C Giant Spectacle
+950 U Goblin Assault
+951 C Goblin Balloon Brigade
+952 U Goblin Bombardment
+953 C Goblin Fireslinger
+954 R Goblin Game
+955 C Goblin Locksmith
+956 U Goblin Matron
+957 C Goblin Motivator
+958 U Goblin Oriflamme
+959 R Goblin Piledriver
+960 C Goblin Roughrider
+961 U Goblin Warchief
+962 C Goblin War Paint
+963 C Gorehorn Minotaurs
+964 C Gore Swine
+965 C Granitic Titan
+966 C Grapeshot
+967 C Gravitic Punch
+968 R Greater Gargadon
+969 C Gut Shot
+970 U Guttersnipe
+971 C Hammerhand
+972 C Hanweir Lancer
+973 C Hardened Berserker
+974 C Hijack
+975 C Hulking Devil
+976 C Hyena Pack
+977 C Ill-Tempered Cyclops
+978 C Impact Tremors
+979 R Impending Disaster
+980 U Incorrigible Youths
+981 C Inferno Fist
+982 U Inferno Jet
+983 C Ingot Chewer
+984 C Insolent Neonate
+985 C Jackal Pup
+986 C Kaervek's Torch
+987 M Kargan Dragonlord
+988 C Keldon Halberdier
+989 C Keldon Overseer
+990 C Khenra Scrapper
+991 M Kiki-Jiki, Mirror Breaker
+992 C Kiln Fiend
+993 C Kird Ape
+994 R Knollspine Dragon
+995 C Kolaghan Stormsinger
+996 R Krenko, Mob Boss
+997 C Krenko's Command
+998 C Krenko's Enforcer
+999 C Leaping Master
+1000 C Leopard-Spotted Jiao
+1001 U Lightning Bolt
+1002 C Lightning Javelin
+1003 C Lightning Shrieker
+1004 C Lightning Talons
+1005 C Madcap Skills
+1006 C Magma Spray
+1007 C Makindi Sliderunner
+1008 C Mardu Warshrieker
+1009 U Mark of Mutiny
+1010 C Maximize Velocity
+1011 C Miner's Bane
+1012 R Mizzix's Mastery
+1013 U Mogg Fanatic
+1014 C Mogg Flunkies
+1015 C Mogg War Marshal
+1016 U Molten Rain
+1017 U Monastery Swiftspear
+1018 C Mutiny
+1019 C Nimble-Blade Khenra
+1020 C Ondu Champion
+1021 C Orcish Cannonade
+1022 C Orcish Oriflamme
+1023 C Outnumber
+1024 C Pillage
+1025 R Preyseizer Dragon
+1026 U Price of Progress
+1027 C Prickleboar
+1028 C Prophetic Ravings
+1029 M Purphoros, God of the Forge
+1030 U Pyrotechnics
+1031 C Quakefoot Cyclops
+1032 R Rage Reflection
+1033 C Rampaging Cyclops
+1034 R Reality Scramble
+1035 C Reckless Fireweaver
+1036 C Reckless Wurm
+1037 U Recoup
+1038 U Release the Ants
+1039 R Release the Gremlins
+1040 C Renegade Tactics
+1041 U Rivals' Duel
+1042 U Roast
+1043 U Rolling Thunder
+1044 C Rubblebelt Maaka
+1045 C Ruinous Gremlin
+1046 C Rummaging Goblin
+1047 C Run Amok
+1048 C Rush of Adrenaline
+1049 C Salivating Gremlins
+1050 C Samut's Sprint
+1051 C Sarkhan's Rage
+1052 C Screamreach Brawler
+1053 C Seismic Shift
+1054 C Seismic Stomp
+1055 C Shatter
+1056 U Shattering Spree
+1057 C Shenanigans
+1058 C Shock
+1059 C Skirk Commando
+1060 C Skirk Prospector
+1061 C Smash to Smithereens
+1062 C Smelt
+1063 C Sparkmage Apprentice
+1064 C Sparkspitter
+1065 C Sparktongue Dragon
+1066 U Spikeshot Goblin
+1067 U Staggershock
+1068 M Star of Extinction
+1069 R Steamflogger Boss
+1070 U Stormblood Berserker
+1071 R Sudden Demise
+1072 U Sulfurous Blast
+1073 C Summit Prowler
+1074 C Sun-Crowned Hunters
+1075 C Swashbuckling
+1076 C Sweatworks Brawler
+1077 C Swift Kick
+1078 C Tarfire
+1079 R Taurean Mauler
+1080 U Tectonic Rift
+1081 C Temur Battle Rage
+1082 C Thresher Lizard
+1083 C Thrill of Possibility
+1084 U Tibalt's Rager
+1085 C Torch Courier
+1086 R Two-Headed Giant
+1087 C Uncaged Fury
+1088 C Undying Rage
+1089 R Urza's Rage
+1090 C Valakut Invoker
+1091 C Valakut Predator
+1092 C Valley Dasher
+1093 C Vandalize
+1094 C Vent Sentinel
+1095 C Vessel of Volatility
+1096 U Viashino Sandstalker
+1097 U Volcanic Dragon
+1098 C Volcanic Rush
+1099 C Voldaren Duelist
+1100 C Wall of Fire
+1101 C Wayward Giant
+1102 R Wheel of Fate
+1103 C Wildfire Emissary
+1104 C Wojek Bodyguard
+1105 U Young Pyromancer
+1106 C Zada's Commando
+1107 C Zealot of the God-Pharaoh
+1108 C Abundant Growth
+1109 U Acidic Slime
+1110 C Adventurous Impulse
+1111 C Aerie Bowmasters
+1112 U Affectionate Indrik
+1113 C Aggressive Instinct
+1114 C Aggressive Urge
+1115 U Ainok Survivalist
+1116 C Alpine Grizzly
+1117 C Ambassador Oak
+1118 U Ana Sanctuary
+1119 U Ancestral Mask
+1120 C Ancient Brontodon
+1121 U Ancient Stirrings
+1122 C Arachnus Web
+1123 C Arbor Armament
+1124 C Arbor Elf
+1125 R Asceticism
+1126 C Aura Gnarlid
+1127 C Avacyn's Pilgrim
+1128 C Backwoods Survivalists
+1129 C Baloth Gorger
+1130 C Basking Rootwalla
+1131 C Bear Cub
+1132 U Beastbreaker of Bala Ged
+1133 R Beastmaster Ascension
+1134 U Beast Within
+1135 U Become Immense
+1136 C Beneath the Sands
+1137 U Bestial Menace
+1138 R Birds of Paradise
+1139 C Bitterblade Warrior
+1140 C Bitterbow Sharpshooters
+1141 U Blanchwood Armor
+1142 C Blastoderm
+1143 R Bloom Tender
+1144 C Blossom Dryad
+1145 C Borderland Explorer
+1146 C Borderland Ranger
+1147 R Bow of Nylea
+1148 U Briarhorn
+1149 C Bristling Boar
+1150 C Broken Bond
+1151 C Broodhunter Wurm
+1152 C Byway Courier
+1153 C Call the Scions
+1154 C Canopy Spider
+1155 C Carnivorous Moss-Beast
+1156 U Carpet of Flowers
+1157 C Caustic Caterpillar
+1158 C Centaur Courser
+1159 U Centaur Glade
+1160 C Charging Rhino
+1161 C Chatter of the Squirrel
+1162 C Citanul Woodreaders
+1163 C Clip Wings
+1164 C Colossal Dreadmaw
+1165 C Combo Attack
+1166 C Commune with Nature
+1167 C Commune with the Gods
+1168 C Conifer Strider
+1169 R Courser of Kruphix
+1170 U Creeping Mold
+1171 C Crop Rotation
+1172 C Crossroads Consecrator
+1173 U The Crowd Goes Wild
+1174 C Crowned Ceratok
+1175 C Crushing Canopy
+1176 C Cultivate
+1177 C Daggerback Basilisk
+1178 C Dawn's Reflection
+1179 C Death-Hood Cobra
+1180 R Defense of the Heart
+1181 U Desert Twister
+1182 U Destructor Dragon
+1183 C Dissenter's Deliverance
+1184 U Domesticated Hydra
+1185 C Dragonscale Boon
+1186 C Dragon-Scarred Bear
+1187 R Dungrove Elder
+1188 C Durkwood Baloth
+1189 C Earthen Arms
+1190 R Eldritch Evolution
+1191 C Elemental Uprising
+1192 C Elephant Guide
+1193 C Elves of Deep Shadow
+1194 C Elvish Fury
+1195 C Elvish Visionary
+1196 C Elvish Warrior
+1197 C Ember Weaver
+1198 C Epic Confrontation
+1199 C Essence Warden
+1200 U Eternal Witness
+1201 U Experiment One
+1202 C Explore
+1203 U Explosive Vegetation
+1204 C Ezuri's Archers
+1205 C Fade into Antiquity
+1206 C Farseek
+1207 C Feed the Clan
+1208 C Feral Krushok
+1209 C Feral Prowler
+1210 C Ferocious Zheng
+1211 C Fertile Ground
+1212 C Fierce Empath
+1213 C Fog
+1214 C Formless Nurturing
+1215 C Frontier Mastodon
+1216 U Gaea's Blessing
+1217 C Gaea's Protector
+1218 C Giant Growth
+1219 C Giant Spider
+1220 C Gift of Growth
+1221 C Gift of Paradise
+1222 C Glade Watcher
+1223 C Gnarlid Pack
+1224 C Grapple with the Past
+1225 C Grazing Gladehart
+1226 C Greater Basilisk
+1227 C Greater Sandwurm
+1228 R Greenbelt Rampager
+1229 C Greenwood Sentinel
+1230 C Groundswell
+1231 C Guardian Shield-Bearer
+1232 U Hamlet Captain
+1233 C Hardy Veteran
+1234 U Harmonize
+1235 C Harrow
+1236 C Hooded Brawler
+1237 C Hooting Mandrills
+1238 R Hornet Nest
+1239 C Hunter's Ambush
+1240 C Hunt the Weak
+1241 R Hurricane
+1242 U Imperious Perfect
+1243 U Invigorate
+1244 C Ivy Lane Denizen
+1245 C Jungle Delver
+1246 C Jungle Wayfinder
+1247 C Kavu Climber
+1248 C Kavu Primarch
+1249 C Khalni Heart Expedition
+1250 C Kin-Tree Warden
+1251 C Kozilek's Predator
+1252 C Kraul Foragers
+1253 C Kraul Warrior
+1254 C Krosan Druid
+1255 C Krosan Tusker
+1256 C Larger Than Life
+1257 C Lay of the Land
+1258 C Lead by Example
+1259 C Lead the Stampede
+1260 C Lifespring Druid
+1261 C Lignify
+1262 C Llanowar Elves
+1263 C Llanowar Empath
+1264 C Longshot Squad
+1265 U Lure
+1266 U Manglehorn
+1267 C Mantle of Webs
+1268 C Map the Wastes
+1269 R Meandering Towershell
+1270 C Might of the Masses
+1271 C Mulch
+1272 R Mycoloth
+1273 C Natural Connection
+1274 C Naturalize
+1275 C Nature's Claim
+1276 C Nature's Lore
+1277 C Nest Invader
+1278 C Nettle Sentinel
+1279 C New Horizons
+1280 C Nimble Mongoose
+1281 M Nissa, Voice of Zendikar
+1282 C Oakgnarl Warrior
+1283 C Ondu Giant
+1284 C Oran-Rief Invoker
+1285 C Overgrown Armasaur
+1286 U Overgrown Battlement
+1287 U Overrun
+1288 C Pack's Favor
+1289 C Peema Outrider
+1290 U Pelakka Wurm
+1291 C Penumbra Spider
+1292 U Phantom Centaur
+1293 C Pierce the Sky
+1294 C Pinion Feast
+1295 C Plummet
+1296 C Pouncing Cheetah
+1297 C Prey's Vengeance
+1298 C Prey Upon
+1299 C Priest of Titania
+1300 C Pulse of Murasa
+1301 C Quiet Disrepair
+1302 U Rain of Thorns
+1303 C Rampant Growth
+1304 U Rancor
+1305 C Ranger's Guile
+1306 C Ravenous Leucrocota
+1307 C Reclaim
+1308 C Reclaiming Vines
+1309 U Regrowth
+1310 C Relic Crush
+1311 C Return to the Earth
+1312 C Revive
+1313 C Rhox Maulers
+1314 C Riparian Tiger
+1315 U River Boa
+1316 U Roar of the Wurm
+1317 C Root Out
+1318 C Roots
+1319 C Rosethorn Halberd
+1320 C Runeclaw Bear
+1321 C Sagu Archer
+1322 C Sakura-Tribe Elder
+1323 C Saproling Migration
+1324 C Savage Punch
+1325 C Scatter the Seeds
+1326 C Seal of Strength
+1327 C Search for Tomorrow
+1328 U Seek the Horizon
+1329 C Seek the Wilds
+1330 M Selvala, Heart of the Wilds
+1331 R Shamanic Revelation
+1332 C Shape the Sands
+1333 C Siege Wurm
+1334 C Silhana Ledgewalker
+1335 C Silkweaver Elite
+1336 C Snake Umbra
+1337 U Snapping Sailback
+1338 R Spawning Grounds
+1339 U Spider Spawning
+1340 R Squirrel Wrangler
+1341 C Stalking Tiger
+1342 C Stoic Builder
+1343 C Strength in Numbers
+1344 C Sylvan Bounty
+1345 U Sylvan Scrying
+1346 C Tajuru Pathwarden
+1347 U Tajuru Warcaller
+1348 C Take Down
+1349 C Talons of Wildwood
+1350 R Tempt with Discovery
+1351 C Terrain Elemental
+1352 C Territorial Baloth
+1353 C Thornhide Wolves
+1354 U Thornscape Battlemage
+1355 C Thornweald Archer
+1356 U Thrashing Brontodon
+1357 C Thrive
+1358 M Thrun, the Last Troll
+1359 U Timberwatch Elf
+1360 C Time to Feed
+1361 R Tireless Tracker
+1362 C Titanic Growth
+1363 U Triumph of the Hordes
+1364 C Tukatongue Thallid
+1365 U Turntimber Basilisk
+1366 C Vastwood Gorger
+1367 U Venom Sliver
+1368 R Vigor
+1369 C Watcher in the Web
+1370 C Wellwisher
+1371 C Wild Growth
+1372 C Wild Mongrel
+1373 C Wild Nacatl
+1374 C Wildsize
+1375 C Wolfkin Bond
+1376 U Woodborn Behemoth
+1377 C Woolly Loxodon
+1378 U Wren's Run Vanquisher
+1379 C Yavimaya Elder
+1380 C Yavimaya Sapherd
+1381 C Yeva's Forcemage
+1382 U Zendikar's Roil
+1383 U Abzan Charm
+1384 C Abzan Guide
+1385 C Agony Warp
+1386 U Akroan Hoplite
+1387 M Animar, Soul of Elements
+1388 U Armadillo Cloak
+1389 U Armament Corps
+1390 R Assemble the Legion
+1391 M Athreos, God of Passage
+1392 U Aura Shards
+1393 U Azorius Charm
+1394 U Azra Oddsmaker
+1395 U Baleful Strix
+1396 U Baloth Null
+1397 U Bear's Companion
+1398 U Belligerent Brontodon
+1399 U Bituminous Blast
+1400 U Bladewing the Risen
+1401 U Blightning
+1402 U Bloodbraid Elf
+1403 U Boros Challenger
+1404 U Bounding Krasis
+1405 U Call of the Nightwing
+1406 U Campaign of Vengeance
+1407 U Cauldron Dance
+1408 U Citadel Castellan
+1409 C Coiling Oracle
+1410 U Contraband Kingpin
+1411 U Corpsejack Menace
+1412 U Crosis's Charm
+1413 U Cunning Breezedancer
+1414 U Deathreap Ritual
+1415 C Deny Reality
+1416 U Draconic Disciple
+1417 M Dragon Broodmother
+1418 M Dragonlord Ojutai
+1419 U Drana's Emissary
+1420 U Engineered Might
+1421 U Esper Charm
+1422 U Ethercaste Knight
+1423 C Ethereal Ambush
+1424 U Extract from Darkness
+1425 U Fires of Yavimaya
+1426 U Flame-Kin Zealot
+1427 U Fusion Elemental
+1428 U Gelectrode
+1429 U Ghor-Clan Rampager
+1430 M The Gitrog Monster
+1431 C Goblin Deathraiders
+1432 C Grim Contest
+1433 R Guided Passage
+1434 C Hammer Dropper
+1435 U Hidden Stockpile
+1436 U Highspire Mantis
+1437 C Hypothesizzle
+1438 U Iroas's Champion
+1439 U Join Shields
+1440 U Jungle Barrier
+1441 U Kathari Remnant
+1442 U Kin-Tree Invocation
+1443 U Kiora's Follower
+1444 U Kiss of the Amesha
+1445 R Kolaghan's Command
+1446 M Kruphix, God of Horizons
+1447 C Lawmage's Binding
+1448 U Lightning Helix
+1449 M Maelstrom Archangel
+1450 U Mardu Roughrider
+1451 C Martial Glory
+1452 U Maverick Thopterist
+1453 R Meddling Mage
+1454 U Mercurial Geists
+1455 M Meren of Clan Nel Toth
+1456 U Migratory Route
+1457 U Mortify
+1458 U Naya Charm
+1459 R Nemesis of Reason
+1460 R Nin, the Pain Artist
+1461 U Obelisk Spider
+1462 U Ochran Assassin
+1463 U Pillory of the Sleepless
+1464 U Plaxcaster Frogling
+1465 U Pollenbright Wings
+1466 U Putrefy
+1467 C Qasali Pridemage
+1468 M Queen Marchesa
+1469 R Questing Phelddagrif
+1470 U Raff Capashen, Ship's Mage
+1471 U Raging Swordtooth
+1472 U Reclusive Artificer
+1473 U Reflector Mage
+1474 U Rhox War Monk
+1475 C Riptide Crab
+1476 R Rith, the Awakener
+1477 U River Hoopoe
+1478 C Rosemane Centaur
+1479 U Satyr Enchanter
+1480 R Savage Knuckleblade
+1481 U Savage Twister
+1482 U Sedraxis Specter
+1483 U Shambling Remains
+1484 U Shardless Agent
+1485 U Shipwreck Singer
+1486 U Skyward Eye Prophets
+1487 M Sliver Hivelord
+1488 U Soul Manipulation
+1489 U Sprouting Thrinax
+1490 U Stormchaser Chimera
+1491 U Sultai Charm
+1492 U Sultai Soothsayer
+1493 R Supreme Verdict
+1494 U Tatyova, Benthic Druid
+1495 C Terminate
+1496 U Thought Erasure
+1497 R Time Sieve
+1498 C Tithe Drinker
+1499 U Tower Gargoyle
+1500 U Treacherous Terrain
+1501 U Underworld Coinsmith
+1502 U Unflinching Courage
+1503 U Unlicensed Disintegration
+1504 U Urban Evolution
+1505 U Vengeful Rebirth
+1506 R Violent Ultimatum
+1507 U Warden of the Eye
+1508 R Wargate
+1509 U Wayfaring Temple
+1510 U Weapons Trainer
+1511 U Wee Dragonauts
+1512 U Winding Constrictor
+1513 U Woolly Thoctar
+1514 R Yavimaya's Embrace
+1515 R Yuriko, the Tiger's Shadow
+1516 U Zealous Persecution
+1517 C Zhur-Taa Druid
+1518 R Boros Reckoner
+1519 R Debtors' Knell
+1520 R Dominus of Fealty
+1521 R Doomgape
+1522 R Enchanted Evening
+1523 C Giantbaiting
+1524 C Gift of Orzhova
+1525 U Gwyllion Hedge-Mage
+1526 C Manamorphose
+1527 U Mistmeadow Witch
+1528 U Nucklavee
+1529 R Oracle of Nectars
+1530 R Rhys the Redeemed
+1531 U Rosheen Meanderer
+1532 U Selesnya Guildmage
+1533 U Shrewd Hatchling
+1534 U Slave of Bolas
+1535 U Thopter Foundry
+1536 U Claim // Fame
+1537 R Commit // Memory
+1538 C Fire // Ice
+1539 R Aetherflux Reservoir
+1540 C Aether Spellbomb
+1541 R Akroan Horse
+1542 C Alchemist's Vial
+1543 M Alhammarret's Archive
+1544 C Alloy Myr
+1545 C Armillary Sphere
+1546 U Ashnod's Altar
+1547 R Basilisk Collar
+1548 R Belbe's Portal
+1549 C Blinding Souleater
+1550 U Bomat Bazaar Barge
+1551 C Bone Saw
+1552 C Bonesplitter
+1553 R Boompile
+1554 U Bottle Gnomes
+1555 U Burnished Hart
+1556 R Caged Sun
+1557 U Cathodion
+1558 R Cauldron of Souls
+1559 R Chromatic Lantern
+1560 C Chromatic Star
+1561 R Coat of Arms
+1562 U Coldsteel Heart
+1563 U Consulate Dreadnought
+1564 U Contagion Clasp
+1565 C Copper Carapace
+1566 R Coveted Jewel
+1567 U Crenellated Wall
+1568 U Crystal Ball
+1569 U Crystal Chimes
+1570 U Crystal Shard
+1571 R Darksteel Garrison
+1572 U Diamond Mare
+1573 R Dolmen Gate
+1574 R Draco
+1575 U Dragon Mask
+1576 R Eater of Days
+1577 M Eldrazi Monument
+1578 U Elixir of Immortality
+1579 U Emmessi Tome
+1580 U Etched Oracle
+1581 U Farmstead Gleaner
+1582 U Filigree Familiar
+1583 C Flayer Husk
+1584 R Font of Mythos
+1585 U Foundry Inspector
+1586 U Fountain of Renewal
+1587 C Frogmite
+1588 R Goblin Charbelcher
+1589 C Gruul Signet
+1590 C Guardians of Meletis
+1591 U Heavy Arbalest
+1592 U Helm of Awakening
+1593 U Herald's Horn
+1594 C Hexplate Golem
+1595 U Hot Soup
+1596 U Icy Manipulator
+1597 C Implement of Malice
+1598 C Irontread Crusher
+1599 U Juggernaut
+1600 U Lightning Greaves
+1601 C Lotus Petal
+1602 U Loxodon Warhammer
+1603 M Mana Crypt
+1604 U Mask of Memory
+1605 U Meteorite
+1606 U Millikin
+1607 U Millstone
+1608 R Mimic Vat
+1609 C Mind Stone
+1610 U Mishra's Bauble
+1611 C Moonglove Extract
+1612 U Mortarpod
+1613 U Myr Retriever
+1614 C Myr Sire
+1615 C Ornithopter
+1616 U Palladium Myr
+1617 C Peace Strider
+1618 U Perilous Myr
+1619 R Phyrexian Soulgorger
+1620 U Pilgrim's Eye
+1621 R Precursor Golem
+1622 C Prophetic Prism
+1623 C Renegade Map
+1624 U Rhonas's Monument
+1625 U Sandstone Oracle
+1626 C Serrated Arrows
+1627 C Short Sword
+1628 U Sigil of Valor
+1629 C Simic Locket
+1630 U Skullclamp
+1631 C Skyscanner
+1632 R Solemn Simulacrum
+1633 U Sol Ring
+1634 U Sorcerer's Broom
+1635 U Spy Kit
+1636 U Sunset Pyramid
+1637 U Suspicious Bookcase
+1638 R Sword of the Animist
+1639 C Thought Vessel
+1640 U Thran Dynamo
+1641 U Thran Golem
+1642 U Tormod's Crypt
+1643 R Tower of Eons
+1644 R Trading Post
+1645 U Trepanation Blade
+1646 U Umbral Mantle
+1647 C Universal Automaton
+1648 C Universal Solvent
+1649 U Whispersilk Cloak
+1650 U Aether Hub
+1651 U Akoum Refuge
+1652 C Ancient Den
+1653 U Ancient Ziggurat
+1654 U Arcane Sanctum
+1655 R Arch of Orazca
+1656 C Ash Barrens
+1657 U Blasted Landscape
+1658 U Blighted Fen
+1659 C Blossoming Sands
+1660 C Bojuka Bog
+1661 U Crumbling Necropolis
+1662 C Darksteel Citadel
+1663 C Dismal Backwater
+1664 U Dreadship Reef
+1665 C Evolving Wilds
+1666 U Faerie Conclave
+1667 U Field of Ruin
+1668 C Forgotten Cave
+1669 U Frontier Bivouac
+1670 C Gateway Plaza
+1671 U Ghost Quarter
+1672 R Gilt-Leaf Palace
+1673 U Goblin Burrows
+1674 U Graypelt Refuge
+1675 C Great Furnace
+1676 C Jungle Hollow
+1677 U Jungle Shrine
+1678 U Kazandu Refuge
+1679 U Krosan Verge
+1680 U Mishra's Factory
+1681 U New Benalia
+1682 C Orzhov Basilica
+1683 U Reliquary Tower
+1684 U Rogue's Passage
+1685 U Sandsteppe Citadel
+1686 C Scoured Barrens
+1687 U Sejiri Refuge
+1688 U Skarrg, the Rage Pits
+1689 C Swiftwater Cliffs
+1690 U Tectonic Edge
+1691 U Temple of the False God
+1692 C Thornwood Falls
+1693 U Unclaimed Territory
+1694 U Wirewood Lodge
diff --git a/forge-gui/res/editions/Theros Beyond Death.txt b/forge-gui/res/editions/Theros Beyond Death.txt
index 65fd9f6ae80..6d8b9f91a2d 100644
--- a/forge-gui/res/editions/Theros Beyond Death.txt
+++ b/forge-gui/res/editions/Theros Beyond Death.txt
@@ -367,17 +367,17 @@ Prerelease=6 Boosters, 1 RareMythic+
350 R Temple of Malice
351 R Temple of Plenty
#Bundle promo
-R Arasta of the Endless Web
+352 R Arasta of the Endless Web
#Promo Pack
-U Alseid of Life's Bounty
-C Thirst for Meaning
-U Gray Merchant of Asphodel
-C Thrill of Possibility
-U Wolfwillow Haven
+353 U Alseid of Life's Bounty
+354 C Thirst for Meaning
+355 U Gray Merchant of Asphodel
+356 C Thrill of Possibility
+357 U Wolfwillow Haven
[tokens]
b_2_2_zombie
-c_0_4_wall_defender
+c_0_4_a_wall_defender
g_1_2_spider_reach
g_2_2_wolf
r_x_1_elemental_trample_haste
diff --git a/forge-gui/res/editions/Throne of Eldraine.txt b/forge-gui/res/editions/Throne of Eldraine.txt
index 1c567deab3e..b08eab5cb35 100644
--- a/forge-gui/res/editions/Throne of Eldraine.txt
+++ b/forge-gui/res/editions/Throne of Eldraine.txt
@@ -284,36 +284,36 @@ Prerelease=6 Boosters, 1 RareMythic+
271 M Oko, Thief of Crowns
272 M The Royal Scions
#Storybook Frames
-C Ardenvale Tactician
-C Faerie Guidemother
-R Giant Killer
-C Lonesome Unicorn
-M Realm-Cloaked Giant
-U Shepherd of the Flock
-C Silverflame Squire
-U Animating Faerie
-M Brazen Borrower
-R Fae of Wishes
-U Hypnotic Sprite
-C Merfolk Secretkeeper
-C Queen of Ice
-U Foulmire Knight
-R Murderous Rider
-U Order of Midnight
-C Reaper of Night
-C Smitten Swordmaster
-R Bonecrusher Giant
-U Embereth Shieldbreaker
-C Merchant of the Vale
-C Rimrock Knight
-U Beanstalk Giant
-C Curious Pair
-U Flaxen Intruder
-C Garenbrig Carver
-R Lovestruck Beast
-C Rosethorn Acolyte
-C Tuinvale Treefolk
-U Oakhame Ranger
+273 C Ardenvale Tactician
+274 C Faerie Guidemother
+275 R Giant Killer
+276 C Lonesome Unicorn
+277 M Realm-Cloaked Giant
+278 U Shepherd of the Flock
+279 C Silverflame Squire
+280 U Animating Faerie
+281 M Brazen Borrower
+282 R Fae of Wishes
+283 U Hypnotic Sprite
+284 C Merfolk Secretkeeper
+285 C Queen of Ice
+286 U Foulmire Knight
+287 R Murderous Rider
+288 U Order of Midnight
+289 C Reaper of Night
+290 C Smitten Swordmaster
+291 R Bonecrusher Giant
+292 U Embereth Shieldbreaker
+293 C Merchant of the Vale
+294 C Rimrock Knight
+295 U Beanstalk Giant
+296 C Curious Pair
+297 U Flaxen Intruder
+298 C Garenbrig Carver
+299 R Lovestruck Beast
+300 C Rosethorn Acolyte
+301 C Tuinvale Treefolk
+302 U Oakhame Ranger
#Buy-A-Box Promo
303 M Kenrith, the Returned King
#Planeswalker Deck Cards
@@ -348,72 +348,72 @@ U Oakhame Ranger
332 R Tome of Legends
333 C Command Tower
#Borderless art rares and mythics
-R Acclaimed Contender
-R Charming Prince
-M The Circle of Loyalty
-R Happily Ever After
-M Harmonious Archon
-R Hushbringer
-R Linden, the Steadfast Queen
-R Worthy Knight
-R Emry, Lurker of the Loch
-R Folio of Fancies
-R Gadwick, the Wizened
-M The Magic Mirror
-R Midnight Clock
-R Mirrormade
-R Stolen by the Fae
-R Vantress Gargoyle
-R Ayara, First of Locthwain
-R Blacklance Paragon
-M The Cauldron of Eternity
-R Clackbridge Troll
-R Oathsworn Knight
-R Piper of the Swarm
-M Rankle, Master of Pranks
-R Wishclaw Talisman
-R Witch's Vengeance
-M Embercleave
-R Fervent Champion
-R Fires of Invention
-R Irencrag Feat
-R Irencrag Pyromancer
-R Opportunistic Dragon
-M Robber of the Rich
-R Sundering Stroke
-R Torbran, Thane of Red Fell
-R Feasting Troll King
-R Gilded Goose
-M The Great Henge
-R Once Upon A Time
-M Questing Beast
-R Return of the Wildspeaker
-R Wicked Wolf
-R Wildborn Preserver
-R Yorvo, Lord of Garenbrig
-R Dance of the Manse
-R Doom Foretold
-R Escape to the Wilds
-R Faeburrow Elder
-R Lochmere Serpent
-M Outlaws' Merriment
-R Stormfist Crusader
-R Sorcerous Spyglass
-R Stonecoil Serpent
-R Castle Ardenvale
-R Castle Embereth
-R Castle Garenbrig
-R Castle Locthwain
-R Castle Vantress
-R Fabled Passage
+334 R Acclaimed Contender
+335 R Charming Prince
+336 M The Circle of Loyalty
+337 R Happily Ever After
+338 M Harmonious Archon
+339 R Hushbringer
+340 R Linden, the Steadfast Queen
+341 R Worthy Knight
+342 R Emry, Lurker of the Loch
+343 R Folio of Fancies
+344 R Gadwick, the Wizened
+345 M The Magic Mirror
+346 R Midnight Clock
+347 R Mirrormade
+348 R Stolen by the Fae
+349 R Vantress Gargoyle
+350 R Ayara, First of Locthwain
+351 R Blacklance Paragon
+352 M The Cauldron of Eternity
+353 R Clackbridge Troll
+354 R Oathsworn Knight
+355 R Piper of the Swarm
+356 M Rankle, Master of Pranks
+357 R Wishclaw Talisman
+358 R Witch's Vengeance
+359 M Embercleave
+360 R Fervent Champion
+361 R Fires of Invention
+362 R Irencrag Feat
+363 R Irencrag Pyromancer
+364 R Opportunistic Dragon
+365 M Robber of the Rich
+366 R Sundering Stroke
+367 R Torbran, Thane of Red Fell
+368 R Feasting Troll King
+369 R Gilded Goose
+370 M The Great Henge
+371 R Once Upon a Time
+372 M Questing Beast
+373 R Return of the Wildspeaker
+374 R Wicked Wolf
+375 R Wildborn Preserver
+376 R Yorvo, Lord of Garenbrig
+377 R Dance of the Manse
+378 R Doom Foretold
+379 R Escape to the Wilds
+380 R Faeburrow Elder
+381 R Lochmere Serpent
+382 M Outlaws' Merriment
+383 R Stormfist Crusader
+384 R Sorcerous Spyglass
+385 R Stonecoil Serpent
+386 R Castle Ardenvale
+387 R Castle Embereth
+388 R Castle Garenbrig
+389 R Castle Locthwain
+390 R Castle Vantress
+391 R Fabled Passage
#Bundle promo
-R Piper of the Swarm
+392 R Piper of the Swarm
#Promo Pack
-U Glass Casket
-U Slaying Fire
-U Kenrith's Transformation
-U Improbable Alliance
-U Inspiring Veteran
+393 U Glass Casket
+394 U Slaying Fire
+395 U Kenrith's Transformation
+396 U Improbable Alliance
+397 U Inspiring Veteran
[tokens]
w_0_1_goat
diff --git a/forge-gui/res/editions/Weatherlight.txt b/forge-gui/res/editions/Weatherlight.txt
index 3689f4a2a66..1ef49097fbf 100644
--- a/forge-gui/res/editions/Weatherlight.txt
+++ b/forge-gui/res/editions/Weatherlight.txt
@@ -178,5 +178,5 @@ R Winding Canyons
R Xanthic Statue
C Zombie Scavengers
-[token]
+[tokens]
g_1_1_squirrel
\ No newline at end of file
diff --git a/forge-gui/res/formats/Casual/Brawl.txt b/forge-gui/res/formats/Casual/Brawl.txt
index 804db4799d5..63db92dec93 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:GRN, RNA, WAR, M20, ELD, THB
-Banned:Sorcerous Spyglass;Oko, Thief of Crowns
+Banned:Golos, Tireless Pilgrim; Oko, Thief of Crowns; Sorcerous Spyglass
diff --git a/forge-gui/res/formats/Sanctioned/Legacy.txt b/forge-gui/res/formats/Sanctioned/Legacy.txt
index 404a575f8cd..5d6162ad978 100644
--- a/forge-gui/res/formats/Sanctioned/Legacy.txt
+++ b/forge-gui/res/formats/Sanctioned/Legacy.txt
@@ -3,4 +3,4 @@ Name:Legacy
Order:105
Subtype:Legacy
Type:Sanctioned
-Banned:Adriana's Valor; Advantageous Proclamation; Assemble the Rank and Vile; Backup Plan; Brago's Favor; Deathrite Shaman; Double Stroke; Echoing Boon; Emissary's Ploy; Gitaxian Probe; Hired Heist; Hold the Perimeter; Hymn of the Wilds; Immediate Action; Incendiary Dissent; Iterative Analysis; Muzzio's Preparations; Natural Unity; Power Play; Secret Summoning; Secrets of Paradise; Sentinel Dispatch; Sovereign's Realm; Summoner's Bond; Unexpected Potential; Weight Advantage; Worldknit; Amulet of Quoz; Bronze Tablet; Contract from Below; Darkpact; Demonic Attorney; Jeweled Bird; Rebirth; Tempest Efreet; Timmerian Fiends; Ancestral Recall; Balance; Bazaar of Baghdad; Black Lotus; Channel; Chaos Orb; Demonic Consultation; Demonic Tutor; Dig Through Time; Earthcraft; Falling Star; Fastbond; Flash; Frantic Search; Goblin Recruiter; Gush; Hermit Druid; Imperial Seal; Library of Alexandria; Mana Crypt; Mana Drain; Mana Vault; Memory Jar; Mental Misstep; Mind Twist; Mind's Desire; Mishra's Workshop; Mox Emerald; Mox Jet; Mox Pearl; Mox Ruby; Mox Sapphire; Mystical Tutor; Necropotence; Oath of Druids; Sensei's Divining Top; Shahrazad; Skullclamp; Sol Ring; Strip Mine; Survival of the Fittest; Time Vault; Time Walk; Timetwister; Tinker; Tolarian Academy; Treasure Cruise; Vampiric Tutor; Wheel of Fortune; Windfall; Wrenn and Six; Yawgmoth's Bargain; Yawgmoth's Will
+Banned:Adriana's Valor; Advantageous Proclamation; Assemble the Rank and Vile; Backup Plan; Brago's Favor; Deathrite Shaman; Double Stroke; Echoing Boon; Emissary's Ploy; Gitaxian Probe; Hired Heist; Hold the Perimeter; Hymn of the Wilds; Immediate Action; Incendiary Dissent; Iterative Analysis; Muzzio's Preparations; Natural Unity; Power Play; Secret Summoning; Secrets of Paradise; Sentinel Dispatch; Sovereign's Realm; Summoner's Bond; Underworld Breach; Unexpected Potential; Weight Advantage; Worldknit; Amulet of Quoz; Bronze Tablet; Contract from Below; Darkpact; Demonic Attorney; Jeweled Bird; Rebirth; Tempest Efreet; Timmerian Fiends; Ancestral Recall; Balance; Bazaar of Baghdad; Black Lotus; Channel; Chaos Orb; Demonic Consultation; Demonic Tutor; Dig Through Time; Earthcraft; Falling Star; Fastbond; Flash; Frantic Search; Goblin Recruiter; Gush; Hermit Druid; Imperial Seal; Library of Alexandria; Mana Crypt; Mana Drain; Mana Vault; Memory Jar; Mental Misstep; Mind Twist; Mind's Desire; Mishra's Workshop; Mox Emerald; Mox Jet; Mox Pearl; Mox Ruby; Mox Sapphire; Mystical Tutor; Necropotence; Oath of Druids; Sensei's Divining Top; Shahrazad; Skullclamp; Sol Ring; Strip Mine; Survival of the Fittest; Time Vault; Time Walk; Timetwister; Tinker; Tolarian Academy; Treasure Cruise; Vampiric Tutor; Wheel of Fortune; Windfall; Wrenn and Six; Yawgmoth's Bargain; Yawgmoth's Will
diff --git a/forge-gui/res/formats/Sanctioned/Modern.txt b/forge-gui/res/formats/Sanctioned/Modern.txt
index 5f00bc45197..78faab16590 100644
--- a/forge-gui/res/formats/Sanctioned/Modern.txt
+++ b/forge-gui/res/formats/Sanctioned/Modern.txt
@@ -4,4 +4,4 @@ Order:103
Subtype:Modern
Type:Sanctioned
Sets:8ED, MRD, DST, 5DN, CHK, BOK, SOK, 9ED, RAV, GPT, DIS, CSP, TSP, TSB, PLC, FUT, 10E, LRW, EVE, SHM, MOR, ALA, CFX, ARB, M10, ZEN, WWK, ROE, M11, SOM, MBS, NPH, M12, ISD, DKA, AVR, M13, RTR, GTC, DGM, M14, THS, BNG, JOU, M15, KTK, FRF, DTK, MM2, ORI, BFZ, OGW, SOI, EMN, KLD, AER, AKH, W17, HOU, XLN, RIX, DOM, M19, G18, GRN, RNA, WAR, MH1, M20, ELD, THB
-Banned:Ancient Den; Birthing Pod; Blazing Shoal; Bridge from Below; Chrome Mox; Cloudpost; Dark Depths; Deathrite Shaman; Dig Through Time; Dread Return; Eye of Ugin; Faithless Looting; Gitaxian Probe; Glimpse of Nature; Golgari Grave-Troll; Great Furnace; Green Sun's Zenith; Hogaak, Arisen Necropolis; Hypergenesis; Krark-Clan Ironworks; Mental Misstep; Mox Opal; Mycosynth Lattice; Oko, Thief of Crowns; Ponder; Preordain; Punishing Fire; Rite of Flame; Seat of the Synod; Second Sunrise; Seething Song; Sensei's Divining Top; Skullclamp; Splinter Twin; Summer Bloom; Treasure Cruise; Tree of Tales; Umezawa's Jitte; Vault of Whispers
+Banned:Ancient Den; Birthing Pod; Blazing Shoal; Bridge from Below; Chrome Mox; Cloudpost; Dark Depths; Deathrite Shaman; Dig Through Time; Dread Return; Eye of Ugin; Faithless Looting; Gitaxian Probe; Glimpse of Nature; Golgari Grave-Troll; Great Furnace; Green Sun's Zenith; Hogaak, Arisen Necropolis; Hypergenesis; Krark-Clan Ironworks; Mental Misstep; Mox Opal; Mycosynth Lattice; Oko, Thief of Crowns; Once Upon A Time; Ponder; Preordain; Punishing Fire; Rite of Flame; Seat of the Synod; Second Sunrise; Seething Song; Sensei's Divining Top; Skullclamp; Splinter Twin; Summer Bloom; Treasure Cruise; Tree of Tales; Umezawa's Jitte; Vault of Whispers
diff --git a/forge-gui/res/languages/de-DE.properties b/forge-gui/res/languages/de-DE.properties
index 48007ba7e84..c336f991d72 100644
--- a/forge-gui/res/languages/de-DE.properties
+++ b/forge-gui/res/languages/de-DE.properties
@@ -50,6 +50,8 @@ btnResetJavaFutureCompatibilityWarnings=Java-Kompatibilitätswarnung zurücksetz
btnClearImageCache=Leere Bildspeicher
btnTokenPreviewer=Spielstein-Vorschau
btnCopyToClipboard=In Zwischenablage kopieren
+cbpAutoUpdater=Auto updater
+nlAutoUpdater=Select the release channel to use for updating Forge
cbpSelectLanguage=Sprache
nlSelectLanguage=Wähle Sprache (Ist noch in Arbeit und nur teilweise umgesetzt.) (Neustart ist erforderlich.)
cbRemoveSmall=Entferne kleine Kreaturen
@@ -180,6 +182,7 @@ KeyboardShortcuts=Tastenkombinationen
#VSubmenuAchievements.java
lblAchievements=Errungenschaften
#VSubmenuDownloaders.java
+btnCheckForUpdates=Check for Updates
btnDownloadSetPics=Bilder(LQ) Sets herunterladen
btnDownloadPicsHQ=Bilder(HQ) Karten herunterladen (Sehr langsam!)
btnDownloadPics=Bilder(LQ) Karten herunterladen
@@ -192,6 +195,7 @@ btnImportPictures=Daten importieren
btnHowToPlay=Wie man spielt
btnDownloadPrices=Kartenpreise herunterladen
btnLicensing=Lizenzhinweis
+lblCheckForUpdates=Check Forge server to see if there's a more recent release
lblDownloadPics=Lädt ein Standardbild pro Karte.
lblDownloadPicsHQ=Lädt ein HQ-Standardbild pro Karte.
lblDownloadSetPics=Lädt alle Bilder pro Karte. Eines für jedes Set, in welchem die Karte auftauchte.
diff --git a/forge-gui/res/languages/en-US.properties b/forge-gui/res/languages/en-US.properties
index 503298d25a2..7b149832456 100644
--- a/forge-gui/res/languages/en-US.properties
+++ b/forge-gui/res/languages/en-US.properties
@@ -50,6 +50,8 @@ btnResetJavaFutureCompatibilityWarnings=Reset Java Compatibility Warnings
btnClearImageCache=Clear Image Cache
btnTokenPreviewer=Token Previewer
btnCopyToClipboard=Copy to Clipboard
+cbpAutoUpdater=Auto updater
+nlAutoUpdater=Select the release channel to use for updating Forge
cbpSelectLanguage=Language
nlSelectLanguage=Select Language (Excluded Game part. Still a work in progress) (RESTART REQUIRED)
cbRemoveSmall=Remove Small Creatures
@@ -180,6 +182,7 @@ KeyboardShortcuts=Keyboard Shortcuts
#VSubmenuAchievements.java
lblAchievements=Achievements
#VSubmenuDownloaders.java
+btnCheckForUpdates=Check for Updates
btnDownloadSetPics=Download LQ Set Pictures
btnDownloadPicsHQ=Download HQ Card Pictures (Very Slow!)
btnDownloadPics=Download LQ Card Pictures
@@ -192,6 +195,7 @@ btnImportPictures=Import Data
btnHowToPlay=How To Play
btnDownloadPrices=Download Card Prices
btnLicensing=License Details
+lblCheckForUpdates=Check Forge server to see if there's a more recent release
lblDownloadPics=Download default card picture for each card.
lblDownloadPicsHQ=Download default card HQ picture for each card.
lblDownloadSetPics=Download all pictures of each card (one for each set the card appeared in)
diff --git a/forge-gui/res/languages/es-ES.properties b/forge-gui/res/languages/es-ES.properties
index 9c4ddf6ed92..29524d91269 100644
--- a/forge-gui/res/languages/es-ES.properties
+++ b/forge-gui/res/languages/es-ES.properties
@@ -50,6 +50,8 @@ btnResetJavaFutureCompatibilityWarnings=Restablecer las advertencias de compatib
btnClearImageCache=Limpiar Caché de Imágenes
btnTokenPreviewer=Previsualizador de Fichas (Token)
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
@@ -180,6 +182,7 @@ KeyboardShortcuts=Atajos de teclado
#VSubmenuAchievements.java
lblAchievements=Logros
#VSubmenuDownloaders.java
+btnCheckForUpdates=Comprobar Actualizaciones
btnDownloadSetPics=Descargar todas las Ediciones de Cartas
btnDownloadPics=Descargar todas las Cartas
btnDownloadPicsHQ=Descargar todas las Cartas en calidad alta (Muy lento!)
@@ -192,6 +195,7 @@ btnImportPictures=Importar Datos
btnHowToPlay=Cómo jugar (Inglés)
btnDownloadPrices=Descargar los precios de las cartas
btnLicensing=Detalles de la licencia
+lblCheckForUpdates=Comprueba si en el servidor de Forge existe alguna versión más reciente
lblDownloadPics=Descargar la imagen de la carta por defecto para cada carta.
lblDownloadPicsHQ=Descargar la imagen en calidad alta de la carta por defecto para cada carta.
lblDownloadSetPics=Descargue todas las imágenes de cada carta (una por cada edición donde apareció la carta)
diff --git a/forge-gui/res/languages/it-IT.properties b/forge-gui/res/languages/it-IT.properties
index 5b059135cd4..c260b57b87c 100644
--- a/forge-gui/res/languages/it-IT.properties
+++ b/forge-gui/res/languages/it-IT.properties
@@ -50,6 +50,8 @@ btnResetJavaFutureCompatibilityWarnings=Ripristina avvisi di compatibilità Java
btnClearImageCache=Cancella cache immagini
btnTokenPreviewer=Anteprima token
btnCopyToClipboard=Copia negli appunti
+cbpAutoUpdater=Auto updater
+nlAutoUpdater=Select the release channel to use for updating Forge
cbpSelectLanguage=Lingua
nlSelectLanguage=Seleziona la lingua (parte di gioco esclusa. Ancora in fase di sviluppo) (RIAVVIO NECESSARIO)
cbRemoveSmall=Rimuovi le piccole creature
@@ -180,6 +182,7 @@ KeyboardShortcuts=Tasti rapidi
#VSubmenuAchievements.java
lblAchievements=realizzazioni
#VSubmenuDownloaders.java
+btnCheckForUpdates=Check for Updates
btnDownloadSetPics=Scarica LQ Set Pictures
btnDownloadPicsHQ=Scarica le immagini della scheda HQ (molto lento!)
btnDownloadPics=Scarica LQ Card Pictures
@@ -192,6 +195,7 @@ btnImportPictures=Importa dati
btnHowToPlay=Come giocare
btnDownloadPrices=Scarica i prezzi delle carte
btnLicensing=Dettagli della licenza
+lblCheckForUpdates=Check Forge server to see if there's a more recent release
lblDownloadPics=Scarica l''immagine della carta predefinita per ogni carta.
lblDownloadPicsHQ=Scarica l''immagine HQ della scheda predefinita per ogni scheda.
lblDownloadSetPics=Scarica tutte le immagini di ogni carta (una per ogni set in cui è apparso la carta)
diff --git a/forge-gui/res/languages/zh-CN.properties b/forge-gui/res/languages/zh-CN.properties
index 409c129d0e7..c72c559cbac 100644
--- a/forge-gui/res/languages/zh-CN.properties
+++ b/forge-gui/res/languages/zh-CN.properties
@@ -50,6 +50,8 @@ btnResetJavaFutureCompatibilityWarnings=重置Java兼容性警告
btnClearImageCache=清除图片缓存
btnTokenPreviewer=衍生物预览器
btnCopyToClipboard=复制到剪切板
+cbpAutoUpdater=Auto updater
+nlAutoUpdater=Select the release channel to use for updating Forge
cbpSelectLanguage=语言
nlSelectLanguage=选择语言(除了正在进行中的游戏)(需要重新启动)
cbRemoveSmall=删除小生物
@@ -180,6 +182,7 @@ KeyboardShortcuts=键盘快捷键
#VSubmenuAchievements.java
lblAchievements=成就
#VSubmenuDownloaders.java
+btnCheckForUpdates=Check for Updates
btnDownloadSetPics=下载低清系列图
btnDownloadPicsHQ=下载高清卡图(这很慢!)
btnDownloadPics=下载低清卡图
@@ -192,6 +195,7 @@ btnImportPictures=导入数据
btnHowToPlay=如何玩
btnDownloadPrices=下载卡牌价格
btnLicensing=许可证详情
+lblCheckForUpdates=Check Forge server to see if there's a more recent release
lblDownloadPics=下载缺省牌的图片
lblDownloadPicsHQ=下载缺省牌的高清图片
lblDownloadSetPics=下载每张牌的图片(每张牌出现一次)
diff --git a/forge-gui/res/puzzle/PS_THB6.pzl b/forge-gui/res/puzzle/PS_THB6.pzl
new file mode 100644
index 00000000000..0fb3f36c66e
--- /dev/null
+++ b/forge-gui/res/puzzle/PS_THB6.pzl
@@ -0,0 +1,18 @@
+[metadata]
+Name:Possibility Storm - Theros Beyond Death #06
+URL:https://i0.wp.com/www.possibilitystorm.com/wp-content/uploads/2020/02/149.-THB6-1-scaled.jpg
+Goal:Win
+Turns:1
+Difficulty:Uncommon
+Description:Win this turn. Assume any unknown cards drawn by either player are not relevant to solving the puzzle. Your opponent starts with 13 cards in their library. Your opponent has a Pollenbright Druid on top of their library, and twelve other unknown cards in it.
+[state]
+humanlife=20
+ailife=18
+turn=1
+activeplayer=human
+activephase=MAIN1
+humanhand=Assassin's Trophy;Unmoored Ego;Applied Biomancy;Underworld Dreams;Tyrant's Scorn
+humanlibrary=Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt
+humanbattlefield=Ob Nixilis, the Hate-Twisted|Counters:LOYALTY=2;Nessian Boar;Thief of Sanity;Thief of Sanity;Watery Grave|NoETBTrigs;Watery Grave|NoETBTrigs;Watery Grave|NoETBTrigs;Watery Grave|NoETBTrigs;Breeding Pool|NoETBTrigs;Breeding Pool|NoETBTrigs;Breeding Pool|NoETBTrigs
+ailibrary=Pollenbright Druid;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt
+aibattlefield=Silhana Wayfinder;Silhana Wayfinder;Blightbeetle;Wavebreak Hippocamp
diff --git a/forge-gui/res/puzzle/PS_THB7.pzl b/forge-gui/res/puzzle/PS_THB7.pzl
new file mode 100644
index 00000000000..bd9f0a62678
--- /dev/null
+++ b/forge-gui/res/puzzle/PS_THB7.pzl
@@ -0,0 +1,16 @@
+[metadata]
+Name:Possibility Storm - Theros Beyond Death #07
+URL:https://i2.wp.com/www.possibilitystorm.com/wp-content/uploads/2020/03/150.-THB7-scaled.jpg
+Goal:Win
+Turns:100
+Difficulty:Mythic
+Description:It's your OPPONENT'S turn (first main phase), and you need to win before you lose. Can you do it? Your opponent has no cards in hand and no available mana (assume they just tapped out to cast Goblin Assault Team). You control your opponent's Dreadhorde Butcher with The Akroan War's first chapter ability. Assume the puzzle starts with no cards in either player's graveyard.
+[state]
+humanlife=3
+ailife=11
+turn=1
+activeplayer=ai
+activephase=MAIN1
+humanhand=Lazotep Plating;Slaying Fire;So Tiny;Shock;Gideon's Triumph;Aspect of Manticore
+humanbattlefield=The Akroan War|Counters:LORE=2|ExecuteScript:DBGainControl->1;Blood Aspirant;Flux Channeler;Naiad of Hidden Coves;Temple of Enlightenment|NoETBTrigs;Temple of Enlightenment|NoETBTrigs;Sacred Foundry|NoETBTrigs;Sacred Foundry|NoETBTrigs
+aibattlefield=Underworld Dreams;Underworld Dreams;Underworld Dreams;Ferocity of the Wilds;Goblin Assault Team;Temple Thief;Mire Triton;Dreadhorde Butcher|Id:1
diff --git a/forge-gui/res/skins/darkred/bg_match.jpg b/forge-gui/res/skins/darkred/bg_match.jpg
index f926fee0812..fb7c0298072 100644
Binary files a/forge-gui/res/skins/darkred/bg_match.jpg and b/forge-gui/res/skins/darkred/bg_match.jpg differ
diff --git a/forge-gui/res/skins/default/font1.ttf b/forge-gui/res/skins/default/font1.ttf
index 4b4ecc66671..8723f9e2252 100644
Binary files a/forge-gui/res/skins/default/font1.ttf and b/forge-gui/res/skins/default/font1.ttf differ
diff --git a/forge-gui/res/skins/default/sprite_border.png b/forge-gui/res/skins/default/sprite_border.png
index c6be80f099a..4fe259b55c7 100644
Binary files a/forge-gui/res/skins/default/sprite_border.png and b/forge-gui/res/skins/default/sprite_border.png differ
diff --git a/forge-gui/res/skins/default/sprite_icons.png b/forge-gui/res/skins/default/sprite_icons.png
index 7cff5a518d1..384ae908ccf 100644
Binary files a/forge-gui/res/skins/default/sprite_icons.png and b/forge-gui/res/skins/default/sprite_icons.png differ
diff --git a/forge-gui/res/skins/default/sprite_manaicons.png b/forge-gui/res/skins/default/sprite_manaicons.png
index 3b8f734e939..8cbbda13212 100644
Binary files a/forge-gui/res/skins/default/sprite_manaicons.png and b/forge-gui/res/skins/default/sprite_manaicons.png differ
diff --git a/forge-gui/res/tokenscripts/c_0_4_wall_defender.txt b/forge-gui/res/tokenscripts/c_0_4_a_wall_defender.txt
similarity index 67%
rename from forge-gui/res/tokenscripts/c_0_4_wall_defender.txt
rename to forge-gui/res/tokenscripts/c_0_4_a_wall_defender.txt
index 03a29952252..2b5be99e3e2 100644
--- a/forge-gui/res/tokenscripts/c_0_4_wall_defender.txt
+++ b/forge-gui/res/tokenscripts/c_0_4_a_wall_defender.txt
@@ -1,6 +1,6 @@
Name:Wall
ManaCost:no cost
-Types:Creature Wall
+Types:Artifact Creature Wall
PT:0/4
K:Defender
Oracle:Defender
diff --git a/forge-gui/src/main/java/forge/assets/FSkinProp.java b/forge-gui/src/main/java/forge/assets/FSkinProp.java
index 5468c1e2914..38edff0ea32 100644
--- a/forge-gui/src/main/java/forge/assets/FSkinProp.java
+++ b/forge-gui/src/main/java/forge/assets/FSkinProp.java
@@ -230,6 +230,15 @@ public enum FSkinProp {
ICO_QUEST_BIG_SWORD (new int[] {320, 1360, 160, 160}, PropType.ICON),
ICO_QUEST_BIG_BAG (new int[] {480, 1360, 160, 160}, PropType.ICON),
+ //menu icon
+ ICO_MENU_GALAXY (new int[] {0, 1520, 80, 80}, PropType.ICON),
+ ICO_MENU_STATS (new int[] {80, 1520, 80, 80}, PropType.ICON),
+ ICO_MENU_PUZZLE (new int[] {160, 1520, 80, 80}, PropType.ICON),
+ ICO_MENU_GAUNTLET (new int[] {240, 1520, 80, 80}, PropType.ICON),
+ ICO_MENU_SEALED (new int[] {320, 1520, 80, 80}, PropType.ICON),
+ ICO_MENU_DRAFT (new int[] {400, 1520, 80, 80}, PropType.ICON),
+ ICO_MENU_CONSTRUCTED (new int[] {480, 1520, 80, 80}, PropType.ICON),
+
//interface icons
ICO_QUESTION (new int[] {560, 800, 32, 32}, PropType.ICON),
ICO_INFORMATION (new int[] {592, 800, 32, 32}, PropType.ICON),
diff --git a/forge-gui/src/main/java/forge/download/AutoUpdater.java b/forge-gui/src/main/java/forge/download/AutoUpdater.java
new file mode 100644
index 00000000000..8d050efecef
--- /dev/null
+++ b/forge-gui/src/main/java/forge/download/AutoUpdater.java
@@ -0,0 +1,247 @@
+package forge.download;
+
+import com.google.common.collect.ImmutableList;
+import forge.GuiBase;
+import forge.model.FModel;
+import forge.properties.ForgePreferences;
+import forge.util.BuildInfo;
+import forge.util.FileUtil;
+import forge.util.WaitCallback;
+import forge.util.gui.SOptionPane;
+import org.apache.commons.lang3.StringUtils;
+
+import javax.swing.*;
+import java.awt.*;
+import java.io.File;
+import java.io.IOException;
+import java.net.*;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class AutoUpdater {
+ private final String SNAPSHOT_VERSION_INDEX = "https://snapshots.cardforge.org/";
+ private final String SNAPSHOT_VERSION_URL = "https://snapshots.cardforge.org/version.txt";
+ private final String SNAPSHOT_PACKAGE = "https://snapshots.cardforge.org/latest/";
+ private final String RELEASE_VERSION_URL = "https://releases.cardforge.org/forge/forge-gui-desktop/version.txt";
+ private final String RELEASE_PACKAGE = "https://releases.cardforge.org/latest/";
+ private final String RELEASE_MAVEN_METADATA = "https://releases.cardforge.org/forge/forge-gui-desktop/maven-metadata.xml";
+ private static final boolean VERSION_FROM_METADATA = true;
+ private static final String TMP_DIR = "tmp/";
+
+ public static String[] updateChannels = new String[]{ "none", "snapshot", "release"};
+
+ private boolean isLoading;
+ private String updateChannel;
+ private String version;
+ private String buildVersion;
+ private String versionUrlString;
+ private String packageUrl;
+ private String packagePath;
+
+ public AutoUpdater(boolean loading) {
+ // What do I need? Preferences? Splashscreen? UI? Skins?
+ isLoading = loading;
+ updateChannel = FModel.getPreferences().getPref(ForgePreferences.FPref.AUTO_UPDATE);
+ buildVersion = BuildInfo.getVersionString();
+ }
+
+ public boolean attemptToUpdate() {
+ if (!verifyUpdateable()) {
+ return false;
+ }
+ try {
+ if (downloadUpdate()) {
+ extractAndRestart();
+ }
+ } catch(IOException | URISyntaxException e) {
+ return false;
+ }
+ return true;
+ }
+
+ private void extractAndRestart() {
+ extractUpdate();
+ restartForge();
+ }
+
+ private boolean verifyUpdateable() {
+ if (buildVersion.contains("GIT")) {
+ //return false;
+ }
+
+ if (isLoading) {
+ // TODO This doesn't work yet, because FSkin isn't loaded at the time.
+ return false;
+ } else if (updateChannel.equals("none")) {
+ String message = "You haven't set an update channel. Do you want to check a channel now?";
+ List options = ImmutableList.of("Cancel", "release", "snapshot");
+ int option = SOptionPane.showOptionDialog(message, "Manual Check", null, options, 0);
+ if (option == 0) {
+ return false;
+ } else {
+ updateChannel = options.get(option);
+ }
+ }
+
+ if (buildVersion.contains("SNAPSHOT")) {
+ if (!updateChannel.equals("snapshot")) {
+ System.out.println("Snapshot build versions must use snapshot update channel to work");
+ return false;
+ }
+
+ versionUrlString = SNAPSHOT_VERSION_URL;
+ packageUrl = SNAPSHOT_PACKAGE;
+ } else {
+ versionUrlString = RELEASE_VERSION_URL;
+ packageUrl = RELEASE_PACKAGE;
+ }
+
+ // Check the internet connection
+ if (!testNetConnection()) {
+ return false;
+ }
+
+ // Download appropriate version file
+ return compareBuildWithLatestChannelVersion();
+ }
+
+ private boolean testNetConnection() {
+ try (Socket socket = new Socket()) {
+ InetSocketAddress address = new InetSocketAddress("releases.cardforge.org", 443);
+ socket.connect(address, 1000);
+ return true;
+ } catch (IOException e) {
+ return false; // Either timeout or unreachable or failed DNS lookup.
+ }
+ }
+
+ private boolean compareBuildWithLatestChannelVersion() {
+ try {
+ retrieveVersion();
+
+ if (StringUtils.isEmpty(version) ) {
+ return false;
+ }
+
+ if (buildVersion.equals(version)) {
+ return false;
+ }
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ // If version doesn't match, it's assummably newer.
+ return true;
+ }
+
+ private void retrieveVersion() throws MalformedURLException {
+ if (VERSION_FROM_METADATA) {
+ if (updateChannel.equals("release")) {
+ extractVersionFromMavenRelease();
+ } else {
+ extractVersionFromSnapshotIndex();
+ }
+ } else {
+ URL versionUrl = new URL(versionUrlString);
+ version = FileUtil.readFileToString(versionUrl);
+ }
+ }
+
+ private void extractVersionFromSnapshotIndex() throws MalformedURLException {
+ URL metadataUrl = new URL(SNAPSHOT_VERSION_INDEX);
+ String index = FileUtil.readFileToString(metadataUrl);
+
+ System.out.println(index);
+ Pattern p = Pattern.compile(">forge-(.*SNAPSHOT)");
+ Matcher m = p.matcher(index);
+ while(m.find()){
+ version = m.group(1);
+ }
+ }
+
+ private void extractVersionFromMavenRelease() throws MalformedURLException {
+ URL metadataUrl = new URL(RELEASE_MAVEN_METADATA);
+ String xml = FileUtil.readFileToString(metadataUrl);
+
+ Pattern p = Pattern.compile("(.*)");
+ Matcher m = p.matcher(xml);
+ while(m.find()){
+ version = m.group(1);
+ }
+ }
+
+ private boolean downloadUpdate() throws URISyntaxException, IOException {
+ // TODO Change the "auto" to be more auto.
+ if (isLoading) {
+ // We need to preload enough of a Skins to show a dialog and a button if we're in loading
+ // splashScreen.prepareForDialogs();
+ return downloadFromBrowser();
+ }
+
+ String message = "A new version of Forge is available (" + version + ").\n" +
+ "You are currently on version (" + buildVersion + ").\n\n" +
+ "Would you like to update to the new version now?";
+
+ final List options = ImmutableList.of("Update Now", "Update Later");
+ if (SOptionPane.showOptionDialog(message, "New Version Available", null, options, 0) == 0) {
+ return downloadFromForge();
+ }
+
+ return false;
+ }
+
+ private boolean downloadFromBrowser() throws URISyntaxException, IOException {
+ final Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null;
+ if (desktop != null && desktop.isSupported(Desktop.Action.BROWSE)) {
+ // Linking directly there will auto download, but won't auto-update
+ desktop.browse(new URI(packageUrl));
+ return true;
+ } else {
+ System.out.println("Download latest version: " + packageUrl);
+ return false;
+ }
+ }
+
+ private boolean downloadFromForge() {
+ WaitCallback callback = new WaitCallback() {
+ @Override
+ public void run() {
+ GuiBase.getInterface().download(new GuiDownloadZipService("Auto Updater", "Download the new version..", packageUrl, "tmp/", null, null) {
+ @Override
+ public void downloadAndUnzip() {
+ packagePath = download(version + "-upgrade.tar.bz2");
+ if (packagePath != null) {
+ extractAndRestart();
+ }
+ }
+ }, this);
+ }
+ };
+
+ SwingUtilities.invokeLater(callback);
+ //
+ return false;
+ }
+
+ private void extractUpdate() {
+ // TODOD Something like https://stackoverflow.com/questions/315618/how-do-i-extract-a-tar-file-in-java
+ final Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null;
+ if (desktop != null) {
+ try {
+ desktop.open(new File(packagePath).getParentFile());
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ } else {
+ System.out.println(packagePath);
+ }
+ }
+
+ private void restartForge() {
+ if (isLoading || SOptionPane.showConfirmDialog("Forge has been downloaded. You should extract the package and restart Forge for the new version.", "Exit now?")) {
+ System.exit(0);
+ }
+ }
+}
diff --git a/forge-gui/src/main/java/forge/download/GuiDownloadZipService.java b/forge-gui/src/main/java/forge/download/GuiDownloadZipService.java
index f1d1dc9b8d4..dd142b04cf4 100644
--- a/forge-gui/src/main/java/forge/download/GuiDownloadZipService.java
+++ b/forge-gui/src/main/java/forge/download/GuiDownloadZipService.java
@@ -73,72 +73,7 @@ public class GuiDownloadZipService extends GuiDownloadService {
String zipFilename = download("temp.zip");
if (zipFilename == null) { return; }
- //if assets.zip downloaded successfully, unzip into destination folder
- try {
- GuiBase.getInterface().preventSystemSleep(true); //prevent system from going into sleep mode while unzipping
-
- if (deleteFolder != null) {
- final File deleteDir = new File(deleteFolder);
- if (deleteDir.exists()) {
- //attempt to delete previous res directory if to be rebuilt
- progressBar.reset();
- progressBar.setDescription("Deleting old " + desc + "...");
- if (deleteFolder.equals(destFolder)) { //move zip file to prevent deleting it
- final String oldZipFilename = zipFilename;
- zipFilename = deleteDir.getParentFile().getAbsolutePath() + File.separator + "temp.zip";
- Files.move(new File(oldZipFilename), new File(zipFilename));
- }
- FileUtil.deleteDirectory(deleteDir);
- }
- }
-
- final ZipFile zipFile = new ZipFile(zipFilename);
- final Enumeration extends ZipEntry> entries = zipFile.entries();
-
- progressBar.reset();
- progressBar.setPercentMode(true);
- progressBar.setDescription("Extracting " + desc);
- progressBar.setMaximum(zipFile.size());
-
- FileUtil.ensureDirectoryExists(destFolder);
-
- int count = 0;
- int failedCount = 0;
- while (entries.hasMoreElements()) {
- if (cancel) { break; }
-
- try {
- final ZipEntry entry = entries.nextElement();
-
- final String path = destFolder + File.separator + entry.getName();
- if (entry.isDirectory()) {
- new File(path).mkdir();
- progressBar.setValue(++count);
- continue;
- }
- copyInputStream(zipFile.getInputStream(entry), path);
- progressBar.setValue(++count);
- filesExtracted++;
- }
- catch (final Exception e) { //don't quit out completely if an entry is not UTF-8
- progressBar.setValue(++count);
- failedCount++;
- }
- }
-
- if (failedCount > 0) {
- Log.error("Downloading " + desc, failedCount + " " + desc + " could not be extracted");
- }
-
- zipFile.close();
- new File(zipFilename).delete();
- }
- catch (final Exception e) {
- e.printStackTrace();
- }
- finally {
- GuiBase.getInterface().preventSystemSleep(false);
- }
+ extract(zipFilename);
}
public String download(final String filename) {
@@ -211,6 +146,75 @@ public class GuiDownloadZipService extends GuiDownloadService {
}
}
+ public void extract(String zipFilename) {
+ //if assets.zip downloaded successfully, unzip into destination folder
+ try {
+ GuiBase.getInterface().preventSystemSleep(true); //prevent system from going into sleep mode while unzipping
+
+ if (deleteFolder != null) {
+ final File deleteDir = new File(deleteFolder);
+ if (deleteDir.exists()) {
+ //attempt to delete previous res directory if to be rebuilt
+ progressBar.reset();
+ progressBar.setDescription("Deleting old " + desc + "...");
+ if (deleteFolder.equals(destFolder)) { //move zip file to prevent deleting it
+ final String oldZipFilename = zipFilename;
+ zipFilename = deleteDir.getParentFile().getAbsolutePath() + File.separator + "temp.zip";
+ Files.move(new File(oldZipFilename), new File(zipFilename));
+ }
+ FileUtil.deleteDirectory(deleteDir);
+ }
+ }
+
+ final ZipFile zipFile = new ZipFile(zipFilename);
+ final Enumeration extends ZipEntry> entries = zipFile.entries();
+
+ progressBar.reset();
+ progressBar.setPercentMode(true);
+ progressBar.setDescription("Extracting " + desc);
+ progressBar.setMaximum(zipFile.size());
+
+ FileUtil.ensureDirectoryExists(destFolder);
+
+ int count = 0;
+ int failedCount = 0;
+ while (entries.hasMoreElements()) {
+ if (cancel) { break; }
+
+ try {
+ final ZipEntry entry = entries.nextElement();
+
+ final String path = destFolder + File.separator + entry.getName();
+ if (entry.isDirectory()) {
+ new File(path).mkdir();
+ progressBar.setValue(++count);
+ continue;
+ }
+ copyInputStream(zipFile.getInputStream(entry), path);
+ progressBar.setValue(++count);
+ filesExtracted++;
+ }
+ catch (final Exception e) { //don't quit out completely if an entry is not UTF-8
+ progressBar.setValue(++count);
+ failedCount++;
+ }
+ }
+
+ if (failedCount > 0) {
+ Log.error("Downloading " + desc, failedCount + " " + desc + " could not be extracted");
+ }
+
+ zipFile.close();
+ new File(zipFilename).delete();
+ }
+ catch (final Exception e) {
+ e.printStackTrace();
+ }
+ finally {
+ GuiBase.getInterface().preventSystemSleep(false);
+ }
+ }
+
protected void copyInputStream(final InputStream in, final String outPath) throws IOException {
final byte[] buffer = new byte[1024];
int len;
diff --git a/forge-gui/src/main/java/forge/model/FModel.java b/forge-gui/src/main/java/forge/model/FModel.java
index d0c182e890c..a574d3cd493 100644
--- a/forge-gui/src/main/java/forge/model/FModel.java
+++ b/forge-gui/src/main/java/forge/model/FModel.java
@@ -28,6 +28,7 @@ import forge.card.CardType;
import forge.deck.CardArchetypeLDAGenerator;
import forge.deck.CardRelationMatrixGenerator;
import forge.deck.io.DeckPreferences;
+import forge.download.AutoUpdater;
import forge.game.GameFormat;
import forge.game.GameType;
import forge.game.card.CardUtil;
@@ -117,7 +118,6 @@ public final class FModel {
Localizer.getInstance().initialize(FModel.getPreferences().getPref(FPref.UI_LANGUAGE), ForgeConstants.LANG_DIR);
- //load card database
final ProgressObserver progressBarBridge = (progressBar == null) ?
ProgressObserver.emptyObserver : new ProgressObserver() {
@Override
@@ -143,6 +143,11 @@ public final class FModel {
}
};
+ if (new AutoUpdater(true).attemptToUpdate()) {
+ //
+ }
+
+ //load card database
final CardStorageReader reader = new CardStorageReader(ForgeConstants.CARD_DATA_DIR, progressBarBridge,
FModel.getPreferences().getPrefBoolean(FPref.LOAD_CARD_SCRIPTS_LAZILY));
final CardStorageReader tokenReader = new CardStorageReader(ForgeConstants.TOKEN_DATA_DIR, progressBarBridge,
@@ -220,8 +225,6 @@ public final class FModel {
achievements.put(GameType.Quest, new QuestAchievements());
achievements.put(GameType.PlanarConquest, new PlanarConquestAchievements());
achievements.put(GameType.Puzzle, new PuzzleAchievements());
-
-
//preload AI profiles
AiProfileUtil.loadAllProfiles(ForgeConstants.AI_PROFILE_DIR);
diff --git a/forge-gui/src/main/java/forge/net/ProtocolMethod.java b/forge-gui/src/main/java/forge/net/ProtocolMethod.java
index 4497b5cf0f9..642e79dec5c 100644
--- a/forge-gui/src/main/java/forge/net/ProtocolMethod.java
+++ b/forge-gui/src/main/java/forge/net/ProtocolMethod.java
@@ -75,7 +75,7 @@ public enum ProtocolMethod {
clearSelectables (Mode.SERVER),
refreshField (Mode.SERVER),
// TODO case "setPlayerAvatar":
- openZones (Mode.SERVER, PlayerZoneUpdates.class, Collection/*ZoneType*/.class, Map/*PlayerView,Object*/.class),
+ openZones (Mode.SERVER, PlayerZoneUpdates.class, PlayerView.class, Collection/*ZoneType*/.class, Map/*PlayerView,Object*/.class),
restoreOldZones (Mode.SERVER, Void.TYPE, PlayerView.class, PlayerZoneUpdates.class),
isUiSetToSkipPhase (Mode.SERVER, Boolean.TYPE, PlayerView.class, PhaseType.class),
setRememberedActions(Mode.SERVER, Void.TYPE),
diff --git a/forge-gui/src/main/java/forge/player/HumanPlaySpellAbility.java b/forge-gui/src/main/java/forge/player/HumanPlaySpellAbility.java
index a337db37099..36f124105a3 100644
--- a/forge-gui/src/main/java/forge/player/HumanPlaySpellAbility.java
+++ b/forge-gui/src/main/java/forge/player/HumanPlaySpellAbility.java
@@ -105,10 +105,7 @@ public class HumanPlaySpellAbility {
if (ability.isSpell() && !ability.isCastFaceDown() && fromState == CardStateName.FaceDown) {
c.turnFaceUp();
}
- c.setCastSA(ability);
- ability.setLastStateBattlefield(game.getLastStateBattlefield());
- ability.setLastStateGraveyard(game.getLastStateGraveyard());
- ability.setHostCard(game.getAction().moveToStack(c, null));
+ ability.setHostCard(game.getAction().moveToStack(c, ability));
}
if (!ability.isCopied()) {
diff --git a/forge-gui/src/main/java/forge/properties/ForgePreferences.java b/forge-gui/src/main/java/forge/properties/ForgePreferences.java
index f9b7c3329a4..c3001f43e0a 100644
--- a/forge-gui/src/main/java/forge/properties/ForgePreferences.java
+++ b/forge-gui/src/main/java/forge/properties/ForgePreferences.java
@@ -153,6 +153,7 @@ public class ForgePreferences extends PreferencesStore {
//TODO This should be removed after the update that requires Java 8.
DISABLE_DISPLAY_JAVA_8_UPDATE_WARNING("false"),
+ AUTO_UPDATE("none"),
USE_SENTRY("false"), // this controls whether automated bug reporting is done or not
MATCH_HOT_SEAT_MODE("false"), //this only applies to mobile game
diff --git a/forge-gui/src/main/java/forge/util/ImageFetcher.java b/forge-gui/src/main/java/forge/util/ImageFetcher.java
index cf219331dc8..ef83a64f414 100644
--- a/forge-gui/src/main/java/forge/util/ImageFetcher.java
+++ b/forge-gui/src/main/java/forge/util/ImageFetcher.java
@@ -6,6 +6,8 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import forge.FThreads;
import forge.ImageKeys;
@@ -45,21 +47,28 @@ public abstract class ImageFetcher {
final String filename = ImageUtil.getImageKey(paperCard, backFace, true);
destFile = new File(ForgeConstants.CACHE_CARD_PICS_DIR + "/" + filename + ".jpg");
- // First try to download the LQ Set URL, then fetch from scryfall/magiccards.info
+ // First try to download the LQ Set URL, then fetch from scryfall
StringBuilder setDownload = new StringBuilder(ForgeConstants.URL_PIC_DOWNLOAD);
setDownload.append(ImageUtil.getDownloadUrl(paperCard, backFace));
downloadUrls.add(setDownload.toString());
+ int artIndex = 1;
+ final Pattern pattern = Pattern.compile(
+ "^.:([^|]*\\|){2}(\\d+).*$"
+ );
+ Matcher matcher = pattern.matcher(imageKey);
+ if (matcher.matches()) {
+ artIndex = Integer.parseInt(matcher.group(2));
+ }
final StaticData data = StaticData.instance();
- final int cardNum = data.getCommonCards().getCardCollectorNumber(paperCard.getName(), paperCard.getEdition());
- if (cardNum != -1) {
+ final String cardNum = data.getCommonCards().getCardCollectorNumber(paperCard.getName(), paperCard.getEdition(), artIndex);
+ if (cardNum != null) {
String suffix = "";
if (paperCard.getRules().getOtherPart() != null) {
suffix = (backFace ? "b" : "a");
}
final String editionMciCode = data.getEditions().getMciCodeByCode(paperCard.getEdition());
- downloadUrls.add(String.format("https://img.scryfall.com/cards/normal/en/%s/%d%s.jpg", editionMciCode, cardNum, suffix));
- downloadUrls.add(String.format("https://magiccards.info/scans/en/%s/%d%s.jpg", editionMciCode, cardNum, suffix));
+ downloadUrls.add(String.format("https://img.scryfall.com/cards/normal/en/%s/%s%s.jpg", editionMciCode, cardNum, suffix));
}
} else if (prefix.equals(ImageKeys.TOKEN_PREFIX)) {
if (tokenImages == null) {