diff --git a/forge-ai/pom.xml b/forge-ai/pom.xml
index 3f176653a65..b8d21660c54 100644
--- a/forge-ai/pom.xml
+++ b/forge-ai/pom.xml
@@ -6,7 +6,7 @@
forgeforge
- 1.6.33-SNAPSHOT
+ 1.6.34-SNAPSHOTforge-ai
diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtil.java b/forge-ai/src/main/java/forge/ai/ComputerUtil.java
index ff73d875785..bec6e19c4d6 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));
}
@@ -2338,7 +2323,7 @@ public class ComputerUtil {
return chosen;
}
- public static Object vote(Player ai, List
* @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/Spell.java b/forge-game/src/main/java/forge/game/spellability/Spell.java
index 87fbb0d4e84..2978d406f34 100644
--- a/forge-game/src/main/java/forge/game/spellability/Spell.java
+++ b/forge-game/src/main/java/forge/game/spellability/Spell.java
@@ -75,12 +75,12 @@ public abstract class Spell extends SpellAbility implements java.io.Serializable
@Override
public boolean canPlay() {
Card card = this.getHostCard();
+ if (card.isInZone(ZoneType.Battlefield)) {
+ return false;
+ }
// Save the original cost and the face down info for a later check since the LKI copy will overwrite them
ManaCost origCost = card.getState(card.isFaceDown() ? CardStateName.Original : card.getCurrentStateName()).getManaCost();
- boolean wasFaceDownInstant = card.isFaceDown()
- && !card.getLastKnownZone().is(ZoneType.Battlefield)
- && card.getState(CardStateName.Original).getType().isInstant();
Player activator = this.getActivatingPlayer();
if (activator == null) {
@@ -95,61 +95,29 @@ public abstract class Spell extends SpellAbility implements java.io.Serializable
return false;
}
- boolean isInstant = card.isInstant();
- // special case for split cards
- if (card.isSplitCard()) {
- CardStateName name = isLeftSplit() ? CardStateName.LeftSplit : CardStateName.RightSplit;
- isInstant = card.getState(name).getType().isInstant();
- } else if (isAdventure()) {
- if (card.hasState(CardStateName.Adventure)) {
- isInstant = card.getState(CardStateName.Adventure).getType().isInstant();
- }
- }
-
boolean lkicheck = false;
- boolean flash = false;
// do performanceMode only for cases where the activator is different than controller
- if (!Spell.performanceMode && activator != null && !card.getController().equals(activator)
- && !card.isInZone(ZoneType.Battlefield)) {
+ if (!Spell.performanceMode && activator != null && !card.getController().equals(activator)) {
// always make a lki copy in this case?
card = CardUtil.getLKICopy(card);
card.setController(activator, 0);
lkicheck = true;
}
- if (isBestow() && !card.isBestowed() && !card.isInZone(ZoneType.Battlefield)) {
- // Rule 601.3: cast Bestow with Flash
- // for the check the card does need to be animated
- // otherwise the StaticAbility will not found them
- if (!card.isLKI()) {
- card = CardUtil.getLKICopy(card);
- }
- card.animateBestow(false);
- lkicheck = true;
- } else if (isCastFaceDown()) {
- // need a copy of the card to turn facedown without trigger anything
- if (!card.isLKI()) {
- card = CardUtil.getLKICopy(card);
- }
- card.turnFaceDownNoUpdate();
- lkicheck = true;
- } else if (isAdventure()) {
- if (!card.isLKI()) {
- card = CardUtil.getLKICopy(card);
- }
-
- card.setState(CardStateName.Adventure, false);
+ Card lkiHost = getAlternateHost(card);
+ if (lkiHost != null) {
+ card = lkiHost;
lkicheck = true;
}
-
if (lkicheck) {
game.getTracker().freeze(); //prevent views flickering during while updating for state-based effects
game.getAction().checkStaticAbilities(false, Sets.newHashSet(card), new CardCollection(card));
}
- flash = card.withFlash(activator);
+ boolean isInstant = card.isInstant();
+ boolean flash = card.withFlash(activator);
// reset static abilities
if (lkicheck) {
@@ -160,8 +128,7 @@ public abstract class Spell extends SpellAbility implements java.io.Serializable
}
if (!(isInstant || activator.canCastSorcery() || flash || getRestrictions().isInstantSpeed()
- || hasSVar("IsCastFromPlayEffect")
- || wasFaceDownInstant)) {
+ || hasSVar("IsCastFromPlayEffect"))) {
return false;
}
@@ -235,4 +202,74 @@ public abstract class Spell extends SpellAbility implements java.io.Serializable
this.castFaceDown = faceDown;
}
+ public Card getAlternateHost(Card source) {
+ boolean lkicheck = false;
+
+ // need to be done before so it works with Vivien and Zoetic Cavern
+ if (source.isFaceDown() && source.isInZone(ZoneType.Exile)) {
+ if (!source.isLKI()) {
+ source = CardUtil.getLKICopy(source);
+ }
+
+ source.turnFaceUp(false, false);
+ lkicheck = true;
+ }
+
+ if (isBestow() && !source.isBestowed()) {
+ if (!source.isLKI()) {
+ source = CardUtil.getLKICopy(source);
+ }
+
+ source.animateBestow(false);
+ lkicheck = true;
+ } else if (isCastFaceDown()) {
+ // need a copy of the card to turn facedown without trigger anything
+ if (!source.isLKI()) {
+ source = CardUtil.getLKICopy(source);
+ }
+ source.turnFaceDownNoUpdate();
+ lkicheck = true;
+ } else if (isAdventure()) {
+ if (!source.isLKI()) {
+ source = CardUtil.getLKICopy(source);
+ }
+
+ source.setState(CardStateName.Adventure, false);
+
+ // need to reset CMC
+ source.setLKICMC(-1);
+ source.setLKICMC(source.getCMC());
+ lkicheck = true;
+ } else if (source.isSplitCard() && (isLeftSplit() || isRightSplit())) {
+ if (!source.isLKI()) {
+ source = CardUtil.getLKICopy(source);
+ }
+ if (isLeftSplit()) {
+ if (!source.hasState(CardStateName.LeftSplit)) {
+ source.addAlternateState(CardStateName.LeftSplit, false);
+ source.getState(CardStateName.LeftSplit).copyFrom(
+ getHostCard().getState(CardStateName.LeftSplit), true);
+ }
+
+ source.setState(CardStateName.LeftSplit, false);
+ }
+
+ if (isRightSplit()) {
+ if (!source.hasState(CardStateName.RightSplit)) {
+ source.addAlternateState(CardStateName.RightSplit, false);
+ source.getState(CardStateName.RightSplit).copyFrom(
+ getHostCard().getState(CardStateName.RightSplit), true);
+ }
+
+ source.setState(CardStateName.RightSplit, false);
+ }
+
+ // need to reset CMC
+ source.setLKICMC(-1);
+ source.setLKICMC(source.getCMC());
+ lkicheck = true;
+ }
+
+ return lkicheck ? source : null;
+ }
}
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/game/staticability/StaticAbility.java b/forge-game/src/main/java/forge/game/staticability/StaticAbility.java
index f8442310ec0..421edc80b60 100644
--- a/forge-game/src/main/java/forge/game/staticability/StaticAbility.java
+++ b/forge-game/src/main/java/forge/game/staticability/StaticAbility.java
@@ -181,15 +181,9 @@ public class StaticAbility extends CardTraitBase implements IIdentifiable, Clone
layers.add(StaticAbilityLayer.MODIFYPT);
}
- if (hasParam("AddHiddenKeyword")) {
- layers.add(StaticAbilityLayer.RULES);
- }
-
- if (hasParam("IgnoreEffectCost") || hasParam("Goad") || hasParam("CanBlockAny") || hasParam("CanBlockAmount")) {
- layers.add(StaticAbilityLayer.RULES);
- }
-
- if (hasParam("AdjustLandPlays")) {
+ if (hasParam("AddHiddenKeyword")
+ || hasParam("IgnoreEffectCost") || hasParam("Goad") || hasParam("CanBlockAny") || hasParam("CanBlockAmount")
+ || hasParam("AdjustLandPlays") || hasParam("ControlVote") || hasParam("AdditionalVote") || hasParam("AdditionalOptionalVote")) {
layers.add(StaticAbilityLayer.RULES);
}
diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java b/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java
index f0b0813bfc3..f6d8a9b6984 100644
--- a/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java
+++ b/forge-game/src/main/java/forge/game/staticability/StaticAbilityContinuous.java
@@ -513,6 +513,20 @@ public final class StaticAbilityContinuous {
}
}
+ if (params.containsKey("ControlVote")) {
+ p.addControlVote(se.getTimestamp());
+ }
+ if (params.containsKey("AdditionalVote")) {
+ String mhs = params.get("AdditionalVote");
+ int add = AbilityUtils.calculateAmount(hostCard, mhs, stAb);
+ p.addAdditionalVote(se.getTimestamp(), add);
+ }
+ if (params.containsKey("AdditionalOptionalVote")) {
+ String mhs = params.get("AdditionalOptionalVote");
+ int add = AbilityUtils.calculateAmount(hostCard, mhs, stAb);
+ p.addAdditionalOptionalVote(se.getTimestamp(), add);
+ }
+
if (params.containsKey("RaiseMaxHandSize")) {
String rmhs = params.get("RaiseMaxHandSize");
int rmax = AbilityUtils.calculateAmount(hostCard, rmhs, stAb);
diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerHandler.java b/forge-game/src/main/java/forge/game/trigger/TriggerHandler.java
index 8dfcc69f698..33a8e48663e 100644
--- a/forge-game/src/main/java/forge/game/trigger/TriggerHandler.java
+++ b/forge-game/src/main/java/forge/game/trigger/TriggerHandler.java
@@ -274,7 +274,7 @@ public class TriggerHandler {
}
private void runStateTrigger(final Map runParams) {
- for (final Trigger t: activeTriggers) {
+ for (final Trigger t: Lists.newArrayList(activeTriggers)) {
if (canRunTrigger(t, TriggerType.Always, runParams)) {
runSingleTrigger(t, runParams);
}
@@ -542,13 +542,20 @@ public class TriggerHandler {
}
sa = AbilityFactory.getAbility(host, name);
+ // need to set as Overriding Abiltiy so it can be copied better
+ regtrig.setOverridingAbility(sa);
+ }
+ sa.setActivatingPlayer(host.getController());
+
+ if (regtrig.isIntrinsic()) {
+ sa.setIntrinsic(true);
+ sa.changeText();
}
} else {
// need to copy the SA because of TriggeringObjects
- sa = sa.copy();
+ sa = sa.copy(host, host.getController(), false);
}
- sa.setHostCard(host);
sa.setLastStateBattlefield(game.getLastStateBattlefield());
sa.setLastStateGraveyard(game.getLastStateGraveyard());
@@ -560,9 +567,7 @@ public class TriggerHandler {
sa.setTriggeringObjects(regtrig.getStoredTriggeredObjects());
}
- if (sa.getActivatingPlayer() == null) { // overriding delayed trigger should have set activator
- sa.setActivatingPlayer(host.getController());
- } else if (sa.getDeltrigActivatingPlayer() != null) {
+ if (sa.getDeltrigActivatingPlayer() != null) {
// make sure that the original delayed trigger activator is restored
// (may have been overwritten by the AI simulation routines, e.g. Rainbow Vale)
sa.setActivatingPlayer(sa.getDeltrigActivatingPlayer());
@@ -577,11 +582,6 @@ public class TriggerHandler {
host.addRemembered(sa.getActivatingPlayer());
}
- if (regtrig.isIntrinsic() && regtrig.getOverridingAbility() == null) {
- sa.setIntrinsic(true);
- sa.changeText();
- }
-
sa.setStackDescription(sa.toString());
if (sa.getApi() == ApiType.Charm && !sa.isWrapper()) {
if (!CharmEffect.makeChoices(sa)) {
diff --git a/forge-game/src/main/java/forge/trackable/TrackableProperty.java b/forge-game/src/main/java/forge/trackable/TrackableProperty.java
index 742ab344d9f..039085ee9d0 100644
--- a/forge-game/src/main/java/forge/trackable/TrackableProperty.java
+++ b/forge-game/src/main/java/forge/trackable/TrackableProperty.java
@@ -134,8 +134,12 @@ public enum TrackableProperty {
HasUnlimitedLandPlay(TrackableTypes.BooleanType),
NumLandThisTurn(TrackableTypes.IntegerType),
NumDrawnThisTurn(TrackableTypes.IntegerType),
+ AdditionalVote(TrackableTypes.IntegerType),
+ OptionalAdditionalVote(TrackableTypes.IntegerType),
+ ControlVotes(TrackableTypes.BooleanType),
Keywords(TrackableTypes.KeywordCollectionViewType, FreezeMode.IgnoresFreeze),
Commander(TrackableTypes.CardViewCollectionType, FreezeMode.IgnoresFreeze),
+ CommanderCast(TrackableTypes.IntegerMapType),
CommanderDamage(TrackableTypes.IntegerMapType),
MindSlaveMaster(TrackableTypes.PlayerViewType),
Ante(TrackableTypes.CardViewCollectionType, FreezeMode.IgnoresFreeze),
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..854f9159678 100644
--- a/forge-gui-android/pom.xml
+++ b/forge-gui-android/pom.xml
@@ -19,7 +19,7 @@
forgeforge
- 1.6.33-SNAPSHOT
+ 1.6.34-SNAPSHOTforge-gui-android
@@ -142,7 +142,7 @@
true
- 25
+ 26true${project.basedir}/AndroidManifest.xml
@@ -183,7 +183,7 @@
false
- 25
+ 26false
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/pom.xml b/forge-gui-desktop/pom.xml
index c2bb8f2388f..e1fa8d95747 100644
--- a/forge-gui-desktop/pom.xml
+++ b/forge-gui-desktop/pom.xml
@@ -4,7 +4,7 @@
forgeforge
- 1.6.33-SNAPSHOT
+ 1.6.34-SNAPSHOTforge-gui-desktop
@@ -213,7 +213,7 @@
com.akathist.maven.plugins.launch4jlaunch4j-maven-plugin
- 1.5.2
+ 1.7.25l4j-gui
@@ -235,7 +235,10 @@
1.8.0
- 1024
+ 4096
+
+ -Dfile.encoding=UTF-8
+
@@ -367,7 +370,7 @@
com.akathist.maven.plugins.launch4jlaunch4j-maven-plugin
- 1.5.2
+ 1.7.25l4j-gui
@@ -389,7 +392,10 @@
1.8.0
- 1024
+ 4096
+
+ -Dfile.encoding=UTF-8
+
@@ -564,7 +570,7 @@
-
+
@@ -675,7 +681,7 @@
-
+
diff --git a/forge-gui-desktop/src/main/config/forge.command b/forge-gui-desktop/src/main/config/forge.command
index e6068616734..1e3165f2ed0 100644
--- a/forge-gui-desktop/src/main/config/forge.command
+++ b/forge-gui-desktop/src/main/config/forge.command
@@ -1,3 +1,3 @@
#!/bin/sh
-cd "`dirname \"$0\"`"
-java -Xmx1024m -jar $project.build.finalName$
\ No newline at end of file
+cd $(dirname "${0}")
+java -Xmx4096m -Dfile.encoding=UTF-8 -jar $project.build.finalName$
diff --git a/forge-gui-desktop/src/main/config/forge.sh b/forge-gui-desktop/src/main/config/forge.sh
index e6068616734..1e3165f2ed0 100644
--- a/forge-gui-desktop/src/main/config/forge.sh
+++ b/forge-gui-desktop/src/main/config/forge.sh
@@ -1,3 +1,3 @@
#!/bin/sh
-cd "`dirname \"$0\"`"
-java -Xmx1024m -jar $project.build.finalName$
\ No newline at end of file
+cd $(dirname "${0}")
+java -Xmx4096m -Dfile.encoding=UTF-8 -jar $project.build.finalName$
diff --git a/forge-gui-desktop/src/main/java/forge/itemmanager/views/DeckStarRenderer.java b/forge-gui-desktop/src/main/java/forge/itemmanager/views/DeckStarRenderer.java
index 15abb763f65..cd6e641c425 100644
--- a/forge-gui-desktop/src/main/java/forge/itemmanager/views/DeckStarRenderer.java
+++ b/forge-gui-desktop/src/main/java/forge/itemmanager/views/DeckStarRenderer.java
@@ -82,7 +82,7 @@ public class DeckStarRenderer extends ItemCellRenderer {
}
else if (DeckPreferences.getPrefs(deck).getStarCount() == 0) {
this.setToolTipText("Click to add " + deck.getName() + " to your favorites");
- skinImage = FSkin.getImage(FSkinProp.IMG_STAR_OUTINE);
+ skinImage = FSkin.getImage(FSkinProp.IMG_STAR_OUTLINE);
}
else { //TODO: consider supporting more than 1 star
this.setToolTipText("Click to remove " + deck.getName() + " from your favorites");
diff --git a/forge-gui-desktop/src/main/java/forge/itemmanager/views/StarRenderer.java b/forge-gui-desktop/src/main/java/forge/itemmanager/views/StarRenderer.java
index 197e791d894..be64ea0bf4d 100644
--- a/forge-gui-desktop/src/main/java/forge/itemmanager/views/StarRenderer.java
+++ b/forge-gui-desktop/src/main/java/forge/itemmanager/views/StarRenderer.java
@@ -83,7 +83,7 @@ public class StarRenderer extends ItemCellRenderer {
}
else if (CardPreferences.getPrefs(card).getStarCount() == 0) {
this.setToolTipText("Click to add " + card.getName() + " to your favorites");
- skinImage = FSkin.getImage(FSkinProp.IMG_STAR_OUTINE);
+ skinImage = FSkin.getImage(FSkinProp.IMG_STAR_OUTLINE);
}
else { //TODO: consider supporting more than 1 star
this.setToolTipText("Click to remove " + card.getName() + " from your favorites");
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/toolbox/FSkin.java b/forge-gui-desktop/src/main/java/forge/toolbox/FSkin.java
index beaa4601708..c400fdee48d 100644
--- a/forge-gui-desktop/src/main/java/forge/toolbox/FSkin.java
+++ b/forge-gui-desktop/src/main/java/forge/toolbox/FSkin.java
@@ -1162,7 +1162,7 @@ public class FSkin {
}
final Localizer localizer = Localizer.getInstance();
- FView.SINGLETON_INSTANCE.setSplashProgessBarMessage(localizer.getMessage("splash.loading.processingimagesprites") + ": ", 8);
+ FView.SINGLETON_INSTANCE.setSplashProgessBarMessage(localizer.getMessage("splash.loading.processingimagesprites") + ": ", 12);
// Grab and test various sprite files.
final String defaultDir = ForgeConstants.DEFAULT_SKINS_DIR;
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-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java b/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java
index c9ee0f75d17..921b860fc40 100644
--- a/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java
+++ b/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java
@@ -486,7 +486,7 @@ public class PlayerControllerForTests extends PlayerController {
}
@Override
- public Object vote(SpellAbility sa, String prompt, List options, ListMultimap votes) {
+ public Object vote(SpellAbility sa, String prompt, List options, ListMultimap votes, Player forPlayer) {
return chooseItem(options);
}
diff --git a/forge-gui-ios/pom.xml b/forge-gui-ios/pom.xml
index a19f7f51625..eee4ce43c2f 100644
--- a/forge-gui-ios/pom.xml
+++ b/forge-gui-ios/pom.xml
@@ -12,7 +12,7 @@
forgeforge
- 1.6.33-SNAPSHOT
+ 1.6.34-SNAPSHOTforge-gui-ios
diff --git a/forge-gui-mobile-dev/pom.xml b/forge-gui-mobile-dev/pom.xml
index bd8d76b98ca..68270592ec9 100644
--- a/forge-gui-mobile-dev/pom.xml
+++ b/forge-gui-mobile-dev/pom.xml
@@ -4,7 +4,7 @@
forgeforge
- 1.6.33-SNAPSHOT
+ 1.6.34-SNAPSHOTforge-gui-mobile-dev
diff --git a/forge-gui-mobile/pom.xml b/forge-gui-mobile/pom.xml
index 3a950b4f673..9062150762e 100644
--- a/forge-gui-mobile/pom.xml
+++ b/forge-gui-mobile/pom.xml
@@ -4,7 +4,7 @@
forgeforge
- 1.6.33-SNAPSHOT
+ 1.6.34-SNAPSHOTforge-gui-mobile
diff --git a/forge-gui-mobile/src/forge/Forge.java b/forge-gui-mobile/src/forge/Forge.java
index 044f6b4ef31..0b1121707a0 100644
--- a/forge-gui-mobile/src/forge/Forge.java
+++ b/forge-gui-mobile/src/forge/Forge.java
@@ -66,6 +66,8 @@ public class Forge implements ApplicationListener {
public static boolean enableUIMask = false;
public static boolean enablePreloadExtendedArt = false;
public static String locale = "en-US";
+ public static boolean hdbuttons = false;
+ public static boolean hdstart = false;
public static ApplicationListener getApp(Clipboard clipboard0, IDeviceAdapter deviceAdapter0, String assetDir0, boolean value) {
if (GuiBase.getInterface() == null) {
diff --git a/forge-gui-mobile/src/forge/assets/FSkin.java b/forge-gui-mobile/src/forge/assets/FSkin.java
index 4d64d273ee2..520c5e6a05c 100644
--- a/forge-gui-mobile/src/forge/assets/FSkin.java
+++ b/forge-gui-mobile/src/forge/assets/FSkin.java
@@ -90,6 +90,10 @@ public class FSkin {
public static void loadLight(String skinName, final SplashScreen splashScreen) {
preferredName = skinName.toLowerCase().replace(' ', '_');
+ //reset hd buttons/icons
+ Forge.hdbuttons = false;
+ Forge.hdstart = false;
+
//ensure skins directory exists
final FileHandle dir = Gdx.files.absolute(ForgeConstants.SKINS_DIR);
if (!dir.exists() || !dir.isDirectory()) {
@@ -190,6 +194,8 @@ public class FSkin {
final FileHandle f8 = getDefaultSkinFile(ForgeConstants.SPRITE_SLEEVES_FILE);
final FileHandle f9 = getDefaultSkinFile(ForgeConstants.SPRITE_SLEEVES2_FILE);
final FileHandle f10 = getDefaultSkinFile(ForgeConstants.SPRITE_BORDER_FILE);
+ final FileHandle f11 = getSkinFile(ForgeConstants.SPRITE_BUTTONS_FILE);
+ final FileHandle f12 = getSkinFile(ForgeConstants.SPRITE_START_FILE);
try {
textures.put(f1.path(), new Texture(f1));
@@ -204,10 +210,22 @@ public class FSkin {
}
if (f7.exists()){
Texture t = new Texture(f7, true);
- t.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
+ //t.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
textures.put(f7.path(), t);
}
-
+ //hdbuttons
+ if (f11.exists()) {
+ Texture t = new Texture(f11, true);
+ t.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
+ textures.put(f11.path(), t);
+ Forge.hdbuttons = true;
+ } else { Forge.hdbuttons = false; } //how to refresh buttons when a theme don't have hd buttons?
+ if (f12.exists()) {
+ Texture t = new Texture(f12, true);
+ t.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
+ textures.put(f12.path(), t);
+ Forge.hdstart = true;
+ } else { Forge.hdstart = false; }
//update colors
for (final FSkinColor.Colors c : FSkinColor.Colors.values()) {
c.setColor(new Color(preferredIcons.getPixel(c.getX(), c.getY())));
diff --git a/forge-gui-mobile/src/forge/assets/FSkinImage.java b/forge-gui-mobile/src/forge/assets/FSkinImage.java
index cdaaceeaaf7..38daeb2ced1 100644
--- a/forge-gui-mobile/src/forge/assets/FSkinImage.java
+++ b/forge-gui-mobile/src/forge/assets/FSkinImage.java
@@ -19,10 +19,22 @@ import forge.util.ImageUtil;
public enum FSkinImage implements FImage {
//Zones
HAND (FSkinProp.IMG_ZONE_HAND, SourceFile.ICONS),
+ HDHAND (FSkinProp.IMG_HDZONE_HAND, SourceFile.BUTTONS),
+
LIBRARY (FSkinProp.IMG_ZONE_LIBRARY, SourceFile.ICONS),
+ HDLIBRARY (FSkinProp.IMG_HDZONE_LIBRARY, SourceFile.BUTTONS),
+
EXILE (FSkinProp.IMG_ZONE_EXILE, SourceFile.ICONS),
+ HDEXILE (FSkinProp.IMG_HDZONE_EXILE, SourceFile.BUTTONS),
+
FLASHBACK (FSkinProp.IMG_ZONE_FLASHBACK, SourceFile.ICONS),
+ HDFLASHBACK (FSkinProp.IMG_HDZONE_FLASHBACK, SourceFile.BUTTONS),
+
GRAVEYARD (FSkinProp.IMG_ZONE_GRAVEYARD, SourceFile.ICONS),
+ HDGRAVEYARD (FSkinProp.IMG_HDZONE_GRAVEYARD, SourceFile.BUTTONS),
+
+ HDMANAPOOL (FSkinProp.IMG_HDZONE_MANAPOOL, SourceFile.BUTTONS),
+
POISON (FSkinProp.IMG_ZONE_POISON, SourceFile.ICONS),
//Mana symbols
@@ -114,6 +126,14 @@ public enum FSkinImage implements FImage {
ARCSON (FSkinProp.ICO_ARCSON, SourceFile.ICONS),
ARCSHOVER (FSkinProp.ICO_ARCSHOVER, SourceFile.ICONS),
+ //choice-search-misc
+ HDCHOICE (FSkinProp.ICO_HDCHOICE, SourceFile.BUTTONS),
+ HDSIDEBOARD (FSkinProp.ICO_HDSIDEBOARD, SourceFile.BUTTONS),
+ HDPREFERENCE (FSkinProp.ICO_HDPREFERENCE, SourceFile.BUTTONS),
+ HDIMPORT (FSkinProp.ICO_HDIMPORT, SourceFile.BUTTONS),
+ HDEXPORT (FSkinProp.ICO_HDEXPORT, SourceFile.BUTTONS),
+ BLANK (FSkinProp.ICO_BLANK, SourceFile.ICONS),
+
//Achievement Trophies
COMMON_TROPHY (FSkinProp.IMG_COMMON_TROPHY, SourceFile.TROPHIES),
UNCOMMON_TROPHY (FSkinProp.IMG_UNCOMMON_TROPHY, SourceFile.TROPHIES),
@@ -156,31 +176,82 @@ public enum FSkinImage implements FImage {
QUEST_MINUS (FSkinProp.ICO_QUEST_MINUS, SourceFile.ICONS),
QUEST_PLUS (FSkinProp.ICO_QUEST_PLUS, SourceFile.ICONS),
QUEST_PLUSPLUS (FSkinProp.ICO_QUEST_PLUSPLUS, SourceFile.ICONS),
+ QUEST_BIG_ELIXIR (FSkinProp.ICO_QUEST_BIG_ELIXIR, SourceFile.ICONS),
+ QUEST_BIG_BREW (FSkinProp.ICO_QUEST_BIG_BREW, SourceFile.ICONS),
+ QUEST_BIG_BM (FSkinProp.ICO_QUEST_BIG_BM, SourceFile.ICONS),
+ QUEST_BIG_STAKES (FSkinProp.ICO_QUEST_BIG_STAKES, SourceFile.ICONS),
+ QUEST_BIG_HOUSE (FSkinProp.ICO_QUEST_BIG_HOUSE, SourceFile.ICONS),
+ QUEST_BIG_COIN (FSkinProp.ICO_QUEST_BIG_COIN, SourceFile.ICONS),
+ QUEST_BIG_BOOK (FSkinProp.ICO_QUEST_BIG_BOOK, SourceFile.ICONS),
+ QUEST_BIG_MAP (FSkinProp.ICO_QUEST_BIG_MAP, SourceFile.ICONS),
+ QUEST_BIG_ZEP (FSkinProp.ICO_QUEST_BIG_ZEP, SourceFile.ICONS),
+ QUEST_BIG_CHARM (FSkinProp.ICO_QUEST_BIG_CHARM, SourceFile.ICONS),
+ QUEST_BIG_BOOTS (FSkinProp.ICO_QUEST_BIG_BOOTS, SourceFile.ICONS),
+ QUEST_BIG_SHIELD (FSkinProp.ICO_QUEST_BIG_SHIELD, SourceFile.ICONS),
+ QUEST_BIG_ARMOR (FSkinProp.ICO_QUEST_BIG_ARMOR, SourceFile.ICONS),
+ QUEST_BIG_AXE (FSkinProp.ICO_QUEST_BIG_AXE, SourceFile.ICONS),
+ 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),
WARNING (FSkinProp.ICO_WARNING, SourceFile.ICONS),
ERROR (FSkinProp.ICO_ERROR, SourceFile.ICONS),
+
DELETE (FSkinProp.ICO_DELETE, SourceFile.ICONS),
+ HDDELETE (FSkinProp.ICO_HDDELETE, SourceFile.BUTTONS),
+
DELETE_OVER (FSkinProp.ICO_DELETE_OVER, SourceFile.ICONS),
+
EDIT (FSkinProp.ICO_EDIT, SourceFile.ICONS),
+ HDEDIT (FSkinProp.ICO_HDEDIT, SourceFile.BUTTONS),
+
EDIT_OVER (FSkinProp.ICO_EDIT_OVER, SourceFile.ICONS),
+
OPEN (FSkinProp.ICO_OPEN, SourceFile.ICONS),
+ HDOPEN (FSkinProp.ICO_HDOPEN, SourceFile.BUTTONS),
+
MINUS (FSkinProp.ICO_MINUS, SourceFile.ICONS),
+ HDMINUS (FSkinProp.ICO_HDMINUS, SourceFile.BUTTONS),
+
NEW (FSkinProp.ICO_NEW, SourceFile.ICONS),
+
PLUS (FSkinProp.ICO_PLUS, SourceFile.ICONS),
+ HDPLUS (FSkinProp.ICO_HDPLUS, SourceFile.BUTTONS),
+
PRINT (FSkinProp.ICO_PRINT, SourceFile.ICONS),
+
SAVE (FSkinProp.ICO_SAVE, SourceFile.ICONS),
+ HDSAVE (FSkinProp.ICO_HDSAVE, SourceFile.BUTTONS),
SAVEAS (FSkinProp.ICO_SAVEAS, SourceFile.ICONS),
+ HDSAVEAS (FSkinProp.ICO_HDSAVEAS, SourceFile.BUTTONS),
+
CLOSE (FSkinProp.ICO_CLOSE, SourceFile.ICONS),
LIST (FSkinProp.ICO_LIST, SourceFile.ICONS),
CARD_IMAGE (FSkinProp.ICO_CARD_IMAGE, SourceFile.ICONS),
+
FOLDER (FSkinProp.ICO_FOLDER, SourceFile.ICONS),
+ HDFOLDER (FSkinProp.ICO_HDFOLDER, SourceFile.BUTTONS),
+
SEARCH (FSkinProp.ICO_SEARCH, SourceFile.ICONS),
+ HDSEARCH (FSkinProp.ICO_HDSEARCH, SourceFile.BUTTONS),
+
UNKNOWN (FSkinProp.ICO_UNKNOWN, SourceFile.ICONS),
LOGO (FSkinProp.ICO_LOGO, SourceFile.ICONS),
+
FLIPCARD (FSkinProp.ICO_FLIPCARD, SourceFile.ICONS),
+ HDFLIPCARD (FSkinProp.ICO_HDFLIPCARD, SourceFile.BUTTONS),
+
FAVICON (FSkinProp.ICO_FAVICON, SourceFile.ICONS),
LOCK (FSkinProp.ICO_LOCK, SourceFile.ICONS),
@@ -193,14 +264,19 @@ public enum FSkinImage implements FImage {
CUR_TAB (FSkinProp.IMG_CUR_TAB, SourceFile.ICONS),
//Editor images
- STAR_OUTINE (FSkinProp.IMG_STAR_OUTINE, SourceFile.ICONS),
+ STAR_OUTLINE (FSkinProp.IMG_STAR_OUTLINE, SourceFile.ICONS),
+ HDSTAR_OUTLINE (FSkinProp.IMG_HDSTAR_OUTLINE, SourceFile.BUTTONS),
STAR_FILLED (FSkinProp.IMG_STAR_FILLED, SourceFile.ICONS),
+ HDSTAR_FILLED (FSkinProp.IMG_HDSTAR_FILLED, SourceFile.BUTTONS),
+
ARTIFACT (FSkinProp.IMG_ARTIFACT, SourceFile.MANAICONS),
CREATURE (FSkinProp.IMG_CREATURE, SourceFile.MANAICONS),
ENCHANTMENT (FSkinProp.IMG_ENCHANTMENT, SourceFile.MANAICONS),
INSTANT (FSkinProp.IMG_INSTANT, SourceFile.MANAICONS),
LAND (FSkinProp.IMG_LAND, SourceFile.MANAICONS),
+ LANDLOGO (FSkinProp.IMG_LANDLOGO, SourceFile.MANAICONS),
MULTI (FSkinProp.IMG_MULTI, SourceFile.ICONS),
+ HDMULTI (FSkinProp.IMG_HDMULTI, SourceFile.MANAICONS),
PLANESWALKER (FSkinProp.IMG_PLANESWALKER, SourceFile.MANAICONS),
PACK (FSkinProp.IMG_PACK, SourceFile.ICONS),
SORCERY (FSkinProp.IMG_SORCERY, SourceFile.MANAICONS),
@@ -228,6 +304,28 @@ public enum FSkinImage implements FImage {
BTN_DISABLED_LEFT (FSkinProp.IMG_BTN_DISABLED_LEFT, SourceFile.ICONS),
BTN_DISABLED_CENTER (FSkinProp.IMG_BTN_DISABLED_CENTER, SourceFile.ICONS),
BTN_DISABLED_RIGHT (FSkinProp.IMG_BTN_DISABLED_RIGHT, SourceFile.ICONS),
+ //Hdbuttons
+ HDBTN_START_UP (FSkinProp.IMG_HDBTN_START_UP, SourceFile.BTNSTART),
+ HDBTN_START_OVER (FSkinProp.IMG_HDBTN_START_OVER, SourceFile.BTNSTART),
+ HDBTN_START_DOWN (FSkinProp.IMG_HDBTN_START_DOWN, SourceFile.BTNSTART),
+ HDBTN_UP_LEFT (FSkinProp.IMG_HDBTN_UP_LEFT, SourceFile.BUTTONS),
+ HDBTN_UP_CENTER (FSkinProp.IMG_HDBTN_UP_CENTER, SourceFile.BUTTONS),
+ HDBTN_UP_RIGHT (FSkinProp.IMG_HDBTN_UP_RIGHT, SourceFile.BUTTONS),
+ HDBTN_OVER_LEFT (FSkinProp.IMG_HDBTN_OVER_LEFT, SourceFile.BUTTONS),
+ HDBTN_OVER_CENTER (FSkinProp.IMG_HDBTN_OVER_CENTER, SourceFile.BUTTONS),
+ HDBTN_OVER_RIGHT (FSkinProp.IMG_HDBTN_OVER_RIGHT, SourceFile.BUTTONS),
+ HDBTN_DOWN_LEFT (FSkinProp.IMG_HDBTN_DOWN_LEFT, SourceFile.BUTTONS),
+ HDBTN_DOWN_CENTER (FSkinProp.IMG_HDBTN_DOWN_CENTER, SourceFile.BUTTONS),
+ HDBTN_DOWN_RIGHT (FSkinProp.IMG_HDBTN_DOWN_RIGHT, SourceFile.BUTTONS),
+ HDBTN_FOCUS_LEFT (FSkinProp.IMG_HDBTN_FOCUS_LEFT, SourceFile.BUTTONS),
+ HDBTN_FOCUS_CENTER (FSkinProp.IMG_HDBTN_FOCUS_CENTER, SourceFile.BUTTONS),
+ HDBTN_FOCUS_RIGHT (FSkinProp.IMG_HDBTN_FOCUS_RIGHT, SourceFile.BUTTONS),
+ HDBTN_TOGGLE_LEFT (FSkinProp.IMG_HDBTN_TOGGLE_LEFT, SourceFile.BUTTONS),
+ HDBTN_TOGGLE_CENTER (FSkinProp.IMG_HDBTN_TOGGLE_CENTER, SourceFile.BUTTONS),
+ HDBTN_TOGGLE_RIGHT (FSkinProp.IMG_HDBTN_TOGGLE_RIGHT, SourceFile.BUTTONS),
+ HDBTN_DISABLED_LEFT (FSkinProp.IMG_HDBTN_DISABLED_LEFT, SourceFile.BUTTONS),
+ HDBTN_DISABLED_CENTER (FSkinProp.IMG_HDBTN_DISABLED_CENTER, SourceFile.BUTTONS),
+ HDBTN_DISABLED_RIGHT (FSkinProp.IMG_HDBTN_DISABLED_RIGHT, SourceFile.BUTTONS),
//Foils
FOIL_01 (FSkinProp.FOIL_01, SourceFile.FOILS),
@@ -312,6 +410,8 @@ public enum FSkinImage implements FImage {
TROPHIES(ForgeConstants.SPRITE_TROPHIES_FILE),
ABILITIES(ForgeConstants.SPRITE_ABILITY_FILE),
BORDERS(ForgeConstants.SPRITE_BORDER_FILE),
+ BUTTONS(ForgeConstants.SPRITE_BUTTONS_FILE),
+ BTNSTART(ForgeConstants.SPRITE_START_FILE),
MANAICONS(ForgeConstants.SPRITE_MANAICONS_FILE),
PLANAR_CONQUEST(ForgeConstants.SPRITE_PLANAR_CONQUEST_FILE);
diff --git a/forge-gui-mobile/src/forge/assets/ImageCache.java b/forge-gui-mobile/src/forge/assets/ImageCache.java
index 74f904e34ac..70919ec452b 100644
--- a/forge-gui-mobile/src/forge/assets/ImageCache.java
+++ b/forge-gui-mobile/src/forge/assets/ImageCache.java
@@ -164,7 +164,7 @@ public class ImageCache {
}
return image;
}
- public static void preloadCache(Iterable keys) {
+ public static void preloadCache(Iterable keys) {
cache.getAll(keys);
}
public static TextureRegion croppedBorderImage(Texture image, boolean fullborder) {
@@ -173,10 +173,9 @@ public class ImageCache {
float rscale = 0.96f;
int rw = Math.round(image.getWidth()*rscale);
int rh = Math.round(image.getHeight()*rscale);
- int rx = Math.round((image.getWidth() - rw)/2);
- int ry = Math.round((image.getHeight() - rh)/2)-2;
- TextureRegion rimage = new TextureRegion(image, rx, ry, rw, rh);
- return rimage;
+ int rx = Math.round((image.getWidth() - rw)/2f);
+ int ry = Math.round((image.getHeight() - rh)/2f)-2;
+ return new TextureRegion(image, rx, ry, rw, rh);
}
public static boolean isWhiteBordered(IPaperCard c) {
if (c == null)
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..d4a04841adc 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)
@@ -481,6 +535,9 @@ public class CardRenderer {
}
public static void drawCardWithOverlays(Graphics g, CardView card, float x, float y, float w, float h, CardStackPosition pos) {
+ drawCardWithOverlays(g, card, x, y, w, h, pos, false);
+ }
+ public static void drawCardWithOverlays(Graphics g, CardView card, float x, float y, float w, float h, CardStackPosition pos, boolean stackview) {
boolean canShow = MatchController.instance.mayView(card);
float oldAlpha = g.getfloatAlphaComposite();
boolean unselectable = !MatchController.instance.isSelectable(card) && MatchController.instance.isSelecting();
@@ -501,32 +558,10 @@ public class CardRenderer {
Color color = FSkinColor.fromRGB(borderColor.r, borderColor.g, borderColor.b);
color = FSkinColor.tintColor(Color.WHITE, color, CardRenderer.PT_BOX_TINT);
- //draw name and mana cost overlays if card is small or default card image being used
- if (h <= NAME_COST_THRESHOLD && canShow) {
- if (showCardNameOverlay(card)) {
- g.drawOutlinedText(CardTranslation.getTranslatedName(details.getName()), FSkinFont.forHeight(h * 0.15f), Color.WHITE, Color.BLACK, x + padding -1f, y + padding, w - 2 * padding, h * 0.4f, true, Align.left, false);
- }
- if (showCardManaCostOverlay(card)) {
- float manaSymbolSize = w / 4.5f;
- if (card.isSplitCard() && card.hasAlternateState()) {
- if (!card.isFaceDown()) { // no need to draw mana symbols on face down split cards (e.g. manifested)
- float dy = manaSymbolSize / 2 + Utils.scale(5);
-
- PaperCard pc = StaticData.instance().getCommonCards().getCard(card.getName());
- if (Card.getCardForUi(pc).hasKeyword(Keyword.AFTERMATH)){
- dy *= -1; // flip card costs for Aftermath cards
- }
-
- drawManaCost(g, card.getAlternateState().getManaCost(), x - padding, y - dy, w + 2 * padding, h, manaSymbolSize);
- drawManaCost(g, card.getCurrentState().getManaCost(), x - padding, y + dy, w + 2 * padding, h, manaSymbolSize);
- }
- }
- else {
- drawManaCost(g, card.getCurrentState().getManaCost(), x - padding, y, w + 2 * padding, h, manaSymbolSize);
- }
- }
- }
+ //card name && manacost original position is here moved at the bottom...
+ if (stackview)
+ return; //override
if (pos == CardStackPosition.BehindVert) { return; } //remaining rendering not needed if card is behind another card in a vertical stack
boolean onTop = (pos == CardStackPosition.Top);
@@ -602,6 +637,7 @@ public class CardRenderer {
float abiSpace = cw / 5.7f;
float abiCount = 0;
+ if (unselectable){ g.setAlphaComposite(0.6f); }
if (onbattlefield && onTop && showAbilityIcons(card)) {
if (card.isToken()){
CardFaceSymbols.drawSymbol("token", g, abiX, abiY, abiScale, abiScale);
@@ -610,85 +646,63 @@ public class CardRenderer {
}
if (card.getCurrentState().hasFlying()) {
CardFaceSymbols.drawSymbol("flying", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
if (card.getCurrentState().hasHaste()) {
CardFaceSymbols.drawSymbol("haste", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
if (card.getCurrentState().hasDoubleStrike()) {
CardFaceSymbols.drawSymbol("doublestrike", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
else if (card.getCurrentState().hasFirstStrike()) {
CardFaceSymbols.drawSymbol("firststrike", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
if (card.getCurrentState().hasDeathtouch()) {
if (abiCount > 5 ) { abiY = cy + (abiSpace * (abiCount - 6)); abiX = cx + ((cw*2)/1.92f); }
CardFaceSymbols.drawSymbol("deathtouch", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
if (card.getCurrentState().hasIndestructible()) {
if (abiCount > 5 ) { abiY = cy + (abiSpace * (abiCount - 6)); abiX = cx + ((cw*2)/1.92f); }
CardFaceSymbols.drawSymbol("indestructible", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
if (card.getCurrentState().hasMenace()) {
if (abiCount > 5 ) { abiY = cy + (abiSpace * (abiCount - 6)); abiX = cx + ((cw*2)/1.92f); }
CardFaceSymbols.drawSymbol("menace", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
if (card.getCurrentState().hasFear()) {
if (abiCount > 5 ) { abiY = cy + (abiSpace * (abiCount - 6)); abiX = cx + ((cw*2)/1.92f); }
CardFaceSymbols.drawSymbol("fear", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
if (card.getCurrentState().hasIntimidate()) {
if (abiCount > 5 ) { abiY = cy + (abiSpace * (abiCount - 6)); abiX = cx + ((cw*2)/1.92f); }
CardFaceSymbols.drawSymbol("intimidate", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
if (card.getCurrentState().hasShadow()) {
if (abiCount > 5 ) { abiY = cy + (abiSpace * (abiCount - 6)); abiX = cx + ((cw*2)/1.92f); }
CardFaceSymbols.drawSymbol("shadow", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
if (card.getCurrentState().hasHorsemanship()) {
if (abiCount > 5 ) { abiY = cy + (abiSpace * (abiCount - 6)); abiX = cx + ((cw*2)/1.92f); }
CardFaceSymbols.drawSymbol("horsemanship", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
@@ -699,57 +713,41 @@ public class CardRenderer {
List listHK = Arrays.asList(splitK);
if (listHK.contains("generic")) {
CardFaceSymbols.drawSymbol("hexproof", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
if (listHK.contains("R")) {
CardFaceSymbols.drawSymbol("hexproofR", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
if (listHK.contains("B")) {
CardFaceSymbols.drawSymbol("hexproofB", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
if (listHK.contains("U")) {
CardFaceSymbols.drawSymbol("hexproofU", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
if (listHK.contains("G")) {
CardFaceSymbols.drawSymbol("hexproofG", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
if (listHK.contains("W")) {
CardFaceSymbols.drawSymbol("hexproofW", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
if (listHK.contains("monocolored")) {
CardFaceSymbols.drawSymbol("hexproofC", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
} else {
CardFaceSymbols.drawSymbol("hexproof", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
@@ -757,48 +755,36 @@ public class CardRenderer {
else if (card.getCurrentState().hasShroud()) {
if (abiCount > 5 ) { abiY = cy + (abiSpace * (abiCount - 6)); abiX = cx + ((cw*2)/1.92f); }
CardFaceSymbols.drawSymbol("shroud", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
if (card.getCurrentState().hasVigilance()) {
if (abiCount > 5 ) { abiY = cy + (abiSpace * (abiCount - 6)); abiX = cx + ((cw*2)/1.92f); }
CardFaceSymbols.drawSymbol("vigilance", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
if (card.getCurrentState().hasTrample()) {
if (abiCount > 5 ) { abiY = cy + (abiSpace * (abiCount - 6)); abiX = cx + ((cw*2)/1.92f); }
CardFaceSymbols.drawSymbol("trample", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
if (card.getCurrentState().hasReach()) {
if (abiCount > 5 ) { abiY = cy + (abiSpace * (abiCount - 6)); abiX = cx + ((cw*2)/1.92f); }
CardFaceSymbols.drawSymbol("reach", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
if (card.getCurrentState().hasLifelink()) {
if (abiCount > 5 ) { abiY = cy + (abiSpace * (abiCount - 6)); abiX = cx + ((cw*2)/1.92f); }
CardFaceSymbols.drawSymbol("lifelink", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
if (card.getCurrentState().hasDefender()) {
if (abiCount > 5 ) { abiY = cy + (abiSpace * (abiCount - 6)); abiX = cx + ((cw*2)/1.92f); }
CardFaceSymbols.drawSymbol("defender", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
@@ -807,132 +793,138 @@ public class CardRenderer {
if (abiCount > 5 ) { abiY = cy + (abiSpace * (abiCount - 6)); abiX = cx + ((cw*2)/1.92f); }
if (card.getCurrentState().getProtectionKey().contains("everything") || card.getCurrentState().getProtectionKey().contains("allcolors")) {
CardFaceSymbols.drawSymbol("protectAll", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
else if (card.getCurrentState().getProtectionKey().contains("coloredspells")) {
CardFaceSymbols.drawSymbol("protectColoredSpells", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
else if (card.getCurrentState().getProtectionKey().equals("R")) {
CardFaceSymbols.drawSymbol("protectR", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
else if (card.getCurrentState().getProtectionKey().equals("G")) {
CardFaceSymbols.drawSymbol("protectG", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
else if (card.getCurrentState().getProtectionKey().equals("B")) {
CardFaceSymbols.drawSymbol("protectB", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
else if (card.getCurrentState().getProtectionKey().equals("U")) {
CardFaceSymbols.drawSymbol("protectU", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
else if (card.getCurrentState().getProtectionKey().equals("W")) {
CardFaceSymbols.drawSymbol("protectW", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
else if (card.getCurrentState().getProtectionKey().equals("RG")||card.getCurrentState().getProtectionKey().equals("GR")) {
CardFaceSymbols.drawSymbol("protectRG", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
else if (card.getCurrentState().getProtectionKey().equals("RB")||card.getCurrentState().getProtectionKey().equals("BR")) {
CardFaceSymbols.drawSymbol("protectRB", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
else if (card.getCurrentState().getProtectionKey().equals("RU")||card.getCurrentState().getProtectionKey().equals("UR")) {
CardFaceSymbols.drawSymbol("protectRU", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
else if (card.getCurrentState().getProtectionKey().equals("RW")||card.getCurrentState().getProtectionKey().equals("WR")) {
CardFaceSymbols.drawSymbol("protectRW", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
else if (card.getCurrentState().getProtectionKey().equals("GB")||card.getCurrentState().getProtectionKey().equals("BG")) {
CardFaceSymbols.drawSymbol("protectGB", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
else if (card.getCurrentState().getProtectionKey().equals("GU")||card.getCurrentState().getProtectionKey().equals("UG")) {
CardFaceSymbols.drawSymbol("protectGU", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
else if (card.getCurrentState().getProtectionKey().equals("GW")||card.getCurrentState().getProtectionKey().equals("WG")) {
CardFaceSymbols.drawSymbol("protectGW", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
else if (card.getCurrentState().getProtectionKey().equals("BU")||card.getCurrentState().getProtectionKey().equals("UB")) {
CardFaceSymbols.drawSymbol("protectBU", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
else if (card.getCurrentState().getProtectionKey().equals("BW")||card.getCurrentState().getProtectionKey().equals("WB")) {
CardFaceSymbols.drawSymbol("protectBW", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
else if (card.getCurrentState().getProtectionKey().equals("UW")||card.getCurrentState().getProtectionKey().equals("WU")) {
CardFaceSymbols.drawSymbol("protectUW", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
else if (card.getCurrentState().getProtectionKey().contains("generic") || card.getCurrentState().getProtectionKey().length() > 2) {
CardFaceSymbols.drawSymbol("protectGeneric", g, abiX, abiY, abiScale, abiScale);
- if (unselectable){
- g.setAlphaComposite(0.6f); g.fillRect(Color.BLACK, abiX, abiY, abiScale, abiScale ); g.setAlphaComposite(oldAlpha);}
abiY += abiSpace;
abiCount += 1;
}
}
}
+ //draw name and mana cost overlays if card is small or default card image being used
+ if (h <= NAME_COST_THRESHOLD && canShow) {
+ if (showCardNameOverlay(card)) {
+ float multiplier;
+ switch (Forge.extrawide) {
+ case "default":
+ multiplier = 0.145f; //good for tablets with 16:10 or similar
+ break;
+ case "wide":
+ multiplier = 0.150f;
+ break;
+ case "extrawide":
+ multiplier = 0.155f; //good for tall phones with 21:9 or similar
+ break;
+ default:
+ multiplier = 0.150f;
+ break;
+ }
+ g.drawOutlinedText(CardTranslation.getTranslatedName(details.getName()), FSkinFont.forHeight(h * multiplier), Color.WHITE, Color.BLACK, x + padding -1f, y + padding, w - 2 * padding, h * 0.4f, true, Align.left, false);
+ }
+ if (showCardManaCostOverlay(card)) {
+ float manaSymbolSize = w / 4.5f;
+ if (card.isSplitCard() && card.hasAlternateState()) {
+ if (!card.isFaceDown()) { // no need to draw mana symbols on face down split cards (e.g. manifested)
+ float dy = manaSymbolSize / 2 + Utils.scale(5);
+
+ PaperCard pc = StaticData.instance().getCommonCards().getCard(card.getName());
+ if (Card.getCardForUi(pc).hasKeyword(Keyword.AFTERMATH)){
+ dy *= -1; // flip card costs for Aftermath cards
+ }
+
+ drawManaCost(g, card.getAlternateState().getManaCost(), x - padding, y - dy, w + 2 * padding, h, manaSymbolSize);
+ drawManaCost(g, card.getCurrentState().getManaCost(), x - padding, y + dy, w + 2 * padding, h, manaSymbolSize);
+ }
+ }
+ else {
+ drawManaCost(g, card.getCurrentState().getManaCost(), x - padding, y, w + 2 * padding, h, manaSymbolSize);
+ }
+ }
+ }
+ //reset alpha
+ g.setAlphaComposite(oldAlpha);
}
private static void drawCounterTabs(final CardView card, final Graphics g, final float x, final float y, final float w, final float h) {
@@ -1119,8 +1111,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 c0f8130e634..2eea37d2ec6 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;
+ 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;
@@ -275,9 +290,15 @@ public class CardZoom extends FOverlay {
if (flipIconBounds != null) {
float imageWidth = cardWidth / 2;
- float imageHeight = imageWidth * FSkinImage.FLIPCARD.getHeight() / FSkinImage.FLIPCARD.getWidth();
- flipIconBounds.set(x + (cardWidth - imageWidth) / 2, y + (cardHeight - imageHeight) / 2, imageWidth, imageHeight);
- g.drawImage(FSkinImage.FLIPCARD, flipIconBounds.x, flipIconBounds.y, flipIconBounds.width, flipIconBounds.height);
+ if (Forge.hdbuttons){
+ float imageHeight = imageWidth * FSkinImage.HDFLIPCARD.getHeight() / FSkinImage.HDFLIPCARD.getWidth();
+ flipIconBounds.set(x + (cardWidth - imageWidth) / 2, y + (cardHeight - imageHeight) / 2, imageWidth, imageHeight);
+ g.drawImage(FSkinImage.HDFLIPCARD, flipIconBounds.x, flipIconBounds.y, flipIconBounds.width, flipIconBounds.height);
+ } else {
+ float imageHeight = imageWidth * FSkinImage.FLIPCARD.getHeight() / FSkinImage.FLIPCARD.getWidth();
+ flipIconBounds.set(x + (cardWidth - imageWidth) / 2, y + (cardHeight - imageHeight) / 2, imageWidth, imageHeight);
+ g.drawImage(FSkinImage.FLIPCARD, flipIconBounds.x, flipIconBounds.y, flipIconBounds.width, flipIconBounds.height);
+ }
}
if (currentActivateAction != null) {
diff --git a/forge-gui-mobile/src/forge/card/GameEntityPicker.java b/forge-gui-mobile/src/forge/card/GameEntityPicker.java
index 276ad3f2652..1a3991fd7c8 100644
--- a/forge-gui-mobile/src/forge/card/GameEntityPicker.java
+++ b/forge-gui-mobile/src/forge/card/GameEntityPicker.java
@@ -6,6 +6,7 @@ import java.util.List;
import com.google.common.collect.ImmutableList;
+import forge.Forge;
import forge.Graphics;
import forge.assets.FImage;
import forge.assets.FSkinFont;
@@ -27,7 +28,7 @@ public class GameEntityPicker extends TabPageScreen {
public GameEntityPicker(String title, Collection extends GameEntityView> choiceList, Collection revealList, String revealListCaption, FImage revealListImage, boolean isOptional, final Callback callback) {
super(new PickerTab[] {
- new PickerTab(choiceList, Localizer.getInstance().getMessage("lblChoices"), FSkinImage.DECKLIST, 1),
+ new PickerTab(choiceList, Localizer.getInstance().getMessage("lblChoices"), Forge.hdbuttons ? FSkinImage.HDCHOICE : FSkinImage.DECKLIST, 1),
new PickerTab(revealList, revealListCaption, revealListImage, 0)
}, false);
diff --git a/forge-gui-mobile/src/forge/deck/AddBasicLandsDialog.java b/forge-gui-mobile/src/forge/deck/AddBasicLandsDialog.java
index 416e66cd080..aab37b4c0a0 100644
--- a/forge-gui-mobile/src/forge/deck/AddBasicLandsDialog.java
+++ b/forge-gui-mobile/src/forge/deck/AddBasicLandsDialog.java
@@ -324,7 +324,7 @@ public class AddBasicLandsDialog extends FDialog {
}
});
lblCount = add(new FLabel.Builder().text("0").font(FSkinFont.get(18)).align(Align.center).build());
- btnSubtract = add(new FLabel.ButtonBuilder().icon(FSkinImage.MINUS).command(new FEventHandler() {
+ btnSubtract = add(new FLabel.ButtonBuilder().icon(Forge.hdbuttons ? FSkinImage.HDMINUS : FSkinImage.MINUS).command(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
if (count > 0) {
@@ -334,7 +334,7 @@ public class AddBasicLandsDialog extends FDialog {
}
}
}).build());
- btnAdd = add(new FLabel.ButtonBuilder().icon(FSkinImage.PLUS).command(new FEventHandler() {
+ btnAdd = add(new FLabel.ButtonBuilder().icon(Forge.hdbuttons ? FSkinImage.HDPLUS : FSkinImage.PLUS).command(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
if (maxCount == 0 || count < maxCount) {
diff --git a/forge-gui-mobile/src/forge/deck/FDeckEditor.java b/forge-gui-mobile/src/forge/deck/FDeckEditor.java
index 29568111671..ac553fb40ab 100644
--- a/forge-gui-mobile/src/forge/deck/FDeckEditor.java
+++ b/forge-gui-mobile/src/forge/deck/FDeckEditor.java
@@ -44,8 +44,8 @@ import java.util.*;
import java.util.Map.Entry;
public class FDeckEditor extends TabPageScreen {
- public static FSkinImage MAIN_DECK_ICON = FSkinImage.DECKLIST;
- public static FSkinImage SIDEBOARD_ICON = FSkinImage.FLASHBACK;
+ public static FSkinImage MAIN_DECK_ICON = Forge.hdbuttons ? FSkinImage.HDLIBRARY :FSkinImage.DECKLIST;
+ public static FSkinImage SIDEBOARD_ICON = Forge.hdbuttons ? FSkinImage.HDSIDEBOARD : FSkinImage.FLASHBACK;
private static final float HEADER_HEIGHT = Math.round(Utils.AVG_FINGER_HEIGHT * 0.8f);
public enum EditorType {
@@ -235,7 +235,7 @@ public class FDeckEditor extends TabPageScreen {
protected final DeckHeader deckHeader = add(new DeckHeader());
protected final FLabel lblName = deckHeader.add(new FLabel.Builder().font(FSkinFont.get(16)).insets(new Vector2(Utils.scale(5), 0)).build());
- private final FLabel btnSave = deckHeader.add(new FLabel.Builder().icon(FSkinImage.SAVE).align(Align.center).pressedColor(Header.BTN_PRESSED_COLOR).build());
+ private final FLabel btnSave = deckHeader.add(new FLabel.Builder().icon(Forge.hdbuttons ? FSkinImage.HDSAVE : FSkinImage.SAVE).align(Align.center).pressedColor(Header.BTN_PRESSED_COLOR).build());
private final FLabel btnMoreOptions = deckHeader.add(new FLabel.Builder().text("...").font(FSkinFont.get(20)).align(Align.center).pressedColor(Header.BTN_PRESSED_COLOR).build());
public FDeckEditor(EditorType editorType0, DeckProxy editDeck, boolean showMainDeck) {
@@ -332,7 +332,7 @@ public class FDeckEditor extends TabPageScreen {
protected void buildMenu() {
final Localizer localizer = Localizer.getInstance();
- addItem(new FMenuItem(localizer.getMessage("lblAddBasicLands"), FSkinImage.LAND, new FEventHandler() {
+ addItem(new FMenuItem(localizer.getMessage("lblAddBasicLands"), FSkinImage.LANDLOGO, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
CardEdition defaultLandSet;
@@ -365,7 +365,7 @@ public class FDeckEditor extends TabPageScreen {
}
}));
if (!isLimitedEditor()) {
- addItem(new FMenuItem(localizer.getMessage("lblImportFromClipboard"), FSkinImage.OPEN, new FEventHandler() {
+ addItem(new FMenuItem(localizer.getMessage("lblImportFromClipboard"), Forge.hdbuttons ? FSkinImage.HDIMPORT : FSkinImage.OPEN, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
FDeckImportDialog dialog = new FDeckImportDialog(!deck.isEmpty(), new Callback() {
@@ -384,7 +384,7 @@ public class FDeckEditor extends TabPageScreen {
setSelectedPage(getMainDeckPage()); //select main deck page if needed so main deck if visible below dialog
}
}));
- addItem(new FMenuItem(localizer.getMessage("lblSaveAs"), FSkinImage.SAVEAS, new FEventHandler() {
+ addItem(new FMenuItem(localizer.getMessage("lblSaveAs"), Forge.hdbuttons ? FSkinImage.HDSAVEAS : FSkinImage.SAVEAS, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
String defaultName = editorType.getController().getNextAvailableName();
@@ -400,7 +400,7 @@ public class FDeckEditor extends TabPageScreen {
}));
}
if (allowRename()) {
- addItem(new FMenuItem(localizer.getMessage("lblRenameDeck"), FSkinImage.EDIT, new FEventHandler() {
+ addItem(new FMenuItem(localizer.getMessage("lblRenameDeck"), Forge.hdbuttons ? FSkinImage.HDEDIT : FSkinImage.EDIT, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
FOptionPane.showInputDialog(localizer.getMessage("lblNewNameDeck"), deck.getName(), new Callback() {
@@ -413,7 +413,7 @@ public class FDeckEditor extends TabPageScreen {
}));
}
if (allowDelete()) {
- addItem(new FMenuItem(localizer.getMessage("lblDeleteDeck"), FSkinImage.DELETE, new FEventHandler() {
+ addItem(new FMenuItem(localizer.getMessage("lblDeleteDeck"), Forge.hdbuttons ? FSkinImage.HDDELETE : FSkinImage.DELETE, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
FOptionPane.showConfirmDialog(
@@ -430,7 +430,7 @@ public class FDeckEditor extends TabPageScreen {
}
}));
}
- addItem(new FMenuItem(localizer.getMessage("btnCopyToClipboard"), new FEventHandler() {
+ addItem(new FMenuItem(localizer.getMessage("btnCopyToClipboard"), Forge.hdbuttons ? FSkinImage.HDEXPORT : FSkinImage.BLANK, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
FDeckViewer.copyDeckToClipboard(deck);
@@ -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");
@@ -974,7 +977,7 @@ public class FDeckEditor extends TabPageScreen {
private boolean initialized, needRefreshWhenShown;
protected CatalogPage(ItemManagerConfig config) {
- this(config, Localizer.getInstance().getMessage("lblCatalog"), FSkinImage.FOLDER);
+ this(config, Localizer.getInstance().getMessage("lblCatalog"), Forge.hdbuttons ? FSkinImage.HDFOLDER : FSkinImage.FOLDER);
}
protected CatalogPage(ItemManagerConfig config, String caption0, FImage icon0) {
super(config, caption0, icon0);
@@ -1166,7 +1169,7 @@ public class FDeckEditor extends TabPageScreen {
//add option to add or remove card from favorites
final CardPreferences prefs = CardPreferences.getPrefs(card);
if (prefs.getStarCount() == 0) {
- menu.addItem(new FMenuItem(localizer.getMessage("lblAddFavorites"), FSkinImage.STAR_FILLED, new FEventHandler() {
+ menu.addItem(new FMenuItem(localizer.getMessage("lblAddFavorites"), Forge.hdbuttons ? FSkinImage.HDSTAR_FILLED : FSkinImage.STAR_FILLED, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
prefs.setStarCount(1);
@@ -1175,7 +1178,7 @@ public class FDeckEditor extends TabPageScreen {
}));
}
else {
- menu.addItem(new FMenuItem(localizer.getMessage("lblRemoveFavorites"), FSkinImage.STAR_OUTINE, new FEventHandler() {
+ menu.addItem(new FMenuItem(localizer.getMessage("lblRemoveFavorites"), Forge.hdbuttons ? FSkinImage.HDSTAR_OUTLINE : FSkinImage.STAR_OUTLINE, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
prefs.setStarCount(0);
@@ -1187,7 +1190,7 @@ public class FDeckEditor extends TabPageScreen {
//if card has more than one art option, add item to change user's preferred art
final List artOptions = FModel.getMagicDb().getCommonCards().getAllCards(card.getName());
if (artOptions != null && artOptions.size() > 1) {
- menu.addItem(new FMenuItem(localizer.getMessage("lblChangePreferredArt"), FSkinImage.SETTINGS, new FEventHandler() {
+ menu.addItem(new FMenuItem(localizer.getMessage("lblChangePreferredArt"), Forge.hdbuttons ? FSkinImage.HDPREFERENCE : FSkinImage.SETTINGS, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
//sort options so current option is on top and selected by default
@@ -1340,7 +1343,7 @@ public class FDeckEditor extends TabPageScreen {
switch (deckSection) {
default:
case Main:
- addItem(menu, localizer.getMessage("lblAdd"), null, FSkinImage.PLUS, true, false, new Callback() {
+ addItem(menu, localizer.getMessage("lblAdd"), null, Forge.hdbuttons ? FSkinImage.HDPLUS : FSkinImage.PLUS, true, false, new Callback() {
@Override
public void run(Integer result) {
if (result == null || result <= 0) { return; }
@@ -1355,7 +1358,7 @@ public class FDeckEditor extends TabPageScreen {
}
});
if (!parentScreen.isLimitedEditor()) {
- addItem(menu, localizer.getMessage("lblRemove"), null, FSkinImage.MINUS, false, false, new Callback() {
+ addItem(menu, localizer.getMessage("lblRemove"), null, Forge.hdbuttons ? FSkinImage.HDMINUS : FSkinImage.MINUS, false, false, new Callback() {
@Override
public void run(Integer result) {
if (result == null || result <= 0) { return; }
@@ -1381,7 +1384,7 @@ public class FDeckEditor extends TabPageScreen {
addCommanderItems(menu, card, false, false);
break;
case Sideboard:
- addItem(menu, localizer.getMessage("lblAdd"), null, FSkinImage.PLUS, true, false, new Callback() {
+ addItem(menu, localizer.getMessage("lblAdd"), null, Forge.hdbuttons ? FSkinImage.HDPLUS : FSkinImage.PLUS, true, false, new Callback() {
@Override
public void run(Integer result) {
if (result == null || result <= 0) { return; }
@@ -1396,7 +1399,7 @@ public class FDeckEditor extends TabPageScreen {
}
});
if (!parentScreen.isLimitedEditor()) {
- addItem(menu, localizer.getMessage("lblRemove"), null, FSkinImage.MINUS, false, false, new Callback() {
+ addItem(menu, localizer.getMessage("lblRemove"), null, Forge.hdbuttons ? FSkinImage.HDMINUS : FSkinImage.MINUS, false, false, new Callback() {
@Override
public void run(Integer result) {
if (result == null || result <= 0) { return; }
@@ -1421,7 +1424,7 @@ public class FDeckEditor extends TabPageScreen {
break;
case Commander:
if (parentScreen.editorType != EditorType.PlanarConquest || isPartnerCommander(card)) {
- addItem(menu, localizer.getMessage("lblRemove"), null, FSkinImage.MINUS, false, false, new Callback() {
+ addItem(menu, localizer.getMessage("lblRemove"), null, Forge.hdbuttons ? FSkinImage.HDMINUS : FSkinImage.MINUS, false, false, new Callback() {
@Override
public void run(Integer result) {
if (result == null || result <= 0) {
@@ -1436,7 +1439,7 @@ public class FDeckEditor extends TabPageScreen {
}
break;
case Avatar:
- addItem(menu, localizer.getMessage("lblRemove"), null, FSkinImage.MINUS, false, false, new Callback() {
+ addItem(menu, localizer.getMessage("lblRemove"), null, Forge.hdbuttons ? FSkinImage.HDMINUS : FSkinImage.MINUS, false, false, new Callback() {
@Override
public void run(Integer result) {
if (result == null || result <= 0) { return; }
@@ -1446,7 +1449,7 @@ public class FDeckEditor extends TabPageScreen {
});
break;
case Schemes:
- addItem(menu, localizer.getMessage("lblAdd"), null, FSkinImage.PLUS, true, false, new Callback() {
+ addItem(menu, localizer.getMessage("lblAdd"), null, Forge.hdbuttons ? FSkinImage.HDPLUS : FSkinImage.PLUS, true, false, new Callback() {
@Override
public void run(Integer result) {
if (result == null || result <= 0) { return; }
@@ -1454,7 +1457,7 @@ public class FDeckEditor extends TabPageScreen {
addCard(card, result);
}
});
- addItem(menu, localizer.getMessage("lblRemove"), null, FSkinImage.MINUS, false, false, new Callback() {
+ addItem(menu, localizer.getMessage("lblRemove"), null, Forge.hdbuttons ? FSkinImage.HDMINUS : FSkinImage.MINUS, false, false, new Callback() {
@Override
public void run(Integer result) {
if (result == null || result <= 0) { return; }
@@ -1464,7 +1467,7 @@ public class FDeckEditor extends TabPageScreen {
});
break;
case Planes:
- addItem(menu, localizer.getMessage("lblAdd"), null, FSkinImage.PLUS, true, false, new Callback() {
+ addItem(menu, localizer.getMessage("lblAdd"), null, Forge.hdbuttons ? FSkinImage.HDPLUS : FSkinImage.PLUS, true, false, new Callback() {
@Override
public void run(Integer result) {
if (result == null || result <= 0) { return; }
@@ -1472,7 +1475,7 @@ public class FDeckEditor extends TabPageScreen {
addCard(card, result);
}
});
- addItem(menu, localizer.getMessage("lblRemove"), null, FSkinImage.MINUS, false, false, new Callback() {
+ addItem(menu, localizer.getMessage("lblRemove"), null, Forge.hdbuttons ? FSkinImage.HDMINUS : FSkinImage.MINUS, false, false, new Callback() {
@Override
public void run(Integer result) {
if (result == null || result <= 0) { return; }
diff --git a/forge-gui-mobile/src/forge/itemmanager/DeckManager.java b/forge-gui-mobile/src/forge/itemmanager/DeckManager.java
index 363a70bf27a..5f0fe585ea5 100644
--- a/forge-gui-mobile/src/forge/itemmanager/DeckManager.java
+++ b/forge-gui-mobile/src/forge/itemmanager/DeckManager.java
@@ -1,5 +1,6 @@
package forge.itemmanager;
+import forge.Forge;
import forge.Graphics;
import forge.assets.FSkinColor;
import forge.assets.FSkinFont;
@@ -124,7 +125,11 @@ public final class DeckManager extends ItemManager implements IHasGam
}
//draw favorite, name, path and color on first line
- g.drawImage(DeckPreferences.getPrefs(deck).getStarCount() > 0 ? FSkinImage.STAR_FILLED : FSkinImage.STAR_OUTINE, x, y, IMAGE_SIZE, IMAGE_SIZE);
+ if (Forge.hdbuttons)
+ g.drawImage(DeckPreferences.getPrefs(deck).getStarCount() > 0 ? FSkinImage.HDSTAR_FILLED : FSkinImage.HDSTAR_OUTLINE, x, y, IMAGE_SIZE, IMAGE_SIZE);
+ else
+ g.drawImage(DeckPreferences.getPrefs(deck).getStarCount() > 0 ? FSkinImage.STAR_FILLED : FSkinImage.STAR_OUTLINE, x, y, IMAGE_SIZE, IMAGE_SIZE);
+
x += IMAGE_SIZE + FList.PADDING;
ColorSet deckColor = deck.getColor();
float availableNameWidth = w - CardFaceSymbols.getWidth(deckColor, IMAGE_SIZE) - IMAGE_SIZE - 2 * FList.PADDING;
diff --git a/forge-gui-mobile/src/forge/itemmanager/ItemManager.java b/forge-gui-mobile/src/forge/itemmanager/ItemManager.java
index 64e1a239a00..373da380dc8 100644
--- a/forge-gui-mobile/src/forge/itemmanager/ItemManager.java
+++ b/forge-gui-mobile/src/forge/itemmanager/ItemManager.java
@@ -87,12 +87,12 @@ public abstract class ItemManager extends FContainer im
private final TextSearchFilter extends T> searchFilter;
private final FLabel btnSearch = new FLabel.ButtonBuilder()
- .icon(FSkinImage.SEARCH).iconScaleFactor(0.9f).build();
+ .icon(Forge.hdbuttons ? FSkinImage.HDSEARCH : FSkinImage.SEARCH).iconScaleFactor(0.9f).build();
private final FLabel btnView = new FLabel.ButtonBuilder()
.iconScaleFactor(0.9f).build(); //icon set later
private final FLabel btnAdvancedSearchOptions = new FLabel.Builder()
.selectable(true).align(Align.center)
- .icon(FSkinImage.SETTINGS).iconScaleFactor(0.9f)
+ .icon(Forge.hdbuttons ? FSkinImage.HDPREFERENCE : FSkinImage.SETTINGS).iconScaleFactor(0.9f)
.build();
private final FComboBox cbxSortOptions;
@@ -148,7 +148,7 @@ public abstract class ItemManager extends FContainer im
FPopupMenu menu = new FPopupMenu() {
@Override
protected void buildMenu() {
- addItem(new FMenuItem(Localizer.getInstance().getMessage("lblAdvancedSearch"), FSkinImage.SEARCH, new FEventHandler() {
+ addItem(new FMenuItem(Localizer.getInstance().getMessage("lblAdvancedSearch"), Forge.hdbuttons ? FSkinImage.HDSEARCH : FSkinImage.SEARCH, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
if (advancedSearchFilter == null) {
@@ -158,7 +158,7 @@ public abstract class ItemManager extends FContainer im
advancedSearchFilter.edit();
}
}));
- addItem(new FMenuItem(Localizer.getInstance().getMessage("lblResetFilters"), FSkinImage.DELETE, new FEventHandler() {
+ addItem(new FMenuItem(Localizer.getInstance().getMessage("lblResetFilters"), Forge.hdbuttons ? FSkinImage.HDDELETE : FSkinImage.DELETE, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
resetFilters();
diff --git a/forge-gui-mobile/src/forge/itemmanager/filters/AdvancedSearchFilter.java b/forge-gui-mobile/src/forge/itemmanager/filters/AdvancedSearchFilter.java
index d028f3812be..d99ee726106 100644
--- a/forge-gui-mobile/src/forge/itemmanager/filters/AdvancedSearchFilter.java
+++ b/forge-gui-mobile/src/forge/itemmanager/filters/AdvancedSearchFilter.java
@@ -118,7 +118,7 @@ public class AdvancedSearchFilter extends ItemFilter
protected void buildMenu() {
//add a menu item for each filter to allow easily editing just that filter
for (final IFilterControl control : model.getControls()) {
- FMenuItem item = new FMenuItem(control.getFilter().toString(), FSkinImage.EDIT, new FEventHandler() {
+ FMenuItem item = new FMenuItem(control.getFilter().toString(), Forge.hdbuttons ? FSkinImage.HDEDIT : FSkinImage.EDIT, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
model.editFilterControl(control, onFilterChange);
@@ -127,13 +127,13 @@ public class AdvancedSearchFilter extends ItemFilter
item.setTextRenderer(new TextRenderer()); //ensure symbols are displayed
addItem(item);
}
- addItem(new FMenuItem(Localizer.getInstance().getMessage("lblEditExpression"), FSkinImage.EDIT, new FEventHandler() {
+ addItem(new FMenuItem(Localizer.getInstance().getMessage("lblEditExpression"), Forge.hdbuttons ? FSkinImage.HDEDIT : FSkinImage.EDIT, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
edit();
}
}));
- addItem(new FMenuItem(Localizer.getInstance().getMessage("lblRemoveFilter"), FSkinImage.DELETE, new FEventHandler() {
+ addItem(new FMenuItem(Localizer.getInstance().getMessage("lblRemoveFilter"), Forge.hdbuttons ? FSkinImage.HDDELETE : FSkinImage.DELETE, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
reset();
diff --git a/forge-gui-mobile/src/forge/screens/LaunchScreen.java b/forge-gui-mobile/src/forge/screens/LaunchScreen.java
index fdc71f3016e..6732e89fb74 100644
--- a/forge-gui-mobile/src/forge/screens/LaunchScreen.java
+++ b/forge-gui-mobile/src/forge/screens/LaunchScreen.java
@@ -12,7 +12,7 @@ import forge.util.Utils;
public abstract class LaunchScreen extends FScreen {
private static final float MAX_START_BUTTON_HEIGHT = 2 * Utils.AVG_FINGER_HEIGHT;
- private static final float START_BUTTON_RATIO = FSkinImage.BTN_START_UP.getWidth() / FSkinImage.BTN_START_UP.getHeight();
+ private float START_BUTTON_RATIO = 0.f;
private static final float PADDING = FOptionPane.PADDING;
protected final StartButton btnStart = add(new StartButton());
@@ -26,6 +26,11 @@ public abstract class LaunchScreen extends FScreen {
@Override
protected final void doLayout(float startY, float width, float height) {
+ if (Forge.hdstart)
+ START_BUTTON_RATIO = FSkinImage.HDBTN_START_UP.getWidth() / FSkinImage.HDBTN_START_UP.getHeight();
+ else
+ START_BUTTON_RATIO = FSkinImage.BTN_START_UP.getWidth() / FSkinImage.BTN_START_UP.getHeight();
+
float buttonWidth = width - 2 * PADDING;
float buttonHeight = buttonWidth / START_BUTTON_RATIO;
if (buttonHeight > MAX_START_BUTTON_HEIGHT) {
@@ -72,8 +77,12 @@ public abstract class LaunchScreen extends FScreen {
@Override
public void draw(Graphics g) {
- g.drawImage(pressed ? FSkinImage.BTN_START_DOWN : FSkinImage.BTN_START_UP,
+ if (Forge.hdstart)
+ g.drawImage(pressed ? FSkinImage.HDBTN_START_DOWN : FSkinImage.HDBTN_START_UP,
0, 0, getWidth(), getHeight());
+ else
+ g.drawImage(pressed ? FSkinImage.BTN_START_DOWN : FSkinImage.BTN_START_UP,
+ 0, 0, getWidth(), getHeight());
//its must be enabled or you can't start any game modes
if (!Forge.isLoadingaMatch()) {
if(!btnStart.isEnabled())
diff --git a/forge-gui-mobile/src/forge/screens/constructed/PlayerPanel.java b/forge-gui-mobile/src/forge/screens/constructed/PlayerPanel.java
index 028a274db9a..5f0ba1e9be1 100644
--- a/forge-gui-mobile/src/forge/screens/constructed/PlayerPanel.java
+++ b/forge-gui-mobile/src/forge/screens/constructed/PlayerPanel.java
@@ -642,7 +642,7 @@ public class PlayerPanel extends FContainer {
private FLabel createNameRandomizer() {
final FLabel newNameBtn = new FLabel.Builder().iconInBackground(false)
- .icon(FSkinImage.EDIT).opaque(false).build();
+ .icon(Forge.hdbuttons ? FSkinImage.HDEDIT : FSkinImage.EDIT).opaque(false).build();
newNameBtn.setCommand(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
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/match/views/VAssignDamage.java b/forge-gui-mobile/src/forge/screens/match/views/VAssignDamage.java
index 24acb489a04..7dc2743c412 100644
--- a/forge-gui-mobile/src/forge/screens/match/views/VAssignDamage.java
+++ b/forge-gui-mobile/src/forge/screens/match/views/VAssignDamage.java
@@ -17,6 +17,7 @@
*/
package forge.screens.match.views;
+import forge.Forge;
import forge.Graphics;
import forge.assets.FImage;
import forge.assets.FSkinColor;
@@ -224,7 +225,7 @@ public class VAssignDamage extends FDialog {
assignDamageTo(card, false);
}
}).build());
- btnAdd = add(new FLabel.ButtonBuilder().icon(FSkinImage.PLUS).command(new FEventHandler() {
+ btnAdd = add(new FLabel.ButtonBuilder().icon(Forge.hdbuttons ? FSkinImage.HDPLUS : FSkinImage.PLUS).command(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
assignDamageTo(card, true);
diff --git a/forge-gui-mobile/src/forge/screens/match/views/VGameMenu.java b/forge-gui-mobile/src/forge/screens/match/views/VGameMenu.java
index cf900c6c192..8e3dd1579a6 100644
--- a/forge-gui-mobile/src/forge/screens/match/views/VGameMenu.java
+++ b/forge-gui-mobile/src/forge/screens/match/views/VGameMenu.java
@@ -1,5 +1,6 @@
package forge.screens.match.views;
+import forge.Forge;
import forge.assets.FSkinImage;
import forge.deck.Deck;
import forge.deck.FDeckViewer;
@@ -85,7 +86,7 @@ public class VGameMenu extends FDropDownMenu {
autoYields.show();
}
}));
- addItem(new FMenuItem(localizer.getMessage("lblSettings"), FSkinImage.SETTINGS, new FEventHandler() {
+ addItem(new FMenuItem(localizer.getMessage("lblSettings"), Forge.hdbuttons ? FSkinImage.HDPREFERENCE : FSkinImage.SETTINGS, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
SettingsScreen.show(false);
diff --git a/forge-gui-mobile/src/forge/screens/match/views/VPlayerPanel.java b/forge-gui-mobile/src/forge/screens/match/views/VPlayerPanel.java
index 3d24cc4d8e8..72fd71397a5 100644
--- a/forge-gui-mobile/src/forge/screens/match/views/VPlayerPanel.java
+++ b/forge-gui-mobile/src/forge/screens/match/views/VPlayerPanel.java
@@ -61,16 +61,16 @@ public class VPlayerPanel extends FContainer {
field = add(new VField(player));
avatar = add(new VAvatar(player, avatarHeight));
lblLife = add(new LifeLabel());
- addZoneDisplay(ZoneType.Hand, FSkinImage.HAND);
- addZoneDisplay(ZoneType.Graveyard, FSkinImage.GRAVEYARD);
- addZoneDisplay(ZoneType.Library, FSkinImage.LIBRARY);
- addZoneDisplay(ZoneType.Flashback, FSkinImage.FLASHBACK);
+ addZoneDisplay(ZoneType.Hand, Forge.hdbuttons ? FSkinImage.HDHAND : FSkinImage.HAND);
+ addZoneDisplay(ZoneType.Graveyard, Forge.hdbuttons ? FSkinImage.HDGRAVEYARD : FSkinImage.GRAVEYARD);
+ addZoneDisplay(ZoneType.Library, Forge.hdbuttons ? FSkinImage.HDLIBRARY : FSkinImage.LIBRARY);
+ addZoneDisplay(ZoneType.Flashback, Forge.hdbuttons ? FSkinImage.HDFLASHBACK :FSkinImage.FLASHBACK);
VManaPool manaPool = add(new VManaPool(player));
- tabManaPool = add(new InfoTab(FSkinImage.MANA_X, manaPool));
+ tabManaPool = add(new InfoTab(Forge.hdbuttons ? FSkinImage.HDMANAPOOL : FSkinImage.MANA_X, manaPool));
tabs.add(tabManaPool);
- addZoneDisplay(ZoneType.Exile, FSkinImage.EXILE);
+ addZoneDisplay(ZoneType.Exile, Forge.hdbuttons ? FSkinImage.HDEXILE : FSkinImage.EXILE);
commandZone = add(new CommandZoneDisplay(player));
diff --git a/forge-gui-mobile/src/forge/screens/match/views/VStack.java b/forge-gui-mobile/src/forge/screens/match/views/VStack.java
index 7d9c5639694..8f83fef3035 100644
--- a/forge-gui-mobile/src/forge/screens/match/views/VStack.java
+++ b/forge-gui-mobile/src/forge/screens/match/views/VStack.java
@@ -40,6 +40,7 @@ import forge.toolbox.FEvent;
import forge.toolbox.FEvent.FEventHandler;
import forge.toolbox.FLabel;
import forge.util.Localizer;
+import forge.util.TextUtil;
import forge.util.collect.FCollectionView;
import forge.util.Utils;
@@ -372,12 +373,35 @@ public class VStack extends FDropDown {
x += PADDING;
y += PADDING;
- CardRenderer.drawCardWithOverlays(g, stackInstance.getSourceCard(), x, y, CARD_WIDTH, CARD_HEIGHT, CardStackPosition.Top);
+ CardRenderer.drawCardWithOverlays(g, stackInstance.getSourceCard(), x, y, CARD_WIDTH, CARD_HEIGHT, CardStackPosition.Top, true);
x += CARD_WIDTH + PADDING;
w -= x + PADDING - BORDER_THICKNESS;
h -= y + PADDING - BORDER_THICKNESS;
- textRenderer.drawText(g, text, FONT, foreColor, x, y, w, h, y, h, true, Align.left, true);
+
+ String name = stackInstance.getSourceCard().getName();
+ int index = text.indexOf(name);
+ String newtext = "";
+ String cId = "(" + stackInstance.getSourceCard().getId() + ")";
+
+ if (index == -1) {
+ newtext = TextUtil.fastReplace(TextUtil.fastReplace(text.trim(),"--","-"),"- -","-");
+ textRenderer.drawText(g, name + " " + (name.length() > 1 ? cId : "") + "\n" + (newtext.length() > 1 ? newtext : ""),
+ FONT, foreColor, x, y, w, h, y, h, true, Align.left, true);
+
+ } else {
+ String trimFirst = TextUtil.fastReplace("\n" + text.substring(0, index) + text.substring(index + name.length()), "- -", "-");
+ String trimSecond = TextUtil.fastReplace(trimFirst, name+" "+cId, name);
+ newtext = TextUtil.fastReplace(trimSecond, " "+cId, name);
+
+ if(newtext.equals("\n"+name))
+ textRenderer.drawText(g, name + " " + cId, FONT, foreColor, x, y, w, h, y, h, true, Align.left, true);
+ else {
+ newtext = TextUtil.fastReplace(TextUtil.fastReplace(newtext,name+" -","-"), "\n ", "\n");
+ newtext = "\n"+ TextUtil.fastReplace(newtext.trim(),"--","-");
+ textRenderer.drawText(g, name+" "+cId+newtext, FONT, foreColor, x, y, w, h, y, h, true, Align.left, true);
+ }
+ }
g.endClip();
diff --git a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestCollectionScreen.java b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestCollectionScreen.java
index c30a1b50372..8a42dad34ba 100644
--- a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestCollectionScreen.java
+++ b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestCollectionScreen.java
@@ -7,6 +7,7 @@ import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import forge.FThreads;
+import forge.Forge;
import forge.assets.FImage;
import forge.assets.FSkinFont;
import forge.assets.FSkinImage;
@@ -236,7 +237,7 @@ public class ConquestCollectionScreen extends TabPageScreen 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 be42d07df08..3cff3b41e84 100644
--- a/forge-gui-mobile/src/forge/screens/quest/QuestMenu.java
+++ b/forge-gui-mobile/src/forge/screens/quest/QuestMenu.java
@@ -43,7 +43,7 @@ public class QuestMenu extends FPopupMenu implements IVQuestStats {
private static final QuestStatsScreen statsScreen = new QuestStatsScreen();
private static final QuestTournamentsScreen tournamentsScreen = new QuestTournamentsScreen();
- private static final FMenuItem duelsItem = new FMenuItem(Localizer.getInstance().getMessage("lblDuels"), FSkinImage.QUEST_GEAR, new FEventHandler() {
+ private static final FMenuItem duelsItem = new FMenuItem(Localizer.getInstance().getMessage("lblDuels"), FSkinImage.QUEST_BIG_SWORD, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
setCurrentScreen(duelsScreen);
@@ -55,13 +55,13 @@ public class QuestMenu extends FPopupMenu implements IVQuestStats {
setCurrentScreen(challengesScreen);
}
});
- private static final FMenuItem tournamentsItem = new FMenuItem(Localizer.getInstance().getMessage("lblTournaments"), FSkinImage.PACK, new FEventHandler() {
+ private static final FMenuItem tournamentsItem = new FMenuItem(Localizer.getInstance().getMessage("lblTournaments"), FSkinImage.QUEST_BIG_SHIELD, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
setCurrentScreen(tournamentsScreen);
}
});
- private static final FMenuItem decksItem = new FMenuItem(Localizer.getInstance().getMessage("lblQuestDecks"), FSkinImage.DECKLIST, new FEventHandler() {
+ private static final FMenuItem decksItem = new FMenuItem(Localizer.getInstance().getMessage("lblQuestDecks"), FSkinImage.QUEST_BIG_BAG, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
setCurrentScreen(decksScreen);
@@ -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.MULTI, 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);
@@ -119,7 +119,7 @@ public class QuestMenu extends FPopupMenu implements IVQuestStats {
});
}
});
- private static final FMenuItem prefsItem = new FMenuItem(Localizer.getInstance().getMessage("Preferences"), FSkinImage.SETTINGS, new FEventHandler() {
+ private static final FMenuItem prefsItem = new FMenuItem(Localizer.getInstance().getMessage("Preferences"), Forge.hdbuttons ? FSkinImage.HDPREFERENCE : FSkinImage.SETTINGS, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
setCurrentScreen(prefsScreen);
@@ -243,9 +243,9 @@ public class QuestMenu extends FPopupMenu implements IVQuestStats {
addItem(decksItem); decksItem.setSelected(currentScreen == decksScreen);
addItem(spellShopItem); spellShopItem.setSelected(currentScreen == spellShopScreen);
addItem(bazaarItem); bazaarItem.setSelected(currentScreen == bazaarScreen);
- addItem(statsItem); statsItem.setSelected(currentScreen == statsScreen);
addItem(unlockSetsItem);
addItem(travelItem);
+ addItem(statsItem); statsItem.setSelected(currentScreen == statsScreen);
addItem(prefsItem); prefsItem.setSelected(currentScreen == prefsScreen);
}
diff --git a/forge-gui-mobile/src/forge/screens/quest/QuestSpellShopScreen.java b/forge-gui-mobile/src/forge/screens/quest/QuestSpellShopScreen.java
index 24f284689e6..2e9b00b9cc6 100644
--- a/forge-gui-mobile/src/forge/screens/quest/QuestSpellShopScreen.java
+++ b/forge-gui-mobile/src/forge/screens/quest/QuestSpellShopScreen.java
@@ -9,6 +9,7 @@ import java.util.Map.Entry;
import com.badlogic.gdx.utils.Align;
import forge.FThreads;
+import forge.Forge;
import forge.assets.FImage;
import forge.assets.FSkinFont;
import forge.assets.FSkinImage;
@@ -306,7 +307,7 @@ public class QuestSpellShopScreen extends TabPageScreen {
@Override
protected FSkinImage getVerbIcon() {
- return FSkinImage.PLUS;
+ return Forge.hdbuttons ? FSkinImage.HDPLUS : FSkinImage.PLUS;
}
@Override
@@ -317,7 +318,7 @@ public class QuestSpellShopScreen extends TabPageScreen {
private static class InventoryPage extends SpellShopBasePage {
protected FLabel lblSellExtras = add(new FLabel.Builder().text(localizer.getMessage("lblSellAllExtras"))
- .icon(FSkinImage.MINUS).iconScaleFactor(1f).align(Align.right).font(FSkinFont.get(16))
+ .icon(Forge.hdbuttons ? FSkinImage.HDMINUS : FSkinImage.MINUS).iconScaleFactor(1f).align(Align.right).font(FSkinFont.get(16))
.command(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
@@ -366,7 +367,7 @@ public class QuestSpellShopScreen extends TabPageScreen {
@Override
protected FSkinImage getVerbIcon() {
- return FSkinImage.MINUS;
+ return Forge.hdbuttons ? FSkinImage.HDMINUS : FSkinImage.MINUS;
}
@Override
diff --git a/forge-gui-mobile/src/forge/screens/quest/QuestTournamentsScreen.java b/forge-gui-mobile/src/forge/screens/quest/QuestTournamentsScreen.java
index 6b9173f79a7..c8613bf9f42 100644
--- a/forge-gui-mobile/src/forge/screens/quest/QuestTournamentsScreen.java
+++ b/forge-gui-mobile/src/forge/screens/quest/QuestTournamentsScreen.java
@@ -455,7 +455,11 @@ public class QuestTournamentsScreen extends QuestLaunchScreen implements IQuestT
FTextureRegionImage avatar1 = new FTextureRegionImage(FSkin.getAvatars().get(iconIDs[j]));
FTextureRegionImage avatar2 = new FTextureRegionImage(FSkin.getAvatars().get(iconIDs[j+1]));
*/
- labels[j] = add(new FLabel.Builder().icon(currentMatch ? FSkinImage.STAR_FILLED : FSkinImage.STAR_OUTINE).text(labelText).align(Align.center).font(FSkinFont.get(16)).build());
+ if (Forge.hdbuttons)
+ labels[j] = add(new FLabel.Builder().icon(currentMatch ? FSkinImage.HDSTAR_FILLED : FSkinImage.HDSTAR_OUTLINE).text(labelText).align(Align.center).font(FSkinFont.get(16)).build());
+ else
+ labels[j] = add(new FLabel.Builder().icon(currentMatch ? FSkinImage.STAR_FILLED : FSkinImage.STAR_OUTLINE).text(labelText).align(Align.center).font(FSkinFont.get(16)).build());
+
labels[j].setBounds(x, y, w, labels[j].getAutoSizeBounds().height);
if (currentMatch) {
labels[j].setTextColor(FSkinColor.get(FSkinColor.Colors.CLR_ACTIVE));
diff --git a/forge-gui-mobile/src/forge/screens/settings/FilesPage.java b/forge-gui-mobile/src/forge/screens/settings/FilesPage.java
index cedfdcdac4d..bb2ff928276 100644
--- a/forge-gui-mobile/src/forge/screens/settings/FilesPage.java
+++ b/forge-gui-mobile/src/forge/screens/settings/FilesPage.java
@@ -1,5 +1,6 @@
package forge.screens.settings;
+import forge.Forge;
import forge.download.GuiDownloadAchievementImages;
import forge.download.GuiDownloadPicturesLQ;
import forge.download.GuiDownloadPrices;
@@ -31,7 +32,7 @@ public class FilesPage extends TabPage {
private final Localizer localizer = Localizer.getInstance();
protected FilesPage() {
- super(Localizer.getInstance().getMessage("lblFiles"), FSkinImage.OPEN);
+ super(Localizer.getInstance().getMessage("lblFiles"), Forge.hdbuttons ? FSkinImage.HDOPEN : FSkinImage.OPEN);
lstItems.setListItemRenderer(new FilesItemRenderer());
diff --git a/forge-gui-mobile/src/forge/screens/settings/SettingsPage.java b/forge-gui-mobile/src/forge/screens/settings/SettingsPage.java
index cefac814338..975eec792e8 100644
--- a/forge-gui-mobile/src/forge/screens/settings/SettingsPage.java
+++ b/forge-gui-mobile/src/forge/screens/settings/SettingsPage.java
@@ -37,7 +37,7 @@ public class SettingsPage extends TabPage {
private final FGroupList lstSettings = add(new FGroupList<>());
public SettingsPage() {
- super(Localizer.getInstance().getMessage("lblSettings"), FSkinImage.SETTINGS);
+ super(Localizer.getInstance().getMessage("lblSettings"), Forge.hdbuttons ? FSkinImage.HDPREFERENCE : FSkinImage.SETTINGS);
final Localizer localizer = Localizer.getInstance();
diff --git a/forge-gui-mobile/src/forge/toolbox/FButton.java b/forge-gui-mobile/src/forge/toolbox/FButton.java
index e3909565f42..33b64b7b4fc 100644
--- a/forge-gui-mobile/src/forge/toolbox/FButton.java
+++ b/forge-gui-mobile/src/forge/toolbox/FButton.java
@@ -1,5 +1,6 @@
package forge.toolbox;
+import forge.Forge;
import org.apache.commons.lang3.StringUtils;
import com.badlogic.gdx.Input.Keys;
@@ -54,10 +55,21 @@ public class FButton extends FDisplayObject implements IButton {
resetImg();
}
+ private boolean hdbuttonskin(){
+ return Forge.hdbuttons;
+ }
+
private void resetImg() {
- imgL = FSkinImage.BTN_UP_LEFT;
- imgM = FSkinImage.BTN_UP_CENTER;
- imgR = FSkinImage.BTN_UP_RIGHT;
+ if (hdbuttonskin())
+ {
+ imgL = FSkinImage.HDBTN_UP_LEFT;
+ imgM = FSkinImage.HDBTN_UP_CENTER;
+ imgR = FSkinImage.HDBTN_UP_RIGHT;
+ } else {
+ imgL = FSkinImage.BTN_UP_LEFT;
+ imgM = FSkinImage.BTN_UP_CENTER;
+ imgR = FSkinImage.BTN_UP_RIGHT;
+ }
}
public String getText() {
@@ -83,9 +95,16 @@ public class FButton extends FDisplayObject implements IButton {
resetImg();
}
else {
- imgL = FSkinImage.BTN_DISABLED_LEFT;
- imgM = FSkinImage.BTN_DISABLED_CENTER;
- imgR = FSkinImage.BTN_DISABLED_RIGHT;
+ if (hdbuttonskin())
+ {
+ imgL = FSkinImage.HDBTN_DISABLED_LEFT;
+ imgM = FSkinImage.HDBTN_DISABLED_CENTER;
+ imgR = FSkinImage.HDBTN_DISABLED_RIGHT;
+ } else {
+ imgL = FSkinImage.BTN_DISABLED_LEFT;
+ imgM = FSkinImage.BTN_DISABLED_CENTER;
+ imgR = FSkinImage.BTN_DISABLED_RIGHT;
+ }
}
}
@@ -102,17 +121,31 @@ public class FButton extends FDisplayObject implements IButton {
toggled = b0;
if (toggled) {
- imgL = FSkinImage.BTN_TOGGLE_LEFT;
- imgM = FSkinImage.BTN_TOGGLE_CENTER;
- imgR = FSkinImage.BTN_TOGGLE_RIGHT;
+ if (hdbuttonskin())
+ {
+ imgL = FSkinImage.HDBTN_TOGGLE_LEFT;
+ imgM = FSkinImage.HDBTN_TOGGLE_CENTER;
+ imgR = FSkinImage.HDBTN_TOGGLE_RIGHT;
+ } else {
+ imgL = FSkinImage.BTN_TOGGLE_LEFT;
+ imgM = FSkinImage.BTN_TOGGLE_CENTER;
+ imgR = FSkinImage.BTN_TOGGLE_RIGHT;
+ }
}
else if (isEnabled()) {
resetImg();
}
else {
- imgL = FSkinImage.BTN_DISABLED_LEFT;
- imgM = FSkinImage.BTN_DISABLED_CENTER;
- imgR = FSkinImage.BTN_DISABLED_RIGHT;
+ if (hdbuttonskin())
+ {
+ imgL = FSkinImage.HDBTN_DISABLED_LEFT;
+ imgM = FSkinImage.HDBTN_DISABLED_CENTER;
+ imgR = FSkinImage.HDBTN_DISABLED_RIGHT;
+ } else {
+ imgL = FSkinImage.BTN_DISABLED_LEFT;
+ imgM = FSkinImage.BTN_DISABLED_CENTER;
+ imgR = FSkinImage.BTN_DISABLED_RIGHT;
+ }
}
}
@@ -137,9 +170,18 @@ public class FButton extends FDisplayObject implements IButton {
@Override
public final boolean press(float x, float y) {
if (isToggled()) { return true; }
- imgL = FSkinImage.BTN_DOWN_LEFT;
- imgM = FSkinImage.BTN_DOWN_CENTER;
- imgR = FSkinImage.BTN_DOWN_RIGHT;
+
+ if (hdbuttonskin())
+ {
+ imgL = FSkinImage.HDBTN_DOWN_LEFT;
+ imgM = FSkinImage.HDBTN_DOWN_CENTER;
+ imgR = FSkinImage.HDBTN_DOWN_RIGHT;
+ } else {
+ imgL = FSkinImage.BTN_DOWN_LEFT;
+ imgM = FSkinImage.BTN_DOWN_CENTER;
+ imgR = FSkinImage.BTN_DOWN_RIGHT;
+ }
+
return true;
}
diff --git a/forge-gui-mobile/src/forge/toolbox/FFileChooser.java b/forge-gui-mobile/src/forge/toolbox/FFileChooser.java
index b6c4939df97..68bfd16368b 100644
--- a/forge-gui-mobile/src/forge/toolbox/FFileChooser.java
+++ b/forge-gui-mobile/src/forge/toolbox/FFileChooser.java
@@ -367,14 +367,14 @@ public class FFileChooser extends FDialog {
@Override
protected void buildMenu() {
String suffix = value.isDirectory() ? " Folder" : " File";
- addItem(new FMenuItem("Rename" + suffix, FSkinImage.EDIT,
+ addItem(new FMenuItem("Rename" + suffix, Forge.hdbuttons ? FSkinImage.HDEDIT : FSkinImage.EDIT,
new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
renameFile(value);
}
}));
- addItem(new FMenuItem("Delete" + suffix, FSkinImage.DELETE,
+ addItem(new FMenuItem("Delete" + suffix, Forge.hdbuttons ? FSkinImage.HDDELETE : FSkinImage.DELETE,
new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
@@ -392,7 +392,7 @@ public class FFileChooser extends FDialog {
public void drawValue(Graphics g, Integer index, File value, FSkinFont font, FSkinColor foreColor, FSkinColor backColor, boolean pressed, float x, float y, float w, float h) {
if (value.isDirectory()) {
float iconSize = h;
- g.drawImage(FSkinImage.FOLDER, x, y + (h - iconSize) / 2, iconSize, iconSize);
+ g.drawImage(Forge.hdbuttons ? FSkinImage.HDFOLDER : FSkinImage.FOLDER, x, y + (h - iconSize) / 2, iconSize, iconSize);
x += iconSize + FList.PADDING;
}
g.drawText(value.getName(), font, foreColor, x, y, w, h, false, Align.left, true);
diff --git a/forge-gui-mobile/src/forge/toolbox/ListChooser.java b/forge-gui-mobile/src/forge/toolbox/ListChooser.java
index a6df1607acb..065e9dce99e 100644
--- a/forge-gui-mobile/src/forge/toolbox/ListChooser.java
+++ b/forge-gui-mobile/src/forge/toolbox/ListChooser.java
@@ -25,6 +25,7 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import forge.FThreads;
+import forge.Forge;
import forge.Graphics;
import forge.assets.FSkinFont;
import forge.assets.FSkinImage;
@@ -105,19 +106,19 @@ public class ListChooser extends FContainer {
advancedSearchFilter = lstChoices.getListItemRenderer().getAdvancedSearchFilter(this);
if (advancedSearchFilter != null) {
btnSearch = add(new FLabel.ButtonBuilder()
- .icon(FSkinImage.SEARCH).iconScaleFactor(0.9f).command(new FEventHandler() {
+ .icon(Forge.hdbuttons ? FSkinImage.HDSEARCH : FSkinImage.SEARCH).iconScaleFactor(0.9f).command(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
FPopupMenu menu = new FPopupMenu() {
@Override
protected void buildMenu() {
- addItem(new FMenuItem(Localizer.getInstance().getMessage("lblAdvancedSearch"), FSkinImage.SEARCH, new FEventHandler() {
+ addItem(new FMenuItem(Localizer.getInstance().getMessage("lblAdvancedSearch"), Forge.hdbuttons ? FSkinImage.HDSEARCH : FSkinImage.SEARCH, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
advancedSearchFilter.edit();
}
}));
- addItem(new FMenuItem(Localizer.getInstance().getMessage("lblResetFilters"), FSkinImage.DELETE, new FEventHandler() {
+ addItem(new FMenuItem(Localizer.getInstance().getMessage("lblResetFilters"), Forge.hdbuttons ? FSkinImage.HDDELETE : FSkinImage.DELETE, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
resetFilters();
diff --git a/forge-gui/pom.xml b/forge-gui/pom.xml
index d94849de169..5a33c84805e 100644
--- a/forge-gui/pom.xml
+++ b/forge-gui/pom.xml
@@ -4,7 +4,7 @@
forgeforge
- 1.6.33-SNAPSHOT
+ 1.6.34-SNAPSHOTforge-gui
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 c98ef6015bd..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
@@ -1775,7 +1775,1860 @@ Temple of Malice|THB|2
Temple of Plenty|THB|2
Arasta of the Endless Web|THB|3
Alseid of Life's Bounty|THB|2
-Thirst For Meaning|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/a/anax_hardened_in_the_forge.txt b/forge-gui/res/cardsfolder/a/anax_hardened_in_the_forge.txt
index dae37e681db..6c12cf5e065 100755
--- a/forge-gui/res/cardsfolder/a/anax_hardened_in_the_forge.txt
+++ b/forge-gui/res/cardsfolder/a/anax_hardened_in_the_forge.txt
@@ -5,9 +5,10 @@ PT:*/3
S:Mode$ Continuous | EffectZone$ All | CharacteristicDefining$ True | SetPower$ X | Description$ CARDNAME's power is equal to your devotion to red.
SVar:X:Count$Devotion.Red
SVar:BuffedBy:Permanent.Red
-T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.YouCtrl+nonToken+powerLT4 | TriggerZones$ Battlefield | Execute$ Trig1Token | TriggerController$ TriggeredCardController | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another nontoken creature you control dies, create a 1/1 red Satyr creature token with "This creature can't block."
-T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.YouCtrl+nonToken+powerGE4 | TriggerZones$ Battlefield | Execute$ Trig2Token | TriggerController$ TriggeredCardController | TriggerDescription$ Whenever CARDNAME or another nontoken creature you control dies, create a 1/1 red Satyr creature token with "This creature can't block." If the creature had power 4 or greater, create two of those tokens instead.
-SVar:Trig1Token:DB$ Token | TokenAmount$ 1 | TokenScript$ r_1_1_satyr_noblock | TokenOwner$ You | LegacyImage$ r 1 1 satyr noblock thb
-SVar:Trig2Token:DB$ Token | TokenAmount$ 2 | TokenScript$ r_1_1_satyr_noblock | TokenOwner$ You | LegacyImage$ r 1 1 satyr noblock thb
+T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.Other+nonToken+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ Whenever CARDNAME or another nontoken creature you control dies, create a 1/1 red Satyr creature token with "This creature can't block." If the creature had power 4 or greater, create two of those tokens instead.
+T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Secondary$ True | Execute$ TrigToken | TriggerController$ TriggeredCardController | TriggerDescription$ Whenever CARDNAME or another nontoken creature you control dies, create a 1/1 red Satyr creature token with "This creature can't block." If the creature had power 4 or greater, create two of those tokens instead.
+SVar:TrigToken:DB$ Token | TokenAmount$ Y | TokenScript$ r_1_1_satyr_noblock | TokenOwner$ You | LegacyImage$ r 1 1 satyr noblock thb | References$ Y,Z
+SVar:Y:Count$Compare Z GE4.2.1
+SVar:Z:TriggeredCard$CardPower
DeckHas:Ability$Token
Oracle:Anax's power is equal to your devotion to red. (Each {R} in the mana costs of permanents you control counts toward your devotion to red.)\nWhenever Anax or another nontoken creature you control dies, create a 1/1 red Satyr creature token with "This creature can't block." If the creature had power 4 or greater, create two of those tokens instead.
diff --git a/forge-gui/res/cardsfolder/b/ballot_broker.txt b/forge-gui/res/cardsfolder/b/ballot_broker.txt
index 23086c0407f..ea6110e74ce 100644
--- a/forge-gui/res/cardsfolder/b/ballot_broker.txt
+++ b/forge-gui/res/cardsfolder/b/ballot_broker.txt
@@ -2,5 +2,5 @@ Name:Ballot Broker
ManaCost:2 W
Types:Creature Human Advisor
PT:2/3
-S:Mode$ Continuous | Affected$ You | AddKeyword$ You may vote an additional time. | Description$ While voting, you may vote an additional time. (The votes can be for different choices or for the same choice.)
-Oracle:While voting, you may vote an additional time. (The votes can be for different choices or for the same choice.)
\ No newline at end of file
+S:Mode$ Continuous | Affected$ You | AdditionalOptionalVote$ 1 | Description$ While voting, you may vote an additional time. (The votes can be for different choices or for the same choice.)
+Oracle:While voting, you may vote an additional time. (The votes can be for different choices or for the same choice.)
diff --git a/forge-gui/res/cardsfolder/b/band_together.txt b/forge-gui/res/cardsfolder/b/band_together.txt
index be270e51b83..4caf0595600 100644
--- a/forge-gui/res/cardsfolder/b/band_together.txt
+++ b/forge-gui/res/cardsfolder/b/band_together.txt
@@ -1,7 +1,10 @@
Name:Band Together
ManaCost:2 G
Types:Instant
-A:SP$ Pump | Cost$ 2 G | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select up to two target creatures you control | AILogic$ PowerDmg | SubAbility$ SoulsDamage | TargetMin$ 0 | TargetMax$ 2 | StackDescription$ None | SpellDescription$ Up to two target creatures you control each deal damage equal to their power to another target creature.
-SVar:SoulsDamage:DB$ DealDamage | ValidTgts$ Creature | TgtPrompt$ Select target creature to be dealt damage | NumDmg$ X | References$ X | TargetUnique$ True | DamageSource$ ParentTarget
-SVar:X:ParentTargeted$CardPower
+A:SP$ Pump | Cost$ 2 G | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select up to two target creatures you control | ImprintCards$ Targeted | AILogic$ PowerDmg | SubAbility$ DBPump | TargetMin$ 0 | TargetMax$ 2 | StackDescription$ SpellDescription | SpellDescription$ Up to two target creatures you control each deal damage equal to their power to another target creature.
+SVar:DBPump:DB$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature to be dealt damage | RememberObjects$ ThisTargetedCard | IsCurse$ True | SubAbility$ DBEachDamage | StackDescription$ None
+SVar:DBEachDamage:DB$ EachDamage | ValidCards$ Creature.IsImprinted | NumDmg$ X | References$ X | DamageDesc$ damage equal to its power | DefinedCards$ Remembered | SubAbility$ DBCleanup | StackDescription$ None
+#NumDmg isn't really used here. It is left for clarity. The AF pulls Damage straight from "X" hardcoded.
+SVar:X:Count$CardPower
+SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearImprinted$ True
Oracle:Up to two target creatures you control each deal damage equal to their power to another target creature.
diff --git a/forge-gui/res/cardsfolder/b/bragos_representative.txt b/forge-gui/res/cardsfolder/b/bragos_representative.txt
index 40fedfb2763..12ff6add8d1 100644
--- a/forge-gui/res/cardsfolder/b/bragos_representative.txt
+++ b/forge-gui/res/cardsfolder/b/bragos_representative.txt
@@ -2,6 +2,6 @@ Name:Brago's Representative
ManaCost:2 W
Types:Creature Human Advisor
PT:1/4
-S:Mode$ Continuous | Affected$ You | AddKeyword$ You get an additional vote. | Description$ While voting, you get an additional vote. (The votes can be for different choices or for the same choice.)
+S:Mode$ Continuous | Affected$ You | AdditionalVote$ 1 | Description$ While voting, you get an additional vote. (The votes can be for different choices or for the same choice.)
SVar:Picture:http://www.wizards.com/global/images/magic/general/bragos_representative.jpg
Oracle:While voting, you get an additional vote. (The votes can be for different choices or for the same choice.)
diff --git a/forge-gui/res/cardsfolder/b/bronze_tablet.txt b/forge-gui/res/cardsfolder/b/bronze_tablet.txt
new file mode 100644
index 00000000000..49d262d1f40
--- /dev/null
+++ b/forge-gui/res/cardsfolder/b/bronze_tablet.txt
@@ -0,0 +1,23 @@
+Name:Bronze Tablet
+ManaCost:6
+Types:Artifact
+K:Remove CARDNAME from your deck before playing if you're not playing for ante.
+K:CARDNAME enters the battlefield tapped.
+A:AB$ Pump | Cost$ 4 T | ValidTgts$ Permanent.nonToken+OppOwn | TgtPrompt$ Select target nontoken permanent an opponent owns | RememberObjects$ TargetedController | SubAbility$ Choice1 | StackDescription$ SpellDescription | SpellDescription$ Exile CARDNAME and target nontoken permanent an opponent owns. That player may pay 10 life. If they do, put Bronze Tablet into its owner’s graveyard. Otherwise, that player owns Bronze Tablet and you own the other exiled card.
+SVar:Choice1:DB$ GenericChoice | Choices$ ExchangeOwnership,Concede | Defined$ TargetedOwner | ConditionCheckSVar$ X | References$ X | ConditionSVarCompare$ LT10 | SubAbility$ Choice2 | StackDescription$ None
+SVar:Choice2:DB$ GenericChoice | Choices$ PayLife,ExchangeOwnership,Concede | Defined$ TargetedOwner | ConditionCheckSVar$ X | References$ X | ConditionSVarCompare$ GE10 | StackDescription$ None
+SVar:X:PlayerCountRemembered$LifeTotal
+SVar:ExchangeOwnership:DB$ GainOwnership | Defined$ Targeted | DefinedPlayer$ You | SubAbility$ TargetToExile1 | SpellDescription$ Exchange ownership of your card for Bronze Tablet (both cards remain exiled)
+SVar:TargetToExile1:DB$ ChangeZone | Defined$ Targeted | Origin$ All | Destination$ Exile | SubAbility$ BronzeExchange
+SVar:BronzeExchange:DB$ GainOwnership | Defined$ Self | DefinedPlayer$ Remembered | SubAbility$ TabletToExile1
+SVar:TabletToExile1:DB$ ChangeZone | Defined$ Self | Origin$ All | Destination$ Exile | SubAbility$ DBCleanup
+SVar:PayLife:DB$ LoseLife | LifeAmount$ 10 | Defined$ TargetedOwner | SubAbility$ TargetToExile2 | SpellDescription$ Pay 10 life (your card remains exiled and Bronze Tablet goes to its owner's graveyard)
+SVar:TargetToExile2:DB$ ChangeZone | Defined$ Targeted | Origin$ All | Destination$ Exile | SubAbility$ TabletToExile2
+SVar:TabletToExile2:DB$ ChangeZone | Defined$ Self | Origin$ All | Destination$ Exile | SubAbility$ TabletToGraveyard
+SVar:TabletToGraveyard:DB$ ChangeZone | Defined$ Self | Origin$ Exile | Destination$ Graveyard | SubAbility$ DBCleanup
+SVar:Concede:DB$ LosesGame | Defined$ TargetedOwner | SpellDescription$ Concede the game | SubAbility$ TargetToExile3
+SVar:TargetToExile3:DB$ ChangeZone | Defined$ Targeted | Origin$ All | Destination$ Exile | SubAbility$ TabletToExile3
+SVar:TabletToExile3:DB$ ChangeZone | Defined$ Self | Origin$ All | Destination$ Exile | SubAbility$ DBCleanup
+SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
+AI:RemoveDeck:All
+Oracle:Remove Bronze Tablet from your deck before playing if you’re not playing for ante.\nBronze Tablet enters the battlefield tapped.\n{4}, {T}: Exile Bronze Tablet and target nontoken permanent an opponent owns. That player may pay 10 life. If they do, put Bronze Tablet into its owner’s graveyard. Otherwise, that player owns Bronze Tablet and you own the other exiled card.
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/c/combo_attack.txt b/forge-gui/res/cardsfolder/c/combo_attack.txt
new file mode 100644
index 00000000000..f9bcd9046bc
--- /dev/null
+++ b/forge-gui/res/cardsfolder/c/combo_attack.txt
@@ -0,0 +1,10 @@
+Name:Combo Attack
+ManaCost:2 G
+Types:Sorcery
+A:SP$ Pump | Cost$ 2 G | ValidTgts$ Creature.YourTeamCtrl | TgtPrompt$ Select two target creatures your team controls | ImprintCards$ Targeted | TargetMin$ 2 | TargetMax$ 2 | AILogic$ PowerDmg | SubAbility$ DBPump | StackDescription$ SpellDescription | SpellDescription$ Two target creatures your team controls each deal damage equal to their power to target creature.
+SVar:DBPump:DB$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature to be dealt damage | RememberObjects$ ThisTargetedCard | IsCurse$ True | SubAbility$ DBEachDamage | StackDescription$ None
+SVar:DBEachDamage:DB$ EachDamage | ValidCards$ Creature.IsImprinted | NumDmg$ X | References$ X | DefinedCards$ Remembered | SubAbility$ DBCleanup | StackDescription$ None
+#NumDmg isn't really used here. It is left for clarity. The AF pulls Damage straight from "X" hardcoded.
+SVar:X:Count$CardPower
+SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearImprinted$ True
+Oracle:Two target creatures your team controls each deal damage equal to their power to target creature.
diff --git a/forge-gui/res/cardsfolder/c/crashing_boars.txt b/forge-gui/res/cardsfolder/c/crashing_boars.txt
index c8f4d34763a..11e5e01f776 100644
--- a/forge-gui/res/cardsfolder/c/crashing_boars.txt
+++ b/forge-gui/res/cardsfolder/c/crashing_boars.txt
@@ -2,8 +2,6 @@ Name:Crashing Boars
ManaCost:3 G G
Types:Creature Boar
PT:4/4
-T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigChoose | TriggerDescription$ Whenever CARDNAME attacks, defending player chooses an untapped creature they control. That creature blocks CARDNAME this turn if able.
-SVar:TrigChoose:DB$ ChooseCard | Defined$ DefendingPlayer | Amount$ 1 | Choices$ Creature.untapped+DefenderCtrl | Mandatory$ True | SubAbility$ DBMustBlock
-SVar:DBMustBlock:DB$ MustBlock | Defined$ ChosenCard
-SVar:Picture:http://www.wizards.com/global/images/magic/general/crashing_boars.jpg
+T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ DBMustBlock | TriggerDescription$ Whenever CARDNAME attacks, defending player chooses an untapped creature they control. That creature blocks CARDNAME this turn if able.
+SVar:DBMustBlock:DB$ MustBlock | Choices$ Creature.untapped+DefenderCtrl | Chooser$ DefendingPlayer
Oracle:Whenever Crashing Boars attacks, defending player chooses an untapped creature they control. That creature blocks Crashing Boars this turn if able.
diff --git a/forge-gui/res/cardsfolder/c/crumble_to_dust.txt b/forge-gui/res/cardsfolder/c/crumble_to_dust.txt
index 0a08f9c367f..94fb7c1b4a2 100644
--- a/forge-gui/res/cardsfolder/c/crumble_to_dust.txt
+++ b/forge-gui/res/cardsfolder/c/crumble_to_dust.txt
@@ -2,8 +2,12 @@ Name:Crumble to Dust
ManaCost:3 R
Types:Sorcery
K:Devoid
-A:SP$ ChangeZone | Cost$ 3 R | Origin$ Battlefield | Destination$ Exile | ValidTgts$ Land.nonBasic | TgtPrompt$ Select target nonbasic land | RememberTargets$ True | ForgetOtherTargets$ True | SubAbility$ DBChangeZoneAll | SpellDescription$ Exile target nonbasic land. Search its controller's graveyard, hand, and library for any number of cards with the same name as that land and exile them. Then that player shuffles his or library.
-SVar:DBChangeZoneAll:DB$ ChangeZoneAll | ChangeType$ Remembered.sameName | Origin$ Graveyard,Hand,Library | Defined$ TargetedController | Destination$ Exile | Search$ True | Shuffle$ True | SubAbility$ DBCleanup
-SVar:DBCleanup:DB$Cleanup | ClearRemembered$ True
-SVar:Picture:http://www.wizards.com/global/images/magic/general/crumble_to_dust.jpg
+A:SP$ ChangeZone | Cost$ 3 R | Origin$ Battlefield | Destination$ Exile | ValidTgts$ Land.nonBasic | TgtPrompt$ Select target nonbasic land | RememberChanged$ True | SubAbility$ ExileYard | SpellDescription$ Exile target nonbasic land. Search its controller's graveyard, hand, and library for any number of cards with the same name as that land and exile them. Then that player shuffles his or library.
+SVar:ExileYard:DB$ ChangeZone | ChangeType$ Remembered.sameName | Origin$ Graveyard | DefinedPlayer$ TargetedController | Chooser$ You | Destination$ Exile | ChangeNum$ NumInYard | References$ NumInYard | Hidden$ True | SubAbility$ ExileHand | StackDescription$ None
+SVar:ExileHand:DB$ ChangeZone | Origin$ Hand | Destination$ Exile | DefinedPlayer$ TargetedController | ChangeType$ Remembered.sameName | ChangeNum$ NumInHand | References$ NumInHand | Chooser$ You | SubAbility$ ExileLib | StackDescription$ None
+SVar:ExileLib:DB$ ChangeZone | Origin$ Library | Destination$ Exile | DefinedPlayer$ TargetedController | ChangeType$ Remembered.sameName | ChangeNum$ NumInLib | References$ NumInLib | Chooser$ You | Shuffle$ True | StackDescription$ None | SubAbility$ DBCleanup
+SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
+SVar:NumInLib:TargetedController$CardsInLibrary
+SVar:NumInHand:TargetedController$CardsInHand
+SVar:NumInYard:TargetedController$CardsInGraveyard
Oracle:Exile target nonbasic land. Search its controller's graveyard, hand, and library for any number of cards with the same name as that land and exile them. Then that player shuffles his or library.
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/d/dwarven_recruiter.txt b/forge-gui/res/cardsfolder/d/dwarven_recruiter.txt
index 3567f8d241b..50088beaa1e 100644
--- a/forge-gui/res/cardsfolder/d/dwarven_recruiter.txt
+++ b/forge-gui/res/cardsfolder/d/dwarven_recruiter.txt
@@ -6,5 +6,6 @@ T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.S
SVar:TrigChangeZone:DB$ ChangeZone | ChangeNum$ X | ChangeType$ Dwarf | Origin$ Library | Destination$ Library | LibraryPosition$ 0 | References$ X
SVar:X:Count$InYourLibrary.Dwarf
AI:RemoveDeck:All
+DeckNeeds:Type$Dwarf
SVar:Picture:http://www.wizards.com/global/images/magic/general/dwarven_recruiter.jpg
Oracle:When Dwarven Recruiter enters the battlefield, search your library for any number of Dwarf cards and reveal those cards. Shuffle your library, then put them on top of it in any order.
diff --git a/forge-gui/res/cardsfolder/e/emergency_powers.txt b/forge-gui/res/cardsfolder/e/emergency_powers.txt
index d82b68b8eb8..84610700c27 100644
--- a/forge-gui/res/cardsfolder/e/emergency_powers.txt
+++ b/forge-gui/res/cardsfolder/e/emergency_powers.txt
@@ -1,8 +1,10 @@
Name:Emergency Powers
ManaCost:5 W U
Types:Instant
-A:SP$ ChangeZoneAll | Cost$ 5 W U | ChangeType$ Card | Origin$ Hand,Graveyard | Destination$ Library | Shuffle$ True | Random$ True | SubAbility$ DBDraw | UseAllOriginZones$ True | AILogic$ Timetwister | SpellDescription$ Each player shuffles their hand and hand into their library, then draws seven cards. Exile CARDNAME.
-SVar:DBDraw:DB$ Draw | NumCards$ 7 | Defined$ Player | SubAbility$ DBChange
-SVar:DBChange:DB$ ChangeZone | Origin$ Stack | Destination$ Exile | SubAbility$ DBAddendum
-SVar:DBAddendum:DB$ ChangeZone | Origin$ Hand | Destination$ Battlefield | ChangeType$ Permanent.cmcLE7+YouCtrl | ChangeNum$ 1 | ConditionPlayerTurn$ True | ConditionPhases$ Main1,Main2 | ConditionDefined$ Self | ConditionPresent$ Card.wasCast | SpellDescription$ Addendum - If you cast this spell during your main phase, you may put a permanent card with converted mana cost 7 or less from your hand onto the battlefield.
+A:SP$ ChangeZoneAll | Cost$ 5 W U | ChangeType$ Card | Origin$ Hand,Graveyard | Destination$ Library | Shuffle$ True | Random$ True | SubAbility$ DBDraw | UseAllOriginZones$ True | AILogic$ Timetwister | StackDescription$ SpellDescription | SpellDescription$ Each player shuffles their hand and hand into their library, then draws seven cards. Exile CARDNAME.
+SVar:DBDraw:DB$ Draw | NumCards$ 7 | Defined$ Player | SubAbility$ DBAddendum | StackDescription$ None
+SVar:DBAddendum:DB$ ChooseCard | ChoiceZone$ Hand | Defined$ You | Amount$ 1 | Choices$ Permanent.cmcLE7+YouCtrl | AILogic$ BestCard | ConditionPlayerTurn$ True | ConditionPhases$ Main1,Main2 | ConditionDefined$ Self | ConditionPresent$ Card.wasCast | SubAbility$ DBChange | StackDescription$ SpellDescription | SpellDescription$ Addendum - If you cast this spell during your main phase, you may put a permanent card with converted mana cost 7 or less from your hand onto the battlefield.
+SVar:DBChange:DB$ ChangeZone | Origin$ Hand | Destination$ Battlefield | Defined$ ChosenCard | ConditionPlayerTurn$ True | ConditionPhases$ Main1,Main2 | ConditionDefined$ Self | ConditionPresent$ Card.wasCast | SubAbility$ DBCleanup | StackDescription$ None
+SVar:DBCleanup:DB$ Cleanup | ClearChosen$ True | SubAbility$ DBExile
+SVar:DBExile:DB$ ChangeZone | Origin$ Stack | Destination$ Exile | StackDescription$ None
Oracle:Each player shuffles their hand and graveyard into their library, then draws seven cards. Exile Emergency Powers.\nAddendum — If you cast this spell during your main phase, you may put a permanent card with converted mana cost 7 or less from your hand onto the battlefield.
diff --git a/forge-gui/res/cardsfolder/e/etchings_of_the_chosen.txt b/forge-gui/res/cardsfolder/e/etchings_of_the_chosen.txt
index 1c228a4560e..1da44289997 100644
--- a/forge-gui/res/cardsfolder/e/etchings_of_the_chosen.txt
+++ b/forge-gui/res/cardsfolder/e/etchings_of_the_chosen.txt
@@ -7,5 +7,5 @@ S:Mode$ Continuous | Affected$ Creature.ChosenType+YouCtrl | AddPower$ 1 | AddTo
AI:RemoveDeck:Random
SVar:PlayMain1:TRUE
SVar:AIPreference:SacCost$Creature.ChosenType+Other
-A:AB$ Pump | Cost$ 1 W B Sac<1/Creature.ChosenType/creature of the chosen type> | ValidTgts$ Creature | TgtPrompt$ Select target creature you control | KW$ Indestructible | SpellDescription$ Target creature you control gains indestructible until end of turn.
+A:AB$ Pump | Cost$ 1 Sac<1/Creature.ChosenType/creature of the chosen type> | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | KW$ Indestructible | SpellDescription$ Target creature you control gains indestructible until end of turn.
Oracle:As Etchings of the Chosen enters the battlefield, choose a creature type.\nCreatures you control of the chosen type get +1/+1.\n{1}, Sacrifice a creature of the chosen type: Target creature you control gains indestructible until end of turn.
diff --git a/forge-gui/res/cardsfolder/e/expropriate.txt b/forge-gui/res/cardsfolder/e/expropriate.txt
new file mode 100644
index 00000000000..3ced790ee5e
--- /dev/null
+++ b/forge-gui/res/cardsfolder/e/expropriate.txt
@@ -0,0 +1,9 @@
+Name:Expropriate
+ManaCost:7 U U
+Types:Sorcery
+A:SP$ Vote | Cost$ 7 U U | Defined$ Player | VoteType$ Time,Money | VoteTime$ DBTime | VoteMoney$ DBMoney | EachVote$ True | SubAbility$ DBChange | SpellDescription$ Council’s dilemma — Starting with you, each player votes for time or money. For each time vote, take an extra turn after this one. For each money vote, choose a permanent owned by the voter and gain control of it. Exile Expropriate.
+SVar:DBTime:DB$ AddTurn | Defined$ You | NumTurns$ 1
+SVar:DBMoney:DB$ ChooseCard | Defined$ You | Choices$ Permanent.RememberedPlayerOwn | SubAbility$ DBControl
+SVar:DBControl:DB$ GainControl | Defined$ ChosenCard | NewController$ You
+SVar:DBChange:DB$ ChangeZone | Origin$ Stack | Destination$ Exile | StackDescription$ None
+Oracle:Council’s dilemma — Starting with you, each player votes for time or money. For each time vote, take an extra turn after this one. For each money vote, choose a permanent owned by the voter and gain control of it. Exile Expropriate.
diff --git a/forge-gui/res/cardsfolder/f/fervent_champion.txt b/forge-gui/res/cardsfolder/f/fervent_champion.txt
index 641b64e0b5d..72f720c033d 100644
--- a/forge-gui/res/cardsfolder/f/fervent_champion.txt
+++ b/forge-gui/res/cardsfolder/f/fervent_champion.txt
@@ -4,8 +4,8 @@ Types:Creature Human Knight
PT:1/1
K:First Strike
K:Haste
-T:Mode$ Attacks | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigPump | TriggerDescription$ Whenever CARDNAME attacks, another target creature you control gets +1/+0 until end of turn.
-SVar:TrigPump:DB$Pump | ValidTgts$ Knight.YouCtrl+Other | TgtPrompt$ Select another target attacking Knight you control | NumAtt$ +1
+T:Mode$ Attacks | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigPump | TriggerDescription$ Whenever CARDNAME attacks, another target attacking Knight you control gets +1/+0 until end of turn.
+SVar:TrigPump:DB$ Pump | ValidTgts$ Knight.YouCtrl+attacking+Other | TgtPrompt$ Select another target attacking Knight you control | NumAtt$ +1
SVar:HasAttackEffect:TRUE
S:Mode$ ReduceCost | ValidTarget$ Card.Self | ValidSpell$ Activated.Equip | Activator$ You | Amount$ 3 | Description$ Equip abilities you activate that target CARDNAME cost {3} less to activate.
Oracle:First strike, haste\nWhenever Fervent Champion attacks, another target attacking Knight you control gets +1/+0 until end of turn.\nEquip abilities you activate that target Fervent Champion cost {3} less to activate.
diff --git a/forge-gui/res/cardsfolder/f/frenetic_sliver.txt b/forge-gui/res/cardsfolder/f/frenetic_sliver.txt
index 5c6cba7d168..ba69c73564a 100644
--- a/forge-gui/res/cardsfolder/f/frenetic_sliver.txt
+++ b/forge-gui/res/cardsfolder/f/frenetic_sliver.txt
@@ -3,12 +3,11 @@ ManaCost:1 U R
Types:Creature Sliver
PT:2/2
S:Mode$ Continuous | Affected$ Sliver | AddAbility$ Frenetic | AddSVar$ DBExile & DelTrig & MoveBack & DBSacSelf | Description$ All Slivers have "{0}: If this permanent is on the battlefield, flip a coin. If you win the flip, exile this permanent and return it to the battlefield under its owner's control at the beginning of the next end step. If you lose the flip, sacrifice it."
-SVar:Frenetic:DB$ FlipACoin | ConditionPresent$ Card.Self | ConditionCompare$ EQ1 | WinSubAbility$ DBExile | LoseSubAbility$ DBSacSelf | SpellDescription$ If this permanent is on the battlefield, flip a coin. If you win the flip, exile this permanent and return it to the battlefield under its owner's control at the beginning of the next end step. If you lose the flip, sacrifice it.
+SVar:Frenetic:AB$ FlipACoin | Cost$ 0 | ConditionPresent$ Card.Self | ConditionCompare$ EQ1 | WinSubAbility$ DBExile | LoseSubAbility$ DBSacSelf | SpellDescription$ If this permanent is on the battlefield, flip a coin. If you win the flip, exile this permanent and return it to the battlefield under its owner's control at the beginning of the next end step. If you lose the flip, sacrifice it.
SVar:DBExile:DB$ ChangeZone | Origin$ Battlefield | Destination$ Exile | Defined$ Self | SubAbility$ DelTrig
SVar:DelTrig:DB$ DelayedTrigger | Mode$ Phase | Phase$ End of Turn | Execute$ MoveBack | Static$ True
SVar:MoveBack:DB$ ChangeZone | Origin$ Exile | Destination$ Battlefield | Defined$ Self
SVar:DBSacSelf:DB$ Sacrifice | Defined$ Self
SVar:PlayMain1:TRUE
AI:RemoveDeck:All
-SVar:Picture:http://www.wizards.com/global/images/magic/general/frenetic_sliver.jpg
Oracle:All Slivers have "{0}: If this permanent is on the battlefield, flip a coin. If you win the flip, exile this permanent and return it to the battlefield under its owner's control at the beginning of the next end step. If you lose the flip, sacrifice it."
diff --git a/forge-gui/res/cardsfolder/f/fumble.txt b/forge-gui/res/cardsfolder/f/fumble.txt
new file mode 100644
index 00000000000..ea6bf8df7f8
--- /dev/null
+++ b/forge-gui/res/cardsfolder/f/fumble.txt
@@ -0,0 +1,13 @@
+Name:Fumble
+ManaCost:1 U
+Types:Instant
+A:SP$ Pump | Cost$ 1 U | IsCurse$ True | ValidTgts$ Creature | TgtPrompt$ Select target creature | SubAbility$ DBRem | StackDescription$ SpellDescription | SpellDescription$ Return target creature to its owner’s hand. Gain control of all Auras and Equipment that were attached to it, then attach them to another creature.
+SVar:DBRem:DB$ PumpAll | ValidCards$ Aura.AttachedTo Targeted,Equipment.AttachedTo Targeted | RememberAllPumped$ True | SubAbility$ DBBounce
+SVar:DBBounce:DB$ ChangeZone | Defined$ Targeted | Origin$ Battlefield | Destination$ Hand | SubAbility$ ChooseNewHost
+SVar:ChooseNewHost:DB$ ChooseCard | Defined$ You | Amount$ 1 | Choices$ Creature.CanBeEnchantedByAllRemembered | ChoiceZone$ Battlefield | SubAbility$ GainControl
+SVar:GainControl:DB$ GainControl | AllValid$ Equipment.IsRemembered,Enchantment.IsRemembered | NewController$ You | ConditionDefined$ ChosenCard | ConditionPresent$ Card | ConditionCompare$ EQ1 | SubAbility$ DBAttach
+SVar:DBAttach:DB$ Attach | Object$ Remembered | Defined$ ChosenCard | SubAbility$ CleanUpEnchantments
+SVar:CleanUpEnchantments:DB$ ChangeZone | Origin$ All | Destination$ Graveyard | ChangeType$ Enchantment.IsRemembered | ConditionDefined$ ChosenCard | ConditionPresent$ Card | ConditionCompare$ EQ0 | SubAbility$ ControlEquipment
+SVar:ControlEquipment:DB$ GainControl | AllValid$ Equipment.IsRemembered | NewController$ You | ConditionDefined$ ChosenCard | ConditionPresent$ Card | ConditionCompare$ EQ0 | SubAbility$ DBCleanUp
+SVar:DBCleanUp:DB$ Cleanup | ClearRemembered$ True
+Oracle:Return target creature to its owner’s hand. Gain control of all Auras and Equipment that were attached to it, then attach them to another creature.
\ No newline at end of file
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/g/glyph_of_delusion.txt b/forge-gui/res/cardsfolder/g/glyph_of_delusion.txt
new file mode 100644
index 00000000000..090f3b5a546
--- /dev/null
+++ b/forge-gui/res/cardsfolder/g/glyph_of_delusion.txt
@@ -0,0 +1,11 @@
+Name:Glyph of Delusion
+ManaCost:U
+Types:Instant
+A:SP$ Pump | Cost$ U | ValidTgts$ Wall.blockedThisTurn | TgtPrompt$ Select target Wall that blocked this turn | SubAbility$ DBPutCounter | StackDescription$ SpellDescription | SpellDescription$ Put X glyph counters on target creature that target Wall blocked this turn, where X is the power of that blocked creature. The creature gains “This creature doesn’t untap during your untap step if it has a glyph counter on it” and “At the beginning of your upkeep, remove a glyph counter from this creature.”
+SVar:DBPutCounter:DB$ PutCounter | CounterType$ GLYPH | CounterNum$ X | References$ X | ValidTgts$ Creature.blockedByValidThisTurn ParentTarget | TgtPrompt$ Select target creature blocked by target Wall this turn to put counters on | SubAbility$ Delude | IsCurse$ True
+SVar:X:Targeted$CardPower
+SVar:Delude:DB$ Animate | Defined$ ParentTarget | staticAbilities$ Delusional | Triggers$ TrigGlyphUpkeep | sVars$ LoseGlyph | Permanent$ True | StackDescription$ None
+SVar:Delusional:Mode$ Continuous | Affected$ Card.Self+counters_GE1_GLYPH | AddHiddenKeyword$ CARDNAME doesn't untap during your untap step. | Description$ CARDNAME doesn't untap during your untap step if it has a glyph counter on it.
+SVar:TrigGlyphUpkeep:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ LoseGlyph | TriggerDescription$ At the beginning of your upkeep, remove a glyph counter from CARDNAME.
+SVar:LoseGlyph:DB$ RemoveCounter | CounterType$ GLYPH | CounterNum$ 1
+Oracle:Put X glyph counters on target creature that target Wall blocked this turn, where X is the power of that blocked creature. The creature gains “This creature doesn’t untap during your untap step if it has a glyph counter on it” and “At the beginning of your upkeep, remove a glyph counter from this creature.”
diff --git a/forge-gui/res/cardsfolder/g/glyph_of_reincarnation.txt b/forge-gui/res/cardsfolder/g/glyph_of_reincarnation.txt
new file mode 100644
index 00000000000..09fe0e77f23
--- /dev/null
+++ b/forge-gui/res/cardsfolder/g/glyph_of_reincarnation.txt
@@ -0,0 +1,10 @@
+Name:Glyph of Reincarnation
+ManaCost:G
+Types:Instant
+A:SP$ Pump | Cost$ G | ValidTgts$ Wall | TgtPrompt$ Select target Wall | AILogic$ Pump | ActivationPhases$ Main2->End of Turn | SubAbility$ DBDestroyAll | StackDescription$ SpellDescription | SpellDescription$ Cast this spell only after combat.
+SVar:DBDestroyAll:DB$ DestroyAll | ValidCards$ Creature.blockedByValidThisTurn ParentTarget | NoRegen$ True | RememberDestroyed$ True | SubAbility$ DBChoose | StackDescription$ SpellDescription | SpellDescription$ Destroy all creatures that were blocked by target Wall this turn. They can’t be regenerated.
+SVar:DBChoose:DB$ ChooseCard | Defined$ You | Choices$ Creature.OwnedBy Player.Active | ChoiceTitle$ Choose creatures to put on the battlefield | ChoiceZone$ Graveyard | Amount$ X | References$ X | Mandatory$ True | AILogic$ WorstCard | SubAbility$ DBChangeZone | StackDescription$ SpellDescription | SpellDescription$ For each creature that died this way, put a creature card from the graveyard of the player who controlled that creature the last time it became blocked by that Wall onto the battlefield under its owner’s control.
+SVar:DBChangeZone:DB$ ChangeZone | Defined$ ChosenCard | Origin$ Graveyard | Destination$ Battlefield | SubAbility$ DBCleanup
+SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
+SVar:X:Count$ValidGraveyard Creature.IsRemembered
+Oracle:Cast this spell only after combat.\nDestroy all creatures that were blocked by target Wall this turn. They can’t be regenerated. For each creature that died this way, put a creature card from the graveyard of the player who controlled that creature the last time it became blocked by that Wall onto the battlefield under its owner’s control.
diff --git a/forge-gui/res/cardsfolder/i/illusion_of_choice.txt b/forge-gui/res/cardsfolder/i/illusion_of_choice.txt
index 851503cf9a0..805ccb7b2eb 100644
--- a/forge-gui/res/cardsfolder/i/illusion_of_choice.txt
+++ b/forge-gui/res/cardsfolder/i/illusion_of_choice.txt
@@ -3,6 +3,6 @@ ManaCost:U
Types:Instant
A:SP$ Effect | Cost$ U | Name$ Illusion of Choice Effect | StaticAbilities$ STVoter | SubAbility$ DBDraw | SpellDescription$ You choose how each player votes this turn. Draw a card.
SVar:DBDraw:DB$ Draw | NumCards$ 1
-SVar:STVoter:Mode$ Continuous | EffectZone$ Command | Affected$ You | AddKeyword$ You choose how each player votes this turn. | Description$ You choose how each player votes this turn.
+SVar:STVoter:Mode$ Continuous | EffectZone$ Command | Affected$ You | ControlVote$ True | Description$ You choose how each player votes this turn.
AI:RemoveDeck:All
-Oracle:You choose how each player votes this turn. Draw a card.
\ No newline at end of file
+Oracle:You choose how each player votes this turn. Draw a card.
diff --git a/forge-gui/res/cardsfolder/i/invasive_surgery.txt b/forge-gui/res/cardsfolder/i/invasive_surgery.txt
index 819ca8c4b2e..b680509c8ce 100644
--- a/forge-gui/res/cardsfolder/i/invasive_surgery.txt
+++ b/forge-gui/res/cardsfolder/i/invasive_surgery.txt
@@ -1,10 +1,14 @@
Name:Invasive Surgery
ManaCost:U
Types:Instant
-A:SP$ Counter | Cost$ U | TargetType$ Spell | ValidTgts$ Sorcery | RememberCountered$ True | ForgetOtherTargets$ True | SubAbility$ DBChangeZoneAll | SpellDescription$ Counter target sorcery spell. Delirium — If there are four or more card types amongst cards in your graveyard, search the graveyard, hand, and library of that spell's controller for cards with the same name as that spell, exile those cards, then that player shuffles their library.
-SVar:DBChangeZoneAll:DB$ ChangeZoneAll | ChangeType$ Remembered.sameName | Condition$ Delirium | Origin$ Graveyard,Hand,Library | Defined$ TargetedController | Destination$ Exile | Search$ True | Shuffle$ True | SubAbility$ DBCleanup
+A:SP$ Counter | Cost$ U | TargetType$ Spell | ValidTgts$ Sorcery | RememberCountered$ True | SubAbility$ ExileYard | SpellDescription$ Counter target sorcery spell. Delirium — If there are four or more card types amongst cards in your graveyard, search the graveyard, hand, and library of that spell's controller for cards with the same name as that spell, exile those cards, then that player shuffles their library.
+SVar:ExileYard:DB$ ChangeZone | Condition$ Delirium | Origin$ Graveyard | Destination$ Exile | DefinedPlayer$ TargetedController | ChangeType$ Remembered.sameName | ChangeNum$ NumInYard | References$ NumInYard | Chooser$ You | Hidden$ True | SubAbility$ ExileHand | StackDescription$ None
+SVar:ExileHand:DB$ ChangeZone | Condition$ Delirium | Origin$ Hand | Destination$ Exile | DefinedPlayer$ TargetedController | ChangeType$ Remembered.sameName | ChangeNum$ NumInHand | References$ NumInHand | Chooser$ You | SubAbility$ ExileLib | StackDescription$ None
+SVar:ExileLib:DB$ ChangeZone | Condition$ Delirium | Origin$ Library | Destination$ Exile | DefinedPlayer$ TargetedController | ChangeType$ Remembered.sameName | ChangeNum$ NumInLib | References$ NumInLib | Chooser$ You | Shuffle$ True | StackDescription$ None | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
+SVar:NumInLib:TargetedController$CardsInLibrary
+SVar:NumInHand:TargetedController$CardsInHand
+SVar:NumInYard:TargetedController$CardsInGraveyard
DeckHints:Ability$Graveyard & Ability$Discard
DeckHas:Ability$Delirium
-SVar:Picture:http://www.wizards.com/global/images/magic/general/invasive_surgery.jpg
Oracle:Counter target sorcery spell.\nDelirium — If there are four or more card types among cards in your graveyard, search the graveyard, hand, and library of that spell's controller for any number of cards with the same name as that spell, exile those cards, then that player shuffles their library.
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/k/kenrith_the_returned_king.txt b/forge-gui/res/cardsfolder/k/kenrith_the_returned_king.txt
index 558bf60f15e..66ff09b0ee5 100644
--- a/forge-gui/res/cardsfolder/k/kenrith_the_returned_king.txt
+++ b/forge-gui/res/cardsfolder/k/kenrith_the_returned_king.txt
@@ -2,10 +2,10 @@ Name:Kenrith, the Returned King
ManaCost:4 W
Types:Legendary Creature Human Noble
PT:5/5
-A:AB$ PumpAll | Cost$ R | ValidCards$ Creature | KW$ Trample & Haste | SpellDescription$ All creatures gain trample and haste until end of turn.
+A:AB$ PumpAll | Cost$ R | ValidCards$ Creature | KW$ Trample & Haste | AILogic$ PumpForTrample | SpellDescription$ All creatures gain trample and haste until end of turn.
A:AB$ PutCounter | Cost$ 1 G | ValidTgts$ Creature | TgtPrompt$ Select target creature | CounterType$ P1P1 | CounterNum$ 1 | SpellDescription$ Put a +1/+1 counter on target creature.
A:AB$ GainLife | Cost$ 2 W | LifeAmount$ 5 | ValidTgts$ Player | TgtPrompt$ Choose a player | SpellDescription$ Target player gains 5 life.
A:AB$ Draw | Cost$ 3 U | NumCards$ 1 | ValidTgts$ Player | TgtPrompt$ Choose a player | SpellDescription$ Target player draws a card.
-A:AB$ ChangeZone | Cost$ 4 B | Origin$ Graveyard | Destination$ Battlefield | ValidTgts$ Creature | ChangeNum$ 1 | SpellDescription$ Put target creature card from a graveyard onto the battlefield under its owner's control.
+A:AB$ ChangeZone | Cost$ 4 B | Origin$ Graveyard | Destination$ Battlefield | ValidTgts$ Creature | AITgts$ Creature.YouOwn | ChangeNum$ 1 | SpellDescription$ Put target creature card from a graveyard onto the battlefield under its owner's control.
DeckHas:Ability$Counters & Ability$LifeGain
Oracle:{R}: All creatures gain trample and haste until end of turn.\n{1}{G}: Put a +1/+1 counter on target creature.\n{2}{W}: Target player gains 5 life.\n{3}{U}: Target player draws a card.\n{4}{B}: Put target creature card from a graveyard onto the battlefield under its owner's control.
diff --git a/forge-gui/res/cardsfolder/k/krovikan_vampire.txt b/forge-gui/res/cardsfolder/k/krovikan_vampire.txt
new file mode 100644
index 00000000000..de9fd12c992
--- /dev/null
+++ b/forge-gui/res/cardsfolder/k/krovikan_vampire.txt
@@ -0,0 +1,17 @@
+Name:Krovikan Vampire
+ManaCost:3 B B
+Types:Creature Vampire
+PT:3/3
+T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.DamagedBy | TriggerZones$ Battlefield | Execute$ TrigPump | Static$ True
+SVar:TrigPump:DB$ Pump | RememberObjects$ TriggeredCard
+T:Mode$ ChangesZone | Origin$ Graveyard | Destination$ Any | ValidCard$ Card.IsRemembered | TriggerZones$ Battlefield | Execute$ LoseTrack | Static$ True
+SVar:LoseTrack:DB$ Pump | ForgetObjects$ TriggeredCard
+T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.Self | Execute$ DBCleanup | Static$ True
+T:Mode$ TurnBegin | Execute$ DBCleanup | Static$ True
+T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ Player | TriggerZones$ Battlefield | CheckSVar$ X | SVarCompare$ GE1 | IsPresent$ Card.Self | Execute$ TrigChange | TriggerDescription$ At the beginning of each end step, if a creature dealt damage by CARDNAME this turn died, put that card onto the battlefield under your control. Sacrifice it when you lose control of CARDNAME.
+SVar:TrigChange:DB$ ChangeZoneAll | ChangeType$ Creature.IsRemembered+ThisTurnEntered_Graveyard_from_Battlefield | Origin$ Graveyard | Destination$ Battlefield | GainControl$ True | RememberChanged$ True | ForgetOtherRemembered$ True | SubAbility$ TrigDelay
+SVar:TrigDelay:DB$ DelayedTrigger | Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.Self | RememberObjects$ Remembered | Execute$ TrigSac | Secondary$ True | SubAbility$ DBCleanup | SpellDescription$ Sacrifice it when you lose control of CARDNAME.
+SVar:TrigSac:DB$ SacrificeAll | Defined$ DelayTriggerRemembered | SubAbility$ DBCleanup
+SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
+SVar:X:Remembered$Amount
+Oracle:At the beginning of each end step, if a creature dealt damage by Krovikan Vampire this turn died, put that card onto the battlefield under your control. Sacrifice it when you lose control of Krovikan Vampire.
diff --git a/forge-gui/res/cardsfolder/l/legions_end.txt b/forge-gui/res/cardsfolder/l/legions_end.txt
index da6a6fa33ac..4d7df9bd677 100644
--- a/forge-gui/res/cardsfolder/l/legions_end.txt
+++ b/forge-gui/res/cardsfolder/l/legions_end.txt
@@ -1,6 +1,7 @@
Name:Legion's End
ManaCost:1 B
Types:Sorcery
-A:SP$ ChangeZone | Cost$ 1 B | Origin$ Battlefield | Destination$ Exile | ValidTgts$ Creature.OppCtrl+cmcLE2 | TgtPrompt$ Select target creature an opponent controls with converted mana cost 2 or less | SubAbility$ DBChangeZoneAll | SpellDescription$ Exile target creature an opponent controls with converted mana cost 2 or less and all other creatures that player controls with the same name as that creature. Then that player reveals their hand and exiles all cards with that name from their hand and graveyard.
-SVar:DBChangeZoneAll:DB$ ChangeZoneAll | Defined$ TargetedController | ChangeType$ Targeted.sameName | Origin$ Battlefield,Graveyard,Hand | Destination$ Exile | Search$ True
+A:SP$ ChangeZone | Cost$ 1 B | Origin$ Battlefield | Destination$ Exile | ValidTgts$ Creature.OppCtrl+cmcLE2 | TgtPrompt$ Select target creature an opponent controls with converted mana cost 2 or less | SubAbility$ DBExileAll | StackDescription$ SpellDescription | SpellDescription$ Exile target creature an opponent controls with converted mana cost 2 or less and all other creatures that player controls with the same name as that creature. Then that player reveals their hand and exiles all cards with that name from their hand and graveyard.
+SVar:DBExileAll:DB$ ChangeZoneAll | Defined$ TargetedController | ChangeType$ Targeted.sameName+Creature | Origin$ Battlefield | Destination$ Exile | SubAbility$ DBChangeZoneAll | StackDescription$ None
+SVar:DBChangeZoneAll:DB$ ChangeZoneAll | Defined$ TargetedController | ChangeType$ Targeted.sameName | Origin$ Graveyard,Hand | Destination$ Exile | Search$ True | StackDescription$ None
Oracle:Exile target creature an opponent controls with converted mana cost 2 or less and all other creatures that player controls with the same name as that creature. Then that player reveals their hand and exiles all cards with that name from their hand and graveyard.
diff --git a/forge-gui/res/cardsfolder/l/lost_legacy.txt b/forge-gui/res/cardsfolder/l/lost_legacy.txt
index 0a3485f444a..fecb15d0378 100644
--- a/forge-gui/res/cardsfolder/l/lost_legacy.txt
+++ b/forge-gui/res/cardsfolder/l/lost_legacy.txt
@@ -1,12 +1,15 @@
Name:Lost Legacy
ManaCost:1 B B
Types:Sorcery
-A:SP$ NameCard | Cost$ 1 B B | Defined$ You | ValidCards$ Card.nonLand+nonArtifact | ValidDesc$ nonartifact, nonland | SubAbility$ ExileHand | SpellDescription$ Choose a nonartifact, nonland card name. Search target player's graveyard, hand, and library for any number of cards with that name and exile them. That player shuffles their library, then draws a card for each card exiled from hand this way. | SpellDescription$ StackDescription
-SVar:ExileHand:DB$ ChangeZoneAll | Origin$ Hand | Destination$ Exile | ValidTgts$ Player | TgtPrompt$ Select target player | ChangeType$ Card.NamedCard | RememberChanged$ True | SubAbility$ Exile
-SVar:Exile:DB$ ChangeZoneAll | Origin$ Graveyard,Hand,Library | Destination$ Exile | Defined$ TargetedPlayer | ChangeType$ Card.NamedCard | Search$ True | Shuffle$ True | SubAbility$ Draw
-SVar:Draw:DB$ Draw | Defined$ TargetedPlayer | NumCards$ X | References$ X | SubAbility$ DBCleanup
+A:SP$ NameCard | Cost$ 1 B B | Defined$ You | ValidCards$ Card.nonLand+nonArtifact | ValidDesc$ nonartifact, nonland | SubAbility$ ExileHand | SpellDescription$ Choose a nonartifact, nonland card name. Search target player's graveyard, hand, and library for any number of cards with that name and exile them. That player shuffles their library, then draws a card for each card exiled from hand this way. | StackDescription$ SpellDescription
+SVar:ExileHand:DB$ ChangeZone | ValidTgts$ Player | TgtPrompt$ Select target player | RememberTargets$ True | Origin$ Hand | Destination$ Exile | DefinedPlayer$ TargetedPlayer | ChangeType$ Card.NamedCard | ChangeNum$ NumInHand | References$ NumInHand | Chooser$ You | SubAbility$ ExileLib | RememberChanged$ True | StackDescription$ None
+SVar:ExileLib:DB$ ChangeZone | Origin$ Library | Destination$ Exile | DefinedPlayer$ TargetedPlayer | ChangeType$ Card.NamedCard | ChangeNum$ NumInLib | References$ NumInLib | Chooser$ You | Shuffle$ True | SubAbility$ ExileYard | StackDescription$ None
+SVar:ExileYard:DB$ ChangeZone | Origin$ Graveyard | Destination$ Exile | DefinedPlayer$ TargetedPlayer | ChangeType$ Card.NamedCard | ChangeNum$ NumInYard | References$ NumInYard | Chooser$ You | Hidden$ True | SubAbility$ Draw | StackDescription$ None
+SVar:Draw:DB$ Draw | Defined$ TargetedPlayer | NumCards$ X | References$ X | SubAbility$ DBCleanup | StackDescription$ None
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:X:Count$RememberedSize
+SVar:NumInHand:TargetedPlayer$CardsInHand
+SVar:NumInLib:TargetedPlayer$CardsInLibrary
+SVar:NumInYard:TargetedPlayer$CardsInGraveyard
AI:RemoveDeck:All
-SVar:Picture:http://www.wizards.com/global/images/magic/general/lost_legacy.jpg
Oracle:Choose a nonartifact, nonland card name. Search target player's graveyard, hand, and library for any number of cards with that name and exile them. That player shuffles their library, then draws a card for each card exiled from hand this way.
diff --git a/forge-gui/res/cardsfolder/m/maddening_imp.txt b/forge-gui/res/cardsfolder/m/maddening_imp.txt
index 3a438d4fcf5..d550666a8bf 100644
--- a/forge-gui/res/cardsfolder/m/maddening_imp.txt
+++ b/forge-gui/res/cardsfolder/m/maddening_imp.txt
@@ -3,12 +3,11 @@ ManaCost:2 B
Types:Creature Imp
PT:1/1
K:Flying
-A:AB$ Effect | Cost$ T | Name$ Maddening Imp Effect | StaticAbilities$ KWPump | ActivationPhases$ Upkeep->Main1 | OpponentTurn$ True | SpellDescription$ Non-Wall creatures the active player controls attack this turn if able. At the beginning of the next end step, destroy each of those creatures that didn't attack this turn. Activate this ability only during an opponent's turn and only before combat. | SubAbility$ DestroyPacifist
-SVar:KWPump:Mode$ Continuous | EffectZone$ Command | Affected$ Creature.ActivePlayerCtrl+nonWall | AffectedZone$ Battlefield | AddHiddenKeyword$ CARDNAME attacks each combat if able. | Description$ Non-Wall creatures the active player controls attack this turn if able.
-SVar:DestroyPacifist:DB$ DelayedTrigger | Mode$ Phase | Phase$ End of Turn | Execute$ TrigDestroy | TriggerDescription$ At the beginning of the next end step, destroy each of those creatures that didn't attack this turn.
-SVar:TrigDestroy:DB$ DestroyAll | ValidCards$ Creature.ActivePlayerCtrl+notAttackedThisTurn+nonWall
+A:AB$ PumpAll | Cost$ T | ValidCards$ Creature.ActivePlayerCtrl+nonWall | KW$ HIDDEN CARDNAME attacks each combat if able. | ActivationPhases$ Upkeep->Main1 | OpponentTurn$ True | SubAbility$ DBEffect | StackDescription$ SpellDescription | SpellDescription$ Non-Wall creatures the active player controls attack this turn if able. At the beginning of the next end step, destroy each of those creatures that didn't attack this turn. Activate this ability only during an opponent's turn and only before combat.
+SVar:DBEffect:DB$ Effect | Name$ Maddening Imp Effect | Triggers$ EndofTurn | SVars$ TrigDestroy | RememberObjects$ Valid Creature.ActivePlayerCtrl+nonWall
+SVar:EndofTurn:Mode$ Phase | Phase$ End of Turn | Execute$ TrigDestroy | TriggerDescription$ At the beginning of the next end step, destroy each of those creatures that didn't attack this turn.
+SVar:TrigDestroy:DB$ DestroyAll | ValidCards$ Creature.IsRemembered+notAttackedThisTurn
AI:RemoveDeck:All
AI:RemoveDeck:Random
SVar:NonCombatPriority:5
-SVar:Picture:http://www.wizards.com/global/images/magic/general/maddening_imp.jpg
Oracle:Flying\n{T}: Non-Wall creatures the active player controls attack this turn if able. At the beginning of the next end step, destroy each of those creatures that didn't attack this turn. Activate this ability only during an opponent's turn and only before combat.
diff --git a/forge-gui/res/cardsfolder/m/maelstrom_nexus.txt b/forge-gui/res/cardsfolder/m/maelstrom_nexus.txt
index 7cffe8fc9f4..8f9a0ef7e53 100644
--- a/forge-gui/res/cardsfolder/m/maelstrom_nexus.txt
+++ b/forge-gui/res/cardsfolder/m/maelstrom_nexus.txt
@@ -1,7 +1,7 @@
Name:Maelstrom Nexus
ManaCost:W U B R G
Types:Enchantment
-S:Mode$ Continuous | Affected$ Card.YouCtrl | AffectedZone$ Exile,Graveyard,Hand,Library,Command | CheckSVar$ Y | SVarCompare$ EQ0 | AddKeyword$ Cascade | Description$ The first spell you cast each turn has cascade. (When you cast your first spell, exile cards from the top of your library until you exile a nonland card that costs less. You may cast it without paying its mana cost. Put the exiled cards on the bottom of your library in a random order.)
+S:Mode$ Continuous | Affected$ Card.YouCtrl | AffectedZone$ Stack | CheckSVar$ Y | SVarCompare$ EQ0 | AddKeyword$ Cascade | Description$ The first spell you cast each turn has cascade. (When you cast your first spell, exile cards from the top of your library until you exile a nonland card that costs less. You may cast it without paying its mana cost. Put the exiled cards on the bottom of your library in a random order.)
SVar:Y:Count$ThisTurnCast_Card.YouCtrl
SVar:Picture:http://www.wizards.com/global/images/magic/general/maelstrom_nexus.jpg
Oracle:The first spell you cast each turn has cascade. (When you cast your first spell, exile cards from the top of your library until you exile a nonland card that costs less. You may cast it without paying its mana cost. Put the exiled cards on the bottom of your library in a random order.)
diff --git a/forge-gui/res/cardsfolder/m/mask_of_immolation.txt b/forge-gui/res/cardsfolder/m/mask_of_immolation.txt
index 9ce881b7435..98c6e6c696f 100644
--- a/forge-gui/res/cardsfolder/m/mask_of_immolation.txt
+++ b/forge-gui/res/cardsfolder/m/mask_of_immolation.txt
@@ -5,7 +5,7 @@ T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Any | Destination$ Battlefi
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ r_1_1_elemental | TokenOwner$ You | LegacyImage$ r 1 1 elemental m20 | RememberTokens$ True | SubAbility$ DBAttach
SVar:DBAttach:DB$ Attach | Defined$ Remembered | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
-S:Mode$ Continuous | Affected$ Card.EquippedBy | AddAbility$ Damage | AddSVar$ ThorncasterSliverDamage | Description$ Equipped creature has flying and gets creature: It deals 1 damage to any target.
+S:Mode$ Continuous | Affected$ Card.EquippedBy | AddAbility$ Damage | Description$ Equipped creature has "Sacrifice this creature: It deals 1 damage to any target."
SVar:Damage:AB$DealDamage | Cost$ Sac<1/CARDNAME> | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target | NumDmg$ 1 | SpellDescription$ CARDNAME deals 1 damage to any target.
SVar:NonStackingAttachEffect:True
AI:RemoveDeck:All
diff --git a/forge-gui/res/cardsfolder/m/mausoleum_wanderer.txt b/forge-gui/res/cardsfolder/m/mausoleum_wanderer.txt
index 93a9b844b84..43032a151c0 100644
--- a/forge-gui/res/cardsfolder/m/mausoleum_wanderer.txt
+++ b/forge-gui/res/cardsfolder/m/mausoleum_wanderer.txt
@@ -3,12 +3,11 @@ ManaCost:U
Types:Creature Spirit
PT:1/1
K:Flying
-T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Spirit+Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigPump | TriggerDescription$ Whenever another Spirit enters the battlefield under your control, Mausoleum Wanderer gets +1/+1 until end of turn.
+T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Spirit+Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigPump | TriggerDescription$ Whenever another Spirit enters the battlefield under your control, CARDNAME gets +1/+1 until end of turn.
SVar:TrigPump:DB$Pump | Defined$ Self | NumAtt$ 1 | NumDef$ 1
-A:AB$ Counter | Cost$ Sac<1/CARDNAME> | TargetType$ Spell | ValidTgts$ Instant,Sorcery | TgtPrompt$ Select target Instant or Sorcery Spell | UnlessCost$ X | References$ X | SpellDescription$Counter target instant or sorcery spell unless its controller pays {X}, where X is Mausoleum Wanderer's power.
+A:AB$ Counter | Cost$ Sac<1/CARDNAME> | TargetType$ Spell | ValidTgts$ Instant,Sorcery | TgtPrompt$ Select target instant or sorcery spell | UnlessCost$ X | References$ X | SpellDescription$ Counter target instant or sorcery spell unless its controller pays {X}, where X is CARDNAME's power.
SVar:X:Count$CardPower
AI:RemoveDeck:Random
SVar:BuffedBy:Spirit
DeckHints:Type$Spirit
-SVar:Picture:http://www.wizards.com/global/images/magic/general/mausoleum_wanderer.jpg
Oracle:Flying\nWhenever another Spirit enters the battlefield under your control, Mausoleum Wanderer gets +1/+1 until end of turn.\nSacrifice Mausoleum Wanderer: Counter target instant or sorcery spell unless its controller pays {X}, where X is Mausoleum Wanderer's power.
diff --git a/forge-gui/res/cardsfolder/m/mercenaries.txt b/forge-gui/res/cardsfolder/m/mercenaries.txt
new file mode 100644
index 00000000000..3f0b98ecf15
--- /dev/null
+++ b/forge-gui/res/cardsfolder/m/mercenaries.txt
@@ -0,0 +1,8 @@
+Name:Mercenaries
+ManaCost:3 W
+Types:Creature Human Mercenary
+PT:3/3
+A:AB$ Effect | Cost$ 3 | EffectOwner$ You | AnyPlayer$ True | ReplacementEffects$ Bribe | SVars$ Bribe,ExileEffect | RememberObjects$ Self | AILogic$ Bribe | SpellDescription$ The next time CARDNAME would deal damage to you this turn, prevent that damage. Any player may activate this ability.
+SVar:Bribe:Event$ DamageDone | ValidSource$ Card.IsRemembered | ValidTarget$ You | ReplaceWith$ ExileEffect | PreventionEffect$ True | Description$ The next time EFFECTSOURCE would deal damage to you this turn, prevent that damage.
+SVar:ExileEffect:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile
+Oracle:{3}: The next time Mercenaries would deal damage to you this turn, prevent that damage. Any player may activate this ability.
diff --git a/forge-gui/res/cardsfolder/m/merieke_ri_berit.txt b/forge-gui/res/cardsfolder/m/merieke_ri_berit.txt
index 62ef6f9f744..8faa699cf53 100644
--- a/forge-gui/res/cardsfolder/m/merieke_ri_berit.txt
+++ b/forge-gui/res/cardsfolder/m/merieke_ri_berit.txt
@@ -3,6 +3,9 @@ ManaCost:W U B
Types:Legendary Creature Human
PT:1/1
K:CARDNAME doesn't untap during your untap step.
-A:AB$ GainControl | Cost$ T | ValidTgts$ Creature | TgtPrompt$ Select target creature | LoseControl$ LeavesPlay,LoseControl | DestroyTgt$ LeavesPlay,LoseControl,Untap | NoRegen$ True | SpellDescription$ Gain control of target creature for as long as you control CARDNAME. When CARDNAME leaves the battlefield or becomes untapped, destroy that creature. It can't be regenerated.
-SVar:Picture:http://www.wizards.com/global/images/magic/general/merieke_ri_berit.jpg
+A:AB$ GainControl | Cost$ T | ValidTgts$ Creature | TgtPrompt$ Select target creature | LoseControl$ LeavesPlay,LoseControl | SubAbility$ DBEffect | SpellDescription$ Gain control of target creature for as long as you control CARDNAME. When CARDNAME leaves the battlefield or becomes untapped, destroy that creature. It can't be regenerated.
+SVar:DBEffect:DB$ Effect | RememberObjects$ ParentTarget | ForgetOnMoved$ Battlefield | Triggers$ LeavesPlay,Untap | References$ LeavesPlay,Untap | Duration$ UntilHostLeavesPlay
+SVar:LeavesPlay:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.EffectSource | Execute$ DBDestroy | TriggerDescription$ When EFFECTSOURCE leaves the battlefield, or becomes untapped, destroy that creature. It can't be regenerated.
+SVar:Untap:Mode$ Untaps | ValidCard$ Card.EffectSource | Execute$ DBDestroy | Secondary$ True | TriggerDescription$ When EFFECTSOURCE leaves the battlefield, or becomes untapped, destroy that creature. It can't be regenerated.
+SVar:DBDestroy:DB$ Destroy | Defined$ Remembered | NoRegen$ True
Oracle:Merieke Ri Berit doesn't untap during your untap step.\n{T}: Gain control of target creature for as long as you control Merieke Ri Berit. When Merieke Ri Berit leaves the battlefield or becomes untapped, destroy that creature. It can't be regenerated.
diff --git a/forge-gui/res/cardsfolder/n/nahiri_the_lithomancer.txt b/forge-gui/res/cardsfolder/n/nahiri_the_lithomancer.txt
index 3afc3d36619..f10d8a12a9e 100644
--- a/forge-gui/res/cardsfolder/n/nahiri_the_lithomancer.txt
+++ b/forge-gui/res/cardsfolder/n/nahiri_the_lithomancer.txt
@@ -3,14 +3,13 @@ ManaCost:3 W W
Types:Legendary Planeswalker Nahiri
Loyalty:3
Text:CARDNAME can be your commander.
-A:AB$ Token | Cost$ AddCounter<2/LOYALTY> | Planeswalker$ True | TokenAmount$ 1 | TokenScript$ w_1_1_kor_soldier | TokenOwner$ You | LegacyImage$ w 1 1 kor soldier c14 | RememberTokens$ True | SubAbility$ DBChooseTarget | SpellDescription$ Create a 1/1 white Kor Soldier creature token. You may attach an Equipment you control to it.
-SVar:DBChooseTarget:DB$ ChooseCard | DefinedCards$ Remembered | Mandatory$ True | ChoiceTitle$ Choose a token: | SubAbility$ DBAttach
-SVar:DBAttach:DB$ Attach | Optional$ True | Object$ Valid Equipment.YouCtrl | ChooseAnObject$ Choose an equipment you control | Defined$ ChosenCard | SubAbility$ DBCleanup
+A:AB$ Token | Cost$ AddCounter<2/LOYALTY> | Planeswalker$ True | TokenAmount$ 1 | TokenScript$ w_1_1_kor_soldier | TokenOwner$ You | LegacyImage$ w 1 1 kor soldier c14 | RememberTokens$ True | SubAbility$ DBChooseToken | SpellDescription$ Create a 1/1 white Kor Soldier creature token. You may attach an Equipment you control to it.
+SVar:DBChooseToken:DB$ ChooseCard | DefinedCards$ Remembered | Mandatory$ True | ChoiceTitle$ Choose a token | SubAbility$ DBAttach | StackDescription$ None
+SVar:DBAttach:DB$ Attach | Optional$ True | Object$ Valid Equipment.YouCtrl | ChooseAnObject$ Choose an Equipment you control | Defined$ ChosenCard | SubAbility$ DBCleanup | StackDescription$ None
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearChosenCard$ True
A:AB$ ChangeZone | Cost$ SubCounter<2/LOYALTY> | Origin$ Hand,Graveyard | Destination$ Battlefield | Hidden$ True | Planeswalker$ True | ChangeType$ Equipment.YouCtrl | Optional$ True | SpellDescription$ You may put an Equipment card from your hand or graveyard onto the battlefield.
A:AB$ Token | Cost$ SubCounter<10/LOYALTY> | Planeswalker$ True | Ultimate$ True | TokenAmount$ 1 | TokenScript$ stoneforged_blade | LegacyImage$ stoneforged blade c14 | TokenOwner$ You | SpellDescription$ Create a colorless Equipment artifact token named Stoneforged Blade. It has indestructible, "Equipped creature gets +5/+5 and has double strike," and equip {0}.
DeckHas:Ability$Token
DeckNeeds:Type$Equipment
AI:RemoveDeck:All
-SVar:Picture:http://www.wizards.com/global/images/magic/general/nahiri_the_lithomancer.jpg
Oracle:[+2]: Create a 1/1 white Kor Soldier creature token. You may attach an Equipment you control to it.\n[-2]: You may put an Equipment card from your hand or graveyard onto the battlefield.\n[-10]: Create a colorless Equipment artifact token named Stoneforged Blade. It has indestructible, "Equipped creature gets +5/+5 and has double strike," and equip {0}.\nNahiri, the Lithomancer can be your commander.
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/p/pelt_collector.txt b/forge-gui/res/cardsfolder/p/pelt_collector.txt
index 56e8b90ad45..d05c265f3aa 100644
--- a/forge-gui/res/cardsfolder/p/pelt_collector.txt
+++ b/forge-gui/res/cardsfolder/p/pelt_collector.txt
@@ -6,6 +6,7 @@ S:Mode$ Continuous | Affected$ Card.Self+counters_GE3_P1P1 | AddKeyword$ Trample
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.YouCtrl+powerGTX+Other | References$ X | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ Whenever another creature you control enters the battlefield or dies, if that creature's power is greater than CARDNAME's, put a +1/+1 counter on CARDNAME.
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.YouCtrl+powerGTX+Other | References$ X | TriggerZones$ Battlefield | Secondary$ True | Execute$ TrigPutCounter | TriggerDescription$ Whenever another creature you control enters the battlefield or dies, if that creature's power is greater than CARDNAME's, put a +1/+1 counter on CARDNAME.
SVar:X:Count$CardPower
-SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1
+SVar:Y:TriggeredCard$CardPower
+SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1 | ConditionCheckSVar$ X | ConditionSVarCompare$ LTY | References$ X,Y
DeckHas:Ability$Counters
Oracle:Whenever another creature you control enters the battlefield or dies, if that creature's power is greater than Pelt Collector's, put a +1/+1 counter on Pelt Collector.\nAs long as Pelt Collector has three or more +1/+1 counters on it, it has trample.
\ No newline at end of file
diff --git a/forge-gui/res/cardsfolder/p/pick_the_brain.txt b/forge-gui/res/cardsfolder/p/pick_the_brain.txt
index 30ec6e9f158..e3fdc792eb3 100644
--- a/forge-gui/res/cardsfolder/p/pick_the_brain.txt
+++ b/forge-gui/res/cardsfolder/p/pick_the_brain.txt
@@ -1,10 +1,14 @@
Name:Pick the Brain
ManaCost:2 B
Types:Sorcery
-A:SP$ ChangeZone | Cost$ 2 B | Origin$ Hand | Destination$ Exile | ValidTgts$ Opponent | DefinedPlayer$ Targeted | Chooser$ You | ChangeType$ Card.nonLand | ChangeNum$ 1 | IsCurse$ True | Mandatory$ True | RememberChanged$ True | SubAbility$ DBChangeZoneAll | SpellDescription$ Target opponent reveals their hand. You choose a nonland card from it and exile that card. Delirium — If there are four or more card types among cards in your graveyard, search that player's graveyard, hand, and library for any number of cards with the same name as the exiled card, exile those cards, then that player shuffles their library.
-SVar:DBChangeZoneAll:DB$ ChangeZoneAll | ChangeType$ Remembered.sameName | Condition$ Delirium | Origin$ Graveyard,Hand,Library | Defined$ Targeted | Destination$ Exile | Search$ True | Shuffle$ True | SubAbility$ DBCleanup
+A:SP$ ChangeZone | Cost$ 2 B | Origin$ Hand | Destination$ Exile | ValidTgts$ Opponent | DefinedPlayer$ Targeted | Chooser$ You | ChangeType$ Card.nonLand | ChangeNum$ 1 | IsCurse$ True | Mandatory$ True | RememberChanged$ True | SubAbility$ ExileYard | SpellDescription$ Target opponent reveals their hand. You choose a nonland card from it and exile that card. Delirium — If there are four or more card types among cards in your graveyard, search that player's graveyard, hand, and library for any number of cards with the same name as the exiled card, exile those cards, then that player shuffles their library.
+SVar:ExileYard:DB$ ChangeZone | Condition$ Delirium | Origin$ Graveyard | Destination$ Exile | DefinedPlayer$ TargetedPlayer | ChangeType$ Remembered.sameName | ChangeNum$ NumInYard | References$ NumInYard | Chooser$ You | Hidden$ True | SubAbility$ ExileHand | StackDescription$ None
+SVar:ExileHand:DB$ ChangeZone | Condition$ Delirium | Origin$ Hand | Destination$ Exile | DefinedPlayer$ TargetedPlayer | ChangeType$ Remembered.sameName | ChangeNum$ NumInHand | References$ NumInHand | Chooser$ You | SubAbility$ ExileLib | StackDescription$ None
+SVar:ExileLib:DB$ ChangeZone | Condition$ Delirium | Origin$ Library | Destination$ Exile | DefinedPlayer$ TargetedPlayer | ChangeType$ Remembered.sameName | ChangeNum$ NumInLib | References$ NumInLib | Chooser$ You | Shuffle$ True | StackDescription$ None | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
+SVar:NumInHand:TargetedPlayer$CardsInHand
+SVar:NumInLib:TargetedPlayer$CardsInLibrary
+SVar:NumInYard:TargetedPlayer$CardsInGraveyard
DeckHints:Ability$Graveyard & Ability$Discard
DeckHas:Ability$Delirium
-SVar:Picture:http://www.wizards.com/global/images/magic/general/pick_the_brain.jpg
Oracle:Target opponent reveals their hand. You choose a nonland card from it and exile that card.\nDelirium — If there are four or more card types among cards in your graveyard, search that player's graveyard, hand, and library for any number of cards with the same name as the exiled card, exile those cards, then that player shuffles their library.
diff --git a/forge-gui/res/cardsfolder/q/quenchable_fire.txt b/forge-gui/res/cardsfolder/q/quenchable_fire.txt
index 1cfa436e855..7c136c6969d 100644
--- a/forge-gui/res/cardsfolder/q/quenchable_fire.txt
+++ b/forge-gui/res/cardsfolder/q/quenchable_fire.txt
@@ -1,11 +1,13 @@
Name:Quenchable Fire
ManaCost:3 R
Types:Sorcery
-A:SP$ DealDamage | Cost$ 3 R | ValidTgts$ Player | TgtPrompt$ Select target player | NumDmg$ 3 | SubAbility$ DBEffect | SpellDescription$ CARDNAME deals 3 damage to target player. It deals an additional 3 damage to that player at the beginning of your next upkeep step unless they pay {U} before that step.
-SVar:DBEffect:DB$ Effect | Name$ Quenchable Fire Effect | EffectOwner$ Targeted | Duration$ Permanent | Triggers$ UpkeepTrig | Abilities$ PayUp | SVars$ Bleed,ExileEffect | RememberObjects$ SourceController | ImprintCards$ Self
-SVar:UpkeepTrig:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ Player.IsRemembered | TriggerZones$ Command | Execute$ Bleed | TriggerDescription$ It deals an additional 3 damage to you at the beginning of that player's next upkeep step unless you pay {U} before that step.
-SVar:Bleed:DB$ DealDamage | Defined$ You | NumDmg$ 3 | DamageSource$ Imprinted | SubAbility$ ExileEffect
+A:SP$ DealDamage | Cost$ 3 R | ValidTgts$ Player,Planeswalker | TgtPrompt$ Select target player or planeswalker | NumDmg$ 3 | SubAbility$ DBEffect | StackDescription$ SpellDescription | SpellDescription$ CARDNAME deals 3 damage to target player or planeswalker. It deals an additional 3 damage to that player or planeswalker at the beginning of your next upkeep step unless that player or that planeswalker's controller pays {U} before that step.
+SVar:DBEffect:DB$ Effect | Name$ Quenchable Fire Effect | EffectOwner$ Targeted | Duration$ Permanent | Triggers$ UpkeepTrig | Abilities$ PayUp | SVars$ Bleed,ExileEffect | RememberObjects$ SourceController | ConditionDefined$ Targeted | ConditionPresent$ Planeswalker | ConditionCompare$ EQ0 | SubAbility$ DBEffect2
+SVar:DBEffect2:DB$ Effect | Name$ Quenchable Fire Effect | EffectOwner$ TargetedController | Duration$ Permanent | ForgetOnMoved$ Battlefield | Triggers$ UpkeepTrig2 | Abilities$ PayUp | SVars$ Bleed2,ExileEffect | RememberObjects$ SourceController,Targeted | ConditionDefined$ Targeted | ConditionPresent$ Planeswalker
+SVar:UpkeepTrig:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ Player.IsRemembered | TriggerZones$ Command | Execute$ Bleed | TriggerDescription$ EFFECTSOURCE deals an additional 3 damage to you at the beginning of that player's next upkeep step unless you pay {U} before that step.
+SVar:Bleed:DB$ DealDamage | Defined$ You | NumDmg$ 3 | DamageSource$ EffectSource | SubAbility$ ExileEffect
SVar:ExileEffect:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile
SVar:PayUp:ST$ ChangeZone | Cost$ U | Defined$ Self | Origin$ Command | Destination$ Exile | ActivationZone$ Command | AILogic$ Always | SpellDescription$ Pay {U} to remove this effect.
-SVar:Picture:http://www.wizards.com/global/images/magic/general/quenchable_fire.jpg
-Oracle:Quenchable Fire deals 3 damage to target player. It deals an additional 3 damage to that player at the beginning of your next upkeep step unless they pay {U} before that step.
+SVar:UpkeepTrig2:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ Player.IsRemembered | TriggerZones$ Command | Execute$ Bleed2 | TriggerDescription$ EFFECTSOURCE deals an additional 3 damage to that planeswalker at the beginning of that player's next upkeep step unless you pay {U} before that step.
+SVar:Bleed2:DB$ DamageAll | ValidCards$ Card.IsRemembered | NumDmg$ 3 | DamageSource$ EffectSource | SubAbility$ ExileEffect
+Oracle:Quenchable Fire deals 3 damage to target player or planeswalker. It deals an additional 3 damage to that player or planeswalker at the beginning of your next upkeep step unless that player or that planeswalker's controller pays {U} before that step.
diff --git a/forge-gui/res/cardsfolder/r/reap_intellect.txt b/forge-gui/res/cardsfolder/r/reap_intellect.txt
index d9c616c8600..ef0b89a219c 100644
--- a/forge-gui/res/cardsfolder/r/reap_intellect.txt
+++ b/forge-gui/res/cardsfolder/r/reap_intellect.txt
@@ -1,9 +1,14 @@
Name:Reap Intellect
ManaCost:X 2 U B
Types:Sorcery
-A:SP$ ChangeZone | Cost$ X 2 U B | Origin$ Hand | Destination$ Exile | ValidTgts$ Opponent | DefinedPlayer$ Targeted | Chooser$ You | ChangeType$ Card.nonLand | ChangeNum$ X | References$ X | IsCurse$ True | Mandatory$ True | RememberChanged$ True | SubAbility$ DBExile | SpellDescription$ Target opponent reveals their hand. You choose X non-land cards from among them. Search that player's library, hand and graveyard for cards with the same name as those cards and exile them. Then, that player shuffles their library.
-SVar:DBExile:DB$ ChangeZoneAll | Origin$ Hand,Library,Graveyard | Destination$ Exile | Defined$ Targeted | Search$ True | ChangeType$ Card.sharesNameWith Remembered | Shuffle$ True | SubAbility$ DBCleanup
+A:SP$ ChangeZone | Cost$ X 2 U B | Origin$ Hand | Destination$ Exile | ValidTgts$ Opponent | DefinedPlayer$ Targeted | Chooser$ You | ChangeType$ Card.nonLand | ChangeNum$ X | References$ X | IsCurse$ True | Mandatory$ True | RememberChanged$ True | SubAbility$ DBRepeat | SpellDescription$ Target opponent reveals their hand. You choose X non-land cards from among them. Search that player's library, hand and graveyard for cards with the same name as those cards and exile them. Then, that player shuffles their library.
+SVar:DBRepeat:DB$ RepeatEach | UseImprinted$ True | RepeatCards$ Card.IsRemembered | Zone$ Exile | RepeatSubAbility$ ExileYard | SubAbility$ DBCleanup
+SVar:ExileYard:DB$ ChangeZone | Origin$ Graveyard | Destination$ Exile | DefinedPlayer$ TargetedPlayer | ChangeType$ Card.sharesNameWith Imprinted | ChangeNum$ NumInYard | References$ NumInYard | Chooser$ You | Hidden$ True | SubAbility$ ExileHand | StackDescription$ None
+SVar:ExileHand:DB$ ChangeZone | Origin$ Hand | Destination$ Exile | DefinedPlayer$ TargetedPlayer | ChangeType$ Card.sharesNameWith Imprinted | ChangeNum$ NumInHand | References$ NumInHand | Chooser$ You | SubAbility$ ExileLib | StackDescription$ None
+SVar:ExileLib:DB$ ChangeZone | Origin$ Library | Destination$ Exile | DefinedPlayer$ TargetedPlayer | ChangeType$ Card.sharesNameWith Imprinted | ChangeNum$ NumInLib | References$ NumInLib | Chooser$ You | Shuffle$ True | StackDescription$ None
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
+SVar:NumInHand:TargetedPlayer$CardsInHand
+SVar:NumInLib:TargetedPlayer$CardsInLibrary
+SVar:NumInYard:TargetedPlayer$CardsInGraveyard
SVar:X:Count$xPaid
-SVar:Picture:http://www.wizards.com/global/images/magic/general/reap_intellect.jpg
Oracle:Target opponent reveals their hand. You choose up to X nonland cards from it and exile them. For each card exiled this way, search that player's graveyard, hand, and library for any number of cards with the same name as that card and exile them. Then that player shuffles their library.
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/tempest_efreet.txt b/forge-gui/res/cardsfolder/t/tempest_efreet.txt
new file mode 100644
index 00000000000..172f10e28d7
--- /dev/null
+++ b/forge-gui/res/cardsfolder/t/tempest_efreet.txt
@@ -0,0 +1,17 @@
+Name:Tempest Efreet
+ManaCost:1 R R R
+Types:Creature Efreet
+PT:3/3
+K:Remove CARDNAME from your deck before playing if you're not playing for ante.
+A:AB$ Pump | Cost$ T Sac<1/CARDNAME> | ValidTgts$ Opponent | SubAbility$ Choice | RememberObjects$ Targeted | StackDescription$ SpellDescription | SpellDescription$ Target opponent may pay 10 life. If that player doesn’t, they reveal a card at random from their hand. Exchange ownership of the revealed card and Tempest Efreet. Put the revealed card into your hand and Tempest Efreet from anywhere into that player’s graveyard. This change in ownership is permanent.
+SVar:Choice:DB$ GenericChoice | Choices$ RevealCard | Defined$ Targeted | ConditionCheckSVar$ X | References$ X | ConditionSVarCompare$ LT10 | SubAbility$ Choice2 | StackDescription$ None
+SVar:Choice2:DB$ GenericChoice | Choices$ PayLife,RevealCard | Defined$ Targeted | ConditionCheckSVar$ X | References$ X | ConditionSVarCompare$ GE10 | StackDescription$ None
+SVar:X:PlayerCountRemembered$LifeTotal
+SVar:PayLife:DB$ LoseLife | LifeAmount$ 10 | Defined$ Targeted | SubAbility$ DBCleanup | SpellDescription$ Pay 10 life.
+SVar:RevealCard:DB$ Reveal | Random$ True | RememberRevealed$ True | Defined$ Targeted | SubAbility$ ExchangeOwn1 | StackDescription$ SpellDescription | SpellDescription$ Reveal a card at random from your hand. Permanently exchange ownership of the revealed card and CARDNAME.
+SVar:ExchangeOwn1:DB$ GainOwnership | Defined$ Remembered | DefinedPlayer$ You | SubAbility$ ToHand
+SVar:ToHand:DB$ ChangeZone | Defined$ Remembered | Origin$ All | Destination$ Hand | SubAbility$ ExchangeOwn2
+SVar:ExchangeOwn2:DB$ GainOwnership | Defined$ Self | DefinedPlayer$ Targeted | SubAbility$ ToGrave
+SVar:ToGrave:DB$ ChangeZone | Defined$ Self | Origin$ All | Destination$ Graveyard | SubAbility$ DBCleanup
+SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
+Oracle:Remove Tempest Efreet from your deck before playing if you’re not playing for ante.\n{T}, Sacrifice Tempest Efreet: Target opponent may pay 10 life. If that player doesn’t, they reveal a card at random from their hand. Exchange ownership of the revealed card and Tempest Efreet. Put the revealed card into your hand and Tempest Efreet from anywhere into that player’s graveyard. This change in ownership is permanent.
diff --git a/forge-gui/res/cardsfolder/t/tezzeret_cruel_machinist.txt b/forge-gui/res/cardsfolder/t/tezzeret_cruel_machinist.txt
index c705ff6ee2f..8334739ca06 100644
--- a/forge-gui/res/cardsfolder/t/tezzeret_cruel_machinist.txt
+++ b/forge-gui/res/cardsfolder/t/tezzeret_cruel_machinist.txt
@@ -3,7 +3,7 @@ ManaCost:4 U U
Loyalty:4
Types:Legendary Planeswalker Tezzeret
A:AB$ Draw | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | NumCards$ 1 | Defined$ You | SpellDescription$ Draw a card.
-A:AB$ Animate | Cost$ AddCounter<0/LOYALTY> | Planeswalker$ True | ValidTgts$ Artifact.YouCtrl | TgtPrompt$ Select target artifact you control | Power$ 5 | Toughness$ 5 | Types$ Artifact | UntilYourNextTurn$ True | SpellDescription$ Until your next turn, target artifact you control becomes a 5/5 creature in addition to its other types.
+A:AB$ Animate | Cost$ AddCounter<0/LOYALTY> | Planeswalker$ True | ValidTgts$ Artifact.YouCtrl | TgtPrompt$ Select target artifact you control | Power$ 5 | Toughness$ 5 | Types$ Creature | UntilYourNextTurn$ True | SpellDescription$ Until your next turn, target artifact you control becomes a 5/5 creature in addition to its other types.
A:AB$ ChangeZone | Cost$ SubCounter<7/LOYALTY> | Planeswalker$ True | Ultimate$ True | Origin$ Hand | Destination$ Battlefield | ChangeType$ Card | ChangeNum$ X | References$ X | FaceDown$ True | FaceDownPower$ 5 | FaceDownToughness$ 5 | FaceDownAddType$ Artifact,Creature | StackDescription$ SpellDescription | SpellDescription$ Put any number of cards from your hand onto the battlefield face down. They're 5/5 artifact creatures.
SVar:X:Count$InYourHand
Oracle:[+1]: Draw a card.\n[0]: Until your next turn, target artifact you control becomes a 5/5 creature in addition to its other types.\n[-7]: Put any number of cards from your hand onto the battlefield face down. They're 5/5 artifact creatures.
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/cardsfolder/t/timmerian_fiends.txt b/forge-gui/res/cardsfolder/t/timmerian_fiends.txt
new file mode 100644
index 00000000000..028e195e54b
--- /dev/null
+++ b/forge-gui/res/cardsfolder/t/timmerian_fiends.txt
@@ -0,0 +1,13 @@
+Name:Timmerian Fiends
+ManaCost:1 B B
+Types:Creature Horror
+PT:1/1
+K:Remove CARDNAME from your deck before playing if you're not playing for ante.
+A:AB$ Pump | Cost$ B B B Sac<1/CARDNAME> | ValidTgts$ Artifact | SubAbility$ DBAnte | ImprintCards$ Targeted | RememberObjects$ TargetedController | StackDescription$ SpellDescription | SpellDescription$ The owner of target artifact may ante the top card of their library. If that player doesn’t, exchange ownership of that artifact and CARDNAME. Put the artifact card into your graveyard and CARDNAME from anywhere into that player’s graveyard. This change in ownership is permanent.
+SVar:DBAnte:DB$ Mill | Defined$ Player.IsRemembered | Destination$ Ante | NumCards$ 1 | RememberMilled$ True | Optional$ True | SubAbility$ ExchangeOwn1 | AILogic$ TimmerianFiends | StackDescription$ None
+SVar:ExchangeOwn1:DB$ GainOwnership | Defined$ Imprinted | DefinedPlayer$ You | SubAbility$ ToGrave1 | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ EQ0
+SVar:ToGrave1:DB$ ChangeZone | Defined$ Imprinted | Origin$ Battlefield | Destination$ Graveyard | SubAbility$ ExchangeOwn2 | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ EQ0 | StackDescription$ None
+SVar:ExchangeOwn2:DB$ GainOwnership | Defined$ Self | DefinedPlayer$ Remembered | SubAbility$ ToGrave | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ EQ0
+SVar:ToGrave:DB$ ChangeZone | Defined$ Self | Origin$ All | Destination$ Graveyard | SubAbility$ DBCleanup | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ EQ0
+SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearImprinted$ True
+Oracle:Remove Timmerian Fiends from your deck before playing if you’re not playing for ante.\n{B}{B}{B}, Sacrifice Timmerian Fiends: The owner of target artifact may ante the top card of their library. If that player doesn’t, exchange ownership of that artifact and Timmerian Fiends. Put the artifact card into your graveyard and Timmerian Fiends from anywhere into that player’s graveyard. This change in ownership is permanent.
diff --git a/forge-gui/res/deckgendecks/Pioneer.lda.dat b/forge-gui/res/deckgendecks/Pioneer.lda.dat
index 63f885b077e..5f0fbcaac3e 100644
Binary files a/forge-gui/res/deckgendecks/Pioneer.lda.dat and b/forge-gui/res/deckgendecks/Pioneer.lda.dat differ
diff --git a/forge-gui/res/deckgendecks/Pioneer.raw.dat b/forge-gui/res/deckgendecks/Pioneer.raw.dat
index c5e5a53bb18..0c6221bcb1b 100644
Binary files a/forge-gui/res/deckgendecks/Pioneer.raw.dat and b/forge-gui/res/deckgendecks/Pioneer.raw.dat differ
diff --git a/forge-gui/res/deckgendecks/Standard.lda.dat b/forge-gui/res/deckgendecks/Standard.lda.dat
index 759106c6bb1..1faf8cd03d0 100644
Binary files a/forge-gui/res/deckgendecks/Standard.lda.dat and b/forge-gui/res/deckgendecks/Standard.lda.dat differ
diff --git a/forge-gui/res/deckgendecks/Standard.raw.dat b/forge-gui/res/deckgendecks/Standard.raw.dat
index 264c1ae8b9d..d25714546dc 100644
Binary files a/forge-gui/res/deckgendecks/Standard.raw.dat and b/forge-gui/res/deckgendecks/Standard.raw.dat differ
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/Grand Prix Promos.txt b/forge-gui/res/editions/Grand Prix Promos.txt
new file mode 100644
index 00000000000..e0c4685f1c7
--- /dev/null
+++ b/forge-gui/res/editions/Grand Prix Promos.txt
@@ -0,0 +1,29 @@
+[metadata]
+Code=PGPX
+Code2=PGPX
+Date=2007-02-24
+Name=Grand Prix Promos
+MciCode=pgpx
+Type=Other
+
+[cards]
+R Spiritmonger
+R Call of the Herd
+R Chrome Mox
+R Umezawa's Jitte
+R Maelstrom Pulse
+R Goblin Guide
+R Lotus Cobra
+M Primeval Titan
+R All Is Dust
+M Batterskull
+M Griselbrand
+R Stoneforge Mystic
+R Sword of Feast and Famine
+M Progenitus
+R Mutavault
+L Plains
+L Island
+L Swamp
+L Mountain
+L Forest
\ No newline at end of file
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/Secret Lair Drop Series.txt b/forge-gui/res/editions/Secret Lair Drop Series.txt
index a2eba070cd7..add00a13e0f 100644
--- a/forge-gui/res/editions/Secret Lair Drop Series.txt
+++ b/forge-gui/res/editions/Secret Lair Drop Series.txt
@@ -36,6 +36,15 @@ Type=Other
34 R Marrow-Gnawer
35 R Pack Rat
36 R Rat Colony
+37 R Thalia, Guardian of Thraben
+38 R Thalia, Guardian of Thraben
+39 R Thalia, Guardian of Thraben
+40 R Thalia, Guardian of Thraben
+51 M Captain Sisay
+52 M Meren of Clan Nel Toth
+53 M Narset, Enlightened Master
+54 M Oona, Queen of the Fae
+55 M Saskia, the Unyielding
68 M Heliod, God of the Sun
69 M Karametra, God of Harvests
70 M Iroas, God of Victory
diff --git a/forge-gui/res/editions/Secret Lair Promos.txt b/forge-gui/res/editions/Secret Lair Promos.txt
index cd9f2fea783..5483d54e7db 100644
--- a/forge-gui/res/editions/Secret Lair Promos.txt
+++ b/forge-gui/res/editions/Secret Lair Promos.txt
@@ -10,8 +10,19 @@ Type=Other
504 U Teyo, the Shieldmage
505 U The Wanderer
506 R Jace, Wielder of Mysteries
+507 U Kasmina, Enigmatic Mentor
+508 U Narset, Parter of Veils
+509 U Davriel, Rogue Shadowmage
+510 M Liliana, Dreadhorde General
+511 U Ob Nixilis, the Hate-Twisted
+512 R Chandra, Fire Artisan
+513 U Jaya, Venerated Firemage
514 R Sarkhan the Masterless
+515 U Tibalt, Rakish Instigator
516 U Arlinn, Voice of the Pack
+517 U Jiang Yanggu, Wildcrafter
+518 R Nissa, Who Shakes the World
+519 R Vivien, Champion of the Wilds
520 R Ajani, the Greathearted
521 R Domri, Anarch of Bolas
522 M Nicol Bolas, Dragon-God
@@ -21,5 +32,11 @@ Type=Other
526 R Teferi, Time Raveler
527 U Angrath, Captain of Chaos
528 U Ashiok, Dream Render
+529 U Dovin, Hand of Control
530 U Huatli, the Sun's Heart
+531 U Kaya, Bane of the Dead
+532 U Kiora, Behemoth Beckoner
533 U Nahiri, Storm of Stone
+534 U Saheeli, Sublime Artificer
+535 U Samut, Tyrant Smasher
+536 U Vraska, Swarm's Eminence
diff --git a/forge-gui/res/editions/Theros Beyond Death.txt b/forge-gui/res/editions/Theros Beyond Death.txt
index af7be4b1772..6d8b9f91a2d 100644
--- a/forge-gui/res/editions/Theros Beyond Death.txt
+++ b/forge-gui/res/editions/Theros Beyond Death.txt
@@ -82,7 +82,7 @@ Prerelease=6 Boosters, 1 RareMythic+
71 M Thassa, Deep-Dwelling
72 R Thassa's Intervention
73 R Thassa's Oracle
-74 C Thirst For Meaning
+74 C Thirst for Meaning
75 U Threnody Singer
76 R Thryx, the Sudden Storm
77 C Towering-Wave Mystic
@@ -233,7 +233,7 @@ Prerelease=6 Boosters, 1 RareMythic+
222 R Kunoros, Hound of Athreos
223 U Mischievous Chimera
224 M Polukranos, Unchained
-225 U Rise To Glory
+225 U Rise to Glory
226 U Siona, Captain of the Pyleas
227 U Slaughter-Priest of Mogis
228 U Staggering Insight
@@ -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/Unsanctioned.txt b/forge-gui/res/editions/Unsanctioned.txt
new file mode 100644
index 00000000000..fbf14409c41
--- /dev/null
+++ b/forge-gui/res/editions/Unsanctioned.txt
@@ -0,0 +1,24 @@
+[metadata]
+Code=UND
+Code2=UND
+Date=2020-02-29
+Name=Unsanctioned
+MciCode=und
+Type=Other
+
+[cards]
+87 L Plains
+88 L Plains
+89 L Island
+90 L Island
+91 L Swamp
+92 L Swamp
+93 L Mountain
+94 L Mountain
+95 L Forest
+96 L Forest
+
+[tokens]
+u_1_1_beeble
+r_1_1_goblin
+g_1_1_squirrel
diff --git a/forge-gui/res/editions/Unstable.txt b/forge-gui/res/editions/Unstable.txt
index 0e4a8f217c7..636eead1d2a 100644
--- a/forge-gui/res/editions/Unstable.txt
+++ b/forge-gui/res/editions/Unstable.txt
@@ -34,8 +34,8 @@ b_2_2_vampire_flying
b_2_2_zombie
b_2_2_zombie
r_1_1_brainiac
-r_3_1_elemental_haste
-r_3_1_elemental_haste
+r_1_1_elemental
+r_1_1_elemental
r_1_1_goblin
g_3_3_beast
g_3_3_beast
diff --git a/forge-gui/res/editions/War of the Spark.txt b/forge-gui/res/editions/War of the Spark.txt
index 25e9a60aab0..01c65804bf3 100644
--- a/forge-gui/res/editions/War of the Spark.txt
+++ b/forge-gui/res/editions/War of the Spark.txt
@@ -285,6 +285,42 @@ BoosterMustContain=Planeswalker
273 R Jace's Ruse
274 C Simic Guildgate
275 M Tezzeret, Master of the Bridge
+1★ R Karn, the Great Creator
+2★ R Ugin, the Ineffable
+13★ M Gideon Blackblade
+32★ U Teyo, the Shieldmage
+37★ U The Wanderer
+54★ R Jace, Wielder of Mysteries
+56★ U Kasmina, Enigmatic Mentor
+61★ U Narset, Parter of Veils
+83★ U Davriel, Rogue Shadowmage
+97★ M Liliana, Dreadhorde General
+100★ U Ob Nixilis, the Hate-Twisted
+119★ R Chandra, Fire Artisan
+135★ U Jaya, Venerated Firemage
+143★ R Sarkhan the Masterless
+146★ U Tibalt, Rakish Instigator
+150★ U Arlinn, Voice of the Pack
+164★ U Jiang Yanggu, Wildcrafter
+169★ R Nissa, Who Shakes the World
+180★ R Vivien, Champion of the Wilds
+184★ R Ajani, the Greathearted
+191★ R Domri, Anarch of Bolas
+207★ M Nicol Bolas, Dragon-God
+211★ R Ral, Storm Conduit
+217★ R Sorin, Vengeful Bloodlord
+220★ R Tamiyo, Collector of Tales
+221★ R Teferi, Time Raveler
+227★ U Angrath, Captain of Chaos
+228★ U Ashiok, Dream Render
+229★ U Dovin, Hand of Control
+230★ U Huatli, the Sun's Heart
+231★ U Kaya, Bane of the Dead
+232★ U Kiora, Behemoth Beckoner
+233★ U Nahiri, Storm of Stone
+234★ U Saheeli, Sublime Artificer
+235★ U Samut, Tyrant Smasher
+236★ U Vraska, Swarm's Eminence
[tokens]
wubrg_2_2_citizen
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 eb748a5aafd..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; 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/formats/Sanctioned/Pioneer.txt b/forge-gui/res/formats/Sanctioned/Pioneer.txt
index b3933f5d814..0fb8f8660a4 100644
--- a/forge-gui/res/formats/Sanctioned/Pioneer.txt
+++ b/forge-gui/res/formats/Sanctioned/Pioneer.txt
@@ -4,4 +4,4 @@ Order:102
Subtype:Pioneer
Type:Sanctioned
Sets:RTR, GTC, DGM, M14, THS, BNG, JOU, M15, KTK, FRF, DTK, ORI, BFZ, OGW, SOI, EMN, KLD, AER, AKH, HOU, XLN, RIX, DOM, M19, GRN, RNA, WAR, M20, ELD, THB
-Banned:Bloodstained Mire; Flooded Strand; Polluted Delta; Windswept Heath; Wooded Foothills; Felidar Guardian; Leyline of Abundance; Oath of Nissa; Veil of Summer; Field of the Dead; Once Upon a Time; Smuggler’s Copter
+Banned:Bloodstained Mire; Felidar Guardian; Field of the Dead; Flooded Strand; Leyline of Abundance; Nexus of Fate; Oath of Nissa; Oko, Thief of Crowns; Once Upon a Time; Polluted Delta; Smuggler's Copter; Veil of Summer; Windswept Heath; Wooded Foothills
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 6fdcdcf86dd..3041bb1895d 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)
@@ -1991,6 +1995,8 @@ lblCardEffectToTargetValueIs={0} effect''s value for {1} is {2}
lblAreYouSureWantPickCard=Are you sure you want to pick ''{0}'' ?
lblSelectThisCardConfirm=Select this card?
#PlayerView.java
+lblCommanderCastCard=Cast from command zone {0} times
+lblCommanderCastPlayer={0} cast from command zone {1} times
lblCommanderDealNDamageToPlayer=Commander damage to {0} from {1}: {2}\r\n
lblNCommanderDamageFromOwnCommander=Commander damage from own commander {0}: {1}\r\n
lblNCommanderDamageFromPlayerCommander=Commander damage from {0} {1}: {2}\r\n
@@ -2004,6 +2010,9 @@ lblDamagepreventionHas=Damage prevention: {0}
lblIsExtraTurn=Extra Turn: Yes
lblExtraTurnCountHas=Extra Turn Count: {0}
lblAntedHas=Ante''d: {0}
+lblAdditionalVotes=You get {0} additional votes.
+lblOptionalAdditionalVotes=You may vote {0} additional times.
+lblControlsVote=You choose how each player votes.
#VStack.java
lblAlwaysYes=Always Yes
lblAlwaysNo=Always No
@@ -2113,6 +2122,7 @@ lblLoadingCurrentConquest=Loading current conquest...
lblSelectCommander=Select Commander
lblCantSelectDeckBecause=Can''t select {0} \nDeck {1}
#ConquestAEtherScreen.java
+lblShardsAE=Shards: {0}
lblHaveNAEShards=Shards: {0} {1}
lblTapToPullFromAE=Tap to pull from the Aether\n{0}
lblSelectCaptionFilter=Select {0} Filter
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/lists/precon-images.txt b/forge-gui/res/lists/precon-images.txt
index 3155ee73774..d21eb0ea12e 100644
--- a/forge-gui/res/lists/precon-images.txt
+++ b/forge-gui/res/lists/precon-images.txt
@@ -1,6 +1,8 @@
https://downloads.cardforge.org/images/products/precons/abzan_siege.jpg
+https://downloads.cardforge.org/images/products/precons/adaptive_enchantment.jpg
https://downloads.cardforge.org/images/products/precons/air_razers.jpg
https://downloads.cardforge.org/images/products/precons/ajani_valiant_protector.jpg
+https://downloads.cardforge.org/images/products/precons/allied_fires.jpg
https://downloads.cardforge.org/images/products/precons/angelic_fury.jpg
https://downloads.cardforge.org/images/products/precons/angelic_might.jpg
https://downloads.cardforge.org/images/products/precons/angrath_minotaur_pirate.jpg
@@ -10,6 +12,7 @@ https://downloads.cardforge.org/images/products/precons/arcaniss_guile.jpg
https://downloads.cardforge.org/images/products/precons/armada.jpg
https://downloads.cardforge.org/images/products/precons/army_of_entropy.jpg
https://downloads.cardforge.org/images/products/precons/army_of_justice.jpg
+https://downloads.cardforge.org/images/products/precons/ashiok_sculptor_of_fears.jpg
https://downloads.cardforge.org/images/products/precons/assassin.jpg
https://downloads.cardforge.org/images/products/precons/assemble_victory.jpg
https://downloads.cardforge.org/images/products/precons/aura_mastery.jpg
@@ -37,6 +40,7 @@ https://downloads.cardforge.org/images/products/precons/breath_of_fire.jpg
https://downloads.cardforge.org/images/products/precons/brute_force.jpg
https://downloads.cardforge.org/images/products/precons/call_of_blood.jpg
https://downloads.cardforge.org/images/products/precons/carnival_of_blood.jpg
+https://downloads.cardforge.org/images/products/precons/cavalcade_charge.jpg
https://downloads.cardforge.org/images/products/precons/chandra_pyrogenius.jpg
https://downloads.cardforge.org/images/products/precons/chandra_bold_pyromancer.jpg
https://downloads.cardforge.org/images/products/precons/cho-mannos_resolve.jpg
@@ -78,6 +82,7 @@ https://downloads.cardforge.org/images/products/precons/eldrazi_arisen.jpg
https://downloads.cardforge.org/images/products/precons/eldrazi_assault.jpg
https://downloads.cardforge.org/images/products/precons/eldritch_onslaught.jpg
https://downloads.cardforge.org/images/products/precons/elementals_path.jpg
+https://downloads.cardforge.org/images/products/precons/elspeth_undaunted_hero.jpg
https://downloads.cardforge.org/images/products/precons/elvish_predation.jpg
https://downloads.cardforge.org/images/products/precons/elvish_rage.jpg
https://downloads.cardforge.org/images/products/precons/enlightened_mastery.jpg
@@ -87,6 +92,7 @@ https://downloads.cardforge.org/images/products/precons/esper_artifice.jpg
https://downloads.cardforge.org/images/products/precons/eternal_siege.jpg
https://downloads.cardforge.org/images/products/precons/evincars_tyranny.jpg
https://downloads.cardforge.org/images/products/precons/expulsion.jpg
+https://downloads.cardforge.org/images/products/precons/exquisite_invention.jpg
https://downloads.cardforge.org/images/products/precons/fangs_of_the_bloodchief.jpg
https://downloads.cardforge.org/images/products/precons/fate_blaster.jpg
https://downloads.cardforge.org/images/products/precons/fates_foreseen.jpg
@@ -94,9 +100,11 @@ https://downloads.cardforge.org/images/products/precons/favors_from_nyx.jpg
https://downloads.cardforge.org/images/products/precons/feast_of_flesh.jpg
https://downloads.cardforge.org/images/products/precons/fiendish_nature.jpg
https://downloads.cardforge.org/images/products/precons/fiery_dawn.jpg
+https://downloads.cardforge.org/images/products/precons/final_adventure.jpg
https://downloads.cardforge.org/images/products/precons/fire_surge.jpg
https://downloads.cardforge.org/images/products/precons/firebomber.jpg
https://downloads.cardforge.org/images/products/precons/flames_of_the_dragon.jpg
+https://downloads.cardforge.org/images/products/precons/flash_of_ferocity.jpg
https://downloads.cardforge.org/images/products/precons/flyover.jpg
https://downloads.cardforge.org/images/products/precons/forged_in_battle.jpg
https://downloads.cardforge.org/images/products/precons/furious_forces.jpg
@@ -169,6 +177,7 @@ https://downloads.cardforge.org/images/products/precons/mortals_of_myth.jpg
https://downloads.cardforge.org/images/products/precons/myr_of_mirrodin.jpg
https://downloads.cardforge.org/images/products/precons/mysterious_realms.jpg
https://downloads.cardforge.org/images/products/precons/mystical_might.jpg
+https://downloads.cardforge.org/images/products/precons/natures_vengeance.jpg
https://downloads.cardforge.org/images/products/precons/naya_behemoths.jpg
https://downloads.cardforge.org/images/products/precons/naya_domain.jpg
https://downloads.cardforge.org/images/products/precons/nicol_bolas_the_deceiver.jpg
@@ -234,6 +243,7 @@ https://downloads.cardforge.org/images/products/precons/spiritcraft.jpg
https://downloads.cardforge.org/images/products/precons/stampede.jpg
https://downloads.cardforge.org/images/products/precons/stampede_of_beasts.jpg
https://downloads.cardforge.org/images/products/precons/stampeding_hordes.jpg
+https://downloads.cardforge.org/images/products/precons/subjective_reality.jpg
https://downloads.cardforge.org/images/products/precons/sultai_schemers.jpg
https://downloads.cardforge.org/images/products/precons/sunburst.jpg
https://downloads.cardforge.org/images/products/precons/superabundance.jpg
diff --git a/forge-gui/res/puzzle/PS_THB4.pzl b/forge-gui/res/puzzle/PS_THB4.pzl
new file mode 100644
index 00000000000..0e4ca0e6589
--- /dev/null
+++ b/forge-gui/res/puzzle/PS_THB4.pzl
@@ -0,0 +1,19 @@
+[metadata]
+Name:Possibility Storm - Theros Beyond Death #04
+URL:https://i2.wp.com/www.possibilitystorm.com/wp-content/uploads/2020/02/147.-THB4-scaled.jpg
+Goal:Win
+Turns:1
+Difficulty:Rare
+Description:Win this turn. You've drawn one card. Assume cards drawn are not relevant to the puzzle. Mu Yanling's +2 targeted Dream Trawler last turn (you didn't give it hexproof). Trapped in the Tower is controlled by your opponent. Colossus Hammer is controlled by you.
+[state]
+humanlife=20
+ailife=8
+turn=1
+activeplayer=human
+activephase=MAIN1
+humanhand=Flicker of Fate;Brought Back;One with the Stars;One with the Stars
+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=Alseid of Life's Bounty;Dream Trawler|Id:1;Colossus Hammer|AttachedTo:1;Shoal Kraken;Trusted Pegasus;Hallowed Fountain|NoETBTrigs;Hallowed Fountain|NoETBTrigs;Hallowed Fountain|NoETBTrigs;Hallowed Fountain|NoETBTrigs;Temple of Enlightenment|NoETBTrigs;Temple of Enlightenment|NoETBTrigs;Temple of Enlightenment|NoETBTrigs;Temple of Enlightenment|NoETBTrigs
+aibattlefield=Mu Yanling, Sky Dancer|Counters:LOYALTY=6;Arboretum Elemental|Id:2;Wings of Hubris|AttachedTo:2;Fae of Wishes;Fae of Wishes;Signpost Scarecrow
+humanprecast=Dream Trawler:TrigPump->1
+aiprecast=Trapped in the Tower->1;Mu Yanling, Sky Dancer:1->1
diff --git a/forge-gui/res/puzzle/PS_THB5.pzl b/forge-gui/res/puzzle/PS_THB5.pzl
new file mode 100644
index 00000000000..a418d543eff
--- /dev/null
+++ b/forge-gui/res/puzzle/PS_THB5.pzl
@@ -0,0 +1,17 @@
+[metadata]
+Name:Possibility Storm - Theros Beyond Death #05
+URL:https://i2.wp.com/www.possibilitystorm.com/wp-content/uploads/2020/02/148.-THB5-scaled.jpg
+Goal:Win
+Turns:1
+Difficulty:Rare
+Description:Win this turn. You have eight cards remaining in your library. Assume these cards are not relevant to the solution.
+[state]
+humanlife=20
+ailife=10
+turn=1
+activeplayer=human
+activephase=MAIN1
+humanhand=Devious Cover-Up;Dawn of Hope;Frogify;Phoenix of Ash;Sentinel's Eyes
+humanlibrary=Opt;Opt;Opt;Opt;Opt;Opt;Opt;Opt
+humanbattlefield=Fblthp, the Lost;Elspeth, Sun's Nemesis|Counters:LOYALTY=4;Glint-Horn Buccaneer|Id:1;Benthic Biomancer;Heliod, Sun-Crowned;Hallowed Fountain|NoETBTrigs;Hallowed Fountain|NoETBTrigs;Hallowed Fountain|NoETBTrigs;Sacred Foundry|NoETBTrigs;Sacred Foundry|NoETBTrigs;Sacred Foundry|NoETBTrigs
+aibattlefield=Hushbringer|Tapped;Bishop of Wings;Gilded Goose;Setessan Champion;Arboreal Grazer;Demotion|AttachedTo:1
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/quest/bazaar/index.xml b/forge-gui/res/quest/bazaar/index.xml
index 64637e66cb1..1eb17455fb1 100644
--- a/forge-gui/res/quest/bazaar/index.xml
+++ b/forge-gui/res/quest/bazaar/index.xml
@@ -1,7 +1,7 @@
- 80
+ 160
@@ -26,7 +26,7 @@
Sleight
-
+ This adventurer's market has a tool for every need ... or so the plaque on the wall claims.Map
@@ -53,22 +53,22 @@
-
+ These volumes explain how to perform the most difficult of sleights.
Effect: Your first mulligan is free.
-
+ These ancient charts should facilitate navigation during your travels significantly.
Effect: Quest challenges become available more frequently.
-
+ This coin is believed to give good luck to its owner.
Effect: Improves the chance of getting a random rare after each match by 15%.
-
+ Land owners have a strong voice in community matters.
Effect: Gives a bonus of %d%% to match winnings.
@@ -81,37 +81,37 @@ Effect: Quest challenges become available more frequently.
Effect: +3 life
Effect: Activate once for a new set of challenges (re-fuels after a challenge is attempted).
-
+ The Alchemist welcomes contributions to his famous Elixir.
But beware, you may build an immunity to its effects...
Effect: Alchemist gives you %d credits.
Effect: Reduces maximum life by 1.
-
+ A salty sweet smell rises from the vials bubbling behind the counter.
Effect: Gives +1 to maximum life.
Fine Print: Loses effectiveness after 15 uses.
+ itemType="CHARM_VIM" icon="ICO_QUEST_BIG_BOOTS">
A charm fills you with energy, speeding your movements.
Effect: You may have each match be best of 1 instead of 3.
+ itemType="CHARM" icon="ICO_QUEST_BIG_CHARM">
A charm to ward off the fatigue of battle.
Effect: You may have each match be best of 5 instead of 3.
-
+ A written agreement with the Spell Shop to acquire cards you lose in an ante match from quest opponents.
Effect: Cards lost in an ante match will be available immediately following the match in the Card Shop.
-
+ A token certifying you as a member of the bank, giving you a greater selection of booster packs when you win.
Effect: Adds one more booster pack to the pack selection after you win.
diff --git a/forge-gui/res/quest/precons/Allied Fires.dck b/forge-gui/res/quest/precons/Allied Fires.dck
new file mode 100644
index 00000000000..2e69e6a8e82
--- /dev/null
+++ b/forge-gui/res/quest/precons/Allied Fires.dck
@@ -0,0 +1,47 @@
+[shop]
+WinsToUnlock=0
+Credits=3000
+MinDifficulty=0
+MaxDifficulty=5
+[metadata]
+Name=Allied Fires - Challenger 2020
+Description=Jeskai Fires of Invention deck, featuring 24 rares and 1 mythic rare.
+Deck Type=constructed
+Set=THB
+Image=allied_fires.jpg
+[Main]
+2 Banishing Light|THB
+3 Deafening Clarion|GRN
+2 Drawn from Dreams|M20
+2 Fae of Wishes|ELD
+4 Fires of Invention|ELD
+4 Interplanar Beacon|WAR
+5 Island|M20
+3 Kasmina, Enigmatic Mentor|WAR
+1 Kenrith, the Returned King|ELD
+2 Mountain|M20
+4 Narset, Parter of Veils|WAR
+4 Omen of the Sea|THB
+2 Plains|M20
+2 Saheeli, Sublime Artificer|WAR
+3 Sarkhan the Masterless|WAR
+1 Steam Vents|GRN
+3 Swiftwater Cliffs|M20
+1 Temple of Enlightenment|THB
+1 Temple of Epiphany|M20
+1 Temple of Triumph|M20
+2 Time Wipe|WAR
+3 Tranquil Cove|M20
+1 Ugin, the Ineffable|WAR
+4 Wind-Scarred Crag|M20
+[Sideboard]
+1 Ashiok, Dream Render|WAR
+2 Devout Decree|M20
+1 Dovin's Veto|WAR
+1 Dovin, Hand of Control|WAR
+2 Fry|M20
+1 Mass Manipulation|RNA
+2 Revoke Existence|THB
+1 Sarkhan the Masterless|WAR
+3 Thirst for Meaning|THB
+1 Time Wipe|WAR
\ No newline at end of file
diff --git a/forge-gui/res/quest/precons/Cavalcade Charge.dck b/forge-gui/res/quest/precons/Cavalcade Charge.dck
new file mode 100644
index 00000000000..ae564f7beec
--- /dev/null
+++ b/forge-gui/res/quest/precons/Cavalcade Charge.dck
@@ -0,0 +1,31 @@
+[shop]
+WinsToUnlock=0
+Credits=3000
+MinDifficulty=0
+MaxDifficulty=5
+[metadata]
+Name=Cavalcade Charge - Challenger 2020
+Description=Mono red aggro deck, featuring 25 rares and 1 mythic rare.
+Deck Type=constructed
+Set=THB
+Image=cavalcade_charge.jpg
+[Main]
+4 Bonecrusher Giant|ELD
+3 Castle Embereth|ELD
+4 Cavalcade of Calamity|RNA
+3 Chandra, Acolyte of Flame|M20
+1 Embercleave|ELD
+4 Fervent Champion|ELD
+4 Light Up the Stage|RNA
+18 Mountain|M20
+4 Rimrock Knight|ELD
+4 Runaway Steam-Kin|GRN
+4 Scorch Spitter|M20
+3 Tin Street Dodger|RNA
+4 Torbran, Thane of Red Fell|ELD
+[Sideboard]
+3 Experimental Frenzy|GRN
+3 Satyr's Cunning|THB
+4 Shock|M20
+3 Slaying Fire|ELD
+2 Tibalt, Rakish Instigator|WAR
\ No newline at end of file
diff --git a/forge-gui/res/quest/precons/Final Adventure.dck b/forge-gui/res/quest/precons/Final Adventure.dck
new file mode 100644
index 00000000000..05da6219889
--- /dev/null
+++ b/forge-gui/res/quest/precons/Final Adventure.dck
@@ -0,0 +1,38 @@
+[shop]
+WinsToUnlock=0
+Credits=3000
+MinDifficulty=0
+MaxDifficulty=5
+[metadata]
+Name=Final Adventure - Challenger 2020
+Description=Golgari Adventure deck, featuring 21 rares and 1 mythic rare.
+Deck Type=constructed
+Set=THB
+Image=final_adventure.jpg
+[Main]
+2 Blacklance Paragon|ELD
+2 Castle Locthwain|ELD
+2 Disfigure|M20
+4 Edgewall Innkeeper|ELD
+1 Fabled Passage|ELD
+2 Find/Finality|GRN
+7 Forest|M20
+4 Foulmire Knight|ELD
+3 Jungle Hollow|M20
+2 Knight of the Ebon Legion|M20
+4 Lovestruck Beast|ELD
+4 Lucky Clover|ELD
+2 Midnight Reaper|GRN
+2 Murderous Rider|ELD
+4 Order of Midnight|ELD
+4 Smitten Swordmaster|ELD
+8 Swamp|M20
+2 Temple of Malady|M20
+1 Vraska, Golgari Queen|GRN
+[Sideboard]
+1 Cling to Dust|THB
+4 Duress|M20
+2 Kraul Harpooner|GRN
+2 Massacre Girl|WAR
+4 Noxious Grasp|M20
+2 Thrashing Brontodon|M20
diff --git a/forge-gui/res/quest/precons/Flash of Ferocity.dck b/forge-gui/res/quest/precons/Flash of Ferocity.dck
new file mode 100644
index 00000000000..03039b54b28
--- /dev/null
+++ b/forge-gui/res/quest/precons/Flash of Ferocity.dck
@@ -0,0 +1,37 @@
+[shop]
+WinsToUnlock=0
+Credits=3000
+MinDifficulty=0
+MaxDifficulty=5
+[metadata]
+Name=Flash of Ferocity - Challenger 2020
+Description=Simic flash deck, featuring 19 rares and 1 mythic rare.
+Deck Type=constructed
+Set=THB
+Image=flash_of_ferocity.jpg
+[Main]
+1 Brazen Borrower|ELD
+4 Brineborn Cutthroat|M20
+2 Castle Vantress|ELD
+1 Fabled Passage|ELD
+8 Forest|M20
+4 Frilled Mystic|RNA
+8 Island|M20
+4 Nightpack Ambusher|M20
+4 Opt|ELD
+4 Quench|RNA
+2 Sinister Sabotage|GRN
+4 Spectral Sailor|M20
+2 Temple of Mystery|M20
+2 Thassa's Intervention|THB
+3 Thornwood Falls|M20
+2 Unsummon|M20
+1 Wavebreak Hippocamp|THB
+4 Wildborn Preserver|ELD
+[Sideboard]
+3 Aether Gust|M20
+2 Disdainful Stroke|GRN
+2 Mystical Dispute|ELD
+2 Negate|M20
+3 Shifting Ceratops|M20
+3 Threnody Singer|THB
\ No newline at end of file
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 56b4276d8f4..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_buttons.png b/forge-gui/res/skins/default/sprite_buttons.png
new file mode 100644
index 00000000000..3f2587a91d5
Binary files /dev/null and b/forge-gui/res/skins/default/sprite_buttons.png differ
diff --git a/forge-gui/res/skins/default/sprite_icons.png b/forge-gui/res/skins/default/sprite_icons.png
index d00063b2f4e..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 bb5275feeb4..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/skins/default/sprite_start.png b/forge-gui/res/skins/default/sprite_start.png
new file mode 100644
index 00000000000..3b20b24c5b7
Binary files /dev/null and b/forge-gui/res/skins/default/sprite_start.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/res/tokenscripts/u_1_1_beeble.txt b/forge-gui/res/tokenscripts/u_1_1_beeble.txt
new file mode 100644
index 00000000000..195e1436abe
--- /dev/null
+++ b/forge-gui/res/tokenscripts/u_1_1_beeble.txt
@@ -0,0 +1,6 @@
+Name:Beeble
+ManaCost:no cost
+Types:Creature Beeble
+Colors:blue
+PT:1/1
+Oracle:
\ No newline at end of file
diff --git a/forge-gui/src/main/config/forge.command b/forge-gui/src/main/config/forge.command
deleted file mode 100644
index e6068616734..00000000000
--- a/forge-gui/src/main/config/forge.command
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh
-cd "`dirname \"$0\"`"
-java -Xmx1024m -jar $project.build.finalName$
\ No newline at end of file
diff --git a/forge-gui/src/main/config/forge.sh b/forge-gui/src/main/config/forge.sh
deleted file mode 100644
index e6068616734..00000000000
--- a/forge-gui/src/main/config/forge.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh
-cd "`dirname \"$0\"`"
-java -Xmx1024m -jar $project.build.finalName$
\ No newline at end of file
diff --git a/forge-gui/src/main/java/forge/assets/FSkinProp.java b/forge-gui/src/main/java/forge/assets/FSkinProp.java
index a2074450960..38edff0ea32 100644
--- a/forge-gui/src/main/java/forge/assets/FSkinProp.java
+++ b/forge-gui/src/main/java/forge/assets/FSkinProp.java
@@ -48,10 +48,22 @@ public enum FSkinProp {
//zone images
IMG_ZONE_HAND (new int[] {280, 40, 40, 40}, PropType.IMAGE),
+ IMG_HDZONE_HAND (new int[] {2, 136, 128, 128}, PropType.BUTTONS),
+
IMG_ZONE_LIBRARY (new int[] {280, 0, 40, 40}, PropType.IMAGE),
+ IMG_HDZONE_LIBRARY (new int[] {132, 136, 128, 128}, PropType.BUTTONS),
+
IMG_ZONE_EXILE (new int[] {320, 40, 40, 40}, PropType.IMAGE),
+ IMG_HDZONE_EXILE (new int[] {262, 136, 128, 128}, PropType.BUTTONS),
+
IMG_ZONE_FLASHBACK (new int[] {280, 80, 40, 40}, PropType.IMAGE),
+ IMG_HDZONE_FLASHBACK (new int[] {262, 6, 128, 128}, PropType.BUTTONS),
+
IMG_ZONE_GRAVEYARD (new int[] {320, 0, 40, 40}, PropType.IMAGE),
+ IMG_HDZONE_GRAVEYARD (new int[] {132, 6, 128, 128}, PropType.BUTTONS),
+
+ IMG_HDZONE_MANAPOOL (new int[] {2, 6, 128, 128}, PropType.BUTTONS),
+
IMG_ZONE_POISON (new int[] {320, 80, 40, 40}, PropType.IMAGE),
//mana images
@@ -170,6 +182,15 @@ public enum FSkinProp {
ICO_ARCSON (new int[] {320, 800, 80, 80}, PropType.ICON),
ICO_ARCSHOVER (new int[] {400, 800, 80, 80}, PropType.ICON),
+ //choice-search-misc
+ ICO_HDCHOICE (new int[] {2, 1792, 128, 128}, PropType.BUTTONS),
+ ICO_HDSIDEBOARD (new int[] {132, 1792, 128, 128}, PropType.BUTTONS),
+ ICO_HDPREFERENCE (new int[] {262, 1792, 128, 128}, PropType.BUTTONS),
+ ICO_HDIMPORT (new int[] {2, 1922, 128, 128}, PropType.BUTTONS),
+ ICO_HDEXPORT (new int[] {132, 1922, 128, 128}, PropType.BUTTONS),
+ ICO_BLANK (new int[] {2, 2, 2, 2}, PropType.ICON), //safe coords, lower than 2 will cause crash on desktop
+ IMG_LANDLOGO (new int[] {84, 822, 80, 80}, PropType.MANAICONS),
+
//quest icons
ICO_QUEST_ZEP (new int[] {0, 480, 80, 80}, PropType.ICON),
ICO_QUEST_GEAR (new int[] {80, 480, 80, 80}, PropType.ICON),
@@ -192,31 +213,82 @@ public enum FSkinProp {
ICO_QUEST_MINUS (new int[] {560, 640, 80, 80}, PropType.ICON),
ICO_QUEST_PLUS (new int[] {480, 640, 80, 80}, PropType.ICON),
ICO_QUEST_PLUSPLUS (new int[] {480, 720, 80, 80}, PropType.ICON),
+ ICO_QUEST_BIG_ELIXIR (new int[] {0, 880, 160, 160}, PropType.ICON),
+ ICO_QUEST_BIG_BREW (new int[] {160, 880, 160, 160}, PropType.ICON),
+ ICO_QUEST_BIG_BM (new int[] {320, 880, 160, 160}, PropType.ICON),
+ ICO_QUEST_BIG_STAKES (new int[] {480, 880, 160, 160}, PropType.ICON),
+ ICO_QUEST_BIG_HOUSE (new int[] {0, 1040, 160, 160}, PropType.ICON),
+ ICO_QUEST_BIG_COIN (new int[] {160, 1040, 160, 160}, PropType.ICON),
+ ICO_QUEST_BIG_BOOK (new int[] {320, 1040, 160, 160}, PropType.ICON),
+ ICO_QUEST_BIG_MAP (new int[] {480, 1040, 160, 160}, PropType.ICON),
+ ICO_QUEST_BIG_ZEP (new int[] {0, 1200, 160, 160}, PropType.ICON),
+ ICO_QUEST_BIG_CHARM (new int[] {160, 1200, 160, 160}, PropType.ICON),
+ ICO_QUEST_BIG_BOOTS (new int[] {320, 1200, 160, 160}, PropType.ICON),
+ ICO_QUEST_BIG_SHIELD (new int[] {480, 1200, 160, 160}, PropType.ICON),
+ ICO_QUEST_BIG_ARMOR (new int[] {0, 1360, 160, 160}, PropType.ICON),
+ ICO_QUEST_BIG_AXE (new int[] {160, 1360, 160, 160}, PropType.ICON),
+ 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),
ICO_WARNING (new int[] {560, 832, 32, 32}, PropType.ICON),
ICO_ERROR (new int[] {592, 832, 32, 32}, PropType.ICON),
+
ICO_DELETE (new int[] {640, 480, 20, 20}, PropType.ICON),
+ ICO_HDDELETE (new int[] {392, 134, 64, 64}, PropType.BUTTONS),
+
ICO_DELETE_OVER (new int[] {660, 480, 20, 20}, PropType.ICON),
+
ICO_EDIT (new int[] {640, 500, 20, 20}, PropType.ICON),
+ ICO_HDEDIT (new int[] {392, 200, 64, 64}, PropType.BUTTONS),
+
ICO_EDIT_OVER (new int[] {660, 500, 20, 20}, PropType.ICON),
+
ICO_OPEN (new int[] {660, 520, 20, 20}, PropType.ICON),
+ ICO_HDOPEN (new int[] {392, 68, 64, 64}, PropType.BUTTONS),
+
ICO_MINUS (new int[] {660, 620, 20, 20}, PropType.ICON),
+ ICO_HDMINUS (new int[] {391, 1506, 64, 64}, PropType.BUTTONS),
+
ICO_NEW (new int[] {660, 540, 20, 20}, PropType.ICON),
+
ICO_PLUS (new int[] {660, 600, 20, 20}, PropType.ICON),
+ ICO_HDPLUS (new int[] {391, 1572, 64, 64}, PropType.BUTTONS),
+
ICO_PRINT (new int[] {660, 640, 20, 20}, PropType.ICON),
+
ICO_SAVE (new int[] {660, 560, 20, 20}, PropType.ICON),
+ ICO_HDSAVE (new int[] {391, 1704, 64, 64}, PropType.BUTTONS),
ICO_SAVEAS (new int[] {660, 580, 20, 20}, PropType.ICON),
+ ICO_HDSAVEAS (new int[] {391, 1638, 64, 64}, PropType.BUTTONS),
+
ICO_CLOSE (new int[] {640, 640, 20, 20}, PropType.ICON),
ICO_LIST (new int[] {640, 660, 20, 20}, PropType.ICON),
ICO_CARD_IMAGE (new int[] {660, 660, 20, 20}, PropType.ICON),
+
ICO_FOLDER (new int[] {640, 680, 20, 20}, PropType.ICON),
+ ICO_HDFOLDER (new int[] {392, 2, 64, 64}, PropType.BUTTONS),
+
ICO_SEARCH (new int[] {660, 680, 20, 20}, PropType.ICON),
+ ICO_HDSEARCH (new int[] {391, 1374, 64, 64}, PropType.BUTTONS),
+
ICO_UNKNOWN (new int[] {0, 720, 80, 80}, PropType.ICON),
ICO_LOGO (new int[] {480, 0, 200, 200}, PropType.ICON),
+
ICO_FLIPCARD (new int[] {400, 0, 80, 120}, PropType.ICON),
+ ICO_HDFLIPCARD (new int[] {2, 1268, 387, 500}, PropType.BUTTONS),
+
ICO_FAVICON (new int[] {0, 640, 80, 80}, PropType.ICON),
ICO_LOCK (new int[] {620, 800, 48, 48}, PropType.ICON),
@@ -229,14 +301,18 @@ public enum FSkinProp {
IMG_CUR_TAB (new int[] {644, 764, 32, 32}, PropType.IMAGE),
//editor images
- IMG_STAR_OUTINE (new int[] {640, 460, 20, 20}, PropType.IMAGE),
+ IMG_STAR_OUTLINE (new int[] {640, 460, 20, 20}, PropType.IMAGE),
+ IMG_HDSTAR_OUTLINE (new int[] {391, 1308, 64, 64}, PropType.BUTTONS),
IMG_STAR_FILLED (new int[] {660, 460, 20, 20}, PropType.IMAGE),
+ IMG_HDSTAR_FILLED (new int[] {391, 1440, 64, 64}, PropType.BUTTONS),
+
IMG_ARTIFACT (new int[] {412, 658, 80, 80}, PropType.MANAICONS),
IMG_CREATURE (new int[] {2, 740, 80, 80}, PropType.MANAICONS),
IMG_ENCHANTMENT (new int[] {84, 740, 80, 80}, PropType.MANAICONS),
IMG_INSTANT (new int[] {166, 740, 80, 80}, PropType.MANAICONS),
IMG_LAND (new int[] {248, 740, 80, 80}, PropType.MANAICONS),
IMG_MULTI (new int[] {80, 720, 40, 40}, PropType.IMAGE),
+ IMG_HDMULTI (new int[] {2, 822, 80, 80}, PropType.MANAICONS),
IMG_PLANESWALKER (new int[] {330, 740, 80, 80}, PropType.MANAICONS),
IMG_PACK (new int[] {80, 760, 40, 40}, PropType.IMAGE),
IMG_SORCERY (new int[] {412, 740, 80, 80}, PropType.MANAICONS),
@@ -284,6 +360,28 @@ public enum FSkinProp {
IMG_BTN_DISABLED_LEFT (new int[] {80, 200, 40, 40}, PropType.ICON),
IMG_BTN_DISABLED_CENTER (new int[] {120, 200, 1, 40}, PropType.ICON),
IMG_BTN_DISABLED_RIGHT (new int[] {160, 200, 40, 40}, PropType.ICON),
+ //hd buttons
+ IMG_HDBTN_START_UP (new int[] {2, 2, 588, 312}, PropType.BTNSTART),
+ IMG_HDBTN_START_OVER (new int[] {1183, 2, 588, 312}, PropType.BTNSTART),
+ IMG_HDBTN_START_DOWN (new int[] {593, 2, 588, 312}, PropType.BTNSTART),
+ IMG_HDBTN_UP_LEFT (new int[] {2, 266, 160, 165}, PropType.BUTTONS),
+ IMG_HDBTN_UP_CENTER (new int[] {162, 266, 1, 165}, PropType.BUTTONS),
+ IMG_HDBTN_UP_RIGHT (new int[] {322, 266, 160, 165}, PropType.BUTTONS),
+ IMG_HDBTN_OVER_LEFT (new int[] {2, 433, 160, 165}, PropType.BUTTONS),
+ IMG_HDBTN_OVER_CENTER (new int[] {162, 433, 1, 165}, PropType.BUTTONS),
+ IMG_HDBTN_OVER_RIGHT (new int[] {322, 433, 160, 165}, PropType.BUTTONS),
+ IMG_HDBTN_DOWN_LEFT (new int[] {2, 600, 160, 165}, PropType.BUTTONS),
+ IMG_HDBTN_DOWN_CENTER (new int[] {162, 600, 1, 165}, PropType.BUTTONS),
+ IMG_HDBTN_DOWN_RIGHT (new int[] {322, 600, 160, 165}, PropType.BUTTONS),
+ IMG_HDBTN_FOCUS_LEFT (new int[] {2, 767, 160, 165}, PropType.BUTTONS),
+ IMG_HDBTN_FOCUS_CENTER (new int[] {162, 767, 1, 165}, PropType.BUTTONS),
+ IMG_HDBTN_FOCUS_RIGHT (new int[] {322, 767, 160, 165}, PropType.BUTTONS),
+ IMG_HDBTN_TOGGLE_LEFT (new int[] {2, 934, 160, 165}, PropType.BUTTONS),
+ IMG_HDBTN_TOGGLE_CENTER (new int[] {162, 934, 1, 165}, PropType.BUTTONS),
+ IMG_HDBTN_TOGGLE_RIGHT (new int[] {322, 934, 160, 165}, PropType.BUTTONS),
+ IMG_HDBTN_DISABLED_LEFT (new int[] {2, 1101, 160, 165}, PropType.BUTTONS),
+ IMG_HDBTN_DISABLED_CENTER (new int[] {162, 1101, 1, 165}, PropType.BUTTONS),
+ IMG_HDBTN_DISABLED_RIGHT (new int[] {322, 1101, 160, 165}, PropType.BUTTONS),
IMG_FAV1 (new int[] {0, 0, 100, 100}, PropType.FAVICON),
IMG_FAV2 (new int[] {100, 0, 100, 100}, PropType.FAVICON),
@@ -378,6 +476,8 @@ public enum FSkinProp {
TROPHY,
ABILITY,
BORDERS,
+ BUTTONS,
+ BTNSTART,
MANAICONS,
PLANAR_CONQUEST,
FAVICON
diff --git a/forge-gui/src/main/java/forge/deck/DeckgenUtil.java b/forge-gui/src/main/java/forge/deck/DeckgenUtil.java
index 2ccc98d7e08..575aa7031b8 100644
--- a/forge-gui/src/main/java/forge/deck/DeckgenUtil.java
+++ b/forge-gui/src/main/java/forge/deck/DeckgenUtil.java
@@ -156,6 +156,9 @@ public class DeckgenUtil {
//}
}
+ //remove any cards not valid in format
+ selectedCards = Lists.newArrayList(Iterables.filter(selectedCards, format.getFilterPrinted()));
+
List toRemove = new ArrayList<>();
//randomly remove cards
@@ -252,6 +255,9 @@ public class DeckgenUtil {
//}
}
+ //remove any cards not valid in format
+ selectedCards = Lists.newArrayList(Iterables.filter(selectedCards, format.getFilterPrinted()));
+
List toRemove = new ArrayList<>();
//randomly remove cards
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/itemmanager/SItemManagerUtil.java b/forge-gui/src/main/java/forge/itemmanager/SItemManagerUtil.java
index af66a90e732..5aeba9487cb 100644
--- a/forge-gui/src/main/java/forge/itemmanager/SItemManagerUtil.java
+++ b/forge-gui/src/main/java/forge/itemmanager/SItemManagerUtil.java
@@ -1,6 +1,7 @@
package forge.itemmanager;
import com.google.common.base.Predicate;
+import forge.GuiBase;
import forge.assets.FSkinProp;
import forge.assets.IHasSkinProp;
import forge.card.CardRules;
@@ -35,7 +36,8 @@ public final class SItemManagerUtil {
RED (FSkinProp.IMG_MANA_R, CardRulesPredicates.Presets.IS_RED, "lblRedcards"),
GREEN (FSkinProp.IMG_MANA_G, CardRulesPredicates.Presets.IS_GREEN, "lblGreencards"),
COLORLESS (FSkinProp.IMG_MANA_COLORLESS, CardRulesPredicates.Presets.IS_COLORLESS, "lblColorlesscards"),
- MULTICOLOR (FSkinProp.IMG_MULTI, CardRulesPredicates.Presets.IS_MULTICOLOR, "lblMulticolorcards"),
+ MULTICOLOR (GuiBase.getInterface().isLibgdxPort() ? FSkinProp.IMG_HDMULTI :
+ FSkinProp.IMG_MULTI, CardRulesPredicates.Presets.IS_MULTICOLOR, "lblMulticolorcards"),
PACK_OR_DECK (FSkinProp.IMG_PACK, null, "lblPackordeck"),
LAND (FSkinProp.IMG_LAND, CardRulesPredicates.Presets.IS_LAND, "lblLands"),
@@ -60,7 +62,8 @@ public final class SItemManagerUtil {
DECK_RED (FSkinProp.IMG_MANA_R, null, "lblReddecks"),
DECK_GREEN (FSkinProp.IMG_MANA_G, null, "lblGreendecks"),
DECK_COLORLESS (FSkinProp.IMG_MANA_COLORLESS, null, "lblColorlessdecks"),
- DECK_MULTICOLOR (FSkinProp.IMG_MULTI, null, "lblMulticolordecks"),
+ DECK_MULTICOLOR (GuiBase.getInterface().isLibgdxPort() ? FSkinProp.IMG_HDMULTI :
+ FSkinProp.IMG_MULTI, null, "lblMulticolordecks"),
FOIL_OLD (FSkinProp.FOIL_11, null, "lblOldstyleFoilcards"),
FOIL_NEW (FSkinProp.FOIL_01, null, "lblNewstyleFoilcards"),
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/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java
index 4022f2d6d04..c67ad331b3c 100644
--- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java
+++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java
@@ -746,7 +746,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
endTempShowCards();
} else {
getGui().message(MessageUtil.formatMessage(localizer.getMessage("lblThereNoCardInPlayerZone", "{player's}", zone.getTranslatedName().toLowerCase()),
- player, owner), fm);
+ getLocalPlayerView(), owner), fm);
}
}
@@ -1181,7 +1181,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
@Override
public Object vote(final SpellAbility sa, final String prompt, final List options,
- final ListMultimap votes) {
+ final ListMultimap votes, Player forPlayer) {
return getGui().one(prompt, options);
}
diff --git a/forge-gui/src/main/java/forge/properties/ForgeConstants.java b/forge-gui/src/main/java/forge/properties/ForgeConstants.java
index 63d3894158a..471e6acbbf0 100644
--- a/forge-gui/src/main/java/forge/properties/ForgeConstants.java
+++ b/forge-gui/src/main/java/forge/properties/ForgeConstants.java
@@ -95,10 +95,12 @@ public final class ForgeConstants {
public static final String SPRITE_TROPHIES_FILE = "sprite_trophies.png";
public static final String SPRITE_ABILITY_FILE = "sprite_ability.png";
public static final String SPRITE_BORDER_FILE = "sprite_border.png";
+ public static final String SPRITE_BUTTONS_FILE = "sprite_buttons.png";
+ public static final String SPRITE_START_FILE = "sprite_start.png";
public static final String SPRITE_MANAICONS_FILE = "sprite_manaicons.png";
public static final String SPRITE_AVATARS_FILE = "sprite_avatars.png";
public static final String SPRITE_SLEEVES_FILE = "sprite_sleeves.png";
- public static final String SPRITE_SLEEVES2_FILE = "sprite_sleeves2.png";
+ public static final String SPRITE_SLEEVES2_FILE = "sprite_sleeves2.png";
public static final String SPRITE_FAVICONS_FILE = "sprite_favicons.png";
public static final String SPRITE_PLANAR_CONQUEST_FILE = "sprite_planar_conquest.png";
public static final String FONT_FILE = "font1.ttf";
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) {
diff --git a/pom.xml b/pom.xml
index 3d50a4419b4..22f1a350b04 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
forgepomForge Parent
- 1.6.33-SNAPSHOT
+ 1.6.34-SNAPSHOT
Forge lets you play the card game Magic: The Gathering against a computer opponent using all of the rules.