Merge branch 'coremaster' into respectbanlist

This commit is contained in:
maustin
2020-03-14 21:18:16 +00:00
104 changed files with 4775 additions and 432 deletions

View File

@@ -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)); sa.setHostCard(game.getAction().moveToStack(source, sa));
} }
@@ -219,9 +216,6 @@ public class ComputerUtil {
final Card source = sa.getHostCard(); final Card source = sa.getHostCard();
if (sa.isSpell() && !source.isCopiedSpell()) { if (sa.isSpell() && !source.isCopiedSpell()) {
source.setCastSA(sa);
sa.setLastStateBattlefield(game.getLastStateBattlefield());
sa.setLastStateGraveyard(game.getLastStateGraveyard());
sa.setHostCard(game.getAction().moveToStack(source, sa)); sa.setHostCard(game.getAction().moveToStack(source, sa));
} }
@@ -246,9 +240,6 @@ public class ComputerUtil {
final Card source = sa.getHostCard(); final Card source = sa.getHostCard();
if (sa.isSpell() && !source.isCopiedSpell()) { if (sa.isSpell() && !source.isCopiedSpell()) {
source.setCastSA(sa);
sa.setLastStateBattlefield(game.getLastStateBattlefield());
sa.setLastStateGraveyard(game.getLastStateGraveyard());
sa.setHostCard(game.getAction().moveToStack(source, sa)); sa.setHostCard(game.getAction().moveToStack(source, sa));
} }
@@ -267,9 +258,6 @@ public class ComputerUtil {
final Card source = newSA.getHostCard(); final Card source = newSA.getHostCard();
if (newSA.isSpell() && !source.isCopiedSpell()) { if (newSA.isSpell() && !source.isCopiedSpell()) {
source.setCastSA(newSA);
sa.setLastStateBattlefield(game.getLastStateBattlefield());
sa.setLastStateGraveyard(game.getLastStateGraveyard());
newSA.setHostCard(game.getAction().moveToStack(source, sa)); newSA.setHostCard(game.getAction().moveToStack(source, sa));
if (newSA.getApi() == ApiType.Charm && !newSA.isWrapper()) { if (newSA.getApi() == ApiType.Charm && !newSA.isWrapper()) {
@@ -290,9 +278,6 @@ public class ComputerUtil {
if (ComputerUtilCost.canPayCost(sa, ai)) { if (ComputerUtilCost.canPayCost(sa, ai)) {
final Card source = sa.getHostCard(); final Card source = sa.getHostCard();
if (sa.isSpell() && !source.isCopiedSpell()) { if (sa.isSpell() && !source.isCopiedSpell()) {
source.setCastSA(sa);
sa.setLastStateBattlefield(game.getLastStateBattlefield());
sa.setLastStateGraveyard(game.getLastStateGraveyard());
sa.setHostCard(game.getAction().moveToStack(source, sa)); sa.setHostCard(game.getAction().moveToStack(source, sa));
} }

View File

@@ -981,6 +981,17 @@ public abstract class GameState {
spellDef = spellDef.substring(0, spellDef.indexOf("->")).trim(); spellDef = spellDef.substring(0, spellDef.indexOf("->")).trim();
} }
Card c = null;
if (StringUtils.isNumeric(spellDef)) {
// Precast from a specific host
c = idToCard.get(Integer.parseInt(spellDef));
if (c == null) {
System.err.println("ERROR: Could not find a card with ID " + spellDef + " to precast!");
return;
}
} else {
// Precast from a card by name
PaperCard pc = StaticData.instance().getCommonCards().getCard(spellDef); PaperCard pc = StaticData.instance().getCommonCards().getCard(spellDef);
if (pc == null) { if (pc == null) {
@@ -988,7 +999,9 @@ public abstract class GameState {
return; return;
} }
Card c = Card.fromPaperCard(pc, activator); c = Card.fromPaperCard(pc, activator);
}
SpellAbility sa = null; SpellAbility sa = null;
if (!scriptID.isEmpty()) { if (!scriptID.isEmpty()) {

View File

@@ -113,7 +113,11 @@ public final class ImageKeys {
} }
//try fullborder... //try fullborder...
if (filename.contains(".full")) { if (filename.contains(".full")) {
file = findFile(dir, TextUtil.fastReplace(filename, ".full", ".fullborder")); String fullborderFile = TextUtil.fastReplace(filename, ".full", ".fullborder");
file = findFile(dir, fullborderFile);
if (file != null) { return file; }
// if there's an art variant try without it
file = findFile(dir, TextUtil.fastReplace(fullborderFile, "1.fullborder", ".fullborder"));
if (file != null) { return file; } if (file != null) { return file; }
} }
//if an image, like phenomenon or planes is missing .full in their filenames but you have an existing images that have .full/.fullborder //if an image, like phenomenon or planes is missing .full in their filenames but you have an existing images that have .full/.fullborder

View File

@@ -312,17 +312,21 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
return tryGetCard(request); return tryGetCard(request);
} }
public int getCardCollectorNumber(String cardName, String reqEdition) { public String getCardCollectorNumber(String cardName, String reqEdition, int artIndex) {
cardName = getName(cardName); cardName = getName(cardName);
CardEdition edition = editions.get(reqEdition); CardEdition edition = editions.get(reqEdition);
if (edition == null) if (edition == null)
return -1; return null;
int numMatches = 0;
for (CardInSet card : edition.getCards()) { for (CardInSet card : edition.getCards()) {
if (card.name.equalsIgnoreCase(cardName)) { if (card.name.equalsIgnoreCase(cardName)) {
numMatches += 1;
if (numMatches == artIndex) {
return card.collectorNumber; return card.collectorNumber;
} }
} }
return -1; }
return null;
} }
private PaperCard tryGetCard(CardRequest request) { private PaperCard tryGetCard(CardRequest request) {

View File

@@ -38,6 +38,8 @@ import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.*; import java.util.*;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** /**
@@ -75,10 +77,10 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
public static class CardInSet { public static class CardInSet {
public final CardRarity rarity; public final CardRarity rarity;
public final int collectorNumber; public final String collectorNumber;
public final String name; public final String name;
public CardInSet(final String name, final int collectorNumber, final CardRarity rarity) { public CardInSet(final String name, final String collectorNumber, final CardRarity rarity) {
this.name = name; this.name = name;
this.collectorNumber = collectorNumber; this.collectorNumber = collectorNumber;
this.rarity = rarity; this.rarity = rarity;
@@ -86,7 +88,7 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
if (collectorNumber != -1) { if (collectorNumber != null) {
sb.append(collectorNumber); sb.append(collectorNumber);
sb.append(' '); sb.append(' ');
} }
@@ -190,6 +192,7 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
public boolean getSmallSetOverride() { return smallSetOverride; } public boolean getSmallSetOverride() { return smallSetOverride; }
public String getBoosterMustContain() { return boosterMustContain; } public String getBoosterMustContain() { return boosterMustContain; }
public CardInSet[] getCards() { return cards; } public CardInSet[] getCards() { return cards; }
public boolean isModern() { return getDate().after(parseDate("2003-07-27")); } //8ED and above are modern except some promo cards and others
public Map<String, Integer> getTokens() { return tokenNormalized; } public Map<String, Integer> getTokens() { return tokenNormalized; }
@@ -266,26 +269,35 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
Map<String, Integer> tokenNormalized = new HashMap<>(); Map<String, Integer> tokenNormalized = new HashMap<>();
List<CardEdition.CardInSet> processedCards = new ArrayList<>(); List<CardEdition.CardInSet> processedCards = new ArrayList<>();
if (contents.containsKey("cards")) { if (contents.containsKey("cards")) {
final Pattern pattern = Pattern.compile(
/*
The following pattern will match the WAR Japanese art entries,
it should also match the Un-set and older alternate art cards
like Merseine from FEM (should the editions files ever be updated)
*/
//"(^(?<cnum>[0-9]+.?) )?((?<rarity>[SCURML]) )?(?<name>.*)$"
/* Ideally we'd use the named group above, but Android 6 and
earlier don't appear to support named groups.
So, untill support for those devices is officially dropped,
we'll have to suffice with numbered groups.
We are looking for:
* cnum - grouping #2
* rarity - grouping #4
* name - grouping #5
*/
"(^([0-9]+.?) )?(([SCURML]) )?(.*)$"
);
for(String line : contents.get("cards")) { for(String line : contents.get("cards")) {
if (StringUtils.isBlank(line)) Matcher matcher = pattern.matcher(line);
continue; if (matcher.matches()) {
String collectorNumber = matcher.group(2);
// Optional collector number at the start. CardRarity r = CardRarity.smartValueOf(matcher.group(4));
String[] split = line.split(" ", 2); String cardName = matcher.group(5);
int collectorNumber = -1;
if (split.length >= 2 && StringUtils.isNumeric(split[0])) {
collectorNumber = Integer.parseInt(split[0]);
line = split[1];
}
// You may omit rarity for early development
CardRarity r = CardRarity.smartValueOf(line.substring(0, 1));
boolean hadRarity = r != CardRarity.Unknown && line.charAt(1) == ' ';
String cardName = hadRarity ? line.substring(2) : line;
CardInSet cis = new CardInSet(cardName, collectorNumber, r); CardInSet cis = new CardInSet(cardName, collectorNumber, r);
processedCards.add(cis); processedCards.add(cis);
} }
} }
}
if (contents.containsKey("tokens")) { if (contents.containsKey("tokens")) {
for(String line : contents.get("tokens")) { for(String line : contents.get("tokens")) {

View File

@@ -222,7 +222,12 @@ public final class CardRules implements ICardCharacteristics {
public boolean canBeBrawlCommander() { public boolean canBeBrawlCommander() {
CardType type = mainPart.getType(); CardType type = mainPart.getType();
return (type.isLegendary() && type.isCreature()) || type.isPlaneswalker(); return type.isLegendary() && (type.isCreature() || type.isPlaneswalker());
}
public boolean canBeTinyLeadersCommander() {
CardType type = mainPart.getType();
return type.isLegendary() && (type.isCreature() || type.isPlaneswalker());
} }
public String getMeldWith() { public String getMeldWith() {

View File

@@ -594,8 +594,10 @@ public final class CardRulesPredicates {
public static final Predicate<CardRules> IS_VANGUARD = CardRulesPredicates.coreType(true, CardType.CoreType.Vanguard); public static final Predicate<CardRules> IS_VANGUARD = CardRulesPredicates.coreType(true, CardType.CoreType.Vanguard);
public static final Predicate<CardRules> IS_CONSPIRACY = CardRulesPredicates.coreType(true, CardType.CoreType.Conspiracy); public static final Predicate<CardRules> IS_CONSPIRACY = CardRulesPredicates.coreType(true, CardType.CoreType.Conspiracy);
public static final Predicate<CardRules> IS_NON_LAND = CardRulesPredicates.coreType(false, CardType.CoreType.Land); public static final Predicate<CardRules> IS_NON_LAND = CardRulesPredicates.coreType(false, CardType.CoreType.Land);
public static final Predicate<CardRules> CAN_BE_BRAWL_COMMANDER = Predicates.or(Presets.IS_PLANESWALKER, public static final Predicate<CardRules> CAN_BE_BRAWL_COMMANDER = Predicates.and(Presets.IS_LEGENDARY,
Predicates.and(Presets.IS_CREATURE, Presets.IS_LEGENDARY)); Predicates.or(Presets.IS_CREATURE, Presets.IS_PLANESWALKER));
public static final Predicate<CardRules> CAN_BE_TINY_LEADERS_COMMANDER = Predicates.and(Presets.IS_LEGENDARY,
Predicates.or(Presets.IS_CREATURE, Presets.IS_PLANESWALKER));
/** The Constant IS_NON_CREATURE_SPELL. **/ /** The Constant IS_NON_CREATURE_SPELL. **/
public static final Predicate<CardRules> IS_NON_CREATURE_SPELL = com.google.common.base.Predicates public static final Predicate<CardRules> IS_NON_CREATURE_SPELL = com.google.common.base.Predicates

View File

@@ -463,6 +463,9 @@ public enum DeckFormat {
if (this.equals(DeckFormat.Brawl)) { if (this.equals(DeckFormat.Brawl)) {
return rules.canBeBrawlCommander(); return rules.canBeBrawlCommander();
} }
if (this.equals(DeckFormat.TinyLeaders)) {
return rules.canBeTinyLeadersCommander();
}
return rules.canBeCommander(); return rules.canBeCommander();
} }

View File

@@ -5,6 +5,8 @@ import forge.item.PaperCard;
import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import com.google.common.collect.ImmutableSortedMap;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@@ -17,6 +19,22 @@ import java.util.Map.Entry;
*/ */
public class TextUtil { public class TextUtil {
static ImmutableSortedMap<Integer,String> romanMap = ImmutableSortedMap.<Integer,String>naturalOrder()
.put(1000, "M").put(900, "CM")
.put(500, "D").put(400, "CD")
.put(100, "C").put(90, "XC")
.put(50, "L").put(40, "XL")
.put(10, "X").put(9, "IX")
.put(5, "V").put(4, "IV").put(1, "I").build();
public final static String toRoman(int number) {
if (number <= 0) {
return "";
}
int l = romanMap.floorKey(number);
return romanMap.get(l) + toRoman(number-l);
}
/** /**
* Safely converts an object to a String. * Safely converts an object to a String.
* *

View File

@@ -547,6 +547,13 @@ public class GameAction {
c.setCastSA(null); c.setCastSA(null);
} else if (zoneTo.is(ZoneType.Stack)) { } else if (zoneTo.is(ZoneType.Stack)) {
c.setCastFrom(zoneFrom.getZoneType()); c.setCastFrom(zoneFrom.getZoneType());
if (cause != null && cause.isSpell() && c.equals(cause.getHostCard()) && !c.isCopiedSpell()) {
cause.setLastStateBattlefield(game.getLastStateBattlefield());
cause.setLastStateGraveyard(game.getLastStateGraveyard());
c.setCastSA(cause);
} else {
c.setCastSA(null);
}
} else if (!(zoneTo.is(ZoneType.Battlefield) && zoneFrom.is(ZoneType.Stack))) { } else if (!(zoneTo.is(ZoneType.Battlefield) && zoneFrom.is(ZoneType.Stack))) {
c.setCastFrom(null); c.setCastFrom(null);
c.setCastSA(null); c.setCastSA(null);

View File

@@ -22,8 +22,10 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import forge.card.MagicColor;
import forge.card.mana.ManaCost; import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostParser; import forge.card.mana.ManaCostParser;
import forge.game.ability.AbilityFactory;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.card.*; import forge.game.card.*;
@@ -32,9 +34,15 @@ import forge.game.cost.Cost;
import forge.game.keyword.KeywordInterface; import forge.game.keyword.KeywordInterface;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.player.PlayerController; import forge.game.player.PlayerController;
import forge.game.replacement.ReplacementEffect;
import forge.game.replacement.ReplacementHandler;
import forge.game.replacement.ReplacementLayer;
import forge.game.spellability.*; import forge.game.spellability.*;
import forge.game.trigger.Trigger; import forge.game.trigger.Trigger;
import forge.game.trigger.TriggerHandler;
import forge.game.trigger.TriggerType;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.util.Lang;
import forge.util.TextUtil; import forge.util.TextUtil;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@@ -363,10 +371,11 @@ public final class GameActionUtil {
} }
SpellAbility result = null; SpellAbility result = null;
final Card host = sa.getHostCard(); final Card host = sa.getHostCard();
final Game game = host.getGame();
final Player activator = sa.getActivatingPlayer(); final Player activator = sa.getActivatingPlayer();
final PlayerController pc = activator.getController(); final PlayerController pc = activator.getController();
host.getGame().getAction().checkStaticAbilities(false); game.getAction().checkStaticAbilities(false);
boolean reset = false; boolean reset = false;
@@ -429,7 +438,60 @@ public final class GameActionUtil {
int v = pc.chooseNumberForKeywordCost(sa, cost, ki, str, Integer.MAX_VALUE); int v = pc.chooseNumberForKeywordCost(sa, cost, ki, str, Integer.MAX_VALUE);
if (v > 0) { if (v > 0) {
host.addReplacementEffect(CardFactoryUtil.makeEtbCounter("etbCounter:P1P1:" + v, host, false));
final Card eff = new Card(game.nextCardId(), game);
eff.setTimestamp(game.getNextTimestamp());
eff.setName(c.getName() + "'s Effect");
eff.addType("Effect");
eff.setToken(true); // Set token to true, so when leaving play it gets nuked
eff.setOwner(activator);
eff.setImageKey(c.getImageKey());
eff.setColor(MagicColor.COLORLESS);
eff.setImmutable(true);
// try to get the SpellAbility from the mana ability
//eff.setEffectSource((SpellAbility)null);
eff.addRemembered(host);
String abStr = "DB$ PutCounter | Defined$ ReplacedCard | CounterType$ P1P1 | ETB$ True | CounterNum$ " + v;
SpellAbility saAb = AbilityFactory.getAbility(abStr, c);
CardFactoryUtil.setupETBReplacementAbility(saAb);
String desc = "It enters the battlefield with ";
desc += Lang.nounWithNumeral(v, CounterType.P1P1.getName() + " counter");
desc += " on it.";
String repeffstr = "Event$ Moved | ValidCard$ Card.IsRemembered | Destination$ Battlefield | Description$ " + desc;
ReplacementEffect re = ReplacementHandler.parseReplacement(repeffstr, eff, true);
re.setLayer(ReplacementLayer.Other);
re.setOverridingAbility(saAb);
eff.addReplacementEffect(re);
// Forgot Trigger
String trig = "Mode$ ChangesZone | ValidCard$ Card.IsRemembered | Origin$ Stack | Destination$ Any | TriggerZones$ Command | Static$ True";
String forgetEffect = "DB$ Pump | ForgetObjects$ TriggeredCard";
String exileEffect = "DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile"
+ " | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ EQ0";
SpellAbility saForget = AbilityFactory.getAbility(forgetEffect, eff);
AbilitySub saExile = (AbilitySub) AbilityFactory.getAbility(exileEffect, eff);
saForget.setSubAbility(saExile);
final Trigger parsedTrigger = TriggerHandler.parseTrigger(trig, eff, true);
parsedTrigger.setOverridingAbility(saForget);
eff.addTrigger(parsedTrigger);
eff.updateStateForView();
// TODO: Add targeting to the effect so it knows who it's dealing with
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
game.getAction().moveTo(ZoneType.Command, eff, null);
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
if (result == null) { if (result == null) {
result = sa.copy(); result = sa.copy();
} }

View File

@@ -6353,6 +6353,10 @@ public class Card extends GameEntity implements Comparable<Card> {
removeSVar("PayX"); // Temporary AI X announcement variable removeSVar("PayX"); // Temporary AI X announcement variable
removeSVar("IsCastFromPlayEffect"); // Temporary SVar indicating that the spell is cast indirectly via AF Play removeSVar("IsCastFromPlayEffect"); // Temporary SVar indicating that the spell is cast indirectly via AF Play
setSunburstValue(0); // Sunburst setSunburstValue(0); // Sunburst
setXManaCostPaid(0);
setXManaCostPaidByColor(null);
setKickerMagnitude(0);
setPseudoMultiKickerMagnitude(0);
} }
public final int getFinalChapterNr() { public final int getFinalChapterNr() {

View File

@@ -20,7 +20,6 @@ package forge.game.card;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.google.common.base.Strings;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
@@ -3010,24 +3009,43 @@ public class CardFactoryUtil {
inst.addTrigger(parsedTrigger); inst.addTrigger(parsedTrigger);
} else if (keyword.startsWith("Saga")) { } else if (keyword.startsWith("Saga")) {
// Saga there doesn't need Max value anymore?
final String[] k = keyword.split(":"); final String[] k = keyword.split(":");
final String[] abs = k[2].split(","); final List<String> abs = Arrays.asList(k[2].split(","));
if (abs.size() != Integer.valueOf(k[1])) {
throw new RuntimeException("Saga max differ from Ability amount");
}
int i = 1; int idx = 0;
for (String ab : abs) { int skipId = 0;
for(String ab : abs) {
idx += 1;
if (idx <= skipId) {
continue;
}
skipId = idx + abs.subList(idx - 1, abs.size()).lastIndexOf(ab);
StringBuilder desc = new StringBuilder();
for (int i = idx; i <= skipId; i++) {
if (i != idx) {
desc.append(", ");
}
desc.append(TextUtil.toRoman(i));
}
for (int i = idx; i <= skipId; i++) {
SpellAbility sa = AbilityFactory.getAbility(card, ab); SpellAbility sa = AbilityFactory.getAbility(card, ab);
sa.setChapter(i); sa.setChapter(i);
// TODO better logic for Roman numbers StringBuilder trigStr = new StringBuilder("Mode$ CounterAdded | ValidCard$ Card.Self | TriggerZones$ Battlefield");
// In the Description try to merge Chapter trigger with the Same Effect trigStr.append("| CounterType$ LORE | CounterAmount$ EQ").append(i);
String trigStr = "Mode$ CounterAdded | ValidCard$ Card.Self | TriggerZones$ Battlefield" if (i != idx) {
+ "| CounterType$ LORE | CounterAmount$ EQ" + i trigStr.append(" | Secondary$ True");
+ "| TriggerDescription$ " + Strings.repeat("I", i) + " - " + sa.getDescription(); }
final Trigger t = TriggerHandler.parseTrigger(trigStr, card, intrinsic); trigStr.append("| TriggerDescription$ ").append(desc).append("").append(sa.getDescription());
final Trigger t = TriggerHandler.parseTrigger(trigStr.toString(), card, intrinsic);
t.setOverridingAbility(sa); t.setOverridingAbility(sa);
inst.addTrigger(t); inst.addTrigger(t);
++i; }
} }
} else if (keyword.equals("Soulbond")) { } else if (keyword.equals("Soulbond")) {
// Setup ETB trigger for card with Soulbond keyword // Setup ETB trigger for card with Soulbond keyword

View File

@@ -882,6 +882,10 @@ public class Combat {
return true; // is blocking something at the moment return true; // is blocking something at the moment
} }
if (!blocker.isLKI()) {
return false;
}
CombatLki lki = lkiCache.get(blocker); CombatLki lki = lkiCache.get(blocker);
return null != lki && !lki.isAttacker; // was blocking something anyway return null != lki && !lki.isAttacker; // was blocking something anyway
} }
@@ -893,6 +897,10 @@ public class Combat {
return true; // is blocking the attacker's band at the moment return true; // is blocking the attacker's band at the moment
} }
if (!blocker.isLKI()) {
return false;
}
CombatLki lki = lkiCache.get(blocker); CombatLki lki = lkiCache.get(blocker);
return null != lki && !lki.isAttacker && lki.relatedBands.contains(ab); // was blocking that very band return null != lki && !lki.isAttacker && lki.relatedBands.contains(ab); // was blocking that very band
} }

View File

@@ -254,7 +254,7 @@ public class ManaPool extends ManaConversionMatrix implements Iterable<Mana> {
} }
} }
if (mana.addsCounters(sa)) { if (mana.addsCounters(sa)) {
mana.getManaAbility().createETBCounters(host); mana.getManaAbility().createETBCounters(host, this.owner);
} }
if (mana.triggersWhenSpent()) { if (mana.triggersWhenSpent()) {
mana.getManaAbility().addTriggersWhenSpent(sa, host); mana.getManaAbility().addTriggersWhenSpent(sa, host);

View File

@@ -19,9 +19,11 @@ package forge.game.spellability;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import forge.card.ColorSet; import forge.card.ColorSet;
import forge.card.MagicColor; import forge.card.MagicColor;
import forge.card.mana.ManaAtom; import forge.card.mana.ManaAtom;
import forge.game.Game;
import forge.game.ability.AbilityFactory; import forge.game.ability.AbilityFactory;
import forge.game.ability.AbilityKey; import forge.game.ability.AbilityKey;
import forge.game.card.Card; import forge.game.card.Card;
@@ -34,6 +36,8 @@ import forge.game.replacement.*;
import forge.game.trigger.Trigger; import forge.game.trigger.Trigger;
import forge.game.trigger.TriggerHandler; import forge.game.trigger.TriggerHandler;
import forge.game.trigger.TriggerType; import forge.game.trigger.TriggerType;
import forge.game.zone.ZoneType;
import forge.util.Lang;
import forge.util.TextUtil; import forge.util.TextUtil;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@@ -227,10 +231,26 @@ public class AbilityManaPart implements java.io.Serializable {
/** /**
* createETBCounters * createETBCounters
*/ */
public void createETBCounters(Card c) { public void createETBCounters(Card c, Player controller) {
String[] parse = this.addsCounters.split("_"); String[] parse = this.addsCounters.split("_");
// Convert random SVars if there are other cards with this effect // Convert random SVars if there are other cards with this effect
if (c.isValid(parse[0], c.getController(), c, null)) { 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] String abStr = "DB$ PutCounter | Defined$ ReplacedCard | CounterType$ " + parse[1]
+ " | ETB$ True | CounterNum$ " + parse[2]; + " | ETB$ True | CounterNum$ " + parse[2];
@@ -240,15 +260,37 @@ public class AbilityManaPart implements java.io.Serializable {
} }
CardFactoryUtil.setupETBReplacementAbility(sa); CardFactoryUtil.setupETBReplacementAbility(sa);
String repeffstr = "Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield " String desc = "It enters the battlefield with ";
+ " | Secondary$ True | Description$ CARDNAME" desc += Lang.nounWithNumeral(parse[2], CounterType.valueOf(parse[1]).getName() + " counter");
+ " enters the battlefield with " + CounterType.valueOf(parse[1]).getName() + " counters."; 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.setLayer(ReplacementLayer.Other);
re.setOverridingAbility(sa); 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);
} }
} }

View File

@@ -1299,6 +1299,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
String announce = getParam("Announce"); String announce = getParam("Announce");
if (StringUtils.isBlank(announce)) { if (StringUtils.isBlank(announce)) {
mapParams.put("Announce", variable); mapParams.put("Announce", variable);
originalMapParams.put("Announce", variable);
return; return;
} }
String[] announcedOnes = TextUtil.split(announce, ','); String[] announcedOnes = TextUtil.split(announce, ',');
@@ -1308,6 +1309,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
} }
} }
mapParams.put("Announce", announce + ";" + variable); mapParams.put("Announce", announce + ";" + variable);
originalMapParams.put("Announce", announce + ";" + variable);
} }
public boolean isXCost() { public boolean isXCost() {

View File

@@ -100,6 +100,7 @@ public class TrackableTypes {
if (newCollection != null) { if (newCollection != null) {
//swap in objects in old collection for objects in new collection //swap in objects in old collection for objects in new collection
for (int i = 0; i < newCollection.size(); i++) { for (int i = 0; i < newCollection.size(); i++) {
try {
T newObj = newCollection.get(i); T newObj = newCollection.get(i);
if (newObj != null) { if (newObj != null) {
T existingObj = from.getTracker().getObj(itemType, newObj.getId()); T existingObj = from.getTracker().getObj(itemType, newObj.getId());
@@ -112,6 +113,9 @@ public class TrackableTypes {
from.getTracker().putObj(itemType, newObj.getId(), newObj); from.getTracker().putObj(itemType, newObj.getId(), newObj);
} }
} }
} catch (IndexOutOfBoundsException e) {
System.err.println("got an IndexOutOfBoundsException, trying to continue ...");
}
} }
} }
to.set(prop, newCollection); to.set(prop, newCollection);

View File

@@ -6,7 +6,7 @@
<uses-sdk <uses-sdk
android:minSdkVersion="19" android:minSdkVersion="19"
android:targetSdkVersion="21" /> android:targetSdkVersion="26" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <!-- This one needs Android Runtime Permission for Android 6+ --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <!-- This one needs Android Runtime Permission for Android 6+ -->
<uses-permission android:name="android.permission.VIBRATE"/> <uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>

View File

@@ -142,7 +142,7 @@
<debug>true</debug> <debug>true</debug>
</sign> </sign>
<sdk> <sdk>
<platform>25</platform> <platform>26</platform>
</sdk> </sdk>
<dexForceJumbo>true</dexForceJumbo> <dexForceJumbo>true</dexForceJumbo>
<androidManifestFile>${project.basedir}/AndroidManifest.xml</androidManifestFile> <androidManifestFile>${project.basedir}/AndroidManifest.xml</androidManifestFile>
@@ -183,7 +183,7 @@
<debug>false</debug> <debug>false</debug>
</sign> </sign>
<sdk> <sdk>
<platform>25</platform> <platform>26</platform>
</sdk> </sdk>
<zipalign> <zipalign>
<verbose>false</verbose> <verbose>false</verbose>

View File

@@ -9,4 +9,4 @@
# Project target. # Project target.
project.type=0 project.type=0
target=android-20 target=android-26

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<color name="ic_launcher_background">#f0f0f0</color> <color name="ic_launcher_background">#ffffff</color>
</resources> </resources>

View File

@@ -103,7 +103,7 @@ public final class CEditorConstructed extends CDeckEditor<Deck> {
case TinyLeaders: case TinyLeaders:
allSections.add(DeckSection.Commander); 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); 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); normalPool = ItemPool.createFrom(FModel.getMagicDb().getCommonCards().getAllCards(), PaperCard.class);

View File

@@ -23,6 +23,13 @@ public enum CSubmenuDownloaders implements ICDoc {
VSubmenuDownloaders.SINGLETON_INSTANCE.showLicensing(); VSubmenuDownloaders.SINGLETON_INSTANCE.showLicensing();
} }
}; };
private final UiCommand cmdCheckForUpdates = new UiCommand() {
@Override
public void run() {
new AutoUpdater(false).attemptToUpdate();
}
};
private final UiCommand cmdPicDownload = new UiCommand() { private final UiCommand cmdPicDownload = new UiCommand() {
@Override public void run() { @Override public void run() {
new GuiDownloader(new GuiDownloadPicturesLQ()).show(); new GuiDownloader(new GuiDownloadPicturesLQ()).show();
@@ -84,6 +91,7 @@ public enum CSubmenuDownloaders implements ICDoc {
@Override @Override
public void initialize() { public void initialize() {
final VSubmenuDownloaders view = VSubmenuDownloaders.SINGLETON_INSTANCE; final VSubmenuDownloaders view = VSubmenuDownloaders.SINGLETON_INSTANCE;
view.setCheckForUpdatesCommand(cmdCheckForUpdates);
view.setDownloadPicsCommand(cmdPicDownload); view.setDownloadPicsCommand(cmdPicDownload);
view.setDownloadPicsHQCommand(cmdPicDownloadHQ); view.setDownloadPicsHQCommand(cmdPicDownloadHQ);
view.setDownloadSetPicsCommand(cmdSetDownload); view.setDownloadSetPicsCommand(cmdSetDownload);

View File

@@ -3,6 +3,7 @@ package forge.screens.home.settings;
import forge.*; import forge.*;
import forge.ai.AiProfileUtil; import forge.ai.AiProfileUtil;
import forge.control.FControl.CloseAction; import forge.control.FControl.CloseAction;
import forge.download.AutoUpdater;
import forge.game.GameLogEntryType; import forge.game.GameLogEntryType;
import forge.gui.framework.FScreen; import forge.gui.framework.FScreen;
import forge.gui.framework.ICDoc; import forge.gui.framework.ICDoc;
@@ -225,6 +226,7 @@ public enum CSubmenuPreferences implements ICDoc {
initializeGameLogVerbosityComboBox(); initializeGameLogVerbosityComboBox();
initializeCloseActionComboBox(); initializeCloseActionComboBox();
initializeDefaultFontSizeComboBox(); initializeDefaultFontSizeComboBox();
initializeAutoUpdaterComboBox();
initializeMulliganRuleComboBox(); initializeMulliganRuleComboBox();
initializeAiProfilesComboBox(); initializeAiProfilesComboBox();
initializeStackAdditionsComboBox(); initializeStackAdditionsComboBox();
@@ -378,6 +380,16 @@ public enum CSubmenuPreferences implements ICDoc {
panel.setComboBox(comboBox, selectedItem); 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<String> panel = this.view.getCbpAutoUpdater();
final FComboBox<String> comboBox = createComboBox(updatePaths, updatePreference);
final String selectedItem = this.prefs.getPref(updatePreference);
panel.setComboBox(comboBox, selectedItem);
}
private void initializeMulliganRuleComboBox() { private void initializeMulliganRuleComboBox() {
final String [] choices = MulliganDefs.getMulliganRuleNames(); final String [] choices = MulliganDefs.getMulliganRuleNames();
final FPref userSetting = FPref.MULLIGAN_RULE; final FPref userSetting = FPref.MULLIGAN_RULE;

View File

@@ -55,6 +55,7 @@ public enum VSubmenuDownloaders implements IVSubmenu<CSubmenuDownloaders> {
private final JPanel pnlContent = new JPanel(new MigLayout("insets 0, gap 0, wrap, ay center")); 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 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 btnDownloadSetPics = _makeButton(localizer.getMessage("btnDownloadSetPics"));
private final FLabel btnDownloadPics = _makeButton(localizer.getMessage("btnDownloadPics")); private final FLabel btnDownloadPics = _makeButton(localizer.getMessage("btnDownloadPics"));
private final FLabel btnDownloadPicsHQ = _makeButton(localizer.getMessage("btnDownloadPicsHQ")); private final FLabel btnDownloadPicsHQ = _makeButton(localizer.getMessage("btnDownloadPicsHQ"));
@@ -80,6 +81,9 @@ public enum VSubmenuDownloaders implements IVSubmenu<CSubmenuDownloaders> {
if (javaRecentEnough()) { if (javaRecentEnough()) {
pnlContent.add(btnCheckForUpdates, constraintsBTN);
pnlContent.add(_makeLabel(localizer.getMessage("lblCheckForUpdates")), constraintsLBL);
pnlContent.add(btnDownloadPics, constraintsBTN); pnlContent.add(btnDownloadPics, constraintsBTN);
pnlContent.add(_makeLabel(localizer.getMessage("lblDownloadPics")), constraintsLBL); pnlContent.add(_makeLabel(localizer.getMessage("lblDownloadPics")), constraintsLBL);
@@ -162,6 +166,7 @@ public enum VSubmenuDownloaders implements IVSubmenu<CSubmenuDownloaders> {
return EMenuGroup.SETTINGS; return EMenuGroup.SETTINGS;
} }
public void setCheckForUpdatesCommand(UiCommand command) { btnCheckForUpdates.setCommand(command); }
public void setDownloadPicsCommand(UiCommand command) { btnDownloadPics.setCommand(command); } public void setDownloadPicsCommand(UiCommand command) { btnDownloadPics.setCommand(command); }
public void setDownloadPicsHQCommand(UiCommand command) { btnDownloadPicsHQ.setCommand(command); } public void setDownloadPicsHQCommand(UiCommand command) { btnDownloadPicsHQ.setCommand(command); }
public void setDownloadSetPicsCommand(UiCommand command) { btnDownloadSetPics.setCommand(command); } public void setDownloadSetPicsCommand(UiCommand command) { btnDownloadSetPics.setCommand(command); }

View File

@@ -25,8 +25,8 @@ import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent; import java.awt.event.FocusEvent;
import java.awt.event.KeyAdapter; import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.util.*;
import java.util.List; import java.util.List;
import java.util.*;
/** /**
@@ -123,6 +123,7 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
private final FComboBoxPanel<String> cbpCounterDisplayLocation =new FComboBoxPanel<>(localizer.getMessage("cbpCounterDisplayLocation")+":"); private final FComboBoxPanel<String> cbpCounterDisplayLocation =new FComboBoxPanel<>(localizer.getMessage("cbpCounterDisplayLocation")+":");
private final FComboBoxPanel<String> cbpGraveyardOrdering = new FComboBoxPanel<>(localizer.getMessage("cbpGraveyardOrdering")+":"); private final FComboBoxPanel<String> cbpGraveyardOrdering = new FComboBoxPanel<>(localizer.getMessage("cbpGraveyardOrdering")+":");
private final FComboBoxPanel<String> cbpDefaultLanguage = new FComboBoxPanel<>(localizer.getMessage("cbpSelectLanguage")+":"); private final FComboBoxPanel<String> cbpDefaultLanguage = new FComboBoxPanel<>(localizer.getMessage("cbpSelectLanguage")+":");
private final FComboBoxPanel<String> cbpAutoUpdater = new FComboBoxPanel<>(localizer.getMessage("cbpAutoUpdater")+":");
/** /**
* Constructor. * Constructor.
@@ -157,6 +158,10 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
pnlPrefs.add(new SectionLabel(localizer.getMessage("GeneralConfiguration")), sectionConstraints); pnlPrefs.add(new SectionLabel(localizer.getMessage("GeneralConfiguration")), sectionConstraints);
// language // language
pnlPrefs.add(cbpAutoUpdater, comboBoxConstraints);
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlAutoUpdater")), descriptionConstraints);
pnlPrefs.add(cbpDefaultLanguage, comboBoxConstraints); pnlPrefs.add(cbpDefaultLanguage, comboBoxConstraints);
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlSelectLanguage")), descriptionConstraints); pnlPrefs.add(new NoteLabel(localizer.getMessage("nlSelectLanguage")), descriptionConstraints);
@@ -531,6 +536,10 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
} }
} }
public final FComboBoxPanel<String> getCbpAutoUpdater() {
return cbpAutoUpdater;
}
/** @return {@link javax.swing.JCheckBox} */ /** @return {@link javax.swing.JCheckBox} */
public final JCheckBox getCbCompactMainMenu() { public final JCheckBox getCbCompactMainMenu() {
return cbCompactMainMenu; return cbCompactMainMenu;

View File

@@ -81,7 +81,7 @@ public final class Main {
break; break;
default: default:
System.out.println("Unknown mode.\nKnown mode is 'sim' "); System.out.println("Unknown mode.\nKnown mode is 'sim', 'parse' ");
break; break;
} }

View File

@@ -209,7 +209,7 @@ public class FSkin {
textures.put(f6.path(), textures.get(f3.path())); textures.put(f6.path(), textures.get(f3.path()));
} }
if (f7.exists()){ if (f7.exists()){
Texture t = new Texture(f7, false); 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); textures.put(f7.path(), t);
} }

View File

@@ -193,6 +193,15 @@ public enum FSkinImage implements FImage {
QUEST_BIG_SWORD (FSkinProp.ICO_QUEST_BIG_SWORD, SourceFile.ICONS), QUEST_BIG_SWORD (FSkinProp.ICO_QUEST_BIG_SWORD, SourceFile.ICONS),
QUEST_BIG_BAG (FSkinProp.ICO_QUEST_BIG_BAG, 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 //Interface icons
QUESTION (FSkinProp.ICO_QUESTION, SourceFile.ICONS), QUESTION (FSkinProp.ICO_QUESTION, SourceFile.ICONS),
INFORMATION (FSkinProp.ICO_INFORMATION, SourceFile.ICONS), INFORMATION (FSkinProp.ICO_INFORMATION, SourceFile.ICONS),

View File

@@ -35,6 +35,9 @@ import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static forge.card.CardRenderer.CROP_MULTIPLIER;
import static forge.card.CardRenderer.isModernFrame;
public class CardImageRenderer { public class CardImageRenderer {
private static final float BASE_IMAGE_WIDTH = 360; private static final float BASE_IMAGE_WIDTH = 360;
private static final float BASE_IMAGE_HEIGHT = 504; private static final float BASE_IMAGE_HEIGHT = 504;
@@ -357,13 +360,19 @@ public class CardImageRenderer {
float new_yRotate = (dispH - new_w) /2; float new_yRotate = (dispH - new_w) /2;
boolean rotateSplit = FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_ROTATE_SPLIT_CARDS); boolean rotateSplit = FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_ROTATE_SPLIT_CARDS);
boolean rotatePlane = FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_ROTATE_PLANE_OR_PHENOMENON); 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 (rotatePlane && (card.getCurrentState().isPhenomenon() || card.getCurrentState().isPlane())) {
if (Forge.enableUIMask){ if (Forge.enableUIMask){
if (ImageCache.isExtendedArt(card)) 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); g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90);
else { 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(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 } else
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90); 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); 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 { 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(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 } 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); 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); g.drawImage(image, x, y, w, h);
else { else {
g.drawImage(ImageCache.getBorderImage(card, canshow), x, y, w, h); 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 { } else {
if (canshow && !ImageKeys.getTokenKey(ImageKeys.MORPH_IMAGE).equals(card.getState(altState).getImageKey())) if (canshow && !ImageKeys.getTokenKey(ImageKeys.MORPH_IMAGE).equals(card.getState(altState).getImageKey()))

View File

@@ -105,6 +105,7 @@ public class CardRenderer {
private static final float NAME_COST_THRESHOLD = Utils.scale(200); private static final float NAME_COST_THRESHOLD = Utils.scale(200);
private static final float BORDER_THICKNESS = Utils.scale(1); private static final float BORDER_THICKNESS = Utils.scale(1);
public static final float PADDING_MULTIPLIER = 0.021f; public static final float PADDING_MULTIPLIER = 0.021f;
public static final float CROP_MULTIPLIER = 0.96f;
private static Map<Integer, BitmapFont> counterFonts = new HashMap<>(); private static Map<Integer, BitmapFont> counterFonts = new HashMap<>();
private static final Color counterBackgroundColor = new Color(0f, 0f, 0f, 0.9f); 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) { public static float getCardListItemHeight(boolean compactMode) {
if (compactMode) { if (compactMode) {
return MANA_SYMBOL_SIZE + 2 * FList.PADDING; 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) { 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(); Texture image = new RendererCachedCardImage(pc, false).getImage();
float radius = (h - w)/8; 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 != null) {
if (image == ImageCache.defaultImage) { if (image == ImageCache.defaultImage) {
CardImageRenderer.drawCardImage(g, CardView.getCardForUi(pc), false, x, y, w, h, pos); 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); g.drawImage(image, x, y, w, h);
else { else {
g.drawImage(ImageCache.getBorderImage(pc), x, y, w, h); 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 } else
g.drawImage(image, x, y, w, h); g.drawImage(image, x, y, w, h);
@@ -437,7 +486,12 @@ public class CardRenderer {
Texture image = new RendererCachedCardImage(card, false).getImage(); Texture image = new RendererCachedCardImage(card, false).getImage();
FImage sleeves = MatchController.getPlayerSleeve(card.getOwner()); FImage sleeves = MatchController.getPlayerSleeve(card.getOwner());
float radius = (h - w)/8; 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 != null) {
if (image == ImageCache.defaultImage) { if (image == ImageCache.defaultImage) {
CardImageRenderer.drawCardImage(g, card, false, x, y, w, h, pos); 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); g.drawRotatedImage(image, x, y, w, h, x + w / 2, y + h / 2, -90);
else { else {
g.drawRotatedImage(FSkin.getBorders().get(0), x, y, w, h, x + w / 2, y + h / 2, -90); 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 } else
g.drawRotatedImage(image, x, y, w, h, x + w / 2, y + h / 2, -90); g.drawRotatedImage(image, x, y, w, h, x + w / 2, y + h / 2, -90);
@@ -461,7 +515,7 @@ public class CardRenderer {
else { else {
boolean t = (card.getCurrentState().getOriginalColors() != card.getCurrentState().getColors()) || card.getCurrentState().hasChangeColors(); 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.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 { } else {
if (canshow) if (canshow)
@@ -1119,8 +1173,14 @@ public class CardRenderer {
public static void drawFoilEffect(Graphics g, CardView card, float x, float y, float w, float h, boolean inZoomer) { 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 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) { 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)) { if (isPreferenceEnabled(FPref.UI_OVERLAY_FOIL_EFFECT) && MatchController.instance.mayView(card)) {
boolean rotateSplit = isPreferenceEnabled(FPref.UI_ROTATE_SPLIT_CARDS) && card.isSplitCard() && inZoomer; boolean rotateSplit = isPreferenceEnabled(FPref.UI_ROTATE_SPLIT_CARDS) && card.isSplitCard() && inZoomer;

View File

@@ -219,7 +219,22 @@ public class CardZoom extends FOverlay {
float w = getWidth(); float w = getWidth();
float h = getHeight(); float h = getHeight();
float messageHeight = FDialog.MSG_HEIGHT; float messageHeight = FDialog.MSG_HEIGHT;
float maxCardHeight = h - 2 * messageHeight; float AspectRatioMultiplier = 2;
switch (Forge.extrawide) {
case "default":
AspectRatioMultiplier = 3; //good for tablets with 16:10 or similar
break;
case "wide":
AspectRatioMultiplier = 2.5f;
break;
case "extrawide":
AspectRatioMultiplier = 2; //good for tall phones with 21:9 or similar
break;
default:
AspectRatioMultiplier = 3;
break;
}
float maxCardHeight = h - AspectRatioMultiplier * messageHeight; //maxheight of currently zoomed card
float cardWidth, cardHeight, y; float cardWidth, cardHeight, y;

View File

@@ -856,6 +856,9 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
case Brawl: case Brawl:
isLegalCommander = card.getRules().canBeBrawlCommander(); isLegalCommander = card.getRules().canBeBrawlCommander();
break; break;
case TinyLeaders:
isLegalCommander = card.getRules().canBeTinyLeadersCommander();
break;
case Oathbreaker: case Oathbreaker:
isLegalCommander = card.getRules().canBeOathbreaker(); isLegalCommander = card.getRules().canBeOathbreaker();
captionSuffix = localizer.getMessage("lblOathbreaker"); captionSuffix = localizer.getMessage("lblOathbreaker");

View File

@@ -20,11 +20,11 @@ import forge.util.Localizer;
public class LoadGameMenu extends FPopupMenu { public class LoadGameMenu extends FPopupMenu {
public enum LoadGameScreen { public enum LoadGameScreen {
BoosterDraft("lblBoosterDraft", FSkinImage.HAND, LoadDraftScreen.class), BoosterDraft("lblBoosterDraft", FSkinImage.MENU_DRAFT, LoadDraftScreen.class),
SealedDeck("lblSealedDeck", FSkinImage.PACK, LoadSealedScreen.class), SealedDeck("lblSealedDeck", FSkinImage.MENU_SEALED, LoadSealedScreen.class),
QuestMode("lblQuestMode", FSkinImage.QUEST_ZEP, LoadQuestScreen.class), QuestMode("lblQuestMode", FSkinImage.QUEST_ZEP, LoadQuestScreen.class),
PlanarConquest("lblPlanarConquest", FSkinImage.MULTIVERSE, LoadConquestScreen.class), PlanarConquest("lblPlanarConquest", FSkinImage.MENU_GALAXY, LoadConquestScreen.class),
Gauntlet("lblGauntlet", FSkinImage.ALPHASTRIKE, LoadGauntletScreen.class); Gauntlet("lblGauntlet", FSkinImage.MENU_GAUNTLET, LoadGauntletScreen.class);
private final FMenuItem item; private final FMenuItem item;
private final Class<? extends FScreen> screenClass; private final Class<? extends FScreen> screenClass;

View File

@@ -24,13 +24,13 @@ public class NewGameMenu extends FPopupMenu {
final static Localizer localizer = Localizer.getInstance(); final static Localizer localizer = Localizer.getInstance();
public enum NewGameScreen { public enum NewGameScreen {
Constructed(localizer.getMessage("lblConstructed"), FSkinImage.DECKLIST, ConstructedScreen.class), Constructed(localizer.getMessage("lblConstructed"), FSkinImage.MENU_CONSTRUCTED, ConstructedScreen.class),
BoosterDraft(localizer.getMessage("lblBoosterDraft"), FSkinImage.HAND, NewDraftScreen.class), BoosterDraft(localizer.getMessage("lblBoosterDraft"), FSkinImage.MENU_DRAFT, NewDraftScreen.class),
SealedDeck(localizer.getMessage("lblSealedDeck"), FSkinImage.PACK, NewSealedScreen.class), SealedDeck(localizer.getMessage("lblSealedDeck"), FSkinImage.MENU_SEALED, NewSealedScreen.class),
QuestMode(localizer.getMessage("lblQuestMode"), FSkinImage.QUEST_ZEP, NewQuestScreen.class), QuestMode(localizer.getMessage("lblQuestMode"), FSkinImage.QUEST_ZEP, NewQuestScreen.class),
PuzzleMode(localizer.getMessage("lblPuzzleMode"), FSkinImage.QUEST_BOOK, PuzzleScreen.class), PuzzleMode(localizer.getMessage("lblPuzzleMode"), FSkinImage.MENU_PUZZLE, PuzzleScreen.class),
PlanarConquest(localizer.getMessage("lblPlanarConquest"), FSkinImage.MULTIVERSE, NewConquestScreen.class), PlanarConquest(localizer.getMessage("lblPlanarConquest"), FSkinImage.MENU_GALAXY, NewConquestScreen.class),
Gauntlet(localizer.getMessage("lblGauntlet"), FSkinImage.ALPHASTRIKE, NewGauntletScreen.class); Gauntlet(localizer.getMessage("lblGauntlet"), FSkinImage.MENU_GAUNTLET, NewGauntletScreen.class);
private final FMenuItem item; private final FMenuItem item;
private final Class<? extends FScreen> screenClass; private final Class<? extends FScreen> screenClass;

View File

@@ -54,9 +54,10 @@ public class PuzzleScreen extends LaunchScreen {
final ArrayList<Puzzle> puzzles = PuzzleIO.loadPuzzles(); final ArrayList<Puzzle> puzzles = PuzzleIO.loadPuzzles();
Collections.sort(puzzles); Collections.sort(puzzles);
GuiChoose.one(Localizer.getInstance().getMessage("lblChooseAPuzzle"), puzzles, new Callback<Puzzle>() { GuiChoose.oneOrNone(Localizer.getInstance().getMessage("lblChooseAPuzzle"), puzzles, new Callback<Puzzle>() {
@Override @Override
public void run(final Puzzle chosen) { public void run(final Puzzle chosen) {
if (chosen != null) {
LoadingOverlay.show(Localizer.getInstance().getMessage("lblLoadingThePuzzle"), new Runnable() { LoadingOverlay.show(Localizer.getInstance().getMessage("lblLoadingThePuzzle"), new Runnable() {
@Override @Override
public void run() { public void run() {
@@ -69,6 +70,13 @@ public class PuzzleScreen extends LaunchScreen {
} }
}); });
hostedMatch.setEndGameHook((new Runnable() {
@Override
public void run() {
chosen.savePuzzleSolve(hostedMatch.getGame().getOutcome().isWinner(GamePlayerUtil.getGuiPlayer()));
}
}));
final List<RegisteredPlayer> players = new ArrayList<>(); final List<RegisteredPlayer> players = new ArrayList<>();
final RegisteredPlayer human = new RegisteredPlayer(new Deck()).setPlayer(GamePlayerUtil.getGuiPlayer()); final RegisteredPlayer human = new RegisteredPlayer(new Deck()).setPlayer(GamePlayerUtil.getGuiPlayer());
human.setStartingHand(0); human.setStartingHand(0);
@@ -85,6 +93,7 @@ public class PuzzleScreen extends LaunchScreen {
} }
}); });
} }
}
}); });
} }

View File

@@ -56,7 +56,7 @@ public class ConquestMenu extends FPopupMenu {
setCurrentScreen(collectionScreen); setCurrentScreen(collectionScreen);
} }
}); });
private static final FMenuItem statsItem = new FMenuItem(Localizer.getInstance().getMessage("lblStatistics"), FSkinImage.HDMULTI, new FEventHandler() { private static final FMenuItem statsItem = new FMenuItem(Localizer.getInstance().getMessage("lblStatistics"), FSkinImage.MENU_STATS, new FEventHandler() {
@Override @Override
public void handleEvent(FEvent e) { public void handleEvent(FEvent e) {
setCurrentScreen(statsScreen); setCurrentScreen(statsScreen);

View File

@@ -244,10 +244,7 @@ public class ConquestRewardDialog extends FScrollPane {
//ensure current card in view //ensure current card in view
if (getScrollHeight() > getHeight() && index < cardCount) { if (getScrollHeight() > getHeight() && index < cardCount) {
CardRevealer currentCard = cardRevealers.get(index); CardRevealer currentCard = cardRevealers.get(index);
if (!Forge.extrawide.equals("default"))
scrollIntoView(currentCard, currentCard.getHeight() / (columnCount * PADDING) / 2); scrollIntoView(currentCard, currentCard.getHeight() / (columnCount * PADDING) / 2);
else
scrollIntoView(currentCard, currentCard.getHeight() / 2 + PADDING); //show half of the card below
} }
} }

View File

@@ -79,7 +79,7 @@ public class QuestMenu extends FPopupMenu implements IVQuestStats {
setCurrentScreen(bazaarScreen); setCurrentScreen(bazaarScreen);
} }
}); });
private static final FMenuItem statsItem = new FMenuItem(Localizer.getInstance().getMessage("lblStatistics"), FSkinImage.HDMULTI, new FEventHandler() { private static final FMenuItem statsItem = new FMenuItem(Localizer.getInstance().getMessage("lblStatistics"), FSkinImage.MENU_STATS, new FEventHandler() {
@Override @Override
public void handleEvent(FEvent e) { public void handleEvent(FEvent e) {
setCurrentScreen(statsScreen); setCurrentScreen(statsScreen);

View File

@@ -84,3 +84,4 @@ Modern Horizons, 3/6/WAR, MH1
Core Set 2020, 3/6/M20, M20 Core Set 2020, 3/6/M20, M20
Throne of Eldraine, 3/6/ELD, ELD Throne of Eldraine, 3/6/ELD, ELD
Theros Beyond Death, 3/6/THB, THB Theros Beyond Death, 3/6/THB, THB
Mystery Booster, 3/6/THB, MB1

File diff suppressed because it is too large Load Diff

View File

@@ -4,8 +4,9 @@ Types:Creature Elemental Knight
PT:4/6 PT:4/6
K:Vigilance 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. 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: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$ TargetedController | LegacyImage$ c 3 3 a golem m20 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. 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 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. 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.

View File

@@ -1,7 +1,7 @@
Name:Ghastly Demise Name:Ghastly Demise
ManaCost:B ManaCost:B
Types:Instant 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: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. Oracle:Destroy target nonblack creature if its toughness is less than or equal to the number of cards in your graveyard.

View File

@@ -1,7 +1,7 @@
Name:Joust Name:Joust
ManaCost:1 R ManaCost:1 R
Types:Sorcery 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 SVar:DBFight:DB$ Fight | Defined$ ParentTarget | ValidTgts$ Creature.YouDontCtrl | AILogic$ Always | TgtPrompt$ Choose target creature you don't control
DeckHints:Type$Knight 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.) 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.)

View File

@@ -1,9 +1,10 @@
Name:Nissa's Pilgrimage Name:Nissa's Pilgrimage
ManaCost:2 G ManaCost:2 G
Types:Sorcery 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. 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:DBChangeZone1:DB$ChangeZone | Origin$ Library | Destination$ Hand | SubAbility$ DBChangeZone2 | ChangeType$ Land.Basic+Forest | ChangeNum$ 1 | ConditionCheckSVar$ X | ConditionSVarCompare$ LT2 | References$ X 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:DBChangeZone2:DB$ChangeZone | Origin$ Library | Destination$ Hand | ChangeType$ Land.Basic+Forest | ChangeNum$ 2 | ConditionCheckSVar$ X | ConditionSVarCompare$ GE2 | References$ X SVar:DBHand:DB$ ChangeZone | Origin$ Library | Destination$ Hand | Defined$ Remembered | NoLooking$ True | StackDescription$ None | SubAbility$ DBCleanup
SVar:X:Count$ValidGraveyard Instant.YouOwn,Sorcery.YouOwn SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:Picture:http://www.wizards.com/global/images/magic/general/nissas_pilgrimage.jpg 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. 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.

View File

@@ -2,7 +2,7 @@ Name:Settle the Wreckage
ManaCost:2 W W ManaCost:2 W W
Types:Instant 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. 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:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:X:Count$RememberedSize SVar:X:Count$RememberedSize
SVar:Picture:http://www.wizards.com/global/images/magic/general/settle_the_wreckage.jpg SVar:Picture:http://www.wizards.com/global/images/magic/general/settle_the_wreckage.jpg

View File

@@ -3,7 +3,7 @@ ManaCost:1 W
Types:Enchantment Saga Types:Enchantment Saga
K:Saga:3:TrigChange,TrigToken,TrigGainLife 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: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. SVar:TrigGainLife:DB$ GainLife | Defined$ You | LifeAmount$ 2 | SpellDescription$ You gain 2 life.
DeckHas:Ability$LifeGain & Ability$Token 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. 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.

View File

@@ -1,7 +1,7 @@
Name:The Triumph of Anax Name:The Triumph of Anax
ManaCost:2 R ManaCost:2 R
Types:Enchantment Saga 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: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:X:Count$CardCounters.LORE
SVar:PlayMain1:TRUE SVar:PlayMain1:TRUE

View File

@@ -196,14 +196,14 @@ AdditionalSetUnlockedInQuest=MPS_KLD
183 C Welder Automaton 183 C Welder Automaton
184 R Spire of Industry 184 R Spire of Industry
185 M Ajani, Valiant Protector 185 M Ajani, Valiant Protector
186 R Ajani's Aid 186 C Inspiring Roar
187 U Ajani's Comrade 187 U Ajani's Comrade
188 C Inspiring Roar 188 R Ajani's Aid
189 C Tranquil Expanse 189 C Tranquil Expanse
190 M Tezzeret, Master of Metal 190 M Tezzeret, Master of Metal
191 R Tezzeret's Betrayal 191 R Tezzeret's Betrayal
192 U Tezzeret's Simulacrum 192 C Pendulum of Patterns
193 C Pendulum of Patterns 193 U Tezzeret's Simulacrum
194 C Submerged Boneyard 194 C Submerged Boneyard
[tokens] [tokens]

View File

@@ -27,10 +27,10 @@ Foil=NotSupported
17 C Curfew 17 C Curfew
18 C Dark Ritual 18 C Dark Ritual
19 R Dirtcowl Wurm 19 R Dirtcowl Wurm
20 U Disenchant 20 C Disenchant
21 C Disruptive Student 21 C Disruptive Student
22 C Drifting Meadow 22 C Drifting Meadow
23 C Elvish Lyrist 23 U Elvish Lyrist
24 C Exhume 24 C Exhume
25 U Fecundity 25 U Fecundity
26 C Fertile Ground 26 C Fertile Ground
@@ -40,16 +40,16 @@ Foil=NotSupported
30 C Gorilla Warrior 30 C Gorilla Warrior
31 C Healing Salve 31 C Healing Salve
32 C Heat Ray 32 C Heat Ray
33 R Hurricane 33 U Hurricane
34 C Infantry Veteran 34 C Infantry Veteran
35 R Land Tax 35 U Land Tax
36 R Lhurgoyf 36 R Lhurgoyf
37 C Lightning Elemental 37 C Lightning Elemental
38 R Living Death 38 R Living Death
39 C Llanowar Elves 39 C Llanowar Elves
40 C Man-o'-War 40 C Man-o'-War
41 C Mana Leak 41 C Mana Leak
42 U Maniacal Rage 42 C Maniacal Rage
43 C Manta Riders 43 C Manta Riders
44 C Master Decoy 44 C Master Decoy
45 U Mogg Hollows 45 U Mogg Hollows
@@ -59,7 +59,7 @@ Foil=NotSupported
49 U Pestilence 49 U Pestilence
50 C Phyrexian Ghoul 50 C Phyrexian Ghoul
51 C Pincher Beetles 51 C Pincher Beetles
52 U Plated Rootwalla 52 C Plated Rootwalla
53 C Polluted Mire 53 C Polluted Mire
54 C Prodigal Sorcerer 54 C Prodigal Sorcerer
55 C Raging Goblin 55 C Raging Goblin
@@ -72,7 +72,7 @@ Foil=NotSupported
62 C Sanctum Custodian 62 C Sanctum Custodian
63 U Sanctum Guardian 63 U Sanctum Guardian
64 C Sandstorm 64 C Sandstorm
65 U Scaled Wurm 65 C Scaled Wurm
66 C Scryb Sprites 66 C Scryb Sprites
67 U Seasoned Marshal 67 U Seasoned Marshal
68 C Seeker of Skybreak 68 C Seeker of Skybreak
@@ -83,7 +83,7 @@ Foil=NotSupported
73 C Slippery Karst 73 C Slippery Karst
74 C Soltari Foot Soldier 74 C Soltari Foot Soldier
75 U Songstitcher 75 U Songstitcher
76 U Soul Warden 76 C Soul Warden
77 C Spike Colony 77 C Spike Colony
78 U Spike Feeder 78 U Spike Feeder
79 R Spike Weaver 79 R Spike Weaver

View File

@@ -135,7 +135,7 @@ Booster=10 Common, 3 Uncommon, 1 fromSheet("BBD RareMythic"), 1 BasicLand
125 C Omenspeaker 125 C Omenspeaker
126 U Opportunity 126 U Opportunity
127 U Oracle's Insight 127 U Oracle's Insight
128 C Peregrine Drake 128 U Peregrine Drake
129 U Phantom Warrior 129 U Phantom Warrior
130 U Reckless Scholar 130 U Reckless Scholar
131 R Sower of Temptation 131 R Sower of Temptation
@@ -203,7 +203,7 @@ Booster=10 Common, 3 Uncommon, 1 fromSheet("BBD RareMythic"), 1 BasicLand
193 C Cowl Prowler 193 C Cowl Prowler
194 C Daggerback Basilisk 194 C Daggerback Basilisk
195 M Doubling Season 195 M Doubling Season
196 U Elvish Visionary 196 C Elvish Visionary
197 U Feral Hydra 197 U Feral Hydra
198 C Fertile Ground 198 C Fertile Ground
199 U Fertilid 199 U Fertilid

View File

@@ -76,7 +76,7 @@ Foil=NotSupported
66 C Yavimaya Wurm 66 C Yavimaya Wurm
67 U Diabolic Vision 67 U Diabolic Vision
68 U Segmented Wurm 68 U Segmented Wurm
69 C Clockwork Avian 69 R Clockwork Avian
70 R Clockwork Beast 70 R Clockwork Beast
71 U Dwarven Ruins 71 U Dwarven Ruins
72 U Ebon Stronghold 72 U Ebon Stronghold

View File

@@ -6,7 +6,8 @@ Code2=CN2
MciCode=cn2 MciCode=cn2
Type=Other Type=Other
BoosterCovers=3 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] [cards]
1 C Adriana's Valor 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 219 R Exotic Orchard
220 U Rogue's Passage 220 U Rogue's Passage
221 U Shimmering Grotto 221 U Shimmering Grotto
222 M Kaya, Ghost Assassin
[tokens] [tokens]
w_1_1_soldier w_1_1_soldier

View File

@@ -184,14 +184,14 @@ Booster=10 Common:!land, 3 Uncommon, 1 RareMythic, 1 fromSheet("FRF Lands"), 0 f
174 C Tranquil Cove 174 C Tranquil Cove
175 C Wind-Scarred Crag 175 C Wind-Scarred Crag
176 L Plains 176 L Plains
176 L Plains 177 L Plains
179 L Island 178 L Island
179 L Island 179 L Island
180 L Swamp
181 L Swamp 181 L Swamp
181 L Swamp 182 L Mountain
183 L Mountain 183 L Mountain
183 L Mountain 184 L Forest
185 L Forest
185 L Forest 185 L Forest
[tokens] [tokens]

View File

@@ -258,26 +258,26 @@ Booster=10 Common, 3 Uncommon, 1 RareMythic, 1 BasicLand KTK
247 C Wind-Scarred Crag 247 C Wind-Scarred Crag
248 R Windswept Heath 248 R Windswept Heath
249 R Wooded Foothills 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 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 259 L Swamp
258 L Swamp 260 L Swamp
258 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] [tokens]
w_3_4_bird_flying w_3_4_bird_flying

View File

@@ -238,26 +238,26 @@ Booster=10 Common, 3 Uncommon, 1 RareMythic, 1 BasicLand
227 U Encroaching Wastes 227 U Encroaching Wastes
228 R Mutavault 228 R Mutavault
229 U Shimmering Grotto 229 U Shimmering Grotto
230 L Plains
231 L Plains 231 L Plains
231 L Plains 232 L Plains
231 L Plains 233 L Plains
231 L Plains
234 L Island
234 L Island
234 L Island
234 L Island 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 242 L Mountain
241 L Swamp 243 L Mountain
241 L Swamp
244 L Mountain
244 L Mountain
244 L Mountain
244 L Mountain 244 L Mountain
245 L Mountain
246 L Forest 246 L Forest
246 L Forest 247 L Forest
246 L Forest 248 L Forest
246 L Forest 249 L Forest
[tokens] [tokens]
c_1_1_sliver c_1_1_sliver

View File

@@ -258,26 +258,26 @@ Booster=10 Common:!fromSheet("M15 Sample Cards"), 3 Uncommon:!fromSheet("M15 Sam
247 R Sliver Hive 247 R Sliver Hive
248 R Urborg, Tomb of Yawgmoth 248 R Urborg, Tomb of Yawgmoth
249 R Yavimaya Coast 249 R Yavimaya Coast
250 L Plains
251 L Plains 251 L Plains
251 L Plains 252 L Plains
251 L Plains 253 L Plains
251 L Plains 254 L Island
255 L Island
255 L Island
255 L Island
255 L Island 255 L Island
256 L Island
257 L Island
258 L Swamp 258 L Swamp
258 L Swamp 259 L Swamp
258 L Swamp 260 L Swamp
258 L Swamp 261 L Swamp
263 L Mountain 262 L Mountain
263 L Mountain
263 L Mountain
263 L Mountain 263 L Mountain
264 L Mountain
265 L Mountain
266 L Forest 266 L Forest
266 L Forest 267 L Forest
266 L Forest 268 L Forest
266 L Forest 269 L Forest
270 R Aegis Angel 270 R Aegis Angel
271 C Divine Verdict 271 C Divine Verdict
272 C Inspired Charge 272 C Inspired Charge

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -367,17 +367,17 @@ Prerelease=6 Boosters, 1 RareMythic+
350 R Temple of Malice 350 R Temple of Malice
351 R Temple of Plenty 351 R Temple of Plenty
#Bundle promo #Bundle promo
R Arasta of the Endless Web 352 R Arasta of the Endless Web
#Promo Pack #Promo Pack
U Alseid of Life's Bounty 353 U Alseid of Life's Bounty
C Thirst for Meaning 354 C Thirst for Meaning
U Gray Merchant of Asphodel 355 U Gray Merchant of Asphodel
C Thrill of Possibility 356 C Thrill of Possibility
U Wolfwillow Haven 357 U Wolfwillow Haven
[tokens] [tokens]
b_2_2_zombie b_2_2_zombie
c_0_4_wall_defender c_0_4_a_wall_defender
g_1_2_spider_reach g_1_2_spider_reach
g_2_2_wolf g_2_2_wolf
r_x_1_elemental_trample_haste r_x_1_elemental_trample_haste

View File

@@ -284,36 +284,36 @@ Prerelease=6 Boosters, 1 RareMythic+
271 M Oko, Thief of Crowns 271 M Oko, Thief of Crowns
272 M The Royal Scions 272 M The Royal Scions
#Storybook Frames #Storybook Frames
C Ardenvale Tactician 273 C Ardenvale Tactician
C Faerie Guidemother 274 C Faerie Guidemother
R Giant Killer 275 R Giant Killer
C Lonesome Unicorn 276 C Lonesome Unicorn
M Realm-Cloaked Giant 277 M Realm-Cloaked Giant
U Shepherd of the Flock 278 U Shepherd of the Flock
C Silverflame Squire 279 C Silverflame Squire
U Animating Faerie 280 U Animating Faerie
M Brazen Borrower 281 M Brazen Borrower
R Fae of Wishes 282 R Fae of Wishes
U Hypnotic Sprite 283 U Hypnotic Sprite
C Merfolk Secretkeeper 284 C Merfolk Secretkeeper
C Queen of Ice 285 C Queen of Ice
U Foulmire Knight 286 U Foulmire Knight
R Murderous Rider 287 R Murderous Rider
U Order of Midnight 288 U Order of Midnight
C Reaper of Night 289 C Reaper of Night
C Smitten Swordmaster 290 C Smitten Swordmaster
R Bonecrusher Giant 291 R Bonecrusher Giant
U Embereth Shieldbreaker 292 U Embereth Shieldbreaker
C Merchant of the Vale 293 C Merchant of the Vale
C Rimrock Knight 294 C Rimrock Knight
U Beanstalk Giant 295 U Beanstalk Giant
C Curious Pair 296 C Curious Pair
U Flaxen Intruder 297 U Flaxen Intruder
C Garenbrig Carver 298 C Garenbrig Carver
R Lovestruck Beast 299 R Lovestruck Beast
C Rosethorn Acolyte 300 C Rosethorn Acolyte
C Tuinvale Treefolk 301 C Tuinvale Treefolk
U Oakhame Ranger 302 U Oakhame Ranger
#Buy-A-Box Promo #Buy-A-Box Promo
303 M Kenrith, the Returned King 303 M Kenrith, the Returned King
#Planeswalker Deck Cards #Planeswalker Deck Cards
@@ -348,72 +348,72 @@ U Oakhame Ranger
332 R Tome of Legends 332 R Tome of Legends
333 C Command Tower 333 C Command Tower
#Borderless art rares and mythics #Borderless art rares and mythics
R Acclaimed Contender 334 R Acclaimed Contender
R Charming Prince 335 R Charming Prince
M The Circle of Loyalty 336 M The Circle of Loyalty
R Happily Ever After 337 R Happily Ever After
M Harmonious Archon 338 M Harmonious Archon
R Hushbringer 339 R Hushbringer
R Linden, the Steadfast Queen 340 R Linden, the Steadfast Queen
R Worthy Knight 341 R Worthy Knight
R Emry, Lurker of the Loch 342 R Emry, Lurker of the Loch
R Folio of Fancies 343 R Folio of Fancies
R Gadwick, the Wizened 344 R Gadwick, the Wizened
M The Magic Mirror 345 M The Magic Mirror
R Midnight Clock 346 R Midnight Clock
R Mirrormade 347 R Mirrormade
R Stolen by the Fae 348 R Stolen by the Fae
R Vantress Gargoyle 349 R Vantress Gargoyle
R Ayara, First of Locthwain 350 R Ayara, First of Locthwain
R Blacklance Paragon 351 R Blacklance Paragon
M The Cauldron of Eternity 352 M The Cauldron of Eternity
R Clackbridge Troll 353 R Clackbridge Troll
R Oathsworn Knight 354 R Oathsworn Knight
R Piper of the Swarm 355 R Piper of the Swarm
M Rankle, Master of Pranks 356 M Rankle, Master of Pranks
R Wishclaw Talisman 357 R Wishclaw Talisman
R Witch's Vengeance 358 R Witch's Vengeance
M Embercleave 359 M Embercleave
R Fervent Champion 360 R Fervent Champion
R Fires of Invention 361 R Fires of Invention
R Irencrag Feat 362 R Irencrag Feat
R Irencrag Pyromancer 363 R Irencrag Pyromancer
R Opportunistic Dragon 364 R Opportunistic Dragon
M Robber of the Rich 365 M Robber of the Rich
R Sundering Stroke 366 R Sundering Stroke
R Torbran, Thane of Red Fell 367 R Torbran, Thane of Red Fell
R Feasting Troll King 368 R Feasting Troll King
R Gilded Goose 369 R Gilded Goose
M The Great Henge 370 M The Great Henge
R Once Upon A Time 371 R Once Upon a Time
M Questing Beast 372 M Questing Beast
R Return of the Wildspeaker 373 R Return of the Wildspeaker
R Wicked Wolf 374 R Wicked Wolf
R Wildborn Preserver 375 R Wildborn Preserver
R Yorvo, Lord of Garenbrig 376 R Yorvo, Lord of Garenbrig
R Dance of the Manse 377 R Dance of the Manse
R Doom Foretold 378 R Doom Foretold
R Escape to the Wilds 379 R Escape to the Wilds
R Faeburrow Elder 380 R Faeburrow Elder
R Lochmere Serpent 381 R Lochmere Serpent
M Outlaws' Merriment 382 M Outlaws' Merriment
R Stormfist Crusader 383 R Stormfist Crusader
R Sorcerous Spyglass 384 R Sorcerous Spyglass
R Stonecoil Serpent 385 R Stonecoil Serpent
R Castle Ardenvale 386 R Castle Ardenvale
R Castle Embereth 387 R Castle Embereth
R Castle Garenbrig 388 R Castle Garenbrig
R Castle Locthwain 389 R Castle Locthwain
R Castle Vantress 390 R Castle Vantress
R Fabled Passage 391 R Fabled Passage
#Bundle promo #Bundle promo
R Piper of the Swarm 392 R Piper of the Swarm
#Promo Pack #Promo Pack
U Glass Casket 393 U Glass Casket
U Slaying Fire 394 U Slaying Fire
U Kenrith's Transformation 395 U Kenrith's Transformation
U Improbable Alliance 396 U Improbable Alliance
U Inspiring Veteran 397 U Inspiring Veteran
[tokens] [tokens]
w_0_1_goat w_0_1_goat

View File

@@ -178,5 +178,5 @@ R Winding Canyons
R Xanthic Statue R Xanthic Statue
C Zombie Scavengers C Zombie Scavengers
[token] [tokens]
g_1_1_squirrel g_1_1_squirrel

View File

@@ -4,4 +4,4 @@ Order:101
Type:Casual Type:Casual
Subtype:Commander Subtype:Commander
Sets:GRN, RNA, WAR, M20, ELD, THB Sets:GRN, RNA, WAR, M20, ELD, THB
Banned:Sorcerous Spyglass;Oko, Thief of Crowns Banned:Golos, Tireless Pilgrim; Oko, Thief of Crowns; Sorcerous Spyglass

View File

@@ -3,4 +3,4 @@ Name:Legacy
Order:105 Order:105
Subtype:Legacy Subtype:Legacy
Type:Sanctioned 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

View File

@@ -4,4 +4,4 @@ Order:103
Subtype:Modern Subtype:Modern
Type:Sanctioned 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 Sets:8ED, MRD, DST, 5DN, CHK, BOK, SOK, 9ED, RAV, GPT, DIS, CSP, TSP, TSB, PLC, FUT, 10E, LRW, EVE, SHM, MOR, ALA, CFX, ARB, M10, ZEN, WWK, ROE, M11, SOM, MBS, NPH, M12, ISD, DKA, AVR, M13, RTR, GTC, DGM, M14, THS, BNG, JOU, M15, KTK, FRF, DTK, MM2, ORI, BFZ, OGW, SOI, EMN, KLD, AER, AKH, W17, HOU, XLN, RIX, DOM, M19, G18, GRN, RNA, WAR, MH1, M20, ELD, THB
Banned:Ancient Den; Birthing Pod; Blazing Shoal; Bridge from Below; Chrome Mox; Cloudpost; Dark Depths; Deathrite Shaman; Dig Through Time; Dread Return; Eye of Ugin; Faithless Looting; Gitaxian Probe; Glimpse of Nature; Golgari Grave-Troll; Great Furnace; Green Sun's Zenith; Hogaak, Arisen Necropolis; Hypergenesis; Krark-Clan Ironworks; Mental Misstep; Mox Opal; Mycosynth Lattice; Oko, Thief of Crowns; Ponder; Preordain; Punishing Fire; Rite of Flame; Seat of the Synod; Second Sunrise; Seething Song; Sensei's Divining Top; Skullclamp; Splinter Twin; Summer Bloom; Treasure Cruise; Tree of Tales; Umezawa's Jitte; Vault of Whispers Banned:Ancient Den; Birthing Pod; Blazing Shoal; Bridge from Below; Chrome Mox; Cloudpost; Dark Depths; Deathrite Shaman; Dig Through Time; Dread Return; Eye of Ugin; Faithless Looting; Gitaxian Probe; Glimpse of Nature; Golgari Grave-Troll; Great Furnace; Green Sun's Zenith; Hogaak, Arisen Necropolis; Hypergenesis; Krark-Clan Ironworks; Mental Misstep; Mox Opal; Mycosynth Lattice; Oko, Thief of Crowns; Once Upon A Time; Ponder; Preordain; Punishing Fire; Rite of Flame; Seat of the Synod; Second Sunrise; Seething Song; Sensei's Divining Top; Skullclamp; Splinter Twin; Summer Bloom; Treasure Cruise; Tree of Tales; Umezawa's Jitte; Vault of Whispers

View File

@@ -50,6 +50,8 @@ btnResetJavaFutureCompatibilityWarnings=Java-Kompatibilitätswarnung zurücksetz
btnClearImageCache=Leere Bildspeicher btnClearImageCache=Leere Bildspeicher
btnTokenPreviewer=Spielstein-Vorschau btnTokenPreviewer=Spielstein-Vorschau
btnCopyToClipboard=In Zwischenablage kopieren btnCopyToClipboard=In Zwischenablage kopieren
cbpAutoUpdater=Auto updater
nlAutoUpdater=Select the release channel to use for updating Forge
cbpSelectLanguage=Sprache cbpSelectLanguage=Sprache
nlSelectLanguage=Wähle Sprache (Ist noch in Arbeit und nur teilweise umgesetzt.) (Neustart ist erforderlich.) nlSelectLanguage=Wähle Sprache (Ist noch in Arbeit und nur teilweise umgesetzt.) (Neustart ist erforderlich.)
cbRemoveSmall=Entferne kleine Kreaturen cbRemoveSmall=Entferne kleine Kreaturen
@@ -180,6 +182,7 @@ KeyboardShortcuts=Tastenkombinationen
#VSubmenuAchievements.java #VSubmenuAchievements.java
lblAchievements=Errungenschaften lblAchievements=Errungenschaften
#VSubmenuDownloaders.java #VSubmenuDownloaders.java
btnCheckForUpdates=Check for Updates
btnDownloadSetPics=Bilder(LQ) Sets herunterladen btnDownloadSetPics=Bilder(LQ) Sets herunterladen
btnDownloadPicsHQ=Bilder(HQ) Karten herunterladen (Sehr langsam!) btnDownloadPicsHQ=Bilder(HQ) Karten herunterladen (Sehr langsam!)
btnDownloadPics=Bilder(LQ) Karten herunterladen btnDownloadPics=Bilder(LQ) Karten herunterladen
@@ -192,6 +195,7 @@ btnImportPictures=Daten importieren
btnHowToPlay=Wie man spielt btnHowToPlay=Wie man spielt
btnDownloadPrices=Kartenpreise herunterladen btnDownloadPrices=Kartenpreise herunterladen
btnLicensing=Lizenzhinweis btnLicensing=Lizenzhinweis
lblCheckForUpdates=Check Forge server to see if there's a more recent release
lblDownloadPics=Lädt ein Standardbild pro Karte. lblDownloadPics=Lädt ein Standardbild pro Karte.
lblDownloadPicsHQ=Lädt ein HQ-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. lblDownloadSetPics=Lädt alle Bilder pro Karte. Eines für jedes Set, in welchem die Karte auftauchte.

View File

@@ -50,6 +50,8 @@ btnResetJavaFutureCompatibilityWarnings=Reset Java Compatibility Warnings
btnClearImageCache=Clear Image Cache btnClearImageCache=Clear Image Cache
btnTokenPreviewer=Token Previewer btnTokenPreviewer=Token Previewer
btnCopyToClipboard=Copy to Clipboard btnCopyToClipboard=Copy to Clipboard
cbpAutoUpdater=Auto updater
nlAutoUpdater=Select the release channel to use for updating Forge
cbpSelectLanguage=Language cbpSelectLanguage=Language
nlSelectLanguage=Select Language (Excluded Game part. Still a work in progress) (RESTART REQUIRED) nlSelectLanguage=Select Language (Excluded Game part. Still a work in progress) (RESTART REQUIRED)
cbRemoveSmall=Remove Small Creatures cbRemoveSmall=Remove Small Creatures
@@ -180,6 +182,7 @@ KeyboardShortcuts=Keyboard Shortcuts
#VSubmenuAchievements.java #VSubmenuAchievements.java
lblAchievements=Achievements lblAchievements=Achievements
#VSubmenuDownloaders.java #VSubmenuDownloaders.java
btnCheckForUpdates=Check for Updates
btnDownloadSetPics=Download LQ Set Pictures btnDownloadSetPics=Download LQ Set Pictures
btnDownloadPicsHQ=Download HQ Card Pictures (Very Slow!) btnDownloadPicsHQ=Download HQ Card Pictures (Very Slow!)
btnDownloadPics=Download LQ Card Pictures btnDownloadPics=Download LQ Card Pictures
@@ -192,6 +195,7 @@ btnImportPictures=Import Data
btnHowToPlay=How To Play btnHowToPlay=How To Play
btnDownloadPrices=Download Card Prices btnDownloadPrices=Download Card Prices
btnLicensing=License Details btnLicensing=License Details
lblCheckForUpdates=Check Forge server to see if there's a more recent release
lblDownloadPics=Download default card picture for each card. lblDownloadPics=Download default card picture for each card.
lblDownloadPicsHQ=Download default card HQ 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) lblDownloadSetPics=Download all pictures of each card (one for each set the card appeared in)

View File

@@ -50,6 +50,8 @@ btnResetJavaFutureCompatibilityWarnings=Restablecer las advertencias de compatib
btnClearImageCache=Limpiar Caché de Imágenes btnClearImageCache=Limpiar Caché de Imágenes
btnTokenPreviewer=Previsualizador de Fichas (Token) btnTokenPreviewer=Previsualizador de Fichas (Token)
btnCopyToClipboard=Copiar al portapapeles btnCopyToClipboard=Copiar al portapapeles
cbpAutoUpdater=Actualizar Forge
nlAutoUpdater=Selecciona la versión a utilizar para actualizar Forge
cbpSelectLanguage=Idioma cbpSelectLanguage=Idioma
nlSelectLanguage=Seleccionar idioma (excepto partida). Todavía un trabajo en progreso) (Es necesario reiniciar Forge) nlSelectLanguage=Seleccionar idioma (excepto partida). Todavía un trabajo en progreso) (Es necesario reiniciar Forge)
cbRemoveSmall=Eliminar Pequeñas Criaturas cbRemoveSmall=Eliminar Pequeñas Criaturas
@@ -180,6 +182,7 @@ KeyboardShortcuts=Atajos de teclado
#VSubmenuAchievements.java #VSubmenuAchievements.java
lblAchievements=Logros lblAchievements=Logros
#VSubmenuDownloaders.java #VSubmenuDownloaders.java
btnCheckForUpdates=Comprobar Actualizaciones
btnDownloadSetPics=Descargar todas las Ediciones de Cartas btnDownloadSetPics=Descargar todas las Ediciones de Cartas
btnDownloadPics=Descargar todas las Cartas btnDownloadPics=Descargar todas las Cartas
btnDownloadPicsHQ=Descargar todas las Cartas en calidad alta (Muy lento!) btnDownloadPicsHQ=Descargar todas las Cartas en calidad alta (Muy lento!)
@@ -192,6 +195,7 @@ btnImportPictures=Importar Datos
btnHowToPlay=Cómo jugar (Inglés) btnHowToPlay=Cómo jugar (Inglés)
btnDownloadPrices=Descargar los precios de las cartas btnDownloadPrices=Descargar los precios de las cartas
btnLicensing=Detalles de la licencia 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. 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. 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) lblDownloadSetPics=Descargue todas las imágenes de cada carta (una por cada edición donde apareció la carta)

View File

@@ -50,6 +50,8 @@ btnResetJavaFutureCompatibilityWarnings=Ripristina avvisi di compatibilità Java
btnClearImageCache=Cancella cache immagini btnClearImageCache=Cancella cache immagini
btnTokenPreviewer=Anteprima token btnTokenPreviewer=Anteprima token
btnCopyToClipboard=Copia negli appunti btnCopyToClipboard=Copia negli appunti
cbpAutoUpdater=Auto updater
nlAutoUpdater=Select the release channel to use for updating Forge
cbpSelectLanguage=Lingua cbpSelectLanguage=Lingua
nlSelectLanguage=Seleziona la lingua (parte di gioco esclusa. Ancora in fase di sviluppo) (RIAVVIO NECESSARIO) nlSelectLanguage=Seleziona la lingua (parte di gioco esclusa. Ancora in fase di sviluppo) (RIAVVIO NECESSARIO)
cbRemoveSmall=Rimuovi le piccole creature cbRemoveSmall=Rimuovi le piccole creature
@@ -180,6 +182,7 @@ KeyboardShortcuts=Tasti rapidi
#VSubmenuAchievements.java #VSubmenuAchievements.java
lblAchievements=realizzazioni lblAchievements=realizzazioni
#VSubmenuDownloaders.java #VSubmenuDownloaders.java
btnCheckForUpdates=Check for Updates
btnDownloadSetPics=Scarica LQ Set Pictures btnDownloadSetPics=Scarica LQ Set Pictures
btnDownloadPicsHQ=Scarica le immagini della scheda HQ (molto lento!) btnDownloadPicsHQ=Scarica le immagini della scheda HQ (molto lento!)
btnDownloadPics=Scarica LQ Card Pictures btnDownloadPics=Scarica LQ Card Pictures
@@ -192,6 +195,7 @@ btnImportPictures=Importa dati
btnHowToPlay=Come giocare btnHowToPlay=Come giocare
btnDownloadPrices=Scarica i prezzi delle carte btnDownloadPrices=Scarica i prezzi delle carte
btnLicensing=Dettagli della licenza 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. lblDownloadPics=Scarica l''immagine della carta predefinita per ogni carta.
lblDownloadPicsHQ=Scarica l''immagine HQ della scheda predefinita per ogni scheda. 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) lblDownloadSetPics=Scarica tutte le immagini di ogni carta (una per ogni set in cui è apparso la carta)

View File

@@ -50,6 +50,8 @@ btnResetJavaFutureCompatibilityWarnings=重置Java兼容性警告
btnClearImageCache=清除图片缓存 btnClearImageCache=清除图片缓存
btnTokenPreviewer=衍生物预览器 btnTokenPreviewer=衍生物预览器
btnCopyToClipboard=复制到剪切板 btnCopyToClipboard=复制到剪切板
cbpAutoUpdater=Auto updater
nlAutoUpdater=Select the release channel to use for updating Forge
cbpSelectLanguage=语言 cbpSelectLanguage=语言
nlSelectLanguage=选择语言(除了正在进行中的游戏)(需要重新启动) nlSelectLanguage=选择语言(除了正在进行中的游戏)(需要重新启动)
cbRemoveSmall=删除小生物 cbRemoveSmall=删除小生物
@@ -180,6 +182,7 @@ KeyboardShortcuts=键盘快捷键
#VSubmenuAchievements.java #VSubmenuAchievements.java
lblAchievements=成就 lblAchievements=成就
#VSubmenuDownloaders.java #VSubmenuDownloaders.java
btnCheckForUpdates=Check for Updates
btnDownloadSetPics=下载低清系列图 btnDownloadSetPics=下载低清系列图
btnDownloadPicsHQ=下载高清卡图(这很慢!) btnDownloadPicsHQ=下载高清卡图(这很慢!)
btnDownloadPics=下载低清卡图 btnDownloadPics=下载低清卡图
@@ -192,6 +195,7 @@ btnImportPictures=导入数据
btnHowToPlay=如何玩 btnHowToPlay=如何玩
btnDownloadPrices=下载卡牌价格 btnDownloadPrices=下载卡牌价格
btnLicensing=许可证详情 btnLicensing=许可证详情
lblCheckForUpdates=Check Forge server to see if there's a more recent release
lblDownloadPics=下载缺省牌的图片 lblDownloadPics=下载缺省牌的图片
lblDownloadPicsHQ=下载缺省牌的高清图片 lblDownloadPicsHQ=下载缺省牌的高清图片
lblDownloadSetPics=下载每张牌的图片(每张牌出现一次) lblDownloadSetPics=下载每张牌的图片(每张牌出现一次)

View File

@@ -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

View File

@@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 534 KiB

After

Width:  |  Height:  |  Size: 533 KiB

View File

@@ -1,6 +1,6 @@
Name:Wall Name:Wall
ManaCost:no cost ManaCost:no cost
Types:Creature Wall Types:Artifact Creature Wall
PT:0/4 PT:0/4
K:Defender K:Defender
Oracle:Defender Oracle:Defender

View File

@@ -230,6 +230,15 @@ public enum FSkinProp {
ICO_QUEST_BIG_SWORD (new int[] {320, 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), 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 //interface icons
ICO_QUESTION (new int[] {560, 800, 32, 32}, PropType.ICON), ICO_QUESTION (new int[] {560, 800, 32, 32}, PropType.ICON),
ICO_INFORMATION (new int[] {592, 800, 32, 32}, PropType.ICON), ICO_INFORMATION (new int[] {592, 800, 32, 32}, PropType.ICON),

View File

@@ -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<String> 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("<release>(.*)</release>");
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<String> 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<Boolean> callback = new WaitCallback<Boolean>() {
@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);
}
}
}

View File

@@ -73,72 +73,7 @@ public class GuiDownloadZipService extends GuiDownloadService {
String zipFilename = download("temp.zip"); String zipFilename = download("temp.zip");
if (zipFilename == null) { return; } if (zipFilename == null) { return; }
//if assets.zip downloaded successfully, unzip into destination folder extract(zipFilename);
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);
}
} }
public String download(final String filename) { 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 { protected void copyInputStream(final InputStream in, final String outPath) throws IOException {
final byte[] buffer = new byte[1024]; final byte[] buffer = new byte[1024];
int len; int len;

View File

@@ -28,6 +28,7 @@ import forge.card.CardType;
import forge.deck.CardArchetypeLDAGenerator; import forge.deck.CardArchetypeLDAGenerator;
import forge.deck.CardRelationMatrixGenerator; import forge.deck.CardRelationMatrixGenerator;
import forge.deck.io.DeckPreferences; import forge.deck.io.DeckPreferences;
import forge.download.AutoUpdater;
import forge.game.GameFormat; import forge.game.GameFormat;
import forge.game.GameType; import forge.game.GameType;
import forge.game.card.CardUtil; 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); Localizer.getInstance().initialize(FModel.getPreferences().getPref(FPref.UI_LANGUAGE), ForgeConstants.LANG_DIR);
//load card database
final ProgressObserver progressBarBridge = (progressBar == null) ? final ProgressObserver progressBarBridge = (progressBar == null) ?
ProgressObserver.emptyObserver : new ProgressObserver() { ProgressObserver.emptyObserver : new ProgressObserver() {
@Override @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, final CardStorageReader reader = new CardStorageReader(ForgeConstants.CARD_DATA_DIR, progressBarBridge,
FModel.getPreferences().getPrefBoolean(FPref.LOAD_CARD_SCRIPTS_LAZILY)); FModel.getPreferences().getPrefBoolean(FPref.LOAD_CARD_SCRIPTS_LAZILY));
final CardStorageReader tokenReader = new CardStorageReader(ForgeConstants.TOKEN_DATA_DIR, progressBarBridge, final CardStorageReader tokenReader = new CardStorageReader(ForgeConstants.TOKEN_DATA_DIR, progressBarBridge,
@@ -221,8 +226,6 @@ public final class FModel {
achievements.put(GameType.PlanarConquest, new PlanarConquestAchievements()); achievements.put(GameType.PlanarConquest, new PlanarConquestAchievements());
achievements.put(GameType.Puzzle, new PuzzleAchievements()); achievements.put(GameType.Puzzle, new PuzzleAchievements());
//preload AI profiles //preload AI profiles
AiProfileUtil.loadAllProfiles(ForgeConstants.AI_PROFILE_DIR); AiProfileUtil.loadAllProfiles(ForgeConstants.AI_PROFILE_DIR);

Some files were not shown because too many files have changed in this diff Show More