Merge branch 'coremaster' into respectbanlist
@@ -91,9 +91,6 @@ public class ComputerUtil {
|
||||
}
|
||||
}
|
||||
|
||||
source.setCastSA(sa);
|
||||
sa.setLastStateBattlefield(game.getLastStateBattlefield());
|
||||
sa.setLastStateGraveyard(game.getLastStateGraveyard());
|
||||
sa.setHostCard(game.getAction().moveToStack(source, sa));
|
||||
}
|
||||
|
||||
@@ -219,9 +216,6 @@ public class ComputerUtil {
|
||||
|
||||
final Card source = sa.getHostCard();
|
||||
if (sa.isSpell() && !source.isCopiedSpell()) {
|
||||
source.setCastSA(sa);
|
||||
sa.setLastStateBattlefield(game.getLastStateBattlefield());
|
||||
sa.setLastStateGraveyard(game.getLastStateGraveyard());
|
||||
sa.setHostCard(game.getAction().moveToStack(source, sa));
|
||||
}
|
||||
|
||||
@@ -246,9 +240,6 @@ public class ComputerUtil {
|
||||
|
||||
final Card source = sa.getHostCard();
|
||||
if (sa.isSpell() && !source.isCopiedSpell()) {
|
||||
source.setCastSA(sa);
|
||||
sa.setLastStateBattlefield(game.getLastStateBattlefield());
|
||||
sa.setLastStateGraveyard(game.getLastStateGraveyard());
|
||||
sa.setHostCard(game.getAction().moveToStack(source, sa));
|
||||
}
|
||||
|
||||
@@ -267,9 +258,6 @@ public class ComputerUtil {
|
||||
|
||||
final Card source = newSA.getHostCard();
|
||||
if (newSA.isSpell() && !source.isCopiedSpell()) {
|
||||
source.setCastSA(newSA);
|
||||
sa.setLastStateBattlefield(game.getLastStateBattlefield());
|
||||
sa.setLastStateGraveyard(game.getLastStateGraveyard());
|
||||
newSA.setHostCard(game.getAction().moveToStack(source, sa));
|
||||
|
||||
if (newSA.getApi() == ApiType.Charm && !newSA.isWrapper()) {
|
||||
@@ -290,9 +278,6 @@ public class ComputerUtil {
|
||||
if (ComputerUtilCost.canPayCost(sa, ai)) {
|
||||
final Card source = sa.getHostCard();
|
||||
if (sa.isSpell() && !source.isCopiedSpell()) {
|
||||
source.setCastSA(sa);
|
||||
sa.setLastStateBattlefield(game.getLastStateBattlefield());
|
||||
sa.setLastStateGraveyard(game.getLastStateGraveyard());
|
||||
sa.setHostCard(game.getAction().moveToStack(source, sa));
|
||||
}
|
||||
|
||||
|
||||
@@ -981,14 +981,27 @@ public abstract class GameState {
|
||||
spellDef = spellDef.substring(0, spellDef.indexOf("->")).trim();
|
||||
}
|
||||
|
||||
PaperCard pc = StaticData.instance().getCommonCards().getCard(spellDef);
|
||||
Card c = null;
|
||||
|
||||
if (pc == null) {
|
||||
System.err.println("ERROR: Could not find a card with name " + spellDef + " to precast!");
|
||||
return;
|
||||
if (StringUtils.isNumeric(spellDef)) {
|
||||
// Precast from a specific host
|
||||
c = idToCard.get(Integer.parseInt(spellDef));
|
||||
if (c == null) {
|
||||
System.err.println("ERROR: Could not find a card with ID " + spellDef + " to precast!");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Precast from a card by name
|
||||
PaperCard pc = StaticData.instance().getCommonCards().getCard(spellDef);
|
||||
|
||||
if (pc == null) {
|
||||
System.err.println("ERROR: Could not find a card with name " + spellDef + " to precast!");
|
||||
return;
|
||||
}
|
||||
|
||||
c = Card.fromPaperCard(pc, activator);
|
||||
}
|
||||
|
||||
Card c = Card.fromPaperCard(pc, activator);
|
||||
SpellAbility sa = null;
|
||||
|
||||
if (!scriptID.isEmpty()) {
|
||||
|
||||
@@ -113,7 +113,11 @@ public final class ImageKeys {
|
||||
}
|
||||
//try fullborder...
|
||||
if (filename.contains(".full")) {
|
||||
file = findFile(dir, TextUtil.fastReplace(filename, ".full", ".fullborder"));
|
||||
String fullborderFile = TextUtil.fastReplace(filename, ".full", ".fullborder");
|
||||
file = findFile(dir, fullborderFile);
|
||||
if (file != null) { return file; }
|
||||
// if there's an art variant try without it
|
||||
file = findFile(dir, TextUtil.fastReplace(fullborderFile, "1.fullborder", ".fullborder"));
|
||||
if (file != null) { return file; }
|
||||
}
|
||||
//if an image, like phenomenon or planes is missing .full in their filenames but you have an existing images that have .full/.fullborder
|
||||
|
||||
@@ -312,17 +312,21 @@ public final class CardDb implements ICardDatabase, IDeckGenPool {
|
||||
return tryGetCard(request);
|
||||
}
|
||||
|
||||
public int getCardCollectorNumber(String cardName, String reqEdition) {
|
||||
public String getCardCollectorNumber(String cardName, String reqEdition, int artIndex) {
|
||||
cardName = getName(cardName);
|
||||
CardEdition edition = editions.get(reqEdition);
|
||||
if (edition == null)
|
||||
return -1;
|
||||
return null;
|
||||
int numMatches = 0;
|
||||
for (CardInSet card : edition.getCards()) {
|
||||
if (card.name.equalsIgnoreCase(cardName)) {
|
||||
return card.collectorNumber;
|
||||
numMatches += 1;
|
||||
if (numMatches == artIndex) {
|
||||
return card.collectorNumber;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
return null;
|
||||
}
|
||||
|
||||
private PaperCard tryGetCard(CardRequest request) {
|
||||
|
||||
@@ -38,6 +38,8 @@ import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
||||
/**
|
||||
@@ -75,10 +77,10 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
|
||||
|
||||
public static class CardInSet {
|
||||
public final CardRarity rarity;
|
||||
public final int collectorNumber;
|
||||
public final String collectorNumber;
|
||||
public final String name;
|
||||
|
||||
public CardInSet(final String name, final int collectorNumber, final CardRarity rarity) {
|
||||
public CardInSet(final String name, final String collectorNumber, final CardRarity rarity) {
|
||||
this.name = name;
|
||||
this.collectorNumber = collectorNumber;
|
||||
this.rarity = rarity;
|
||||
@@ -86,7 +88,7 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (collectorNumber != -1) {
|
||||
if (collectorNumber != null) {
|
||||
sb.append(collectorNumber);
|
||||
sb.append(' ');
|
||||
}
|
||||
@@ -190,6 +192,7 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
|
||||
public boolean getSmallSetOverride() { return smallSetOverride; }
|
||||
public String getBoosterMustContain() { return boosterMustContain; }
|
||||
public CardInSet[] getCards() { return cards; }
|
||||
public boolean isModern() { return getDate().after(parseDate("2003-07-27")); } //8ED and above are modern except some promo cards and others
|
||||
|
||||
public Map<String, Integer> getTokens() { return tokenNormalized; }
|
||||
|
||||
@@ -266,24 +269,33 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
|
||||
Map<String, Integer> tokenNormalized = new HashMap<>();
|
||||
List<CardEdition.CardInSet> processedCards = new ArrayList<>();
|
||||
if (contents.containsKey("cards")) {
|
||||
final Pattern pattern = Pattern.compile(
|
||||
/*
|
||||
The following pattern will match the WAR Japanese art entries,
|
||||
it should also match the Un-set and older alternate art cards
|
||||
like Merseine from FEM (should the editions files ever be updated)
|
||||
*/
|
||||
//"(^(?<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")) {
|
||||
if (StringUtils.isBlank(line))
|
||||
continue;
|
||||
|
||||
// Optional collector number at the start.
|
||||
String[] split = line.split(" ", 2);
|
||||
int collectorNumber = -1;
|
||||
if (split.length >= 2 && StringUtils.isNumeric(split[0])) {
|
||||
collectorNumber = Integer.parseInt(split[0]);
|
||||
line = split[1];
|
||||
Matcher matcher = pattern.matcher(line);
|
||||
if (matcher.matches()) {
|
||||
String collectorNumber = matcher.group(2);
|
||||
CardRarity r = CardRarity.smartValueOf(matcher.group(4));
|
||||
String cardName = matcher.group(5);
|
||||
CardInSet cis = new CardInSet(cardName, collectorNumber, r);
|
||||
processedCards.add(cis);
|
||||
}
|
||||
|
||||
// You may omit rarity for early development
|
||||
CardRarity r = CardRarity.smartValueOf(line.substring(0, 1));
|
||||
boolean hadRarity = r != CardRarity.Unknown && line.charAt(1) == ' ';
|
||||
String cardName = hadRarity ? line.substring(2) : line;
|
||||
CardInSet cis = new CardInSet(cardName, collectorNumber, r);
|
||||
processedCards.add(cis);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -222,7 +222,12 @@ public final class CardRules implements ICardCharacteristics {
|
||||
|
||||
public boolean canBeBrawlCommander() {
|
||||
CardType type = mainPart.getType();
|
||||
return (type.isLegendary() && type.isCreature()) || type.isPlaneswalker();
|
||||
return type.isLegendary() && (type.isCreature() || type.isPlaneswalker());
|
||||
}
|
||||
|
||||
public boolean canBeTinyLeadersCommander() {
|
||||
CardType type = mainPart.getType();
|
||||
return type.isLegendary() && (type.isCreature() || type.isPlaneswalker());
|
||||
}
|
||||
|
||||
public String getMeldWith() {
|
||||
|
||||
@@ -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_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> CAN_BE_BRAWL_COMMANDER = Predicates.or(Presets.IS_PLANESWALKER,
|
||||
Predicates.and(Presets.IS_CREATURE, Presets.IS_LEGENDARY));
|
||||
public static final Predicate<CardRules> CAN_BE_BRAWL_COMMANDER = Predicates.and(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. **/
|
||||
public static final Predicate<CardRules> IS_NON_CREATURE_SPELL = com.google.common.base.Predicates
|
||||
|
||||
@@ -463,6 +463,9 @@ public enum DeckFormat {
|
||||
if (this.equals(DeckFormat.Brawl)) {
|
||||
return rules.canBeBrawlCommander();
|
||||
}
|
||||
if (this.equals(DeckFormat.TinyLeaders)) {
|
||||
return rules.canBeTinyLeadersCommander();
|
||||
}
|
||||
return rules.canBeCommander();
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ import forge.item.PaperCard;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@@ -17,6 +19,22 @@ import java.util.Map.Entry;
|
||||
*/
|
||||
public class TextUtil {
|
||||
|
||||
static ImmutableSortedMap<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.
|
||||
*
|
||||
|
||||
@@ -547,6 +547,13 @@ public class GameAction {
|
||||
c.setCastSA(null);
|
||||
} else if (zoneTo.is(ZoneType.Stack)) {
|
||||
c.setCastFrom(zoneFrom.getZoneType());
|
||||
if (cause != null && cause.isSpell() && c.equals(cause.getHostCard()) && !c.isCopiedSpell()) {
|
||||
cause.setLastStateBattlefield(game.getLastStateBattlefield());
|
||||
cause.setLastStateGraveyard(game.getLastStateGraveyard());
|
||||
c.setCastSA(cause);
|
||||
} else {
|
||||
c.setCastSA(null);
|
||||
}
|
||||
} else if (!(zoneTo.is(ZoneType.Battlefield) && zoneFrom.is(ZoneType.Stack))) {
|
||||
c.setCastFrom(null);
|
||||
c.setCastSA(null);
|
||||
|
||||
@@ -22,8 +22,10 @@ import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import forge.card.MagicColor;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.card.mana.ManaCostParser;
|
||||
import forge.game.ability.AbilityFactory;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.ApiType;
|
||||
import forge.game.card.*;
|
||||
@@ -32,9 +34,15 @@ import forge.game.cost.Cost;
|
||||
import forge.game.keyword.KeywordInterface;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerController;
|
||||
import forge.game.replacement.ReplacementEffect;
|
||||
import forge.game.replacement.ReplacementHandler;
|
||||
import forge.game.replacement.ReplacementLayer;
|
||||
import forge.game.spellability.*;
|
||||
import forge.game.trigger.Trigger;
|
||||
import forge.game.trigger.TriggerHandler;
|
||||
import forge.game.trigger.TriggerType;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.Lang;
|
||||
import forge.util.TextUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@@ -363,10 +371,11 @@ public final class GameActionUtil {
|
||||
}
|
||||
SpellAbility result = null;
|
||||
final Card host = sa.getHostCard();
|
||||
final Game game = host.getGame();
|
||||
final Player activator = sa.getActivatingPlayer();
|
||||
final PlayerController pc = activator.getController();
|
||||
|
||||
host.getGame().getAction().checkStaticAbilities(false);
|
||||
game.getAction().checkStaticAbilities(false);
|
||||
|
||||
boolean reset = false;
|
||||
|
||||
@@ -429,7 +438,60 @@ public final class GameActionUtil {
|
||||
int v = pc.chooseNumberForKeywordCost(sa, cost, ki, str, Integer.MAX_VALUE);
|
||||
|
||||
if (v > 0) {
|
||||
host.addReplacementEffect(CardFactoryUtil.makeEtbCounter("etbCounter:P1P1:" + v, host, false));
|
||||
|
||||
final Card eff = new Card(game.nextCardId(), game);
|
||||
eff.setTimestamp(game.getNextTimestamp());
|
||||
eff.setName(c.getName() + "'s Effect");
|
||||
eff.addType("Effect");
|
||||
eff.setToken(true); // Set token to true, so when leaving play it gets nuked
|
||||
eff.setOwner(activator);
|
||||
|
||||
eff.setImageKey(c.getImageKey());
|
||||
eff.setColor(MagicColor.COLORLESS);
|
||||
eff.setImmutable(true);
|
||||
// try to get the SpellAbility from the mana ability
|
||||
//eff.setEffectSource((SpellAbility)null);
|
||||
|
||||
eff.addRemembered(host);
|
||||
|
||||
String abStr = "DB$ PutCounter | Defined$ ReplacedCard | CounterType$ P1P1 | ETB$ True | CounterNum$ " + v;
|
||||
|
||||
SpellAbility saAb = AbilityFactory.getAbility(abStr, c);
|
||||
|
||||
CardFactoryUtil.setupETBReplacementAbility(saAb);
|
||||
|
||||
String desc = "It enters the battlefield with ";
|
||||
desc += Lang.nounWithNumeral(v, CounterType.P1P1.getName() + " counter");
|
||||
desc += " on it.";
|
||||
|
||||
String repeffstr = "Event$ Moved | ValidCard$ Card.IsRemembered | Destination$ Battlefield | Description$ " + desc;
|
||||
|
||||
ReplacementEffect re = ReplacementHandler.parseReplacement(repeffstr, eff, true);
|
||||
re.setLayer(ReplacementLayer.Other);
|
||||
re.setOverridingAbility(saAb);
|
||||
|
||||
eff.addReplacementEffect(re);
|
||||
|
||||
// Forgot Trigger
|
||||
String trig = "Mode$ ChangesZone | ValidCard$ Card.IsRemembered | Origin$ Stack | Destination$ Any | TriggerZones$ Command | Static$ True";
|
||||
String forgetEffect = "DB$ Pump | ForgetObjects$ TriggeredCard";
|
||||
String exileEffect = "DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile"
|
||||
+ " | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ EQ0";
|
||||
|
||||
SpellAbility saForget = AbilityFactory.getAbility(forgetEffect, eff);
|
||||
AbilitySub saExile = (AbilitySub) AbilityFactory.getAbility(exileEffect, eff);
|
||||
saForget.setSubAbility(saExile);
|
||||
|
||||
final Trigger parsedTrigger = TriggerHandler.parseTrigger(trig, eff, true);
|
||||
parsedTrigger.setOverridingAbility(saForget);
|
||||
eff.addTrigger(parsedTrigger);
|
||||
eff.updateStateForView();
|
||||
|
||||
// TODO: Add targeting to the effect so it knows who it's dealing with
|
||||
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
||||
game.getAction().moveTo(ZoneType.Command, eff, null);
|
||||
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
||||
|
||||
if (result == null) {
|
||||
result = sa.copy();
|
||||
}
|
||||
|
||||
@@ -6353,6 +6353,10 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
removeSVar("PayX"); // Temporary AI X announcement variable
|
||||
removeSVar("IsCastFromPlayEffect"); // Temporary SVar indicating that the spell is cast indirectly via AF Play
|
||||
setSunburstValue(0); // Sunburst
|
||||
setXManaCostPaid(0);
|
||||
setXManaCostPaidByColor(null);
|
||||
setKickerMagnitude(0);
|
||||
setPseudoMultiKickerMagnitude(0);
|
||||
}
|
||||
|
||||
public final int getFinalChapterNr() {
|
||||
|
||||
@@ -20,7 +20,6 @@ package forge.game.card;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
@@ -3010,24 +3009,43 @@ public class CardFactoryUtil {
|
||||
|
||||
inst.addTrigger(parsedTrigger);
|
||||
} else if (keyword.startsWith("Saga")) {
|
||||
// Saga there doesn't need Max value anymore?
|
||||
final String[] k = keyword.split(":");
|
||||
final String[] abs = k[2].split(",");
|
||||
final List<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;
|
||||
for (String ab : abs) {
|
||||
SpellAbility sa = AbilityFactory.getAbility(card, ab);
|
||||
sa.setChapter(i);
|
||||
int idx = 0;
|
||||
int skipId = 0;
|
||||
for(String ab : abs) {
|
||||
idx += 1;
|
||||
if (idx <= skipId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO better logic for Roman numbers
|
||||
// In the Description try to merge Chapter trigger with the Same Effect
|
||||
String trigStr = "Mode$ CounterAdded | ValidCard$ Card.Self | TriggerZones$ Battlefield"
|
||||
+ "| CounterType$ LORE | CounterAmount$ EQ" + i
|
||||
+ "| TriggerDescription$ " + Strings.repeat("I", i) + " - " + sa.getDescription();
|
||||
final Trigger t = TriggerHandler.parseTrigger(trigStr, card, intrinsic);
|
||||
t.setOverridingAbility(sa);
|
||||
inst.addTrigger(t);
|
||||
++i;
|
||||
skipId = idx + abs.subList(idx - 1, abs.size()).lastIndexOf(ab);
|
||||
StringBuilder desc = new StringBuilder();
|
||||
for (int i = idx; i <= skipId; i++) {
|
||||
if (i != idx) {
|
||||
desc.append(", ");
|
||||
}
|
||||
desc.append(TextUtil.toRoman(i));
|
||||
}
|
||||
|
||||
for (int i = idx; i <= skipId; i++) {
|
||||
SpellAbility sa = AbilityFactory.getAbility(card, ab);
|
||||
sa.setChapter(i);
|
||||
|
||||
StringBuilder trigStr = new StringBuilder("Mode$ CounterAdded | ValidCard$ Card.Self | TriggerZones$ Battlefield");
|
||||
trigStr.append("| CounterType$ LORE | CounterAmount$ EQ").append(i);
|
||||
if (i != idx) {
|
||||
trigStr.append(" | Secondary$ True");
|
||||
}
|
||||
trigStr.append("| TriggerDescription$ ").append(desc).append(" — ").append(sa.getDescription());
|
||||
final Trigger t = TriggerHandler.parseTrigger(trigStr.toString(), card, intrinsic);
|
||||
t.setOverridingAbility(sa);
|
||||
inst.addTrigger(t);
|
||||
}
|
||||
}
|
||||
} else if (keyword.equals("Soulbond")) {
|
||||
// Setup ETB trigger for card with Soulbond keyword
|
||||
|
||||
@@ -882,6 +882,10 @@ public class Combat {
|
||||
return true; // is blocking something at the moment
|
||||
}
|
||||
|
||||
if (!blocker.isLKI()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CombatLki lki = lkiCache.get(blocker);
|
||||
return null != lki && !lki.isAttacker; // was blocking something anyway
|
||||
}
|
||||
@@ -893,6 +897,10 @@ public class Combat {
|
||||
return true; // is blocking the attacker's band at the moment
|
||||
}
|
||||
|
||||
if (!blocker.isLKI()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CombatLki lki = lkiCache.get(blocker);
|
||||
return null != lki && !lki.isAttacker && lki.relatedBands.contains(ab); // was blocking that very band
|
||||
}
|
||||
|
||||
@@ -254,7 +254,7 @@ public class ManaPool extends ManaConversionMatrix implements Iterable<Mana> {
|
||||
}
|
||||
}
|
||||
if (mana.addsCounters(sa)) {
|
||||
mana.getManaAbility().createETBCounters(host);
|
||||
mana.getManaAbility().createETBCounters(host, this.owner);
|
||||
}
|
||||
if (mana.triggersWhenSpent()) {
|
||||
mana.getManaAbility().addTriggersWhenSpent(sa, host);
|
||||
|
||||
@@ -19,9 +19,11 @@ package forge.game.spellability;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import forge.card.ColorSet;
|
||||
import forge.card.MagicColor;
|
||||
import forge.card.mana.ManaAtom;
|
||||
import forge.game.Game;
|
||||
import forge.game.ability.AbilityFactory;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
@@ -34,6 +36,8 @@ import forge.game.replacement.*;
|
||||
import forge.game.trigger.Trigger;
|
||||
import forge.game.trigger.TriggerHandler;
|
||||
import forge.game.trigger.TriggerType;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.Lang;
|
||||
import forge.util.TextUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@@ -227,10 +231,26 @@ public class AbilityManaPart implements java.io.Serializable {
|
||||
/**
|
||||
* createETBCounters
|
||||
*/
|
||||
public void createETBCounters(Card c) {
|
||||
public void createETBCounters(Card c, Player controller) {
|
||||
String[] parse = this.addsCounters.split("_");
|
||||
// Convert random SVars if there are other cards with this effect
|
||||
if (c.isValid(parse[0], c.getController(), c, null)) {
|
||||
final Game game = this.sourceCard.getGame();
|
||||
final Card eff = new Card(game.nextCardId(), game);
|
||||
eff.setTimestamp(game.getNextTimestamp());
|
||||
eff.setName(sourceCard.getName() + "'s Effect");
|
||||
eff.addType("Effect");
|
||||
eff.setToken(true); // Set token to true, so when leaving play it gets nuked
|
||||
eff.setOwner(controller);
|
||||
|
||||
eff.setImageKey(sourceCard.getImageKey());
|
||||
eff.setColor(MagicColor.COLORLESS);
|
||||
eff.setImmutable(true);
|
||||
// try to get the SpellAbility from the mana ability
|
||||
//eff.setEffectSource((SpellAbility)null);
|
||||
|
||||
eff.addRemembered(c);
|
||||
|
||||
String abStr = "DB$ PutCounter | Defined$ ReplacedCard | CounterType$ " + parse[1]
|
||||
+ " | ETB$ True | CounterNum$ " + parse[2];
|
||||
|
||||
@@ -240,15 +260,37 @@ public class AbilityManaPart implements java.io.Serializable {
|
||||
}
|
||||
CardFactoryUtil.setupETBReplacementAbility(sa);
|
||||
|
||||
String repeffstr = "Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield "
|
||||
+ " | Secondary$ True | Description$ CARDNAME"
|
||||
+ " enters the battlefield with " + CounterType.valueOf(parse[1]).getName() + " counters.";
|
||||
String desc = "It enters the battlefield with ";
|
||||
desc += Lang.nounWithNumeral(parse[2], CounterType.valueOf(parse[1]).getName() + " counter");
|
||||
desc += " on it.";
|
||||
|
||||
ReplacementEffect re = ReplacementHandler.parseReplacement(repeffstr, c, false);
|
||||
String repeffstr = "Event$ Moved | ValidCard$ Card.IsRemembered | Destination$ Battlefield | Description$ " + desc;
|
||||
|
||||
ReplacementEffect re = ReplacementHandler.parseReplacement(repeffstr, eff, true);
|
||||
re.setLayer(ReplacementLayer.Other);
|
||||
re.setOverridingAbility(sa);
|
||||
|
||||
c.addReplacementEffect(re);
|
||||
eff.addReplacementEffect(re);
|
||||
|
||||
// Forgot Trigger
|
||||
String trig = "Mode$ ChangesZone | ValidCard$ Card.IsRemembered | Origin$ Stack | Destination$ Any | TriggerZones$ Command | Static$ True";
|
||||
String forgetEffect = "DB$ Pump | ForgetObjects$ TriggeredCard";
|
||||
String exileEffect = "DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile"
|
||||
+ " | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ EQ0";
|
||||
|
||||
SpellAbility saForget = AbilityFactory.getAbility(forgetEffect, eff);
|
||||
AbilitySub saExile = (AbilitySub) AbilityFactory.getAbility(exileEffect, eff);
|
||||
saForget.setSubAbility(saExile);
|
||||
|
||||
final Trigger parsedTrigger = TriggerHandler.parseTrigger(trig, eff, true);
|
||||
parsedTrigger.setOverridingAbility(saForget);
|
||||
eff.addTrigger(parsedTrigger);
|
||||
eff.updateStateForView();
|
||||
|
||||
// TODO: Add targeting to the effect so it knows who it's dealing with
|
||||
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
||||
game.getAction().moveTo(ZoneType.Command, eff, null);
|
||||
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1299,6 +1299,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
String announce = getParam("Announce");
|
||||
if (StringUtils.isBlank(announce)) {
|
||||
mapParams.put("Announce", variable);
|
||||
originalMapParams.put("Announce", variable);
|
||||
return;
|
||||
}
|
||||
String[] announcedOnes = TextUtil.split(announce, ',');
|
||||
@@ -1308,6 +1309,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
}
|
||||
}
|
||||
mapParams.put("Announce", announce + ";" + variable);
|
||||
originalMapParams.put("Announce", announce + ";" + variable);
|
||||
}
|
||||
|
||||
public boolean isXCost() {
|
||||
|
||||
@@ -100,17 +100,21 @@ public class TrackableTypes {
|
||||
if (newCollection != null) {
|
||||
//swap in objects in old collection for objects in new collection
|
||||
for (int i = 0; i < newCollection.size(); i++) {
|
||||
T newObj = newCollection.get(i);
|
||||
if (newObj != null) {
|
||||
T existingObj = from.getTracker().getObj(itemType, newObj.getId());
|
||||
if (existingObj != null) { //if object exists already, update its changed properties
|
||||
existingObj.copyChangedProps(newObj);
|
||||
newCollection.remove(i);
|
||||
newCollection.add(i, existingObj);
|
||||
}
|
||||
else { //if object is new, cache in object lookup
|
||||
from.getTracker().putObj(itemType, newObj.getId(), newObj);
|
||||
try {
|
||||
T newObj = newCollection.get(i);
|
||||
if (newObj != null) {
|
||||
T existingObj = from.getTracker().getObj(itemType, newObj.getId());
|
||||
if (existingObj != null) { //if object exists already, update its changed properties
|
||||
existingObj.copyChangedProps(newObj);
|
||||
newCollection.remove(i);
|
||||
newCollection.add(i, existingObj);
|
||||
}
|
||||
else { //if object is new, cache in object lookup
|
||||
from.getTracker().putObj(itemType, newObj.getId(), newObj);
|
||||
}
|
||||
}
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
System.err.println("got an IndexOutOfBoundsException, trying to continue ...");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<uses-sdk
|
||||
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.VIBRATE"/>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
|
||||
@@ -142,7 +142,7 @@
|
||||
<debug>true</debug>
|
||||
</sign>
|
||||
<sdk>
|
||||
<platform>25</platform>
|
||||
<platform>26</platform>
|
||||
</sdk>
|
||||
<dexForceJumbo>true</dexForceJumbo>
|
||||
<androidManifestFile>${project.basedir}/AndroidManifest.xml</androidManifestFile>
|
||||
@@ -183,7 +183,7 @@
|
||||
<debug>false</debug>
|
||||
</sign>
|
||||
<sdk>
|
||||
<platform>25</platform>
|
||||
<platform>26</platform>
|
||||
</sdk>
|
||||
<zipalign>
|
||||
<verbose>false</verbose>
|
||||
|
||||
@@ -9,4 +9,4 @@
|
||||
|
||||
# Project target.
|
||||
project.type=0
|
||||
target=android-20
|
||||
target=android-26
|
||||
|
||||
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#f0f0f0</color>
|
||||
<color name="ic_launcher_background">#ffffff</color>
|
||||
</resources>
|
||||
@@ -103,7 +103,7 @@ public final class CEditorConstructed extends CDeckEditor<Deck> {
|
||||
case TinyLeaders:
|
||||
allSections.add(DeckSection.Commander);
|
||||
|
||||
commanderFilter = CardRulesPredicates.Presets.CAN_BE_COMMANDER;
|
||||
commanderFilter = CardRulesPredicates.Presets.CAN_BE_TINY_LEADERS_COMMANDER;
|
||||
commanderPool = ItemPool.createFrom(FModel.getMagicDb().getCommonCards().getAllCards(Predicates.compose(commanderFilter, PaperCard.FN_GET_RULES)), PaperCard.class);
|
||||
normalPool = ItemPool.createFrom(FModel.getMagicDb().getCommonCards().getAllCards(), PaperCard.class);
|
||||
|
||||
|
||||
@@ -23,6 +23,13 @@ public enum CSubmenuDownloaders implements ICDoc {
|
||||
VSubmenuDownloaders.SINGLETON_INSTANCE.showLicensing();
|
||||
}
|
||||
};
|
||||
private final UiCommand cmdCheckForUpdates = new UiCommand() {
|
||||
@Override
|
||||
public void run() {
|
||||
new AutoUpdater(false).attemptToUpdate();
|
||||
}
|
||||
};
|
||||
|
||||
private final UiCommand cmdPicDownload = new UiCommand() {
|
||||
@Override public void run() {
|
||||
new GuiDownloader(new GuiDownloadPicturesLQ()).show();
|
||||
@@ -84,6 +91,7 @@ public enum CSubmenuDownloaders implements ICDoc {
|
||||
@Override
|
||||
public void initialize() {
|
||||
final VSubmenuDownloaders view = VSubmenuDownloaders.SINGLETON_INSTANCE;
|
||||
view.setCheckForUpdatesCommand(cmdCheckForUpdates);
|
||||
view.setDownloadPicsCommand(cmdPicDownload);
|
||||
view.setDownloadPicsHQCommand(cmdPicDownloadHQ);
|
||||
view.setDownloadSetPicsCommand(cmdSetDownload);
|
||||
|
||||
@@ -3,6 +3,7 @@ package forge.screens.home.settings;
|
||||
import forge.*;
|
||||
import forge.ai.AiProfileUtil;
|
||||
import forge.control.FControl.CloseAction;
|
||||
import forge.download.AutoUpdater;
|
||||
import forge.game.GameLogEntryType;
|
||||
import forge.gui.framework.FScreen;
|
||||
import forge.gui.framework.ICDoc;
|
||||
@@ -225,6 +226,7 @@ public enum CSubmenuPreferences implements ICDoc {
|
||||
initializeGameLogVerbosityComboBox();
|
||||
initializeCloseActionComboBox();
|
||||
initializeDefaultFontSizeComboBox();
|
||||
initializeAutoUpdaterComboBox();
|
||||
initializeMulliganRuleComboBox();
|
||||
initializeAiProfilesComboBox();
|
||||
initializeStackAdditionsComboBox();
|
||||
@@ -378,6 +380,16 @@ public enum CSubmenuPreferences implements ICDoc {
|
||||
panel.setComboBox(comboBox, selectedItem);
|
||||
}
|
||||
|
||||
private void initializeAutoUpdaterComboBox() {
|
||||
// TODO: Ideally we would filter out update paths based on the type of Forge people have
|
||||
final String[] updatePaths = AutoUpdater.updateChannels;
|
||||
final FPref updatePreference = FPref.AUTO_UPDATE;
|
||||
final FComboBoxPanel<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() {
|
||||
final String [] choices = MulliganDefs.getMulliganRuleNames();
|
||||
final FPref userSetting = FPref.MULLIGAN_RULE;
|
||||
|
||||
@@ -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 FScrollPane scrContent = new FScrollPane(pnlContent, false);
|
||||
|
||||
private final FLabel btnCheckForUpdates = _makeButton(localizer.getMessage("btnCheckForUpdates"));
|
||||
private final FLabel btnDownloadSetPics = _makeButton(localizer.getMessage("btnDownloadSetPics"));
|
||||
private final FLabel btnDownloadPics = _makeButton(localizer.getMessage("btnDownloadPics"));
|
||||
private final FLabel btnDownloadPicsHQ = _makeButton(localizer.getMessage("btnDownloadPicsHQ"));
|
||||
@@ -80,6 +81,9 @@ public enum VSubmenuDownloaders implements IVSubmenu<CSubmenuDownloaders> {
|
||||
|
||||
if (javaRecentEnough()) {
|
||||
|
||||
pnlContent.add(btnCheckForUpdates, constraintsBTN);
|
||||
pnlContent.add(_makeLabel(localizer.getMessage("lblCheckForUpdates")), constraintsLBL);
|
||||
|
||||
pnlContent.add(btnDownloadPics, constraintsBTN);
|
||||
pnlContent.add(_makeLabel(localizer.getMessage("lblDownloadPics")), constraintsLBL);
|
||||
|
||||
@@ -162,6 +166,7 @@ public enum VSubmenuDownloaders implements IVSubmenu<CSubmenuDownloaders> {
|
||||
return EMenuGroup.SETTINGS;
|
||||
}
|
||||
|
||||
public void setCheckForUpdatesCommand(UiCommand command) { btnCheckForUpdates.setCommand(command); }
|
||||
public void setDownloadPicsCommand(UiCommand command) { btnDownloadPics.setCommand(command); }
|
||||
public void setDownloadPicsHQCommand(UiCommand command) { btnDownloadPicsHQ.setCommand(command); }
|
||||
public void setDownloadSetPicsCommand(UiCommand command) { btnDownloadSetPics.setCommand(command); }
|
||||
|
||||
@@ -25,8 +25,8 @@ import java.awt.event.FocusAdapter;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
/**
|
||||
@@ -123,6 +123,7 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
|
||||
private final FComboBoxPanel<String> cbpCounterDisplayLocation =new FComboBoxPanel<>(localizer.getMessage("cbpCounterDisplayLocation")+":");
|
||||
private final FComboBoxPanel<String> cbpGraveyardOrdering = new FComboBoxPanel<>(localizer.getMessage("cbpGraveyardOrdering")+":");
|
||||
private final FComboBoxPanel<String> cbpDefaultLanguage = new FComboBoxPanel<>(localizer.getMessage("cbpSelectLanguage")+":");
|
||||
private final FComboBoxPanel<String> cbpAutoUpdater = new FComboBoxPanel<>(localizer.getMessage("cbpAutoUpdater")+":");
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@@ -157,6 +158,10 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
|
||||
pnlPrefs.add(new SectionLabel(localizer.getMessage("GeneralConfiguration")), sectionConstraints);
|
||||
|
||||
// language
|
||||
|
||||
pnlPrefs.add(cbpAutoUpdater, comboBoxConstraints);
|
||||
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlAutoUpdater")), descriptionConstraints);
|
||||
|
||||
pnlPrefs.add(cbpDefaultLanguage, comboBoxConstraints);
|
||||
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlSelectLanguage")), descriptionConstraints);
|
||||
|
||||
@@ -531,6 +536,10 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
|
||||
}
|
||||
}
|
||||
|
||||
public final FComboBoxPanel<String> getCbpAutoUpdater() {
|
||||
return cbpAutoUpdater;
|
||||
}
|
||||
|
||||
/** @return {@link javax.swing.JCheckBox} */
|
||||
public final JCheckBox getCbCompactMainMenu() {
|
||||
return cbCompactMainMenu;
|
||||
|
||||
@@ -81,7 +81,7 @@ public final class Main {
|
||||
break;
|
||||
|
||||
default:
|
||||
System.out.println("Unknown mode.\nKnown mode is 'sim' ");
|
||||
System.out.println("Unknown mode.\nKnown mode is 'sim', 'parse' ");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -209,7 +209,7 @@ public class FSkin {
|
||||
textures.put(f6.path(), textures.get(f3.path()));
|
||||
}
|
||||
if (f7.exists()){
|
||||
Texture t = new Texture(f7, false);
|
||||
Texture t = new Texture(f7, true);
|
||||
//t.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
|
||||
textures.put(f7.path(), t);
|
||||
}
|
||||
|
||||
@@ -193,6 +193,15 @@ public enum FSkinImage implements FImage {
|
||||
QUEST_BIG_SWORD (FSkinProp.ICO_QUEST_BIG_SWORD, SourceFile.ICONS),
|
||||
QUEST_BIG_BAG (FSkinProp.ICO_QUEST_BIG_BAG, SourceFile.ICONS),
|
||||
|
||||
//menu icon
|
||||
MENU_GALAXY (FSkinProp.ICO_MENU_GALAXY, SourceFile.ICONS),
|
||||
MENU_STATS (FSkinProp.ICO_MENU_STATS, SourceFile.ICONS),
|
||||
MENU_PUZZLE (FSkinProp.ICO_MENU_PUZZLE, SourceFile.ICONS),
|
||||
MENU_GAUNTLET (FSkinProp.ICO_MENU_GAUNTLET, SourceFile.ICONS),
|
||||
MENU_SEALED (FSkinProp.ICO_MENU_SEALED, SourceFile.ICONS),
|
||||
MENU_DRAFT (FSkinProp.ICO_MENU_DRAFT, SourceFile.ICONS),
|
||||
MENU_CONSTRUCTED (FSkinProp.ICO_MENU_CONSTRUCTED, SourceFile.ICONS),
|
||||
|
||||
//Interface icons
|
||||
QUESTION (FSkinProp.ICO_QUESTION, SourceFile.ICONS),
|
||||
INFORMATION (FSkinProp.ICO_INFORMATION, SourceFile.ICONS),
|
||||
|
||||
@@ -35,6 +35,9 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static forge.card.CardRenderer.CROP_MULTIPLIER;
|
||||
import static forge.card.CardRenderer.isModernFrame;
|
||||
|
||||
public class CardImageRenderer {
|
||||
private static final float BASE_IMAGE_WIDTH = 360;
|
||||
private static final float BASE_IMAGE_HEIGHT = 504;
|
||||
@@ -357,13 +360,19 @@ public class CardImageRenderer {
|
||||
float new_yRotate = (dispH - new_w) /2;
|
||||
boolean rotateSplit = FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_ROTATE_SPLIT_CARDS);
|
||||
boolean rotatePlane = FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_ROTATE_PLANE_OR_PHENOMENON);
|
||||
float croppedArea = isModernFrame(card) ? CROP_MULTIPLIER : 0.97f;
|
||||
float minusxy = isModernFrame(card) ? 0.0f : 0.13f*radius;
|
||||
if (card.getCurrentState().getSetCode().equals("LEA")||card.getCurrentState().getSetCode().equals("LEB")) {
|
||||
croppedArea = 0.975f;
|
||||
minusxy = 0.135f*radius;
|
||||
}
|
||||
if (rotatePlane && (card.getCurrentState().isPhenomenon() || card.getCurrentState().isPlane())) {
|
||||
if (Forge.enableUIMask){
|
||||
if (ImageCache.isExtendedArt(card))
|
||||
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90);
|
||||
else {
|
||||
g.drawRotatedImage(FSkin.getBorders().get(0), new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90);
|
||||
g.drawRotatedImage(ImageCache.croppedBorderImage(image, fullborder), new_x+radius/2, new_y+radius/2, new_w*0.96f, new_h*0.96f, (new_x+radius/2) + (new_w*0.96f) / 2, (new_y+radius/2) + (new_h*0.96f) / 2, -90);
|
||||
g.drawRotatedImage(ImageCache.croppedBorderImage(image, fullborder), new_x+radius/2-minusxy, new_y+radius/2-minusxy, new_w*croppedArea, new_h*croppedArea, (new_x+radius/2-minusxy) + (new_w*croppedArea) / 2, (new_y+radius/2-minusxy) + (new_h*croppedArea) / 2, -90);
|
||||
}
|
||||
} else
|
||||
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90);
|
||||
@@ -374,7 +383,7 @@ public class CardImageRenderer {
|
||||
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90);
|
||||
else {
|
||||
g.drawRotatedImage(FSkin.getBorders().get(ImageCache.getFSkinBorders(card)), new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90);
|
||||
g.drawRotatedImage(ImageCache.croppedBorderImage(image, fullborder), new_x + radius / 2, new_y + radius / 2, new_w * 0.96f, new_h * 0.96f, (new_x + radius / 2) + (new_w * 0.96f) / 2, (new_y + radius / 2) + (new_h * 0.96f) / 2, isAftermath ? 90 : -90);
|
||||
g.drawRotatedImage(ImageCache.croppedBorderImage(image, fullborder), new_x + radius / 2-minusxy, new_y + radius / 2-minusxy, new_w * croppedArea, new_h * croppedArea, (new_x + radius / 2-minusxy) + (new_w * croppedArea) / 2, (new_y + radius / 2-minusxy) + (new_h * croppedArea) / 2, isAftermath ? 90 : -90);
|
||||
}
|
||||
} else
|
||||
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90);
|
||||
@@ -384,7 +393,7 @@ public class CardImageRenderer {
|
||||
g.drawImage(image, x, y, w, h);
|
||||
else {
|
||||
g.drawImage(ImageCache.getBorderImage(card, canshow), x, y, w, h);
|
||||
g.drawImage(ImageCache.croppedBorderImage(image, fullborder), x + radius / 2.4f, y + radius / 2, w * 0.96f, h * 0.96f);
|
||||
g.drawImage(ImageCache.croppedBorderImage(image, fullborder), x + radius / 2.4f-minusxy, y + radius / 2-minusxy, w * croppedArea, h * croppedArea);
|
||||
}
|
||||
} else {
|
||||
if (canshow && !ImageKeys.getTokenKey(ImageKeys.MORPH_IMAGE).equals(card.getState(altState).getImageKey()))
|
||||
|
||||
@@ -105,6 +105,7 @@ public class CardRenderer {
|
||||
private static final float NAME_COST_THRESHOLD = Utils.scale(200);
|
||||
private static final float BORDER_THICKNESS = Utils.scale(1);
|
||||
public static final float PADDING_MULTIPLIER = 0.021f;
|
||||
public static final float CROP_MULTIPLIER = 0.96f;
|
||||
|
||||
private static Map<Integer, BitmapFont> counterFonts = new HashMap<>();
|
||||
private static final Color counterBackgroundColor = new Color(0f, 0f, 0f, 0.9f);
|
||||
@@ -142,6 +143,49 @@ public class CardRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isModernFrame(IPaperCard c) {
|
||||
if (c == null)
|
||||
return false;
|
||||
|
||||
CardEdition ed = FModel.getMagicDb().getEditions().get(c.getEdition());
|
||||
if (ed != null) {
|
||||
switch (ed.getCode()) {
|
||||
case "MED":
|
||||
case "ME2":
|
||||
case "ME3":
|
||||
case "ME4":
|
||||
case "TSB":
|
||||
return false;
|
||||
default:
|
||||
return ed.isModern();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isModernFrame(CardView c) {
|
||||
if (c == null)
|
||||
return false;
|
||||
|
||||
CardView.CardStateView state = c.getCurrentState();
|
||||
CardEdition ed = FModel.getMagicDb().getEditions().get(state.getSetCode());
|
||||
if (ed != null) {
|
||||
switch (ed.getCode()) {
|
||||
case "MED":
|
||||
case "ME2":
|
||||
case "ME3":
|
||||
case "ME4":
|
||||
case "TSB":
|
||||
return false;
|
||||
default:
|
||||
return ed.isModern();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static float getCardListItemHeight(boolean compactMode) {
|
||||
if (compactMode) {
|
||||
return MANA_SYMBOL_SIZE + 2 * FList.PADDING;
|
||||
@@ -402,7 +446,12 @@ public class CardRenderer {
|
||||
public static void drawCard(Graphics g, IPaperCard pc, float x, float y, float w, float h, CardStackPosition pos) {
|
||||
Texture image = new RendererCachedCardImage(pc, false).getImage();
|
||||
float radius = (h - w)/8;
|
||||
|
||||
float croppedArea = isModernFrame(pc) ? CROP_MULTIPLIER : 0.97f;
|
||||
float minusxy = isModernFrame(pc) ? 0.0f : 0.13f*radius;
|
||||
if (pc.getEdition().equals("LEA")||pc.getEdition().equals("LEB")) {
|
||||
croppedArea = 0.975f;
|
||||
minusxy = 0.135f*radius;
|
||||
}
|
||||
if (image != null) {
|
||||
if (image == ImageCache.defaultImage) {
|
||||
CardImageRenderer.drawCardImage(g, CardView.getCardForUi(pc), false, x, y, w, h, pos);
|
||||
@@ -413,7 +462,7 @@ public class CardRenderer {
|
||||
g.drawImage(image, x, y, w, h);
|
||||
else {
|
||||
g.drawImage(ImageCache.getBorderImage(pc), x, y, w, h);
|
||||
g.drawImage(ImageCache.croppedBorderImage(image, fullborder), x + radius / 2.4f, y + radius / 2, w * 0.96f, h * 0.96f);
|
||||
g.drawImage(ImageCache.croppedBorderImage(image, fullborder), x + radius / 2.4f-minusxy, y + radius / 2-minusxy, w * croppedArea, h * croppedArea);
|
||||
}
|
||||
} else
|
||||
g.drawImage(image, x, y, w, h);
|
||||
@@ -437,7 +486,12 @@ public class CardRenderer {
|
||||
Texture image = new RendererCachedCardImage(card, false).getImage();
|
||||
FImage sleeves = MatchController.getPlayerSleeve(card.getOwner());
|
||||
float radius = (h - w)/8;
|
||||
|
||||
float croppedArea = isModernFrame(card) ? CROP_MULTIPLIER : 0.97f;
|
||||
float minusxy = isModernFrame(card) ? 0.0f : 0.13f*radius;
|
||||
if (card.getCurrentState().getSetCode().equals("LEA")||card.getCurrentState().getSetCode().equals("LEB")) {
|
||||
croppedArea = 0.975f;
|
||||
minusxy = 0.135f*radius;
|
||||
}
|
||||
if (image != null) {
|
||||
if (image == ImageCache.defaultImage) {
|
||||
CardImageRenderer.drawCardImage(g, card, false, x, y, w, h, pos);
|
||||
@@ -450,7 +504,7 @@ public class CardRenderer {
|
||||
g.drawRotatedImage(image, x, y, w, h, x + w / 2, y + h / 2, -90);
|
||||
else {
|
||||
g.drawRotatedImage(FSkin.getBorders().get(0), x, y, w, h, x + w / 2, y + h / 2, -90);
|
||||
g.drawRotatedImage(ImageCache.croppedBorderImage(image, fullborder), x+radius/2.3f, y+radius/2, w*0.96f, h*0.96f, (x+radius/2.3f) + (w*0.96f) / 2, (y+radius/2) + (h*0.96f) / 2, -90);
|
||||
g.drawRotatedImage(ImageCache.croppedBorderImage(image, fullborder), x+radius/2.3f-minusxy, y+radius/2-minusxy, w*croppedArea, h*croppedArea, (x+radius/2.3f-minusxy) + (w*croppedArea) / 2, (y+radius/2-minusxy) + (h*croppedArea) / 2, -90);
|
||||
}
|
||||
} else
|
||||
g.drawRotatedImage(image, x, y, w, h, x + w / 2, y + h / 2, -90);
|
||||
@@ -461,7 +515,7 @@ public class CardRenderer {
|
||||
else {
|
||||
boolean t = (card.getCurrentState().getOriginalColors() != card.getCurrentState().getColors()) || card.getCurrentState().hasChangeColors();
|
||||
g.drawBorderImage(ImageCache.getBorderImage(card, canshow), ImageCache.getTint(card), x, y, w, h, t); //tint check for changed colors
|
||||
g.drawImage(ImageCache.croppedBorderImage(image, fullborder), x + radius / 2.4f, y + radius / 2, w * 0.96f, h * 0.96f);
|
||||
g.drawImage(ImageCache.croppedBorderImage(image, fullborder), x + radius / 2.4f-minusxy, y + radius / 2-minusxy, w * croppedArea, h * croppedArea);
|
||||
}
|
||||
} else {
|
||||
if (canshow)
|
||||
@@ -1119,8 +1173,14 @@ public class CardRenderer {
|
||||
|
||||
public static void drawFoilEffect(Graphics g, CardView card, float x, float y, float w, float h, boolean inZoomer) {
|
||||
float new_x = x; float new_y = y; float new_w = w; float new_h = h; float radius = (h - w)/8;
|
||||
float croppedArea = isModernFrame(card) ? CROP_MULTIPLIER : 0.97f;
|
||||
float minusxy = isModernFrame(card) ? 0.0f : 0.13f*radius;
|
||||
if (card.getCurrentState().getSetCode().equals("LEA")||card.getCurrentState().getSetCode().equals("LEB")) {
|
||||
croppedArea = 0.975f;
|
||||
minusxy = 0.135f*radius;
|
||||
}
|
||||
if (Forge.enableUIMask) {
|
||||
new_x += radius/2.4f; new_y += radius/2; new_w = w * 0.96f; new_h = h * 0.96f;
|
||||
new_x += radius/2.4f-minusxy; new_y += radius/2-minusxy; new_w = w * croppedArea; new_h = h * croppedArea;
|
||||
}
|
||||
if (isPreferenceEnabled(FPref.UI_OVERLAY_FOIL_EFFECT) && MatchController.instance.mayView(card)) {
|
||||
boolean rotateSplit = isPreferenceEnabled(FPref.UI_ROTATE_SPLIT_CARDS) && card.isSplitCard() && inZoomer;
|
||||
|
||||
@@ -219,7 +219,22 @@ public class CardZoom extends FOverlay {
|
||||
float w = getWidth();
|
||||
float h = getHeight();
|
||||
float messageHeight = FDialog.MSG_HEIGHT;
|
||||
float maxCardHeight = h - 2 * messageHeight;
|
||||
float AspectRatioMultiplier = 2;
|
||||
switch (Forge.extrawide) {
|
||||
case "default":
|
||||
AspectRatioMultiplier = 3; //good for tablets with 16:10 or similar
|
||||
break;
|
||||
case "wide":
|
||||
AspectRatioMultiplier = 2.5f;
|
||||
break;
|
||||
case "extrawide":
|
||||
AspectRatioMultiplier = 2; //good for tall phones with 21:9 or similar
|
||||
break;
|
||||
default:
|
||||
AspectRatioMultiplier = 3;
|
||||
break;
|
||||
}
|
||||
float maxCardHeight = h - AspectRatioMultiplier * messageHeight; //maxheight of currently zoomed card
|
||||
|
||||
float cardWidth, cardHeight, y;
|
||||
|
||||
|
||||
@@ -856,6 +856,9 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
||||
case Brawl:
|
||||
isLegalCommander = card.getRules().canBeBrawlCommander();
|
||||
break;
|
||||
case TinyLeaders:
|
||||
isLegalCommander = card.getRules().canBeTinyLeadersCommander();
|
||||
break;
|
||||
case Oathbreaker:
|
||||
isLegalCommander = card.getRules().canBeOathbreaker();
|
||||
captionSuffix = localizer.getMessage("lblOathbreaker");
|
||||
|
||||
@@ -20,11 +20,11 @@ import forge.util.Localizer;
|
||||
|
||||
public class LoadGameMenu extends FPopupMenu {
|
||||
public enum LoadGameScreen {
|
||||
BoosterDraft("lblBoosterDraft", FSkinImage.HAND, LoadDraftScreen.class),
|
||||
SealedDeck("lblSealedDeck", FSkinImage.PACK, LoadSealedScreen.class),
|
||||
BoosterDraft("lblBoosterDraft", FSkinImage.MENU_DRAFT, LoadDraftScreen.class),
|
||||
SealedDeck("lblSealedDeck", FSkinImage.MENU_SEALED, LoadSealedScreen.class),
|
||||
QuestMode("lblQuestMode", FSkinImage.QUEST_ZEP, LoadQuestScreen.class),
|
||||
PlanarConquest("lblPlanarConquest", FSkinImage.MULTIVERSE, LoadConquestScreen.class),
|
||||
Gauntlet("lblGauntlet", FSkinImage.ALPHASTRIKE, LoadGauntletScreen.class);
|
||||
PlanarConquest("lblPlanarConquest", FSkinImage.MENU_GALAXY, LoadConquestScreen.class),
|
||||
Gauntlet("lblGauntlet", FSkinImage.MENU_GAUNTLET, LoadGauntletScreen.class);
|
||||
|
||||
private final FMenuItem item;
|
||||
private final Class<? extends FScreen> screenClass;
|
||||
|
||||
@@ -24,13 +24,13 @@ public class NewGameMenu extends FPopupMenu {
|
||||
final static Localizer localizer = Localizer.getInstance();
|
||||
|
||||
public enum NewGameScreen {
|
||||
Constructed(localizer.getMessage("lblConstructed"), FSkinImage.DECKLIST, ConstructedScreen.class),
|
||||
BoosterDraft(localizer.getMessage("lblBoosterDraft"), FSkinImage.HAND, NewDraftScreen.class),
|
||||
SealedDeck(localizer.getMessage("lblSealedDeck"), FSkinImage.PACK, NewSealedScreen.class),
|
||||
Constructed(localizer.getMessage("lblConstructed"), FSkinImage.MENU_CONSTRUCTED, ConstructedScreen.class),
|
||||
BoosterDraft(localizer.getMessage("lblBoosterDraft"), FSkinImage.MENU_DRAFT, NewDraftScreen.class),
|
||||
SealedDeck(localizer.getMessage("lblSealedDeck"), FSkinImage.MENU_SEALED, NewSealedScreen.class),
|
||||
QuestMode(localizer.getMessage("lblQuestMode"), FSkinImage.QUEST_ZEP, NewQuestScreen.class),
|
||||
PuzzleMode(localizer.getMessage("lblPuzzleMode"), FSkinImage.QUEST_BOOK, PuzzleScreen.class),
|
||||
PlanarConquest(localizer.getMessage("lblPlanarConquest"), FSkinImage.MULTIVERSE, NewConquestScreen.class),
|
||||
Gauntlet(localizer.getMessage("lblGauntlet"), FSkinImage.ALPHASTRIKE, NewGauntletScreen.class);
|
||||
PuzzleMode(localizer.getMessage("lblPuzzleMode"), FSkinImage.MENU_PUZZLE, PuzzleScreen.class),
|
||||
PlanarConquest(localizer.getMessage("lblPlanarConquest"), FSkinImage.MENU_GALAXY, NewConquestScreen.class),
|
||||
Gauntlet(localizer.getMessage("lblGauntlet"), FSkinImage.MENU_GAUNTLET, NewGauntletScreen.class);
|
||||
|
||||
private final FMenuItem item;
|
||||
private final Class<? extends FScreen> screenClass;
|
||||
|
||||
@@ -54,36 +54,45 @@ public class PuzzleScreen extends LaunchScreen {
|
||||
final ArrayList<Puzzle> puzzles = PuzzleIO.loadPuzzles();
|
||||
Collections.sort(puzzles);
|
||||
|
||||
GuiChoose.one(Localizer.getInstance().getMessage("lblChooseAPuzzle"), puzzles, new Callback<Puzzle>() {
|
||||
GuiChoose.oneOrNone(Localizer.getInstance().getMessage("lblChooseAPuzzle"), puzzles, new Callback<Puzzle>() {
|
||||
@Override
|
||||
public void run(final Puzzle chosen) {
|
||||
LoadingOverlay.show(Localizer.getInstance().getMessage("lblLoadingThePuzzle"), new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Load selected puzzle
|
||||
final HostedMatch hostedMatch = GuiBase.getInterface().hostMatch();
|
||||
hostedMatch.setStartGameHook(new Runnable() {
|
||||
@Override
|
||||
public final void run() {
|
||||
chosen.applyToGame(hostedMatch.getGame());
|
||||
}
|
||||
});
|
||||
if (chosen != null) {
|
||||
LoadingOverlay.show(Localizer.getInstance().getMessage("lblLoadingThePuzzle"), new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Load selected puzzle
|
||||
final HostedMatch hostedMatch = GuiBase.getInterface().hostMatch();
|
||||
hostedMatch.setStartGameHook(new Runnable() {
|
||||
@Override
|
||||
public final void run() {
|
||||
chosen.applyToGame(hostedMatch.getGame());
|
||||
}
|
||||
});
|
||||
|
||||
final List<RegisteredPlayer> players = new ArrayList<>();
|
||||
final RegisteredPlayer human = new RegisteredPlayer(new Deck()).setPlayer(GamePlayerUtil.getGuiPlayer());
|
||||
human.setStartingHand(0);
|
||||
players.add(human);
|
||||
hostedMatch.setEndGameHook((new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
chosen.savePuzzleSolve(hostedMatch.getGame().getOutcome().isWinner(GamePlayerUtil.getGuiPlayer()));
|
||||
}
|
||||
}));
|
||||
|
||||
final RegisteredPlayer ai = new RegisteredPlayer(new Deck()).setPlayer(GamePlayerUtil.createAiPlayer());
|
||||
ai.setStartingHand(0);
|
||||
players.add(ai);
|
||||
final List<RegisteredPlayer> players = new ArrayList<>();
|
||||
final RegisteredPlayer human = new RegisteredPlayer(new Deck()).setPlayer(GamePlayerUtil.getGuiPlayer());
|
||||
human.setStartingHand(0);
|
||||
players.add(human);
|
||||
|
||||
GameRules rules = new GameRules(GameType.Puzzle);
|
||||
rules.setGamesPerMatch(1);
|
||||
hostedMatch.startMatch(rules, null, players, human, GuiBase.getInterface().getNewGuiGame());
|
||||
FOptionPane.showMessageDialog(chosen.getGoalDescription(), chosen.getName());
|
||||
}
|
||||
});
|
||||
final RegisteredPlayer ai = new RegisteredPlayer(new Deck()).setPlayer(GamePlayerUtil.createAiPlayer());
|
||||
ai.setStartingHand(0);
|
||||
players.add(ai);
|
||||
|
||||
GameRules rules = new GameRules(GameType.Puzzle);
|
||||
rules.setGamesPerMatch(1);
|
||||
hostedMatch.startMatch(rules, null, players, human, GuiBase.getInterface().getNewGuiGame());
|
||||
FOptionPane.showMessageDialog(chosen.getGoalDescription(), chosen.getName());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ public class ConquestMenu extends FPopupMenu {
|
||||
setCurrentScreen(collectionScreen);
|
||||
}
|
||||
});
|
||||
private static final FMenuItem statsItem = new FMenuItem(Localizer.getInstance().getMessage("lblStatistics"), FSkinImage.HDMULTI, new FEventHandler() {
|
||||
private static final FMenuItem statsItem = new FMenuItem(Localizer.getInstance().getMessage("lblStatistics"), FSkinImage.MENU_STATS, new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
setCurrentScreen(statsScreen);
|
||||
|
||||
@@ -244,10 +244,7 @@ public class ConquestRewardDialog extends FScrollPane {
|
||||
//ensure current card in view
|
||||
if (getScrollHeight() > getHeight() && index < cardCount) {
|
||||
CardRevealer currentCard = cardRevealers.get(index);
|
||||
if (!Forge.extrawide.equals("default"))
|
||||
scrollIntoView(currentCard, currentCard.getHeight() / (columnCount * PADDING) / 2);
|
||||
else
|
||||
scrollIntoView(currentCard, currentCard.getHeight() / 2 + PADDING); //show half of the card below
|
||||
scrollIntoView(currentCard, currentCard.getHeight() / (columnCount * PADDING) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ public class QuestMenu extends FPopupMenu implements IVQuestStats {
|
||||
setCurrentScreen(bazaarScreen);
|
||||
}
|
||||
});
|
||||
private static final FMenuItem statsItem = new FMenuItem(Localizer.getInstance().getMessage("lblStatistics"), FSkinImage.HDMULTI, new FEventHandler() {
|
||||
private static final FMenuItem statsItem = new FMenuItem(Localizer.getInstance().getMessage("lblStatistics"), FSkinImage.MENU_STATS, new FEventHandler() {
|
||||
@Override
|
||||
public void handleEvent(FEvent e) {
|
||||
setCurrentScreen(statsScreen);
|
||||
|
||||
@@ -84,3 +84,4 @@ Modern Horizons, 3/6/WAR, MH1
|
||||
Core Set 2020, 3/6/M20, M20
|
||||
Throne of Eldraine, 3/6/ELD, ELD
|
||||
Theros Beyond Death, 3/6/THB, THB
|
||||
Mystery Booster, 3/6/THB, MB1
|
||||
@@ -4,8 +4,9 @@ Types:Creature Elemental Knight
|
||||
PT:4/6
|
||||
K:Vigilance
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDestroy | TriggerDescription$ When CARDNAME enters the battlefield, destroy up to one target nonland permanent. Its controller creates a 3/3 colorless Golem artifact creature token.
|
||||
SVar:TrigDestroy:DB$ Destroy | TargetMin$ 0 | TargetMax$ 1 | ValidTgts$ Permanent.nonLand | TgtPrompt$ Select target nonland permanent | SubAbility$ DBToken
|
||||
SVar:DBToken:DB$ Token | TokenAmount$ 1 | TokenScript$ c_3_3_a_golem | TokenOwner$ TargetedController | LegacyImage$ c 3 3 a golem m20
|
||||
SVar:TrigDestroy:DB$ Destroy | TargetMin$ 0 | TargetMax$ 1 | ValidTgts$ Permanent.nonLand | TgtPrompt$ Select target nonland permanent | RememberLKI$ True | SubAbility$ DBToken
|
||||
SVar:DBToken:DB$ Token | TokenAmount$ 1 | TokenScript$ c_3_3_a_golem | TokenOwner$ RememberedController | LegacyImage$ c 3 3 a golem m20 | SubAbility$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigChangeZone | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME dies, return target artifact or enchantment card from your graveyard to your hand.
|
||||
SVar:TrigChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Hand | ValidTgts$ Artifact.YouCtrl,Enchantment.YouCtrl
|
||||
Oracle:Vigilance\nWhen Cavalier of Dawn enters the battlefield, destroy up to one target nonland permanent. Its controller creates a 3/3 colorless Golem artifact creature token.\nWhen Cavalier of Dawn dies, return target artifact or enchantment card from your graveyard to your hand.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Name:Ghastly Demise
|
||||
ManaCost:B
|
||||
Types:Instant
|
||||
A:SP$ Destroy | Cost$ B | ValidTgts$ Creature.nonBlack+toughnessLEX | TgtPrompt$ Select target nonblack creature with toughness less than or equal to the number of cards in your graveyard. | References$ X | SpellDescription$ Destroy target nonblack creature if its toughness is less than or equal to the number of cards in your graveyard.
|
||||
A:SP$ Destroy | Cost$ B | ValidTgts$ Creature.nonBlack | TgtPrompt$ Select target nonblack creature | ConditionCheckSVar$ Y | ConditionSVarCompare$ LEX | References$ X,Y | StackDescription$ SpellDescription | SpellDescription$ Destroy target nonblack creature if its toughness is less than or equal to the number of cards in your graveyard.
|
||||
SVar:Y:Targeted$CardToughness
|
||||
SVar:X:Count$InYourYard
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/ghastly_demise.jpg
|
||||
Oracle:Destroy target nonblack creature if its toughness is less than or equal to the number of cards in your graveyard.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Name:Joust
|
||||
ManaCost:1 R
|
||||
Types:Sorcery
|
||||
A:SP$ Pump | Cost$ 1 R | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | NumAtt$ +2 | NumDef$ +1 | ConditionDefined$ ThisTargetedCard | ConditionPresent$ Knight | SubAbility$ DBFight | SpellDescription$ Choose target creature you control and target creature you don't control. The creature you control gets +2/+1 until end of turn if it's a Knight. Then those creatures fight each other. (Each deals damage equal to its power to the other.)
|
||||
A:SP$ Pump | Cost$ 1 R | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | NumAtt$ +2 | NumDef$ +1 | AILogic$ Fight | ConditionDefined$ ThisTargetedCard | ConditionPresent$ Knight | SubAbility$ DBFight | SpellDescription$ Choose target creature you control and target creature you don't control. The creature you control gets +2/+1 until end of turn if it's a Knight. Then those creatures fight each other. (Each deals damage equal to its power to the other.)
|
||||
SVar:DBFight:DB$ Fight | Defined$ ParentTarget | ValidTgts$ Creature.YouDontCtrl | AILogic$ Always | TgtPrompt$ Choose target creature you don't control
|
||||
DeckHints:Type$Knight
|
||||
Oracle:Choose target creature you control and target creature you don't control. The creature you control gets +2/+1 until end of turn if it's a Knight. Then those creatures fight each other. (Each deals damage equal to its power to the other.)
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
Name:Nissa's Pilgrimage
|
||||
ManaCost:2 G
|
||||
Types:Sorcery
|
||||
A:SP$ ChangeZone | Cost$ 2 G | Origin$ Library | Destination$ Battlefield | Tapped$ True | ChangeType$ Land.Basic+Forest | ChangeNum$ 1 | SubAbility$ DBChangeZone1 | NoShuffle$ True | SpellDescription$ Search your library for up to two basic Forest cards, reveal those cards, and put one onto the battlefield tapped and the rest into your hand. Then shuffle your library. Spell mastery — If there are two or more instant or sorcery cards in your graveyard, search your library for up to three basic Forest cards instead of two.
|
||||
SVar:DBChangeZone1:DB$ChangeZone | Origin$ Library | Destination$ Hand | SubAbility$ DBChangeZone2 | ChangeType$ Land.Basic+Forest | ChangeNum$ 1 | ConditionCheckSVar$ X | ConditionSVarCompare$ LT2 | References$ X
|
||||
SVar:DBChangeZone2:DB$ChangeZone | Origin$ Library | Destination$ Hand | ChangeType$ Land.Basic+Forest | ChangeNum$ 2 | ConditionCheckSVar$ X | ConditionSVarCompare$ GE2 | References$ X
|
||||
SVar:X:Count$ValidGraveyard Instant.YouOwn,Sorcery.YouOwn
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/nissas_pilgrimage.jpg
|
||||
A:SP$ ChangeZone | Cost$ 2 G | Origin$ Library | Destination$ Library | ChangeType$ Land.Basic+Forest | ChangeNum$ X | References$ X,Y | RememberChanged$ True | SubAbility$ DBBattlefield | Shuffle$ False | StackDescription$ SpellDescription | SpellDescription$ Search your library for up to two basic Forest cards, reveal those cards, and put one onto the battlefield tapped and the rest into your hand. Then shuffle your library. Spell mastery — If there are two or more instant or sorcery cards in your graveyard, search your library for up to three basic Forest cards instead of two.
|
||||
SVar:DBBattlefield:DB$ ChangeZone | Origin$ Library | Destination$ Battlefield | Tapped$ True | SubAbility$ DBHand | ChangeType$ Card.IsRemembered | ChangeNum$ 1 | Mandatory$ True | NoLooking$ True | SelectPrompt$ Select a card to go to the battlefield | Shuffle$ False | StackDescription$ None
|
||||
SVar:DBHand:DB$ ChangeZone | Origin$ Library | Destination$ Hand | Defined$ Remembered | NoLooking$ True | StackDescription$ None | SubAbility$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
SVar:X:Count$Compare Y GE2.3.2
|
||||
SVar:Y:Count$ValidGraveyard Instant.YouOwn,Sorcery.YouOwn
|
||||
Oracle:Search your library for up to two basic Forest cards, reveal those cards, and put one onto the battlefield tapped and the rest into your hand. Then shuffle your library.\nSpell mastery — If there are two or more instant or sorcery cards in your graveyard, search your library for up to three basic Forest cards instead of two.
|
||||
|
||||
@@ -2,7 +2,7 @@ Name:Settle the Wreckage
|
||||
ManaCost:2 W W
|
||||
Types:Instant
|
||||
A:SP$ ChangeZoneAll | Cost$ 2 W W | ValidTgts$ Player | ChangeType$ Creature.attacking | TgtPrompt$ Select target player | Origin$ Battlefield | Destination$ Exile | RememberChanged$ True | SubAbility$ DBGetLands | SpellDescription$ Exile all attacking creatures target player controls. That player may search their library for that many basic lands, put those cards onto the battlefield tapped, then shuffle their library.
|
||||
SVar:DBGetLands:DB$ ChangeZone | Optional$ True | Origin$ Library | Destination$ Battlefield | Tapped$ True | ChangeType$ Land.Basic | ChangeNum$ X | References$ X | DefinedPlayer$ RememberedController | ShuffleNonMandatory$ True | SubAbility$ DBCleanup
|
||||
SVar:DBGetLands:DB$ ChangeZone | Optional$ True | Origin$ Library | Destination$ Battlefield | Tapped$ True | ChangeType$ Land.Basic | ChangeNum$ X | References$ X | DefinedPlayer$ TargetedPlayer | ShuffleNonMandatory$ True | SubAbility$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
SVar:X:Count$RememberedSize
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/settle_the_wreckage.jpg
|
||||
|
||||
@@ -3,7 +3,7 @@ ManaCost:1 W
|
||||
Types:Enchantment Saga
|
||||
K:Saga:3:TrigChange,TrigToken,TrigGainLife
|
||||
SVar:TrigChange:DB$ ChangeZone | Origin$ Library | Destination$ Hand | ChangeType$ Land.Plains+Basic | ChangeNum$ 1 | SpellDescription$ Search your library for a basic Plains card, reveal it, put it into your hand, then shuffle your library.
|
||||
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ c_0_4_wall_defender | TokenOwner$ You | LegacyImage$ c 0 4 wall defender thb | SpellDescription$ Create a 0/4 colorless Wall artifact creature token with defender.
|
||||
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ c_0_4_a_wall_defender | TokenOwner$ You | LegacyImage$ c 0 4 wall defender thb | SpellDescription$ Create a 0/4 colorless Wall artifact creature token with defender.
|
||||
SVar:TrigGainLife:DB$ GainLife | Defined$ You | LifeAmount$ 2 | SpellDescription$ You gain 2 life.
|
||||
DeckHas:Ability$LifeGain & Ability$Token
|
||||
Oracle:(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)\nI - Search your library for a basic Plains card, reveal it, put it into your hand, then shuffle your library.\nII - Create a 0/4 colorless Wall artifact creature token with defender.\nIII - You gain 2 life.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Name:The Triumph of Anax
|
||||
ManaCost:2 R
|
||||
Types:Enchantment Saga
|
||||
K:Saga:3:DBPump,DBPump,DBPump,DBPick
|
||||
K:Saga:4:DBPump,DBPump,DBPump,DBPick
|
||||
SVar:DBPump:DB$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ +X | References$ X | KW$ Trample | SpellDescription$ Until end of turn, target creature gains trample and gets +X/+0, where X is the number of lore counters on CARDNAME.
|
||||
SVar:X:Count$CardCounters.LORE
|
||||
SVar:PlayMain1:TRUE
|
||||
|
||||
@@ -196,14 +196,14 @@ AdditionalSetUnlockedInQuest=MPS_KLD
|
||||
183 C Welder Automaton
|
||||
184 R Spire of Industry
|
||||
185 M Ajani, Valiant Protector
|
||||
186 R Ajani's Aid
|
||||
186 C Inspiring Roar
|
||||
187 U Ajani's Comrade
|
||||
188 C Inspiring Roar
|
||||
188 R Ajani's Aid
|
||||
189 C Tranquil Expanse
|
||||
190 M Tezzeret, Master of Metal
|
||||
191 R Tezzeret's Betrayal
|
||||
192 U Tezzeret's Simulacrum
|
||||
193 C Pendulum of Patterns
|
||||
192 C Pendulum of Patterns
|
||||
193 U Tezzeret's Simulacrum
|
||||
194 C Submerged Boneyard
|
||||
|
||||
[tokens]
|
||||
|
||||
@@ -27,10 +27,10 @@ Foil=NotSupported
|
||||
17 C Curfew
|
||||
18 C Dark Ritual
|
||||
19 R Dirtcowl Wurm
|
||||
20 U Disenchant
|
||||
20 C Disenchant
|
||||
21 C Disruptive Student
|
||||
22 C Drifting Meadow
|
||||
23 C Elvish Lyrist
|
||||
23 U Elvish Lyrist
|
||||
24 C Exhume
|
||||
25 U Fecundity
|
||||
26 C Fertile Ground
|
||||
@@ -40,16 +40,16 @@ Foil=NotSupported
|
||||
30 C Gorilla Warrior
|
||||
31 C Healing Salve
|
||||
32 C Heat Ray
|
||||
33 R Hurricane
|
||||
33 U Hurricane
|
||||
34 C Infantry Veteran
|
||||
35 R Land Tax
|
||||
35 U Land Tax
|
||||
36 R Lhurgoyf
|
||||
37 C Lightning Elemental
|
||||
38 R Living Death
|
||||
39 C Llanowar Elves
|
||||
40 C Man-o'-War
|
||||
41 C Mana Leak
|
||||
42 U Maniacal Rage
|
||||
42 C Maniacal Rage
|
||||
43 C Manta Riders
|
||||
44 C Master Decoy
|
||||
45 U Mogg Hollows
|
||||
@@ -59,7 +59,7 @@ Foil=NotSupported
|
||||
49 U Pestilence
|
||||
50 C Phyrexian Ghoul
|
||||
51 C Pincher Beetles
|
||||
52 U Plated Rootwalla
|
||||
52 C Plated Rootwalla
|
||||
53 C Polluted Mire
|
||||
54 C Prodigal Sorcerer
|
||||
55 C Raging Goblin
|
||||
@@ -72,7 +72,7 @@ Foil=NotSupported
|
||||
62 C Sanctum Custodian
|
||||
63 U Sanctum Guardian
|
||||
64 C Sandstorm
|
||||
65 U Scaled Wurm
|
||||
65 C Scaled Wurm
|
||||
66 C Scryb Sprites
|
||||
67 U Seasoned Marshal
|
||||
68 C Seeker of Skybreak
|
||||
@@ -83,7 +83,7 @@ Foil=NotSupported
|
||||
73 C Slippery Karst
|
||||
74 C Soltari Foot Soldier
|
||||
75 U Songstitcher
|
||||
76 U Soul Warden
|
||||
76 C Soul Warden
|
||||
77 C Spike Colony
|
||||
78 U Spike Feeder
|
||||
79 R Spike Weaver
|
||||
|
||||
@@ -135,7 +135,7 @@ Booster=10 Common, 3 Uncommon, 1 fromSheet("BBD RareMythic"), 1 BasicLand
|
||||
125 C Omenspeaker
|
||||
126 U Opportunity
|
||||
127 U Oracle's Insight
|
||||
128 C Peregrine Drake
|
||||
128 U Peregrine Drake
|
||||
129 U Phantom Warrior
|
||||
130 U Reckless Scholar
|
||||
131 R Sower of Temptation
|
||||
@@ -203,7 +203,7 @@ Booster=10 Common, 3 Uncommon, 1 fromSheet("BBD RareMythic"), 1 BasicLand
|
||||
193 C Cowl Prowler
|
||||
194 C Daggerback Basilisk
|
||||
195 M Doubling Season
|
||||
196 U Elvish Visionary
|
||||
196 C Elvish Visionary
|
||||
197 U Feral Hydra
|
||||
198 C Fertile Ground
|
||||
199 U Fertilid
|
||||
|
||||
@@ -76,7 +76,7 @@ Foil=NotSupported
|
||||
66 C Yavimaya Wurm
|
||||
67 U Diabolic Vision
|
||||
68 U Segmented Wurm
|
||||
69 C Clockwork Avian
|
||||
69 R Clockwork Avian
|
||||
70 R Clockwork Beast
|
||||
71 U Dwarven Ruins
|
||||
72 U Ebon Stronghold
|
||||
|
||||
@@ -6,7 +6,8 @@ Code2=CN2
|
||||
MciCode=cn2
|
||||
Type=Other
|
||||
BoosterCovers=3
|
||||
Booster=10 Common:!fromSheet("CN2 Draft Matters"), 3 Uncommon:!fromSheet("CN2 Draft Matters"), 1 RareMythic:!fromSheet("CN2 Draft Matters"), 1 fromSheet("CN2 Draft Matters")
|
||||
Booster=10 Common:!fromSheet("CN2 Not In Normal Slots"), 3 Uncommon:!fromSheet("CN2 Not In Normal Slots"), 1 RareMythic:!fromSheet("CN2 Not In Normal Slots"), 1 fromSheet("CN2 Draft Matters")
|
||||
AdditionalSheetForFoils=fromSheet("CN2 Foil Kaya")
|
||||
|
||||
[cards]
|
||||
1 C Adriana's Valor
|
||||
@@ -230,6 +231,7 @@ Booster=10 Common:!fromSheet("CN2 Draft Matters"), 3 Uncommon:!fromSheet("CN2 Dr
|
||||
219 R Exotic Orchard
|
||||
220 U Rogue's Passage
|
||||
221 U Shimmering Grotto
|
||||
222 M Kaya, Ghost Assassin
|
||||
|
||||
[tokens]
|
||||
w_1_1_soldier
|
||||
|
||||
@@ -184,14 +184,14 @@ Booster=10 Common:!land, 3 Uncommon, 1 RareMythic, 1 fromSheet("FRF Lands"), 0 f
|
||||
174 C Tranquil Cove
|
||||
175 C Wind-Scarred Crag
|
||||
176 L Plains
|
||||
176 L Plains
|
||||
179 L Island
|
||||
177 L Plains
|
||||
178 L Island
|
||||
179 L Island
|
||||
180 L Swamp
|
||||
181 L Swamp
|
||||
181 L Swamp
|
||||
182 L Mountain
|
||||
183 L Mountain
|
||||
183 L Mountain
|
||||
185 L Forest
|
||||
184 L Forest
|
||||
185 L Forest
|
||||
|
||||
[tokens]
|
||||
|
||||
@@ -258,26 +258,26 @@ Booster=10 Common, 3 Uncommon, 1 RareMythic, 1 BasicLand KTK
|
||||
247 C Wind-Scarred Crag
|
||||
248 R Windswept Heath
|
||||
249 R Wooded Foothills
|
||||
269 L Forest
|
||||
269 L Forest
|
||||
269 L Forest
|
||||
269 L Forest
|
||||
257 L Island
|
||||
257 L Island
|
||||
257 L Island
|
||||
257 L Island
|
||||
263 L Mountain
|
||||
263 L Mountain
|
||||
263 L Mountain
|
||||
263 L Mountain
|
||||
250 L Plains
|
||||
250 L Plains
|
||||
250 L Plains
|
||||
250 L Plains
|
||||
251 L Plains
|
||||
252 L Plains
|
||||
253 L Plains
|
||||
254 L Island
|
||||
255 L Island
|
||||
256 L Island
|
||||
257 L Island
|
||||
258 L Swamp
|
||||
258 L Swamp
|
||||
258 L Swamp
|
||||
258 L Swamp
|
||||
259 L Swamp
|
||||
260 L Swamp
|
||||
261 L Swamp
|
||||
262 L Mountain
|
||||
263 L Mountain
|
||||
264 L Mountain
|
||||
265 L Mountain
|
||||
266 L Forest
|
||||
267 L Forest
|
||||
268 L Forest
|
||||
269 L Forest
|
||||
|
||||
[tokens]
|
||||
w_3_4_bird_flying
|
||||
|
||||
@@ -238,26 +238,26 @@ Booster=10 Common, 3 Uncommon, 1 RareMythic, 1 BasicLand
|
||||
227 U Encroaching Wastes
|
||||
228 R Mutavault
|
||||
229 U Shimmering Grotto
|
||||
230 L Plains
|
||||
231 L Plains
|
||||
231 L Plains
|
||||
231 L Plains
|
||||
231 L Plains
|
||||
234 L Island
|
||||
234 L Island
|
||||
234 L Island
|
||||
232 L Plains
|
||||
233 L Plains
|
||||
234 L Island
|
||||
235 L Island
|
||||
236 L Island
|
||||
237 L Island
|
||||
238 L Swamp
|
||||
239 L Swamp
|
||||
240 L Swamp
|
||||
241 L Swamp
|
||||
241 L Swamp
|
||||
241 L Swamp
|
||||
241 L Swamp
|
||||
244 L Mountain
|
||||
244 L Mountain
|
||||
244 L Mountain
|
||||
242 L Mountain
|
||||
243 L Mountain
|
||||
244 L Mountain
|
||||
245 L Mountain
|
||||
246 L Forest
|
||||
246 L Forest
|
||||
246 L Forest
|
||||
246 L Forest
|
||||
247 L Forest
|
||||
248 L Forest
|
||||
249 L Forest
|
||||
|
||||
[tokens]
|
||||
c_1_1_sliver
|
||||
|
||||
@@ -258,26 +258,26 @@ Booster=10 Common:!fromSheet("M15 Sample Cards"), 3 Uncommon:!fromSheet("M15 Sam
|
||||
247 R Sliver Hive
|
||||
248 R Urborg, Tomb of Yawgmoth
|
||||
249 R Yavimaya Coast
|
||||
250 L Plains
|
||||
251 L Plains
|
||||
251 L Plains
|
||||
251 L Plains
|
||||
251 L Plains
|
||||
255 L Island
|
||||
255 L Island
|
||||
255 L Island
|
||||
252 L Plains
|
||||
253 L Plains
|
||||
254 L Island
|
||||
255 L Island
|
||||
256 L Island
|
||||
257 L Island
|
||||
258 L Swamp
|
||||
258 L Swamp
|
||||
258 L Swamp
|
||||
258 L Swamp
|
||||
263 L Mountain
|
||||
263 L Mountain
|
||||
263 L Mountain
|
||||
259 L Swamp
|
||||
260 L Swamp
|
||||
261 L Swamp
|
||||
262 L Mountain
|
||||
263 L Mountain
|
||||
264 L Mountain
|
||||
265 L Mountain
|
||||
266 L Forest
|
||||
266 L Forest
|
||||
266 L Forest
|
||||
266 L Forest
|
||||
267 L Forest
|
||||
268 L Forest
|
||||
269 L Forest
|
||||
270 R Aegis Angel
|
||||
271 C Divine Verdict
|
||||
272 C Inspired Charge
|
||||
|
||||
128
forge-gui/res/editions/Mystery Booster Retail Edition Foils.txt
Normal 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
|
||||
1704
forge-gui/res/editions/Mystery Booster.txt
Normal file
@@ -367,17 +367,17 @@ Prerelease=6 Boosters, 1 RareMythic+
|
||||
350 R Temple of Malice
|
||||
351 R Temple of Plenty
|
||||
#Bundle promo
|
||||
R Arasta of the Endless Web
|
||||
352 R Arasta of the Endless Web
|
||||
#Promo Pack
|
||||
U Alseid of Life's Bounty
|
||||
C Thirst for Meaning
|
||||
U Gray Merchant of Asphodel
|
||||
C Thrill of Possibility
|
||||
U Wolfwillow Haven
|
||||
353 U Alseid of Life's Bounty
|
||||
354 C Thirst for Meaning
|
||||
355 U Gray Merchant of Asphodel
|
||||
356 C Thrill of Possibility
|
||||
357 U Wolfwillow Haven
|
||||
|
||||
[tokens]
|
||||
b_2_2_zombie
|
||||
c_0_4_wall_defender
|
||||
c_0_4_a_wall_defender
|
||||
g_1_2_spider_reach
|
||||
g_2_2_wolf
|
||||
r_x_1_elemental_trample_haste
|
||||
|
||||
@@ -284,36 +284,36 @@ Prerelease=6 Boosters, 1 RareMythic+
|
||||
271 M Oko, Thief of Crowns
|
||||
272 M The Royal Scions
|
||||
#Storybook Frames
|
||||
C Ardenvale Tactician
|
||||
C Faerie Guidemother
|
||||
R Giant Killer
|
||||
C Lonesome Unicorn
|
||||
M Realm-Cloaked Giant
|
||||
U Shepherd of the Flock
|
||||
C Silverflame Squire
|
||||
U Animating Faerie
|
||||
M Brazen Borrower
|
||||
R Fae of Wishes
|
||||
U Hypnotic Sprite
|
||||
C Merfolk Secretkeeper
|
||||
C Queen of Ice
|
||||
U Foulmire Knight
|
||||
R Murderous Rider
|
||||
U Order of Midnight
|
||||
C Reaper of Night
|
||||
C Smitten Swordmaster
|
||||
R Bonecrusher Giant
|
||||
U Embereth Shieldbreaker
|
||||
C Merchant of the Vale
|
||||
C Rimrock Knight
|
||||
U Beanstalk Giant
|
||||
C Curious Pair
|
||||
U Flaxen Intruder
|
||||
C Garenbrig Carver
|
||||
R Lovestruck Beast
|
||||
C Rosethorn Acolyte
|
||||
C Tuinvale Treefolk
|
||||
U Oakhame Ranger
|
||||
273 C Ardenvale Tactician
|
||||
274 C Faerie Guidemother
|
||||
275 R Giant Killer
|
||||
276 C Lonesome Unicorn
|
||||
277 M Realm-Cloaked Giant
|
||||
278 U Shepherd of the Flock
|
||||
279 C Silverflame Squire
|
||||
280 U Animating Faerie
|
||||
281 M Brazen Borrower
|
||||
282 R Fae of Wishes
|
||||
283 U Hypnotic Sprite
|
||||
284 C Merfolk Secretkeeper
|
||||
285 C Queen of Ice
|
||||
286 U Foulmire Knight
|
||||
287 R Murderous Rider
|
||||
288 U Order of Midnight
|
||||
289 C Reaper of Night
|
||||
290 C Smitten Swordmaster
|
||||
291 R Bonecrusher Giant
|
||||
292 U Embereth Shieldbreaker
|
||||
293 C Merchant of the Vale
|
||||
294 C Rimrock Knight
|
||||
295 U Beanstalk Giant
|
||||
296 C Curious Pair
|
||||
297 U Flaxen Intruder
|
||||
298 C Garenbrig Carver
|
||||
299 R Lovestruck Beast
|
||||
300 C Rosethorn Acolyte
|
||||
301 C Tuinvale Treefolk
|
||||
302 U Oakhame Ranger
|
||||
#Buy-A-Box Promo
|
||||
303 M Kenrith, the Returned King
|
||||
#Planeswalker Deck Cards
|
||||
@@ -348,72 +348,72 @@ U Oakhame Ranger
|
||||
332 R Tome of Legends
|
||||
333 C Command Tower
|
||||
#Borderless art rares and mythics
|
||||
R Acclaimed Contender
|
||||
R Charming Prince
|
||||
M The Circle of Loyalty
|
||||
R Happily Ever After
|
||||
M Harmonious Archon
|
||||
R Hushbringer
|
||||
R Linden, the Steadfast Queen
|
||||
R Worthy Knight
|
||||
R Emry, Lurker of the Loch
|
||||
R Folio of Fancies
|
||||
R Gadwick, the Wizened
|
||||
M The Magic Mirror
|
||||
R Midnight Clock
|
||||
R Mirrormade
|
||||
R Stolen by the Fae
|
||||
R Vantress Gargoyle
|
||||
R Ayara, First of Locthwain
|
||||
R Blacklance Paragon
|
||||
M The Cauldron of Eternity
|
||||
R Clackbridge Troll
|
||||
R Oathsworn Knight
|
||||
R Piper of the Swarm
|
||||
M Rankle, Master of Pranks
|
||||
R Wishclaw Talisman
|
||||
R Witch's Vengeance
|
||||
M Embercleave
|
||||
R Fervent Champion
|
||||
R Fires of Invention
|
||||
R Irencrag Feat
|
||||
R Irencrag Pyromancer
|
||||
R Opportunistic Dragon
|
||||
M Robber of the Rich
|
||||
R Sundering Stroke
|
||||
R Torbran, Thane of Red Fell
|
||||
R Feasting Troll King
|
||||
R Gilded Goose
|
||||
M The Great Henge
|
||||
R Once Upon A Time
|
||||
M Questing Beast
|
||||
R Return of the Wildspeaker
|
||||
R Wicked Wolf
|
||||
R Wildborn Preserver
|
||||
R Yorvo, Lord of Garenbrig
|
||||
R Dance of the Manse
|
||||
R Doom Foretold
|
||||
R Escape to the Wilds
|
||||
R Faeburrow Elder
|
||||
R Lochmere Serpent
|
||||
M Outlaws' Merriment
|
||||
R Stormfist Crusader
|
||||
R Sorcerous Spyglass
|
||||
R Stonecoil Serpent
|
||||
R Castle Ardenvale
|
||||
R Castle Embereth
|
||||
R Castle Garenbrig
|
||||
R Castle Locthwain
|
||||
R Castle Vantress
|
||||
R Fabled Passage
|
||||
334 R Acclaimed Contender
|
||||
335 R Charming Prince
|
||||
336 M The Circle of Loyalty
|
||||
337 R Happily Ever After
|
||||
338 M Harmonious Archon
|
||||
339 R Hushbringer
|
||||
340 R Linden, the Steadfast Queen
|
||||
341 R Worthy Knight
|
||||
342 R Emry, Lurker of the Loch
|
||||
343 R Folio of Fancies
|
||||
344 R Gadwick, the Wizened
|
||||
345 M The Magic Mirror
|
||||
346 R Midnight Clock
|
||||
347 R Mirrormade
|
||||
348 R Stolen by the Fae
|
||||
349 R Vantress Gargoyle
|
||||
350 R Ayara, First of Locthwain
|
||||
351 R Blacklance Paragon
|
||||
352 M The Cauldron of Eternity
|
||||
353 R Clackbridge Troll
|
||||
354 R Oathsworn Knight
|
||||
355 R Piper of the Swarm
|
||||
356 M Rankle, Master of Pranks
|
||||
357 R Wishclaw Talisman
|
||||
358 R Witch's Vengeance
|
||||
359 M Embercleave
|
||||
360 R Fervent Champion
|
||||
361 R Fires of Invention
|
||||
362 R Irencrag Feat
|
||||
363 R Irencrag Pyromancer
|
||||
364 R Opportunistic Dragon
|
||||
365 M Robber of the Rich
|
||||
366 R Sundering Stroke
|
||||
367 R Torbran, Thane of Red Fell
|
||||
368 R Feasting Troll King
|
||||
369 R Gilded Goose
|
||||
370 M The Great Henge
|
||||
371 R Once Upon a Time
|
||||
372 M Questing Beast
|
||||
373 R Return of the Wildspeaker
|
||||
374 R Wicked Wolf
|
||||
375 R Wildborn Preserver
|
||||
376 R Yorvo, Lord of Garenbrig
|
||||
377 R Dance of the Manse
|
||||
378 R Doom Foretold
|
||||
379 R Escape to the Wilds
|
||||
380 R Faeburrow Elder
|
||||
381 R Lochmere Serpent
|
||||
382 M Outlaws' Merriment
|
||||
383 R Stormfist Crusader
|
||||
384 R Sorcerous Spyglass
|
||||
385 R Stonecoil Serpent
|
||||
386 R Castle Ardenvale
|
||||
387 R Castle Embereth
|
||||
388 R Castle Garenbrig
|
||||
389 R Castle Locthwain
|
||||
390 R Castle Vantress
|
||||
391 R Fabled Passage
|
||||
#Bundle promo
|
||||
R Piper of the Swarm
|
||||
392 R Piper of the Swarm
|
||||
#Promo Pack
|
||||
U Glass Casket
|
||||
U Slaying Fire
|
||||
U Kenrith's Transformation
|
||||
U Improbable Alliance
|
||||
U Inspiring Veteran
|
||||
393 U Glass Casket
|
||||
394 U Slaying Fire
|
||||
395 U Kenrith's Transformation
|
||||
396 U Improbable Alliance
|
||||
397 U Inspiring Veteran
|
||||
|
||||
[tokens]
|
||||
w_0_1_goat
|
||||
|
||||
@@ -178,5 +178,5 @@ R Winding Canyons
|
||||
R Xanthic Statue
|
||||
C Zombie Scavengers
|
||||
|
||||
[token]
|
||||
[tokens]
|
||||
g_1_1_squirrel
|
||||
@@ -4,4 +4,4 @@ Order:101
|
||||
Type:Casual
|
||||
Subtype:Commander
|
||||
Sets:GRN, RNA, WAR, M20, ELD, THB
|
||||
Banned:Sorcerous Spyglass;Oko, Thief of Crowns
|
||||
Banned:Golos, Tireless Pilgrim; Oko, Thief of Crowns; Sorcerous Spyglass
|
||||
|
||||
@@ -3,4 +3,4 @@ Name:Legacy
|
||||
Order:105
|
||||
Subtype:Legacy
|
||||
Type:Sanctioned
|
||||
Banned:Adriana's Valor; Advantageous Proclamation; Assemble the Rank and Vile; Backup Plan; Brago's Favor; Deathrite Shaman; Double Stroke; Echoing Boon; Emissary's Ploy; Gitaxian Probe; Hired Heist; Hold the Perimeter; Hymn of the Wilds; Immediate Action; Incendiary Dissent; Iterative Analysis; Muzzio's Preparations; Natural Unity; Power Play; Secret Summoning; Secrets of Paradise; Sentinel Dispatch; Sovereign's Realm; Summoner's Bond; Unexpected Potential; Weight Advantage; Worldknit; Amulet of Quoz; Bronze Tablet; Contract from Below; Darkpact; Demonic Attorney; Jeweled Bird; Rebirth; Tempest Efreet; Timmerian Fiends; Ancestral Recall; Balance; Bazaar of Baghdad; Black Lotus; Channel; Chaos Orb; Demonic Consultation; Demonic Tutor; Dig Through Time; Earthcraft; Falling Star; Fastbond; Flash; Frantic Search; Goblin Recruiter; Gush; Hermit Druid; Imperial Seal; Library of Alexandria; Mana Crypt; Mana Drain; Mana Vault; Memory Jar; Mental Misstep; Mind Twist; Mind's Desire; Mishra's Workshop; Mox Emerald; Mox Jet; Mox Pearl; Mox Ruby; Mox Sapphire; Mystical Tutor; Necropotence; Oath of Druids; Sensei's Divining Top; Shahrazad; Skullclamp; Sol Ring; Strip Mine; Survival of the Fittest; Time Vault; Time Walk; Timetwister; Tinker; Tolarian Academy; Treasure Cruise; Vampiric Tutor; Wheel of Fortune; Windfall; Wrenn and Six; Yawgmoth's Bargain; Yawgmoth's Will
|
||||
Banned:Adriana's Valor; Advantageous Proclamation; Assemble the Rank and Vile; Backup Plan; Brago's Favor; Deathrite Shaman; Double Stroke; Echoing Boon; Emissary's Ploy; Gitaxian Probe; Hired Heist; Hold the Perimeter; Hymn of the Wilds; Immediate Action; Incendiary Dissent; Iterative Analysis; Muzzio's Preparations; Natural Unity; Power Play; Secret Summoning; Secrets of Paradise; Sentinel Dispatch; Sovereign's Realm; Summoner's Bond; Underworld Breach; Unexpected Potential; Weight Advantage; Worldknit; Amulet of Quoz; Bronze Tablet; Contract from Below; Darkpact; Demonic Attorney; Jeweled Bird; Rebirth; Tempest Efreet; Timmerian Fiends; Ancestral Recall; Balance; Bazaar of Baghdad; Black Lotus; Channel; Chaos Orb; Demonic Consultation; Demonic Tutor; Dig Through Time; Earthcraft; Falling Star; Fastbond; Flash; Frantic Search; Goblin Recruiter; Gush; Hermit Druid; Imperial Seal; Library of Alexandria; Mana Crypt; Mana Drain; Mana Vault; Memory Jar; Mental Misstep; Mind Twist; Mind's Desire; Mishra's Workshop; Mox Emerald; Mox Jet; Mox Pearl; Mox Ruby; Mox Sapphire; Mystical Tutor; Necropotence; Oath of Druids; Sensei's Divining Top; Shahrazad; Skullclamp; Sol Ring; Strip Mine; Survival of the Fittest; Time Vault; Time Walk; Timetwister; Tinker; Tolarian Academy; Treasure Cruise; Vampiric Tutor; Wheel of Fortune; Windfall; Wrenn and Six; Yawgmoth's Bargain; Yawgmoth's Will
|
||||
|
||||
@@ -4,4 +4,4 @@ Order:103
|
||||
Subtype:Modern
|
||||
Type:Sanctioned
|
||||
Sets:8ED, MRD, DST, 5DN, CHK, BOK, SOK, 9ED, RAV, GPT, DIS, CSP, TSP, TSB, PLC, FUT, 10E, LRW, EVE, SHM, MOR, ALA, CFX, ARB, M10, ZEN, WWK, ROE, M11, SOM, MBS, NPH, M12, ISD, DKA, AVR, M13, RTR, GTC, DGM, M14, THS, BNG, JOU, M15, KTK, FRF, DTK, MM2, ORI, BFZ, OGW, SOI, EMN, KLD, AER, AKH, W17, HOU, XLN, RIX, DOM, M19, G18, GRN, RNA, WAR, MH1, M20, ELD, THB
|
||||
Banned:Ancient Den; Birthing Pod; Blazing Shoal; Bridge from Below; Chrome Mox; Cloudpost; Dark Depths; Deathrite Shaman; Dig Through Time; Dread Return; Eye of Ugin; Faithless Looting; Gitaxian Probe; Glimpse of Nature; Golgari Grave-Troll; Great Furnace; Green Sun's Zenith; Hogaak, Arisen Necropolis; Hypergenesis; Krark-Clan Ironworks; Mental Misstep; Mox Opal; Mycosynth Lattice; Oko, Thief of Crowns; Ponder; Preordain; Punishing Fire; Rite of Flame; Seat of the Synod; Second Sunrise; Seething Song; Sensei's Divining Top; Skullclamp; Splinter Twin; Summer Bloom; Treasure Cruise; Tree of Tales; Umezawa's Jitte; Vault of Whispers
|
||||
Banned:Ancient Den; Birthing Pod; Blazing Shoal; Bridge from Below; Chrome Mox; Cloudpost; Dark Depths; Deathrite Shaman; Dig Through Time; Dread Return; Eye of Ugin; Faithless Looting; Gitaxian Probe; Glimpse of Nature; Golgari Grave-Troll; Great Furnace; Green Sun's Zenith; Hogaak, Arisen Necropolis; Hypergenesis; Krark-Clan Ironworks; Mental Misstep; Mox Opal; Mycosynth Lattice; Oko, Thief of Crowns; Once Upon A Time; Ponder; Preordain; Punishing Fire; Rite of Flame; Seat of the Synod; Second Sunrise; Seething Song; Sensei's Divining Top; Skullclamp; Splinter Twin; Summer Bloom; Treasure Cruise; Tree of Tales; Umezawa's Jitte; Vault of Whispers
|
||||
|
||||
@@ -50,6 +50,8 @@ btnResetJavaFutureCompatibilityWarnings=Java-Kompatibilitätswarnung zurücksetz
|
||||
btnClearImageCache=Leere Bildspeicher
|
||||
btnTokenPreviewer=Spielstein-Vorschau
|
||||
btnCopyToClipboard=In Zwischenablage kopieren
|
||||
cbpAutoUpdater=Auto updater
|
||||
nlAutoUpdater=Select the release channel to use for updating Forge
|
||||
cbpSelectLanguage=Sprache
|
||||
nlSelectLanguage=Wähle Sprache (Ist noch in Arbeit und nur teilweise umgesetzt.) (Neustart ist erforderlich.)
|
||||
cbRemoveSmall=Entferne kleine Kreaturen
|
||||
@@ -180,6 +182,7 @@ KeyboardShortcuts=Tastenkombinationen
|
||||
#VSubmenuAchievements.java
|
||||
lblAchievements=Errungenschaften
|
||||
#VSubmenuDownloaders.java
|
||||
btnCheckForUpdates=Check for Updates
|
||||
btnDownloadSetPics=Bilder(LQ) Sets herunterladen
|
||||
btnDownloadPicsHQ=Bilder(HQ) Karten herunterladen (Sehr langsam!)
|
||||
btnDownloadPics=Bilder(LQ) Karten herunterladen
|
||||
@@ -192,6 +195,7 @@ btnImportPictures=Daten importieren
|
||||
btnHowToPlay=Wie man spielt
|
||||
btnDownloadPrices=Kartenpreise herunterladen
|
||||
btnLicensing=Lizenzhinweis
|
||||
lblCheckForUpdates=Check Forge server to see if there's a more recent release
|
||||
lblDownloadPics=Lädt ein Standardbild pro Karte.
|
||||
lblDownloadPicsHQ=Lädt ein HQ-Standardbild pro Karte.
|
||||
lblDownloadSetPics=Lädt alle Bilder pro Karte. Eines für jedes Set, in welchem die Karte auftauchte.
|
||||
|
||||
@@ -50,6 +50,8 @@ btnResetJavaFutureCompatibilityWarnings=Reset Java Compatibility Warnings
|
||||
btnClearImageCache=Clear Image Cache
|
||||
btnTokenPreviewer=Token Previewer
|
||||
btnCopyToClipboard=Copy to Clipboard
|
||||
cbpAutoUpdater=Auto updater
|
||||
nlAutoUpdater=Select the release channel to use for updating Forge
|
||||
cbpSelectLanguage=Language
|
||||
nlSelectLanguage=Select Language (Excluded Game part. Still a work in progress) (RESTART REQUIRED)
|
||||
cbRemoveSmall=Remove Small Creatures
|
||||
@@ -180,6 +182,7 @@ KeyboardShortcuts=Keyboard Shortcuts
|
||||
#VSubmenuAchievements.java
|
||||
lblAchievements=Achievements
|
||||
#VSubmenuDownloaders.java
|
||||
btnCheckForUpdates=Check for Updates
|
||||
btnDownloadSetPics=Download LQ Set Pictures
|
||||
btnDownloadPicsHQ=Download HQ Card Pictures (Very Slow!)
|
||||
btnDownloadPics=Download LQ Card Pictures
|
||||
@@ -192,6 +195,7 @@ btnImportPictures=Import Data
|
||||
btnHowToPlay=How To Play
|
||||
btnDownloadPrices=Download Card Prices
|
||||
btnLicensing=License Details
|
||||
lblCheckForUpdates=Check Forge server to see if there's a more recent release
|
||||
lblDownloadPics=Download default card picture for each card.
|
||||
lblDownloadPicsHQ=Download default card HQ picture for each card.
|
||||
lblDownloadSetPics=Download all pictures of each card (one for each set the card appeared in)
|
||||
|
||||
@@ -50,6 +50,8 @@ btnResetJavaFutureCompatibilityWarnings=Restablecer las advertencias de compatib
|
||||
btnClearImageCache=Limpiar Caché de Imágenes
|
||||
btnTokenPreviewer=Previsualizador de Fichas (Token)
|
||||
btnCopyToClipboard=Copiar al portapapeles
|
||||
cbpAutoUpdater=Actualizar Forge
|
||||
nlAutoUpdater=Selecciona la versión a utilizar para actualizar Forge
|
||||
cbpSelectLanguage=Idioma
|
||||
nlSelectLanguage=Seleccionar idioma (excepto partida). Todavía un trabajo en progreso) (Es necesario reiniciar Forge)
|
||||
cbRemoveSmall=Eliminar Pequeñas Criaturas
|
||||
@@ -180,6 +182,7 @@ KeyboardShortcuts=Atajos de teclado
|
||||
#VSubmenuAchievements.java
|
||||
lblAchievements=Logros
|
||||
#VSubmenuDownloaders.java
|
||||
btnCheckForUpdates=Comprobar Actualizaciones
|
||||
btnDownloadSetPics=Descargar todas las Ediciones de Cartas
|
||||
btnDownloadPics=Descargar todas las Cartas
|
||||
btnDownloadPicsHQ=Descargar todas las Cartas en calidad alta (Muy lento!)
|
||||
@@ -192,6 +195,7 @@ btnImportPictures=Importar Datos
|
||||
btnHowToPlay=Cómo jugar (Inglés)
|
||||
btnDownloadPrices=Descargar los precios de las cartas
|
||||
btnLicensing=Detalles de la licencia
|
||||
lblCheckForUpdates=Comprueba si en el servidor de Forge existe alguna versión más reciente
|
||||
lblDownloadPics=Descargar la imagen de la carta por defecto para cada carta.
|
||||
lblDownloadPicsHQ=Descargar la imagen en calidad alta de la carta por defecto para cada carta.
|
||||
lblDownloadSetPics=Descargue todas las imágenes de cada carta (una por cada edición donde apareció la carta)
|
||||
|
||||
@@ -50,6 +50,8 @@ btnResetJavaFutureCompatibilityWarnings=Ripristina avvisi di compatibilità Java
|
||||
btnClearImageCache=Cancella cache immagini
|
||||
btnTokenPreviewer=Anteprima token
|
||||
btnCopyToClipboard=Copia negli appunti
|
||||
cbpAutoUpdater=Auto updater
|
||||
nlAutoUpdater=Select the release channel to use for updating Forge
|
||||
cbpSelectLanguage=Lingua
|
||||
nlSelectLanguage=Seleziona la lingua (parte di gioco esclusa. Ancora in fase di sviluppo) (RIAVVIO NECESSARIO)
|
||||
cbRemoveSmall=Rimuovi le piccole creature
|
||||
@@ -180,6 +182,7 @@ KeyboardShortcuts=Tasti rapidi
|
||||
#VSubmenuAchievements.java
|
||||
lblAchievements=realizzazioni
|
||||
#VSubmenuDownloaders.java
|
||||
btnCheckForUpdates=Check for Updates
|
||||
btnDownloadSetPics=Scarica LQ Set Pictures
|
||||
btnDownloadPicsHQ=Scarica le immagini della scheda HQ (molto lento!)
|
||||
btnDownloadPics=Scarica LQ Card Pictures
|
||||
@@ -192,6 +195,7 @@ btnImportPictures=Importa dati
|
||||
btnHowToPlay=Come giocare
|
||||
btnDownloadPrices=Scarica i prezzi delle carte
|
||||
btnLicensing=Dettagli della licenza
|
||||
lblCheckForUpdates=Check Forge server to see if there's a more recent release
|
||||
lblDownloadPics=Scarica l''immagine della carta predefinita per ogni carta.
|
||||
lblDownloadPicsHQ=Scarica l''immagine HQ della scheda predefinita per ogni scheda.
|
||||
lblDownloadSetPics=Scarica tutte le immagini di ogni carta (una per ogni set in cui è apparso la carta)
|
||||
|
||||
@@ -50,6 +50,8 @@ btnResetJavaFutureCompatibilityWarnings=重置Java兼容性警告
|
||||
btnClearImageCache=清除图片缓存
|
||||
btnTokenPreviewer=衍生物预览器
|
||||
btnCopyToClipboard=复制到剪切板
|
||||
cbpAutoUpdater=Auto updater
|
||||
nlAutoUpdater=Select the release channel to use for updating Forge
|
||||
cbpSelectLanguage=语言
|
||||
nlSelectLanguage=选择语言(除了正在进行中的游戏)(需要重新启动)
|
||||
cbRemoveSmall=删除小生物
|
||||
@@ -180,6 +182,7 @@ KeyboardShortcuts=键盘快捷键
|
||||
#VSubmenuAchievements.java
|
||||
lblAchievements=成就
|
||||
#VSubmenuDownloaders.java
|
||||
btnCheckForUpdates=Check for Updates
|
||||
btnDownloadSetPics=下载低清系列图
|
||||
btnDownloadPicsHQ=下载高清卡图(这很慢!)
|
||||
btnDownloadPics=下载低清卡图
|
||||
@@ -192,6 +195,7 @@ btnImportPictures=导入数据
|
||||
btnHowToPlay=如何玩
|
||||
btnDownloadPrices=下载卡牌价格
|
||||
btnLicensing=许可证详情
|
||||
lblCheckForUpdates=Check Forge server to see if there's a more recent release
|
||||
lblDownloadPics=下载缺省牌的图片
|
||||
lblDownloadPicsHQ=下载缺省牌的高清图片
|
||||
lblDownloadSetPics=下载每张牌的图片(每张牌出现一次)
|
||||
|
||||
18
forge-gui/res/puzzle/PS_THB6.pzl
Normal 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
|
||||
16
forge-gui/res/puzzle/PS_THB7.pzl
Normal 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
|
||||
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 163 KiB |
|
Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 534 KiB After Width: | Height: | Size: 533 KiB |
@@ -1,6 +1,6 @@
|
||||
Name:Wall
|
||||
ManaCost:no cost
|
||||
Types:Creature Wall
|
||||
Types:Artifact Creature Wall
|
||||
PT:0/4
|
||||
K:Defender
|
||||
Oracle:Defender
|
||||
@@ -230,6 +230,15 @@ public enum FSkinProp {
|
||||
ICO_QUEST_BIG_SWORD (new int[] {320, 1360, 160, 160}, PropType.ICON),
|
||||
ICO_QUEST_BIG_BAG (new int[] {480, 1360, 160, 160}, PropType.ICON),
|
||||
|
||||
//menu icon
|
||||
ICO_MENU_GALAXY (new int[] {0, 1520, 80, 80}, PropType.ICON),
|
||||
ICO_MENU_STATS (new int[] {80, 1520, 80, 80}, PropType.ICON),
|
||||
ICO_MENU_PUZZLE (new int[] {160, 1520, 80, 80}, PropType.ICON),
|
||||
ICO_MENU_GAUNTLET (new int[] {240, 1520, 80, 80}, PropType.ICON),
|
||||
ICO_MENU_SEALED (new int[] {320, 1520, 80, 80}, PropType.ICON),
|
||||
ICO_MENU_DRAFT (new int[] {400, 1520, 80, 80}, PropType.ICON),
|
||||
ICO_MENU_CONSTRUCTED (new int[] {480, 1520, 80, 80}, PropType.ICON),
|
||||
|
||||
//interface icons
|
||||
ICO_QUESTION (new int[] {560, 800, 32, 32}, PropType.ICON),
|
||||
ICO_INFORMATION (new int[] {592, 800, 32, 32}, PropType.ICON),
|
||||
|
||||
247
forge-gui/src/main/java/forge/download/AutoUpdater.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,72 +73,7 @@ public class GuiDownloadZipService extends GuiDownloadService {
|
||||
String zipFilename = download("temp.zip");
|
||||
if (zipFilename == null) { return; }
|
||||
|
||||
//if assets.zip downloaded successfully, unzip into destination folder
|
||||
try {
|
||||
GuiBase.getInterface().preventSystemSleep(true); //prevent system from going into sleep mode while unzipping
|
||||
|
||||
if (deleteFolder != null) {
|
||||
final File deleteDir = new File(deleteFolder);
|
||||
if (deleteDir.exists()) {
|
||||
//attempt to delete previous res directory if to be rebuilt
|
||||
progressBar.reset();
|
||||
progressBar.setDescription("Deleting old " + desc + "...");
|
||||
if (deleteFolder.equals(destFolder)) { //move zip file to prevent deleting it
|
||||
final String oldZipFilename = zipFilename;
|
||||
zipFilename = deleteDir.getParentFile().getAbsolutePath() + File.separator + "temp.zip";
|
||||
Files.move(new File(oldZipFilename), new File(zipFilename));
|
||||
}
|
||||
FileUtil.deleteDirectory(deleteDir);
|
||||
}
|
||||
}
|
||||
|
||||
final ZipFile zipFile = new ZipFile(zipFilename);
|
||||
final Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
||||
|
||||
progressBar.reset();
|
||||
progressBar.setPercentMode(true);
|
||||
progressBar.setDescription("Extracting " + desc);
|
||||
progressBar.setMaximum(zipFile.size());
|
||||
|
||||
FileUtil.ensureDirectoryExists(destFolder);
|
||||
|
||||
int count = 0;
|
||||
int failedCount = 0;
|
||||
while (entries.hasMoreElements()) {
|
||||
if (cancel) { break; }
|
||||
|
||||
try {
|
||||
final ZipEntry entry = entries.nextElement();
|
||||
|
||||
final String path = destFolder + File.separator + entry.getName();
|
||||
if (entry.isDirectory()) {
|
||||
new File(path).mkdir();
|
||||
progressBar.setValue(++count);
|
||||
continue;
|
||||
}
|
||||
copyInputStream(zipFile.getInputStream(entry), path);
|
||||
progressBar.setValue(++count);
|
||||
filesExtracted++;
|
||||
}
|
||||
catch (final Exception e) { //don't quit out completely if an entry is not UTF-8
|
||||
progressBar.setValue(++count);
|
||||
failedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (failedCount > 0) {
|
||||
Log.error("Downloading " + desc, failedCount + " " + desc + " could not be extracted");
|
||||
}
|
||||
|
||||
zipFile.close();
|
||||
new File(zipFilename).delete();
|
||||
}
|
||||
catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
finally {
|
||||
GuiBase.getInterface().preventSystemSleep(false);
|
||||
}
|
||||
extract(zipFilename);
|
||||
}
|
||||
|
||||
public String download(final String filename) {
|
||||
@@ -211,6 +146,75 @@ public class GuiDownloadZipService extends GuiDownloadService {
|
||||
}
|
||||
}
|
||||
|
||||
public void extract(String zipFilename) {
|
||||
//if assets.zip downloaded successfully, unzip into destination folder
|
||||
try {
|
||||
GuiBase.getInterface().preventSystemSleep(true); //prevent system from going into sleep mode while unzipping
|
||||
|
||||
if (deleteFolder != null) {
|
||||
final File deleteDir = new File(deleteFolder);
|
||||
if (deleteDir.exists()) {
|
||||
//attempt to delete previous res directory if to be rebuilt
|
||||
progressBar.reset();
|
||||
progressBar.setDescription("Deleting old " + desc + "...");
|
||||
if (deleteFolder.equals(destFolder)) { //move zip file to prevent deleting it
|
||||
final String oldZipFilename = zipFilename;
|
||||
zipFilename = deleteDir.getParentFile().getAbsolutePath() + File.separator + "temp.zip";
|
||||
Files.move(new File(oldZipFilename), new File(zipFilename));
|
||||
}
|
||||
FileUtil.deleteDirectory(deleteDir);
|
||||
}
|
||||
}
|
||||
|
||||
final ZipFile zipFile = new ZipFile(zipFilename);
|
||||
final Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
||||
|
||||
progressBar.reset();
|
||||
progressBar.setPercentMode(true);
|
||||
progressBar.setDescription("Extracting " + desc);
|
||||
progressBar.setMaximum(zipFile.size());
|
||||
|
||||
FileUtil.ensureDirectoryExists(destFolder);
|
||||
|
||||
int count = 0;
|
||||
int failedCount = 0;
|
||||
while (entries.hasMoreElements()) {
|
||||
if (cancel) { break; }
|
||||
|
||||
try {
|
||||
final ZipEntry entry = entries.nextElement();
|
||||
|
||||
final String path = destFolder + File.separator + entry.getName();
|
||||
if (entry.isDirectory()) {
|
||||
new File(path).mkdir();
|
||||
progressBar.setValue(++count);
|
||||
continue;
|
||||
}
|
||||
copyInputStream(zipFile.getInputStream(entry), path);
|
||||
progressBar.setValue(++count);
|
||||
filesExtracted++;
|
||||
}
|
||||
catch (final Exception e) { //don't quit out completely if an entry is not UTF-8
|
||||
progressBar.setValue(++count);
|
||||
failedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (failedCount > 0) {
|
||||
Log.error("Downloading " + desc, failedCount + " " + desc + " could not be extracted");
|
||||
}
|
||||
|
||||
zipFile.close();
|
||||
new File(zipFilename).delete();
|
||||
}
|
||||
catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
finally {
|
||||
GuiBase.getInterface().preventSystemSleep(false);
|
||||
}
|
||||
}
|
||||
|
||||
protected void copyInputStream(final InputStream in, final String outPath) throws IOException {
|
||||
final byte[] buffer = new byte[1024];
|
||||
int len;
|
||||
|
||||
@@ -28,6 +28,7 @@ import forge.card.CardType;
|
||||
import forge.deck.CardArchetypeLDAGenerator;
|
||||
import forge.deck.CardRelationMatrixGenerator;
|
||||
import forge.deck.io.DeckPreferences;
|
||||
import forge.download.AutoUpdater;
|
||||
import forge.game.GameFormat;
|
||||
import forge.game.GameType;
|
||||
import forge.game.card.CardUtil;
|
||||
@@ -117,7 +118,6 @@ public final class FModel {
|
||||
|
||||
Localizer.getInstance().initialize(FModel.getPreferences().getPref(FPref.UI_LANGUAGE), ForgeConstants.LANG_DIR);
|
||||
|
||||
//load card database
|
||||
final ProgressObserver progressBarBridge = (progressBar == null) ?
|
||||
ProgressObserver.emptyObserver : new ProgressObserver() {
|
||||
@Override
|
||||
@@ -143,6 +143,11 @@ public final class FModel {
|
||||
}
|
||||
};
|
||||
|
||||
if (new AutoUpdater(true).attemptToUpdate()) {
|
||||
//
|
||||
}
|
||||
|
||||
//load card database
|
||||
final CardStorageReader reader = new CardStorageReader(ForgeConstants.CARD_DATA_DIR, progressBarBridge,
|
||||
FModel.getPreferences().getPrefBoolean(FPref.LOAD_CARD_SCRIPTS_LAZILY));
|
||||
final CardStorageReader tokenReader = new CardStorageReader(ForgeConstants.TOKEN_DATA_DIR, progressBarBridge,
|
||||
@@ -221,8 +226,6 @@ public final class FModel {
|
||||
achievements.put(GameType.PlanarConquest, new PlanarConquestAchievements());
|
||||
achievements.put(GameType.Puzzle, new PuzzleAchievements());
|
||||
|
||||
|
||||
|
||||
//preload AI profiles
|
||||
AiProfileUtil.loadAllProfiles(ForgeConstants.AI_PROFILE_DIR);
|
||||
|
||||
|
||||