From 5ad58f59c1bcfbe4748d206f7d8e51a9fcc78ba7 Mon Sep 17 00:00:00 2001 From: Neil Gentleman Date: Tue, 27 Oct 2015 20:32:17 -0700 Subject: [PATCH 01/35] compare cards with mtgjson --- .gitignore | 5 + Mage.Verify/pom.xml | 76 ++++++++ .../mage/verify/CompareWithMtgjsonTest.java | 182 ++++++++++++++++++ pom.xml | 1 + 4 files changed, 264 insertions(+) create mode 100644 Mage.Verify/pom.xml create mode 100644 Mage.Verify/src/test/java/mage/verify/CompareWithMtgjsonTest.java diff --git a/.gitignore b/.gitignore index 8c1d40ad0d7..d9d5853e3f8 100644 --- a/.gitignore +++ b/.gitignore @@ -77,6 +77,11 @@ Mage/target Mage.Updater/target mage.updater.client/target +# Mage.Verify +Mage.Verify/target +Mage.Verify/AllCards.json.zip +Mage.Verify/AllSets.json.zip + releases Utils/author.txt .DS_Store diff --git a/Mage.Verify/pom.xml b/Mage.Verify/pom.xml new file mode 100644 index 00000000000..64e0d4c0e9e --- /dev/null +++ b/Mage.Verify/pom.xml @@ -0,0 +1,76 @@ + + + 4.0.0 + + + org.mage + mage-root + 1.4.16 + + + mage-verify + jar + Mage Verify + + + + ${project.groupId} + mage + ${mage-version} + + + ${project.groupId} + mage-sets + ${mage-version} + + + junit + junit + test + + + com.fasterxml.jackson.core + jackson-databind + 2.6.3 + + + + log4j + log4j + jar + + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + -Dfile.encoding=UTF-8 + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + maven-resources-plugin + + UTF-8 + + + + + mage-verify + + + + + diff --git a/Mage.Verify/src/test/java/mage/verify/CompareWithMtgjsonTest.java b/Mage.Verify/src/test/java/mage/verify/CompareWithMtgjsonTest.java new file mode 100644 index 00000000000..b50370afdba --- /dev/null +++ b/Mage.Verify/src/test/java/mage/verify/CompareWithMtgjsonTest.java @@ -0,0 +1,182 @@ +package mage.verify; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import mage.ObjectColor; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.ExpansionSet; +import mage.cards.Sets; +import mage.cards.SplitCard; +import mage.constants.CardType; +import mage.util.ClassScanner; +import org.junit.Test; + +import java.io.IOException; +import java.text.Normalizer; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.Objects; + +public class CompareWithMtgjsonTest { + + @Test + public void testSets() throws IOException { + Collection sets = Sets.getInstance().values(); + + Map> reference = new ObjectMapper().readValue( + CompareWithMtgjsonTest.class.getResourceAsStream("AllCards.json"), + new TypeReference>>() {}); + + Map aliases = new HashMap<>(); + for (String name : reference.keySet()) { + String unaccented = stripAccents(name); + if (!name.equals(unaccented)) { + aliases.put(name, unaccented); + } + } + for (Map.Entry mapping : aliases.entrySet()) { + reference.put(mapping.getValue(), reference.get(mapping.getKey())); + } + + for (ExpansionSet set : sets) { + for (ExpansionSet.SetCardInfo setInfo : set.getSetCardInfo()) { + Card card = CardImpl.createCard(setInfo.getCardClass(), new CardSetInfo(setInfo.getName(), set.getCode(), + setInfo.getCardNumber(), setInfo.getRarity(), setInfo.getGraphicInfo())); + if (card.isSplitCard()) { + check(reference, ((SplitCard) card).getLeftHalfCard()); + check(reference, ((SplitCard) card).getRightHalfCard()); + } else { + check(reference, card); + } + } + } + } + + private String stripAccents(String str) { + String decomposed = Normalizer.normalize(str, Normalizer.Form.NFKD); + return decomposed.replaceAll("[\\p{InCombiningDiacriticalMarks}]", ""); + } + + private void check(Map> reference, Card card) { + String name = card.getName(); + Map ref = reference.get(name); + if (ref == null) { + name = name.replaceFirst("\\bA[Ee]", "Æ"); + ref = reference.get(name); + } + if (ref == null) { + name = name.replace("'", "\""); // for Kongming, "Sleeping Dragon" & Pang Tong, "Young Phoenix" + ref = reference.get(name); + } + if (ref == null) { + System.out.println("Missing card reference for " + card); + return; + } + checkAll(card, ref); + } + + private void checkAll(Card card, Map ref) { + checkCost(card, ref); + checkPT(card, ref); + checkSubtypes(card, ref); + checkSupertypes(card, ref); + checkTypes(card, ref); + checkColors(card, ref); + } + + private void checkColors(Card card, Map ref) { + Collection expected = (Collection) ref.get("colors"); + ObjectColor color = card.getColor(null); + if (expected == null) { + expected = Collections.emptyList(); + } + if (expected.size() != color.getColorCount() || + (color.isBlack() && !expected.contains("Black")) || + (color.isBlue() && !expected.contains("Blue")) || + (color.isGreen() && !expected.contains("Green")) || + (color.isRed() && !expected.contains("Red")) || + (color.isWhite() && !expected.contains("White"))) { + System.out.println(color + " != " + expected + " for " + card); + } + } + + private void checkSubtypes(Card card, Map ref) { + Collection expected = (Collection) ref.get("subtypes"); + if (expected != null && expected.contains("Urza’s")) { + expected = new ArrayList<>(expected); + for (ListIterator it = ((List) expected).listIterator(); it.hasNext();) { + if (it.next().equals("Urza’s")) { + it.set("Urza's"); + } + } + } + if (!eqSet(card.getSubtype(null), expected)) { + System.out.println(card.getSubtype(null) + " != " + expected + " for " + card); + } + } + + private void checkSupertypes(Card card, Map ref) { + Collection expected = (Collection) ref.get("supertypes"); + if (!eqSet(card.getSupertype(), expected)) { + System.out.println(card.getSupertype() + " != " + expected + " for " + card); + } + } + + private void checkTypes(Card card, Map ref) { + Collection expected = (Collection) ref.get("types"); + List type = new ArrayList<>(); + for (CardType cardType : card.getCardType()) { + type.add(cardType.toString()); + } + if (!eqSet(type, expected)) { + System.out.println(type + " != " + expected + " for " + card); + } + } + + private static boolean eqSet(Collection a, Collection b) { + if (a == null || a.isEmpty()) { + return b == null || b.isEmpty(); + } + return b != null && a.size() == b.size() && a.containsAll(b); + } + + private void checkPT(Card card, Map ref) { + String pt = card.getPower() + "/" + card.getToughness(); + String expected = ref.get("power") + "/" + ref.get("toughness"); + if ("0/0".equals(pt) && ("null/null".equals(expected) || "*/*".equals(expected))) { + // ok + } else if (!Objects.equals(pt, expected.replace("*", "0"))) { + System.out.println(pt + " != " + expected + " for " + card); + } + } + + private void checkCost(Card card, Map ref) { + String expected = (String) ref.get("manaCost"); + String cost = join(card.getManaCost().getSymbols()); + if ("".equals(cost)) { + cost = null; + } + if (cost != null) { + cost = cost.replaceAll("P\\}", "/P}"); + } + if (!Objects.equals(cost, expected)) { + System.out.println(cost + " != " + expected + " for " + card); + } + } + + private String join(Iterable items) { + StringBuilder result = new StringBuilder(); + for (Object item : items) { + result.append(item); + } + return result.toString(); + } + +} diff --git a/pom.xml b/pom.xml index 9c20bd429b2..65e49f22b24 100644 --- a/pom.xml +++ b/pom.xml @@ -61,6 +61,7 @@ Mage.Tests Mage.Updater Mage.Stats + Mage.Verify From 584b53259818f888af960d1fc0a7841b6dba9512 Mon Sep 17 00:00:00 2001 From: Neil Gentleman Date: Wed, 28 Oct 2015 23:25:52 -0700 Subject: [PATCH 02/35] check card source for unexpected types needs more tuning - very noisy right now --- .../mage/verify/CompareWithMtgjsonTest.java | 86 +++++++++++++++---- 1 file changed, 67 insertions(+), 19 deletions(-) diff --git a/Mage.Verify/src/test/java/mage/verify/CompareWithMtgjsonTest.java b/Mage.Verify/src/test/java/mage/verify/CompareWithMtgjsonTest.java index b50370afdba..5f1c8a07a62 100644 --- a/Mage.Verify/src/test/java/mage/verify/CompareWithMtgjsonTest.java +++ b/Mage.Verify/src/test/java/mage/verify/CompareWithMtgjsonTest.java @@ -10,19 +10,17 @@ import mage.cards.ExpansionSet; import mage.cards.Sets; import mage.cards.SplitCard; import mage.constants.CardType; -import mage.util.ClassScanner; import org.junit.Test; import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Paths; import java.text.Normalizer; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; -import java.util.Objects; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class CompareWithMtgjsonTest { @@ -47,25 +45,67 @@ public class CompareWithMtgjsonTest { for (ExpansionSet set : sets) { for (ExpansionSet.SetCardInfo setInfo : set.getSetCardInfo()) { + Set tokens = findSourceTokens(setInfo.getCardClass()); Card card = CardImpl.createCard(setInfo.getCardClass(), new CardSetInfo(setInfo.getName(), set.getCode(), setInfo.getCardNumber(), setInfo.getRarity(), setInfo.getGraphicInfo())); if (card.isSplitCard()) { - check(reference, ((SplitCard) card).getLeftHalfCard()); - check(reference, ((SplitCard) card).getRightHalfCard()); + check(reference, ((SplitCard) card).getLeftHalfCard(), null); + check(reference, ((SplitCard) card).getRightHalfCard(), null); } else { - check(reference, card); + check(reference, card, tokens); } } } } + private static final Pattern SHORT_JAVA_STRING = Pattern.compile("(?<=\")[A-Z][a-z]+(?=\")"); + + private Set findSourceTokens(Class c) throws IOException { + String path = "../Mage.Sets/src/" + c.getName().replace(".", "/") + ".java"; + try { + String source = new String(Files.readAllBytes(Paths.get(path)), StandardCharsets.UTF_8); + Matcher matcher = SHORT_JAVA_STRING.matcher(source); + Set tokens = new HashSet<>(); + while (matcher.find()) { + tokens.add(matcher.group()); + } + return tokens; + } catch (NoSuchFileException e) { + System.out.println("failed to read " + path); + return Collections.emptySet(); + } + } + private String stripAccents(String str) { String decomposed = Normalizer.normalize(str, Normalizer.Form.NFKD); return decomposed.replaceAll("[\\p{InCombiningDiacriticalMarks}]", ""); } - private void check(Map> reference, Card card) { - String name = card.getName(); + private void check(Map> reference, Card card, Set tokens) { + Map ref = findReference(reference, card.getName()); + if (ref == null) { + System.out.println("Missing card reference for " + card); + return; + } + checkAll(card, ref); + if (tokens != null) { + Map ref2 = null; + if (card.isFlipCard()) { + ref2 = findReference(reference, card.getFlipCardName()); + } + for (String token : tokens) { + if (!(token.equals(card.getName()) + || containsInTypesOrText(ref, token) + || containsInTypesOrText(ref, token.toLowerCase()) + || (ref2 != null && (containsInTypesOrText(ref2, token) || containsInTypesOrText(ref2, token.toLowerCase()))) + )) { + System.out.println("unexpected token " + token + " in " + card); + } + } + } + } + + private Map findReference(Map> reference, String name) { Map ref = reference.get(name); if (ref == null) { name = name.replaceFirst("\\bA[Ee]", "Æ"); @@ -75,11 +115,19 @@ public class CompareWithMtgjsonTest { name = name.replace("'", "\""); // for Kongming, "Sleeping Dragon" & Pang Tong, "Young Phoenix" ref = reference.get(name); } - if (ref == null) { - System.out.println("Missing card reference for " + card); - return; - } - checkAll(card, ref); + return ref; + } + + private boolean containsInTypesOrText(Map ref, String token) { + return contains(ref, "types", token) + || contains(ref, "subtypes", token) + || contains(ref, "supertypes", token) + || ((String) ref.get("text")).contains(token); + } + + private boolean contains(Map ref, String key, String value) { + Collection options = (Collection) ref.get(key); + return options != null && options.contains(value); } private void checkAll(Card card, Map ref) { From 26b8b88963dccb6e77c2e9251dcef44ff991f5c3 Mon Sep 17 00:00:00 2001 From: Neil Gentleman Date: Thu, 19 Nov 2015 18:28:24 -0800 Subject: [PATCH 03/35] update verification now using java types instead of Map --- .../src/main/java/mage/verify/JsonCard.java | 50 ++++++ .../src/main/java/mage/verify/JsonSet.java | 31 ++++ .../src/main/java/mage/verify/MtgJson.java | 57 +++++++ ...gjsonTest.java => VerifyCardDataTest.java} | 144 +++++++++--------- 4 files changed, 213 insertions(+), 69 deletions(-) create mode 100644 Mage.Verify/src/main/java/mage/verify/JsonCard.java create mode 100644 Mage.Verify/src/main/java/mage/verify/JsonSet.java create mode 100644 Mage.Verify/src/main/java/mage/verify/MtgJson.java rename Mage.Verify/src/test/java/mage/verify/{CompareWithMtgjsonTest.java => VerifyCardDataTest.java} (59%) diff --git a/Mage.Verify/src/main/java/mage/verify/JsonCard.java b/Mage.Verify/src/main/java/mage/verify/JsonCard.java new file mode 100644 index 00000000000..01ea6884710 --- /dev/null +++ b/Mage.Verify/src/main/java/mage/verify/JsonCard.java @@ -0,0 +1,50 @@ +package mage.verify; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +class JsonCard { + + static Map loadAll() throws IOException { + return new ObjectMapper().readValue( + JsonCard.class.getResourceAsStream("AllCards.json"), + new TypeReference>() {}); + } + + public String layout; + public String name; + public List names; // flip cards + public String manaCost; + public int cmc; + public List colors; + public String type; + public List supertypes; + public List types; + public List subtypes; + public String text; + public String power; + public String toughness; + public int loyalty; + public String imageName; + public boolean starter; // only available in boxed sets and not in boosters + public int hand; // vanguard + public int life; // vanguard + + // only available in AllSets.json + public String artist; + public String flavor; + public String id; + public int multiverseid; + public String rarity; + public boolean reserved; + public int[] variations; + public String number; + public String releaseDate; // promos + public String border; + public String watermark; + public boolean timeshifted; +} diff --git a/Mage.Verify/src/main/java/mage/verify/JsonSet.java b/Mage.Verify/src/main/java/mage/verify/JsonSet.java new file mode 100644 index 00000000000..93406447560 --- /dev/null +++ b/Mage.Verify/src/main/java/mage/verify/JsonSet.java @@ -0,0 +1,31 @@ +package mage.verify; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +class JsonSet { + + static Map loadAll() throws IOException { + return new ObjectMapper().readValue( + JsonSet.class.getResourceAsStream("AllSets.json"), + new TypeReference>() {}); + } + + public String name; + public String code; + public String oldCode; + public String gathererCode; + public String magicCardsInfoCode; + public String[] magicRaritiesCodes; + public String releaseDate; + public String border; + public String type; + public List booster; // [String|[String]] + public List cards; + public String block; + public boolean onlineOnly; +} diff --git a/Mage.Verify/src/main/java/mage/verify/MtgJson.java b/Mage.Verify/src/main/java/mage/verify/MtgJson.java new file mode 100644 index 00000000000..930f8e06ba2 --- /dev/null +++ b/Mage.Verify/src/main/java/mage/verify/MtgJson.java @@ -0,0 +1,57 @@ +package mage.verify; + +import java.io.IOException; +import java.text.Normalizer; +import java.util.HashMap; +import java.util.Map; + +public class MtgJson { + + private static class CardHolder { + private static final Map cards; + static { + try { + cards = JsonCard.loadAll(); + addAliases(cards); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + public static JsonCard find(String name) { + return findReference(CardHolder.cards, name); + } + + private static T findReference(Map reference, String name) { + T ref = reference.get(name); + if (ref == null) { + name = name.replaceFirst("\\bA[Ee]", "Æ"); + ref = reference.get(name); + } + if (ref == null) { + name = name.replace("'", "\""); // for Kongming, "Sleeping Dragon" & Pang Tong, "Young Phoenix" + ref = reference.get(name); + } + return ref; + } + + private static void addAliases(Map reference) { + Map aliases = new HashMap<>(); + for (String name : reference.keySet()) { + String unaccented = stripAccents(name); + if (!name.equals(unaccented)) { + aliases.put(name, unaccented); + } + } + for (Map.Entry mapping : aliases.entrySet()) { + reference.put(mapping.getValue(), reference.get(mapping.getKey())); + } + } + + private static String stripAccents(String str) { + String decomposed = Normalizer.normalize(str, Normalizer.Form.NFKD); + return decomposed.replaceAll("[\\p{InCombiningDiacriticalMarks}]", ""); + } + +} diff --git a/Mage.Verify/src/test/java/mage/verify/CompareWithMtgjsonTest.java b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java similarity index 59% rename from Mage.Verify/src/test/java/mage/verify/CompareWithMtgjsonTest.java rename to Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java index 5f1c8a07a62..e3469fab3c1 100644 --- a/Mage.Verify/src/test/java/mage/verify/CompareWithMtgjsonTest.java +++ b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java @@ -1,7 +1,5 @@ package mage.verify; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import mage.ObjectColor; import mage.cards.Card; import mage.cards.CardImpl; @@ -17,43 +15,70 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Paths; -import java.text.Normalizer; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; -public class CompareWithMtgjsonTest { +public class VerifyCardDataTest { @Test - public void testSets() throws IOException { - Collection sets = Sets.getInstance().values(); + public void verifySets() throws IOException { + Map reference = JsonSet.loadAll(); - Map> reference = new ObjectMapper().readValue( - CompareWithMtgjsonTest.class.getResourceAsStream("AllCards.json"), - new TypeReference>>() {}); - - Map aliases = new HashMap<>(); - for (String name : reference.keySet()) { - String unaccented = stripAccents(name); - if (!name.equals(unaccented)) { - aliases.put(name, unaccented); + for (ExpansionSet set : Sets.getInstance().values()) { + JsonSet ref = reference.get(set.getCode()); + if (ref == null) { + for (JsonSet js : reference.values()) { + if (set.getCode().equals(js.oldCode) || set.getCode().toLowerCase().equals(js.magicCardsInfoCode)) { + ref = js; + break; + } + } + if (ref == null) { + System.out.println("missing reference for " + set); + continue; + } + } + if (!String.format("%tF", set.getReleaseDate()).equals(ref.releaseDate)) { + System.out.printf("%40s %-20s %20tF %20s%n", set, "release date", set.getReleaseDate(), ref.releaseDate); + } + if (set.hasBoosters() != (ref.booster != null)) { + System.out.printf("%40s %-20s %20s %20s%n", set, "has boosters", set.hasBoosters(), ref.booster != null); + } + boolean refHasBasicLands = false; + for (JsonCard card : ref.cards) { + if ("Mountain".equals(card.name)) { + refHasBasicLands = true; + break; + } + } + if (set.hasBasicLands() != refHasBasicLands) { + System.out.printf("%40s %-20s %20s %20s%n", set, "has basic lands", set.hasBasicLands(), refHasBasicLands); } } - for (Map.Entry mapping : aliases.entrySet()) { - reference.put(mapping.getValue(), reference.get(mapping.getKey())); - } + } + public static List allCards() { + Collection sets = Sets.getInstance().values(); + List cards = new ArrayList<>(); for (ExpansionSet set : sets) { for (ExpansionSet.SetCardInfo setInfo : set.getSetCardInfo()) { - Set tokens = findSourceTokens(setInfo.getCardClass()); - Card card = CardImpl.createCard(setInfo.getCardClass(), new CardSetInfo(setInfo.getName(), set.getCode(), - setInfo.getCardNumber(), setInfo.getRarity(), setInfo.getGraphicInfo())); - if (card.isSplitCard()) { - check(reference, ((SplitCard) card).getLeftHalfCard(), null); - check(reference, ((SplitCard) card).getRightHalfCard(), null); - } else { - check(reference, card, tokens); - } + cards.add(CardImpl.createCard(setInfo.getCardClass(), new CardSetInfo(setInfo.getName(), set.getCode(), + setInfo.getCardNumber(), setInfo.getRarity(), setInfo.getGraphicInfo()))); + } + } + return cards; + } + + @Test + public void verifyCards() throws IOException { + for (Card card : allCards()) { + Set tokens = findSourceTokens(card.getClass()); + if (card.isSplitCard()) { + check(((SplitCard) card).getLeftHalfCard(), null); + check(((SplitCard) card).getRightHalfCard(), null); + } else { + check(card, tokens); } } } @@ -76,22 +101,17 @@ public class CompareWithMtgjsonTest { } } - private String stripAccents(String str) { - String decomposed = Normalizer.normalize(str, Normalizer.Form.NFKD); - return decomposed.replaceAll("[\\p{InCombiningDiacriticalMarks}]", ""); - } - - private void check(Map> reference, Card card, Set tokens) { - Map ref = findReference(reference, card.getName()); + private void check(Card card, Set tokens) { + JsonCard ref = MtgJson.find(card.getName()); if (ref == null) { System.out.println("Missing card reference for " + card); return; } checkAll(card, ref); if (tokens != null) { - Map ref2 = null; + JsonCard ref2 = null; if (card.isFlipCard()) { - ref2 = findReference(reference, card.getFlipCardName()); + ref2 = MtgJson.find(card.getFlipCardName()); } for (String token : tokens) { if (!(token.equals(card.getName()) @@ -105,32 +125,18 @@ public class CompareWithMtgjsonTest { } } - private Map findReference(Map> reference, String name) { - Map ref = reference.get(name); - if (ref == null) { - name = name.replaceFirst("\\bA[Ee]", "Æ"); - ref = reference.get(name); - } - if (ref == null) { - name = name.replace("'", "\""); // for Kongming, "Sleeping Dragon" & Pang Tong, "Young Phoenix" - ref = reference.get(name); - } - return ref; + private boolean containsInTypesOrText(JsonCard ref, String token) { + return contains(ref.types, token) + || contains(ref.subtypes, token) + || contains(ref.supertypes, token) + || ref.text.contains(token); } - private boolean containsInTypesOrText(Map ref, String token) { - return contains(ref, "types", token) - || contains(ref, "subtypes", token) - || contains(ref, "supertypes", token) - || ((String) ref.get("text")).contains(token); - } - - private boolean contains(Map ref, String key, String value) { - Collection options = (Collection) ref.get(key); + private boolean contains(Collection options, String value) { return options != null && options.contains(value); } - private void checkAll(Card card, Map ref) { + private void checkAll(Card card, JsonCard ref) { checkCost(card, ref); checkPT(card, ref); checkSubtypes(card, ref); @@ -139,8 +145,8 @@ public class CompareWithMtgjsonTest { checkColors(card, ref); } - private void checkColors(Card card, Map ref) { - Collection expected = (Collection) ref.get("colors"); + private void checkColors(Card card, JsonCard ref) { + Collection expected = ref.colors; ObjectColor color = card.getColor(null); if (expected == null) { expected = Collections.emptyList(); @@ -155,8 +161,8 @@ public class CompareWithMtgjsonTest { } } - private void checkSubtypes(Card card, Map ref) { - Collection expected = (Collection) ref.get("subtypes"); + private void checkSubtypes(Card card, JsonCard ref) { + Collection expected = ref.subtypes; if (expected != null && expected.contains("Urza’s")) { expected = new ArrayList<>(expected); for (ListIterator it = ((List) expected).listIterator(); it.hasNext();) { @@ -170,15 +176,15 @@ public class CompareWithMtgjsonTest { } } - private void checkSupertypes(Card card, Map ref) { - Collection expected = (Collection) ref.get("supertypes"); + private void checkSupertypes(Card card, JsonCard ref) { + Collection expected = ref.supertypes; if (!eqSet(card.getSupertype(), expected)) { System.out.println(card.getSupertype() + " != " + expected + " for " + card); } } - private void checkTypes(Card card, Map ref) { - Collection expected = (Collection) ref.get("types"); + private void checkTypes(Card card, JsonCard ref) { + Collection expected = ref.types; List type = new ArrayList<>(); for (CardType cardType : card.getCardType()) { type.add(cardType.toString()); @@ -195,9 +201,9 @@ public class CompareWithMtgjsonTest { return b != null && a.size() == b.size() && a.containsAll(b); } - private void checkPT(Card card, Map ref) { + private void checkPT(Card card, JsonCard ref) { String pt = card.getPower() + "/" + card.getToughness(); - String expected = ref.get("power") + "/" + ref.get("toughness"); + String expected = ref.power + "/" + ref.toughness; if ("0/0".equals(pt) && ("null/null".equals(expected) || "*/*".equals(expected))) { // ok } else if (!Objects.equals(pt, expected.replace("*", "0"))) { @@ -205,8 +211,8 @@ public class CompareWithMtgjsonTest { } } - private void checkCost(Card card, Map ref) { - String expected = (String) ref.get("manaCost"); + private void checkCost(Card card, JsonCard ref) { + String expected = ref.manaCost; String cost = join(card.getManaCost().getSymbols()); if ("".equals(cost)) { cost = null; From 510f7a86b614dafa0fa06adbc16175f82c7f8f6f Mon Sep 17 00:00:00 2001 From: Neil Gentleman Date: Sun, 14 Feb 2016 14:33:32 -0800 Subject: [PATCH 04/35] download the json at runtime --- .../src/main/java/mage/verify/JsonCard.java | 14 +---- .../src/main/java/mage/verify/JsonSet.java | 14 +---- .../src/main/java/mage/verify/MtgJson.java | 56 ++++++++++++++++++- .../java/mage/verify/VerifyCardDataTest.java | 22 +++++--- 4 files changed, 73 insertions(+), 33 deletions(-) diff --git a/Mage.Verify/src/main/java/mage/verify/JsonCard.java b/Mage.Verify/src/main/java/mage/verify/JsonCard.java index 01ea6884710..ac0c0dc0691 100644 --- a/Mage.Verify/src/main/java/mage/verify/JsonCard.java +++ b/Mage.Verify/src/main/java/mage/verify/JsonCard.java @@ -1,26 +1,15 @@ package mage.verify; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; - -import java.io.IOException; import java.util.List; -import java.util.Map; class JsonCard { - - static Map loadAll() throws IOException { - return new ObjectMapper().readValue( - JsonCard.class.getResourceAsStream("AllCards.json"), - new TypeReference>() {}); - } - public String layout; public String name; public List names; // flip cards public String manaCost; public int cmc; public List colors; + public List colorIdentity; public String type; public List supertypes; public List types; @@ -33,6 +22,7 @@ class JsonCard { public boolean starter; // only available in boxed sets and not in boosters public int hand; // vanguard public int life; // vanguard + public String mciNumber; // only available in AllSets.json public String artist; diff --git a/Mage.Verify/src/main/java/mage/verify/JsonSet.java b/Mage.Verify/src/main/java/mage/verify/JsonSet.java index 93406447560..4a56a5bd301 100644 --- a/Mage.Verify/src/main/java/mage/verify/JsonSet.java +++ b/Mage.Verify/src/main/java/mage/verify/JsonSet.java @@ -1,20 +1,9 @@ package mage.verify; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; - -import java.io.IOException; import java.util.List; import java.util.Map; class JsonSet { - - static Map loadAll() throws IOException { - return new ObjectMapper().readValue( - JsonSet.class.getResourceAsStream("AllSets.json"), - new TypeReference>() {}); - } - public String name; public String code; public String oldCode; @@ -28,4 +17,7 @@ class JsonSet { public List cards; public String block; public boolean onlineOnly; + public String mkm_id; + public String mkm_name; + public Map translations; } diff --git a/Mage.Verify/src/main/java/mage/verify/MtgJson.java b/Mage.Verify/src/main/java/mage/verify/MtgJson.java index 930f8e06ba2..04488fdfe66 100644 --- a/Mage.Verify/src/main/java/mage/verify/MtgJson.java +++ b/Mage.Verify/src/main/java/mage/verify/MtgJson.java @@ -1,17 +1,28 @@ package mage.verify; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.File; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; import java.text.Normalizer; import java.util.HashMap; import java.util.Map; +import java.util.zip.ZipInputStream; public class MtgJson { + private MtgJson() {} private static class CardHolder { private static final Map cards; static { try { - cards = JsonCard.loadAll(); + cards = loadAllCards(); addAliases(cards); } catch (IOException e) { throw new RuntimeException(e); @@ -19,7 +30,48 @@ public class MtgJson { } } - public static JsonCard find(String name) { + private static class SetHolder { + private static final Map sets; + static { + try { + sets = loadAllSets(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + private static Map loadAllCards() throws IOException { + return readFromZip("AllCards.json.zip", new TypeReference>() {}); + } + + private static Map loadAllSets() throws IOException { + return readFromZip("AllSets.json.zip", new TypeReference>() {}); + } + + private static T readFromZip(String filename, TypeReference ref) throws IOException { + InputStream stream = MtgJson.class.getResourceAsStream(filename); + if (stream == null) { + File file = new File(filename); + if (!file.exists()) { + InputStream download = new URL("http://mtgjson.com/json/" + filename).openStream(); + Files.copy(download, file.toPath(), StandardCopyOption.REPLACE_EXISTING); + System.out.println("Downloaded " + filename + " to " + file.getAbsolutePath()); + } else { + System.out.println("Using " + filename + " from " + file.getAbsolutePath()); + } + stream = new FileInputStream(file); + } + ZipInputStream zipInputStream = new ZipInputStream(stream); + zipInputStream.getNextEntry(); + return new ObjectMapper().readValue(zipInputStream, ref); + } + + public static Map sets() { + return SetHolder.sets; + } + + public static JsonCard card(String name) { return findReference(CardHolder.cards, name); } diff --git a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java index e3469fab3c1..7b0e04fa655 100644 --- a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java +++ b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java @@ -23,7 +23,7 @@ public class VerifyCardDataTest { @Test public void verifySets() throws IOException { - Map reference = JsonSet.loadAll(); + Map reference = MtgJson.sets(); for (ExpansionSet set : Sets.getInstance().values()) { JsonSet ref = reference.get(set.getCode()); @@ -102,7 +102,7 @@ public class VerifyCardDataTest { } private void check(Card card, Set tokens) { - JsonCard ref = MtgJson.find(card.getName()); + JsonCard ref = MtgJson.card(card.getName()); if (ref == null) { System.out.println("Missing card reference for " + card); return; @@ -111,7 +111,7 @@ public class VerifyCardDataTest { if (tokens != null) { JsonCard ref2 = null; if (card.isFlipCard()) { - ref2 = MtgJson.find(card.getFlipCardName()); + ref2 = MtgJson.card(card.getFlipCardName()); } for (String token : tokens) { if (!(token.equals(card.getName()) @@ -202,15 +202,21 @@ public class VerifyCardDataTest { } private void checkPT(Card card, JsonCard ref) { - String pt = card.getPower() + "/" + card.getToughness(); - String expected = ref.power + "/" + ref.toughness; - if ("0/0".equals(pt) && ("null/null".equals(expected) || "*/*".equals(expected))) { - // ok - } else if (!Objects.equals(pt, expected.replace("*", "0"))) { + if (!eqPT(card.getPower().toString(), ref.power) || !eqPT(card.getToughness().toString(), ref.toughness)) { + String pt = card.getPower() + "/" + card.getToughness(); + String expected = ref.power + "/" + ref.toughness; System.out.println(pt + " != " + expected + " for " + card); } } + private boolean eqPT(String found, String expected) { + if (expected == null) { + return "0".equals(found); + } else { + return found.equals(expected) || expected.contains("*"); + } + } + private void checkCost(Card card, JsonCard ref) { String expected = ref.manaCost; String cost = join(card.getManaCost().getSymbols()); From 335950ee8f8b77be873a7c326328362f8a19622f Mon Sep 17 00:00:00 2001 From: Neil Gentleman Date: Sun, 16 Oct 2016 10:34:06 -0700 Subject: [PATCH 05/35] actually fail the test on errors explicitly ignoring the one known error in gatherer and all custom sets --- .../java/mage/verify/VerifyCardDataTest.java | 40 +++++++++++++++---- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java index 7b0e04fa655..055ba315ab0 100644 --- a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java +++ b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java @@ -7,7 +7,9 @@ import mage.cards.CardSetInfo; import mage.cards.ExpansionSet; import mage.cards.Sets; import mage.cards.SplitCard; +import mage.cards.basiclands.BasicLand; import mage.constants.CardType; +import org.junit.Assert; import org.junit.Test; import java.io.IOException; @@ -62,6 +64,9 @@ public class VerifyCardDataTest { Collection sets = Sets.getInstance().values(); List cards = new ArrayList<>(); for (ExpansionSet set : sets) { + if (set.isCustomSet()) { + continue; + } for (ExpansionSet.SetCardInfo setInfo : set.getSetCardInfo()) { cards.add(CardImpl.createCard(setInfo.getCardClass(), new CardSetInfo(setInfo.getName(), set.getCode(), setInfo.getCardNumber(), setInfo.getRarity(), setInfo.getGraphicInfo()))); @@ -70,6 +75,17 @@ public class VerifyCardDataTest { return cards; } + private void warn(Card card, String message) { + System.out.println("Warning: " + message + " for " + card.getName()); + } + + private void fail(Card card, String category, String message) { + failed++; + System.out.println("Error: (" + category + ") " + message + " for " + card.getName()); + } + + private int failed = 0; + @Test public void verifyCards() throws IOException { for (Card card : allCards()) { @@ -81,11 +97,17 @@ public class VerifyCardDataTest { check(card, tokens); } } + if (failed > 0) { + Assert.fail(failed + " Errors"); + } } private static final Pattern SHORT_JAVA_STRING = Pattern.compile("(?<=\")[A-Z][a-z]+(?=\")"); private Set findSourceTokens(Class c) throws IOException { + if (BasicLand.class.isAssignableFrom(c)) { + return Collections.emptySet(); + } String path = "../Mage.Sets/src/" + c.getName().replace(".", "/") + ".java"; try { String source = new String(Files.readAllBytes(Paths.get(path)), StandardCharsets.UTF_8); @@ -104,7 +126,7 @@ public class VerifyCardDataTest { private void check(Card card, Set tokens) { JsonCard ref = MtgJson.card(card.getName()); if (ref == null) { - System.out.println("Missing card reference for " + card); + warn(card, "Missing card reference"); return; } checkAll(card, ref); @@ -146,6 +168,10 @@ public class VerifyCardDataTest { } private void checkColors(Card card, JsonCard ref) { + // gatherer is missing the color indicator on one card: + if ("Ulrich, Uncontested Alpha".equals(ref.name)) { + return; + } Collection expected = ref.colors; ObjectColor color = card.getColor(null); if (expected == null) { @@ -157,7 +183,7 @@ public class VerifyCardDataTest { (color.isGreen() && !expected.contains("Green")) || (color.isRed() && !expected.contains("Red")) || (color.isWhite() && !expected.contains("White"))) { - System.out.println(color + " != " + expected + " for " + card); + fail(card, "colors", color + " != " + expected); } } @@ -172,14 +198,14 @@ public class VerifyCardDataTest { } } if (!eqSet(card.getSubtype(null), expected)) { - System.out.println(card.getSubtype(null) + " != " + expected + " for " + card); + fail(card, "subtypes", card.getSubtype(null) + " != " + expected); } } private void checkSupertypes(Card card, JsonCard ref) { Collection expected = ref.supertypes; if (!eqSet(card.getSupertype(), expected)) { - System.out.println(card.getSupertype() + " != " + expected + " for " + card); + fail(card, "supertypes", card.getSupertype() + " != " + expected); } } @@ -190,7 +216,7 @@ public class VerifyCardDataTest { type.add(cardType.toString()); } if (!eqSet(type, expected)) { - System.out.println(type + " != " + expected + " for " + card); + fail(card, "types", type + " != " + expected); } } @@ -205,7 +231,7 @@ public class VerifyCardDataTest { if (!eqPT(card.getPower().toString(), ref.power) || !eqPT(card.getToughness().toString(), ref.toughness)) { String pt = card.getPower() + "/" + card.getToughness(); String expected = ref.power + "/" + ref.toughness; - System.out.println(pt + " != " + expected + " for " + card); + fail(card, "pt", pt + " != " + expected); } } @@ -227,7 +253,7 @@ public class VerifyCardDataTest { cost = cost.replaceAll("P\\}", "/P}"); } if (!Objects.equals(cost, expected)) { - System.out.println(cost + " != " + expected + " for " + card); + fail(card, "cost", cost + " != " + expected); } } From 2779f81764556bce8f34ea12b71abe035b698cd0 Mon Sep 17 00:00:00 2001 From: Neil Gentleman Date: Sun, 16 Oct 2016 12:02:13 -0700 Subject: [PATCH 06/35] remove tests without assertions - source token checking is very noisy, so disabled it for now - set verification wasn't showing anything interesting --- .../java/mage/verify/VerifyCardDataTest.java | 44 +++---------------- 1 file changed, 5 insertions(+), 39 deletions(-) diff --git a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java index 055ba315ab0..0fe8f7b7418 100644 --- a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java +++ b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java @@ -23,42 +23,8 @@ import java.util.regex.Pattern; public class VerifyCardDataTest { - @Test - public void verifySets() throws IOException { - Map reference = MtgJson.sets(); - - for (ExpansionSet set : Sets.getInstance().values()) { - JsonSet ref = reference.get(set.getCode()); - if (ref == null) { - for (JsonSet js : reference.values()) { - if (set.getCode().equals(js.oldCode) || set.getCode().toLowerCase().equals(js.magicCardsInfoCode)) { - ref = js; - break; - } - } - if (ref == null) { - System.out.println("missing reference for " + set); - continue; - } - } - if (!String.format("%tF", set.getReleaseDate()).equals(ref.releaseDate)) { - System.out.printf("%40s %-20s %20tF %20s%n", set, "release date", set.getReleaseDate(), ref.releaseDate); - } - if (set.hasBoosters() != (ref.booster != null)) { - System.out.printf("%40s %-20s %20s %20s%n", set, "has boosters", set.hasBoosters(), ref.booster != null); - } - boolean refHasBasicLands = false; - for (JsonCard card : ref.cards) { - if ("Mountain".equals(card.name)) { - refHasBasicLands = true; - break; - } - } - if (set.hasBasicLands() != refHasBasicLands) { - System.out.printf("%40s %-20s %20s %20s%n", set, "has basic lands", set.hasBasicLands(), refHasBasicLands); - } - } - } + // right now this is very noisy, and not useful enough to make any assertions on + private static final boolean CHECK_SOURCE_TOKENS = false; public static List allCards() { Collection sets = Sets.getInstance().values(); @@ -105,8 +71,8 @@ public class VerifyCardDataTest { private static final Pattern SHORT_JAVA_STRING = Pattern.compile("(?<=\")[A-Z][a-z]+(?=\")"); private Set findSourceTokens(Class c) throws IOException { - if (BasicLand.class.isAssignableFrom(c)) { - return Collections.emptySet(); + if (!CHECK_SOURCE_TOKENS || BasicLand.class.isAssignableFrom(c)) { + return null; } String path = "../Mage.Sets/src/" + c.getName().replace(".", "/") + ".java"; try { @@ -119,7 +85,7 @@ public class VerifyCardDataTest { return tokens; } catch (NoSuchFileException e) { System.out.println("failed to read " + path); - return Collections.emptySet(); + return null; } } From 99fa296e3715c01f73f2df6cab430fc9194ad62e Mon Sep 17 00:00:00 2001 From: emerald000 Date: Tue, 18 Oct 2016 23:14:07 -0400 Subject: [PATCH 07/35] Added Flux and Withdraw. --- Mage.Sets/src/mage/cards/f/Flux.java | 95 ++++ Mage.Sets/src/mage/cards/w/Withdraw.java | 119 +++++ Mage.Sets/src/mage/sets/Portal.java | 545 +++++++++++----------- Mage.Sets/src/mage/sets/Prophecy.java | 307 ++++++------ Mage.Sets/src/mage/sets/Weatherlight.java | 387 +++++++-------- 5 files changed, 835 insertions(+), 618 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/f/Flux.java create mode 100644 Mage.Sets/src/mage/cards/w/Withdraw.java diff --git a/Mage.Sets/src/mage/cards/f/Flux.java b/Mage.Sets/src/mage/cards/f/Flux.java new file mode 100644 index 00000000000..e213929da8b --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/Flux.java @@ -0,0 +1,95 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.f; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author emerald000 + */ +public class Flux extends CardImpl { + + public Flux(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{U}"); + + // Each player discards any number of cards, then draws that many cards. + this.getSpellAbility().addEffect(new FluxEffect()); + + // Draw a card. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + } + + public Flux(final Flux card) { + super(card); + } + + @Override + public Flux copy() { + return new Flux(this); + } +} + +class FluxEffect extends OneShotEffect { + + FluxEffect() { + super(Outcome.DrawCard); + this.staticText = "Each player discards any number of cards, then draws that many cards"; + } + + FluxEffect(final FluxEffect effect) { + super(effect); + } + + @Override + public FluxEffect copy() { + return new FluxEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + int numToDiscard = player.getAmount(0, player.getHand().size(), "Discard how many cards?", game); + player.discard(numToDiscard, false, source, game); + player.drawCards(numToDiscard, game); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/w/Withdraw.java b/Mage.Sets/src/mage/cards/w/Withdraw.java new file mode 100644 index 00000000000..b56eadce608 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/Withdraw.java @@ -0,0 +1,119 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.w; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.costs.Cost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherTargetPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author emerald000 + */ +public class Withdraw extends CardImpl { + + public Withdraw(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}{U}"); + + // Return target creature to its owner's hand. Then return another target creature to its owner's hand unless its controller pays {1}. + this.getSpellAbility().addEffect(new WithdrawEffect()); + Target target = new TargetCreaturePermanent(new FilterCreaturePermanent("creature to return unconditionally")); + target.setTargetTag(1); + this.getSpellAbility().addTarget(target); + + FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature to return unless {1} is paid"); + filter.add(new AnotherTargetPredicate(2)); + target = new TargetCreaturePermanent(filter); + target.setTargetTag(2); + this.getSpellAbility().addTarget(target); + } + + public Withdraw(final Withdraw card) { + super(card); + } + + @Override + public Withdraw copy() { + return new Withdraw(this); + } +} + +class WithdrawEffect extends OneShotEffect { + + WithdrawEffect() { + super(Outcome.ReturnToHand); + this.staticText = "Return target creature to its owner's hand. Then return another target creature to its owner's hand unless its controller pays {1}"; + } + + WithdrawEffect(final WithdrawEffect effect) { + super(effect); + } + + @Override + public WithdrawEffect copy() { + return new WithdrawEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Effect effect = new ReturnToHandTargetEffect(); + effect.setTargetPointer(new FixedTarget(source.getFirstTarget())); + effect.apply(game, source); + Permanent secondCreature = game.getPermanent(source.getTargets().get(1).getFirstTarget()); + if (secondCreature != null) { + Player creatureController = game.getPlayer(secondCreature.getControllerId()); + if (creatureController != null) { + Cost cost = new GenericManaCost(1); + if (creatureController.chooseUse(Outcome.Benefit, "Pay {1}? (Otherwise " + secondCreature.getName() + " will be returned to its owner's hand)", source, game)) { + cost.pay(source, game, source.getSourceId(), creatureController.getId(), false); + } + if (!cost.isPaid()) { + creatureController.moveCards(secondCreature, Zone.HAND, source, game); + } + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/Portal.java b/Mage.Sets/src/mage/sets/Portal.java index 1d7eae6edfc..4bc69093273 100644 --- a/Mage.Sets/src/mage/sets/Portal.java +++ b/Mage.Sets/src/mage/sets/Portal.java @@ -1,273 +1,274 @@ -/* - * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of BetaSteward_at_googlemail.com. - */ - -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.SetType; -import mage.constants.Rarity; -import mage.cards.CardGraphicInfo; - -/** - * - * @author Plopman - */ - -public class Portal extends ExpansionSet { - - private static final Portal fINSTANCE = new Portal(); - - /** - * - * @return - */ - public static Portal getInstance() { - return fINSTANCE; - } - - private Portal() { - super("Portal", "POR", ExpansionSet.buildDate(1997, 5, 1), SetType.SUPPLEMENTAL); - this.blockName = "Beginner"; - this.hasBasicLands = true; - this.hasBoosters = true; - this.numBoosterLands = 0; - this.numBoosterCommon = 11; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - cards.add(new SetCardInfo("Alabaster Dragon", 163, Rarity.RARE, mage.cards.a.AlabasterDragon.class)); - cards.add(new SetCardInfo("Alluring Scent", 80, Rarity.RARE, mage.cards.a.AlluringScent.class)); - cards.add(new SetCardInfo("Anaconda", 81, Rarity.UNCOMMON, mage.cards.a.Anaconda.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Anaconda", 82, Rarity.UNCOMMON, mage.cards.a.Anaconda.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Ancestral Memories", 41, Rarity.RARE, mage.cards.a.AncestralMemories.class)); - cards.add(new SetCardInfo("Angelic Blessing", 164, Rarity.COMMON, mage.cards.a.AngelicBlessing.class)); - cards.add(new SetCardInfo("Archangel", 165, Rarity.RARE, mage.cards.a.Archangel.class)); - cards.add(new SetCardInfo("Ardent Militia", 166, Rarity.UNCOMMON, mage.cards.a.ArdentMilitia.class)); - cards.add(new SetCardInfo("Armageddon", 167, Rarity.RARE, mage.cards.a.Armageddon.class)); - cards.add(new SetCardInfo("Armored Pegasus", 168, Rarity.COMMON, mage.cards.a.ArmoredPegasus.class)); - cards.add(new SetCardInfo("Arrogant Vampire", 1, Rarity.UNCOMMON, mage.cards.a.ArrogantVampire.class)); - cards.add(new SetCardInfo("Balance of Power", 42, Rarity.RARE, mage.cards.b.BalanceOfPower.class)); - cards.add(new SetCardInfo("Baleful Stare", 43, Rarity.UNCOMMON, mage.cards.b.BalefulStare.class)); - cards.add(new SetCardInfo("Bee Sting", 83, Rarity.UNCOMMON, mage.cards.b.BeeSting.class)); - cards.add(new SetCardInfo("Blaze", 122, Rarity.UNCOMMON, mage.cards.b.Blaze.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Blaze", 123, Rarity.UNCOMMON, mage.cards.b.Blaze.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Blessed Reversal", 169, Rarity.RARE, mage.cards.b.BlessedReversal.class)); - cards.add(new SetCardInfo("Blinding Light", 170, Rarity.RARE, mage.cards.b.BlindingLight.class)); - cards.add(new SetCardInfo("Bog Imp", 3, Rarity.COMMON, mage.cards.b.BogImp.class)); - cards.add(new SetCardInfo("Bog Raiders", 4, Rarity.COMMON, mage.cards.b.BogRaiders.class)); - cards.add(new SetCardInfo("Bog Wraith", 5, Rarity.UNCOMMON, mage.cards.b.BogWraith.class)); - cards.add(new SetCardInfo("Boiling Seas", 124, Rarity.UNCOMMON, mage.cards.b.BoilingSeas.class)); - cards.add(new SetCardInfo("Border Guard", 171, Rarity.COMMON, mage.cards.b.BorderGuard.class)); - cards.add(new SetCardInfo("Breath of Life", 172, Rarity.COMMON, mage.cards.b.BreathOfLife.class)); - cards.add(new SetCardInfo("Bull Hippo", 84, Rarity.UNCOMMON, mage.cards.b.BullHippo.class)); - cards.add(new SetCardInfo("Burning Cloak", 125, Rarity.COMMON, mage.cards.b.BurningCloak.class)); - cards.add(new SetCardInfo("Capricious Sorcerer", 44, Rarity.RARE, mage.cards.c.CapriciousSorcerer.class)); - cards.add(new SetCardInfo("Charging Bandits", 6, Rarity.UNCOMMON, mage.cards.c.ChargingBandits.class)); - cards.add(new SetCardInfo("Charging Paladin", 173, Rarity.UNCOMMON, mage.cards.c.ChargingPaladin.class)); - cards.add(new SetCardInfo("Charging Rhino", 85, Rarity.RARE, mage.cards.c.ChargingRhino.class)); - cards.add(new SetCardInfo("Cloak of Feathers", 45, Rarity.COMMON, mage.cards.c.CloakOfFeathers.class)); - cards.add(new SetCardInfo("Cloud Dragon", 46, Rarity.RARE, mage.cards.c.CloudDragon.class)); - cards.add(new SetCardInfo("Cloud Pirates", 47, Rarity.COMMON, mage.cards.c.CloudPirates.class)); - cards.add(new SetCardInfo("Cloud Spirit", 48, Rarity.UNCOMMON, mage.cards.c.CloudSpirit.class)); - cards.add(new SetCardInfo("Coral Eel", 50, Rarity.COMMON, mage.cards.c.CoralEel.class)); - cards.add(new SetCardInfo("Craven Giant", 126, Rarity.COMMON, mage.cards.c.CravenGiant.class)); - cards.add(new SetCardInfo("Craven Knight", 7, Rarity.COMMON, mage.cards.c.CravenKnight.class)); - cards.add(new SetCardInfo("Cruel Bargain", 8, Rarity.RARE, mage.cards.c.CruelBargain.class)); - cards.add(new SetCardInfo("Cruel Tutor", 9, Rarity.RARE, mage.cards.c.CruelTutor.class)); - cards.add(new SetCardInfo("Deep-Sea Serpent", 52, Rarity.UNCOMMON, mage.cards.d.DeepSeaSerpent.class)); - cards.add(new SetCardInfo("Deja Vu", 53, Rarity.COMMON, mage.cards.d.DejaVu.class)); - cards.add(new SetCardInfo("Desert Drake", 127, Rarity.UNCOMMON, mage.cards.d.DesertDrake.class)); - cards.add(new SetCardInfo("Devastation", 128, Rarity.RARE, mage.cards.d.Devastation.class)); - cards.add(new SetCardInfo("Devoted Hero", 175, Rarity.COMMON, mage.cards.d.DevotedHero.class)); - cards.add(new SetCardInfo("Djinn of the Lamp", 54, Rarity.RARE, mage.cards.d.DjinnOfTheLamp.class)); - cards.add(new SetCardInfo("Dread Reaper", 11, Rarity.RARE, mage.cards.d.DreadReaper.class)); - cards.add(new SetCardInfo("Dry Spell", 12, Rarity.UNCOMMON, mage.cards.d.DrySpell1.class)); - cards.add(new SetCardInfo("Earthquake", 129, Rarity.RARE, mage.cards.e.Earthquake.class)); - cards.add(new SetCardInfo("Ebon Dragon", 13, Rarity.RARE, mage.cards.e.EbonDragon.class)); - cards.add(new SetCardInfo("Elite Cat Warrior", 87, Rarity.COMMON, mage.cards.e.EliteCatWarrior1.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Elite Cat Warrior", 88, Rarity.COMMON, mage.cards.e.EliteCatWarrior1.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Elven Cache", 89, Rarity.COMMON, mage.cards.e.ElvenCache.class)); - cards.add(new SetCardInfo("Elvish Ranger", 90, Rarity.COMMON, mage.cards.e.ElvishRanger.class)); - cards.add(new SetCardInfo("Endless Cockroaches", 14, Rarity.RARE, mage.cards.e.EndlessCockroaches.class)); - cards.add(new SetCardInfo("Exhaustion", 55, Rarity.RARE, mage.cards.e.Exhaustion.class)); - cards.add(new SetCardInfo("False Peace", 176, Rarity.COMMON, mage.cards.f.FalsePeace.class)); - cards.add(new SetCardInfo("Feral Shadow", 15, Rarity.COMMON, mage.cards.f.FeralShadow.class)); - cards.add(new SetCardInfo("Final Strike", 16, Rarity.RARE, mage.cards.f.FinalStrike.class)); - cards.add(new SetCardInfo("Fire Dragon", 130, Rarity.RARE, mage.cards.f.FireDragon.class)); - cards.add(new SetCardInfo("Fire Imp", 131, Rarity.UNCOMMON, mage.cards.f.FireImp.class)); - cards.add(new SetCardInfo("Fire Snake", 132, Rarity.COMMON, mage.cards.f.FireSnake.class)); - cards.add(new SetCardInfo("Fire Tempest", 133, Rarity.RARE, mage.cards.f.FireTempest.class)); - cards.add(new SetCardInfo("Flashfires", 134, Rarity.UNCOMMON, mage.cards.f.Flashfires.class)); - cards.add(new SetCardInfo("Fleet-Footed Monk", 177, Rarity.COMMON, mage.cards.f.FleetFootedMonk.class)); - cards.add(new SetCardInfo("Foot Soldiers", 178, Rarity.COMMON, mage.cards.f.FootSoldiers.class)); - cards.add(new SetCardInfo("Forest", 203, Rarity.LAND, mage.cards.basiclands.Forest.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Forest", 204, Rarity.LAND, mage.cards.basiclands.Forest.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Forest", 205, Rarity.LAND, mage.cards.basiclands.Forest.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Forest", 206, Rarity.LAND, mage.cards.basiclands.Forest.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Fruition", 91, Rarity.COMMON, mage.cards.f.Fruition.class)); - cards.add(new SetCardInfo("Giant Octopus", 57, Rarity.COMMON, mage.cards.g.GiantOctopus.class)); - cards.add(new SetCardInfo("Giant Spider", 92, Rarity.COMMON, mage.cards.g.GiantSpider.class)); - cards.add(new SetCardInfo("Gift of Estates", 179, Rarity.RARE, mage.cards.g.GiftOfEstates.class)); - cards.add(new SetCardInfo("Goblin Bully", 136, Rarity.COMMON, mage.cards.g.GoblinBully.class)); - cards.add(new SetCardInfo("Gorilla Warrior", 93, Rarity.COMMON, mage.cards.g.GorillaWarrior.class)); - cards.add(new SetCardInfo("Gravedigger", 17, Rarity.UNCOMMON, mage.cards.g.Gravedigger.class)); - cards.add(new SetCardInfo("Grizzly Bears", 94, Rarity.COMMON, mage.cards.g.GrizzlyBears.class)); - cards.add(new SetCardInfo("Hand of Death", 18, Rarity.COMMON, mage.cards.h.HandOfDeath.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Hand of Death", 19, Rarity.COMMON, mage.cards.h.HandOfDeath.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Highland Giant", 137, Rarity.COMMON, mage.cards.h.HighlandGiant.class)); - cards.add(new SetCardInfo("Hill Giant", 138, Rarity.COMMON, mage.cards.h.HillGiant.class)); - cards.add(new SetCardInfo("Horned Turtle", 58, Rarity.COMMON, mage.cards.h.HornedTurtle.class)); - cards.add(new SetCardInfo("Howling Fury", 20, Rarity.COMMON, mage.cards.h.HowlingFury.class)); - cards.add(new SetCardInfo("Hulking Cyclops", 139, Rarity.UNCOMMON, mage.cards.h.HulkingCyclops.class)); - cards.add(new SetCardInfo("Hulking Goblin", 140, Rarity.COMMON, mage.cards.h.HulkingGoblin.class)); - cards.add(new SetCardInfo("Hurricane", 95, Rarity.RARE, mage.cards.h.Hurricane.class)); - cards.add(new SetCardInfo("Ingenious Thief", 59, Rarity.UNCOMMON, mage.cards.i.IngeniousThief.class)); - cards.add(new SetCardInfo("Island", 207, Rarity.LAND, mage.cards.basiclands.Island.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Island", 208, Rarity.LAND, mage.cards.basiclands.Island.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Island", 209, Rarity.LAND, mage.cards.basiclands.Island.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Island", 210, Rarity.LAND, mage.cards.basiclands.Island.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Jungle Lion", 96, Rarity.COMMON, mage.cards.j.JungleLion.class)); - cards.add(new SetCardInfo("Keen-Eyed Archers", 181, Rarity.COMMON, mage.cards.k.KeenEyedArchers.class)); - cards.add(new SetCardInfo("King's Assassin", 21, Rarity.RARE, mage.cards.k.KingsAssassin.class)); - cards.add(new SetCardInfo("Knight Errant", 182, Rarity.COMMON, mage.cards.k.KnightErrant.class)); - cards.add(new SetCardInfo("Last Chance", 141, Rarity.RARE, mage.cards.l.LastChance.class)); - cards.add(new SetCardInfo("Lava Axe", 142, Rarity.COMMON, mage.cards.l.LavaAxe.class)); - cards.add(new SetCardInfo("Lava Flow", 143, Rarity.UNCOMMON, mage.cards.l.LavaFlow.class)); - cards.add(new SetCardInfo("Lizard Warrior", 144, Rarity.COMMON, mage.cards.l.LizardWarrior.class)); - cards.add(new SetCardInfo("Man-o'-War", 60, Rarity.UNCOMMON, mage.cards.m.ManOWar.class)); - cards.add(new SetCardInfo("Mercenary Knight", 22, Rarity.RARE, mage.cards.m.MercenaryKnight.class)); - cards.add(new SetCardInfo("Merfolk of the Pearl Trident", 61, Rarity.COMMON, mage.cards.m.MerfolkOfThePearlTrident.class)); - cards.add(new SetCardInfo("Mind Knives", 23, Rarity.COMMON, mage.cards.m.MindKnives.class)); - cards.add(new SetCardInfo("Mind Rot", 24, Rarity.COMMON, mage.cards.m.MindRot.class)); - cards.add(new SetCardInfo("Minotaur Warrior", 145, Rarity.COMMON, mage.cards.m.MinotaurWarrior.class)); - cards.add(new SetCardInfo("Mobilize", 97, Rarity.COMMON, mage.cards.m.Mobilize.class)); - cards.add(new SetCardInfo("Monstrous Growth", 98, Rarity.COMMON, mage.cards.m.MonstrousGrowth.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Monstrous Growth", 99, Rarity.COMMON, mage.cards.m.MonstrousGrowth.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Moon Sprite", 100, Rarity.UNCOMMON, mage.cards.m.MoonSprite.class)); - cards.add(new SetCardInfo("Mountain", 211, Rarity.LAND, mage.cards.basiclands.Mountain.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Mountain", 212, Rarity.LAND, mage.cards.basiclands.Mountain.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Mountain", 213, Rarity.LAND, mage.cards.basiclands.Mountain.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Mountain", 214, Rarity.LAND, mage.cards.basiclands.Mountain.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Mountain Goat", 146, Rarity.UNCOMMON, mage.cards.m.MountainGoat.class)); - cards.add(new SetCardInfo("Muck Rats", 25, Rarity.COMMON, mage.cards.m.MuckRats.class)); - cards.add(new SetCardInfo("Mystic Denial", 62, Rarity.UNCOMMON, mage.cards.m.MysticDenial.class)); - cards.add(new SetCardInfo("Natural Order", 101, Rarity.RARE, mage.cards.n.NaturalOrder.class)); - cards.add(new SetCardInfo("Natural Spring", 102, Rarity.UNCOMMON, mage.cards.n.NaturalSpring.class)); - cards.add(new SetCardInfo("Nature's Cloak", 103, Rarity.RARE, mage.cards.n.NaturesCloak.class)); - cards.add(new SetCardInfo("Nature's Lore", 104, Rarity.COMMON, mage.cards.n.NaturesLore.class)); - cards.add(new SetCardInfo("Nature's Ruin", 26, Rarity.UNCOMMON, mage.cards.n.NaturesRuin.class)); - cards.add(new SetCardInfo("Needle Storm", 105, Rarity.UNCOMMON, mage.cards.n.NeedleStorm.class)); - cards.add(new SetCardInfo("Noxious Toad", 27, Rarity.UNCOMMON, mage.cards.n.NoxiousToad.class)); - cards.add(new SetCardInfo("Omen", 63, Rarity.COMMON, mage.cards.o.Omen.class)); - cards.add(new SetCardInfo("Owl Familiar", 64, Rarity.COMMON, mage.cards.o.OwlFamiliar.class)); - cards.add(new SetCardInfo("Panther Warriors", 106, Rarity.COMMON, mage.cards.p.PantherWarriors.class)); - cards.add(new SetCardInfo("Personal Tutor", 65, Rarity.UNCOMMON, mage.cards.p.PersonalTutor.class)); - cards.add(new SetCardInfo("Phantom Warrior", 66, Rarity.RARE, mage.cards.p.PhantomWarrior.class)); - cards.add(new SetCardInfo("Pillaging Horde", 147, Rarity.RARE, mage.cards.p.PillagingHorde.class)); - cards.add(new SetCardInfo("Plains", 215, Rarity.LAND, mage.cards.basiclands.Plains.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Plains", 216, Rarity.LAND, mage.cards.basiclands.Plains.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Plains", 217, Rarity.LAND, mage.cards.basiclands.Plains.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Plains", 218, Rarity.LAND, mage.cards.basiclands.Plains.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Plant Elemental", 107, Rarity.UNCOMMON, mage.cards.p.PlantElemental.class)); - cards.add(new SetCardInfo("Primeval Force", 108, Rarity.RARE, mage.cards.p.PrimevalForce.class)); - cards.add(new SetCardInfo("Prosperity", 67, Rarity.RARE, mage.cards.p.Prosperity.class)); - cards.add(new SetCardInfo("Pyroclasm", 148, Rarity.RARE, mage.cards.p.Pyroclasm.class)); - cards.add(new SetCardInfo("Python", 28, Rarity.COMMON, mage.cards.p.Python.class)); - cards.add(new SetCardInfo("Raging Cougar", 149, Rarity.COMMON, mage.cards.r.RagingCougar.class)); - cards.add(new SetCardInfo("Raging Goblin", 150, Rarity.COMMON, mage.cards.r.RagingGoblin.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Raging Goblin", 151, Rarity.COMMON, mage.cards.r.RagingGoblin.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Raging Minotaur", 152, Rarity.COMMON, mage.cards.r.RagingMinotaur.class)); - cards.add(new SetCardInfo("Rain of Salt", 153, Rarity.UNCOMMON, mage.cards.r.RainOfSalt.class)); - cards.add(new SetCardInfo("Rain of Tears", 29, Rarity.UNCOMMON, mage.cards.r.RainOfTears.class)); - cards.add(new SetCardInfo("Raise Dead", 30, Rarity.COMMON, mage.cards.r.RaiseDead.class)); - cards.add(new SetCardInfo("Redwood Treefolk", 109, Rarity.COMMON, mage.cards.r.RedwoodTreefolk.class)); - cards.add(new SetCardInfo("Regal Unicorn", 184, Rarity.COMMON, mage.cards.r.RegalUnicorn.class)); - cards.add(new SetCardInfo("Renewing Dawn", 185, Rarity.UNCOMMON, mage.cards.r.RenewingDawn.class)); - cards.add(new SetCardInfo("Rowan Treefolk", 110, Rarity.COMMON, mage.cards.r.RowanTreefolk.class)); - cards.add(new SetCardInfo("Sacred Knight", 186, Rarity.COMMON, mage.cards.s.SacredKnight.class)); - cards.add(new SetCardInfo("Sacred Nectar", 187, Rarity.COMMON, mage.cards.s.SacredNectar.class)); - cards.add(new SetCardInfo("Scorching Spear", 154, Rarity.COMMON, mage.cards.s.ScorchingSpear.class)); - cards.add(new SetCardInfo("Seasoned Marshal", 188, Rarity.UNCOMMON, mage.cards.s.SeasonedMarshal.class)); - cards.add(new SetCardInfo("Serpent Assassin", 31, Rarity.RARE, mage.cards.s.SerpentAssassin.class)); - cards.add(new SetCardInfo("Serpent Warrior", 32, Rarity.COMMON, mage.cards.s.SerpentWarrior.class)); - cards.add(new SetCardInfo("Skeletal Crocodile", 33, Rarity.COMMON, mage.cards.s.SkeletalCrocodile.class)); - cards.add(new SetCardInfo("Skeletal Snake", 34, Rarity.COMMON, mage.cards.s.SkeletalSnake.class)); - cards.add(new SetCardInfo("Snapping Drake", 68, Rarity.COMMON, mage.cards.s.SnappingDrake.class)); - cards.add(new SetCardInfo("Sorcerous Sight", 69, Rarity.COMMON, mage.cards.s.SorcerousSight.class)); - cards.add(new SetCardInfo("Soul Shred", 35, Rarity.COMMON, mage.cards.s.SoulShred.class)); - cards.add(new SetCardInfo("Spined Wurm", 111, Rarity.COMMON, mage.cards.s.SpinedWurm.class)); - cards.add(new SetCardInfo("Spiritual Guardian", 189, Rarity.RARE, mage.cards.s.SpiritualGuardian.class)); - cards.add(new SetCardInfo("Spitting Earth", 156, Rarity.COMMON, mage.cards.s.SpittingEarth.class)); - cards.add(new SetCardInfo("Spotted Griffin", 190, Rarity.COMMON, mage.cards.s.SpottedGriffin.class)); - cards.add(new SetCardInfo("Stalking Tiger", 112, Rarity.COMMON, mage.cards.s.StalkingTiger.class)); - cards.add(new SetCardInfo("Starlight", 191, Rarity.UNCOMMON, mage.cards.s.Starlight.class)); - cards.add(new SetCardInfo("Starlit Angel", 192, Rarity.UNCOMMON, mage.cards.s.StarlitAngel.class)); - cards.add(new SetCardInfo("Steadfastness", 193, Rarity.COMMON, mage.cards.s.Steadfastness.class)); - cards.add(new SetCardInfo("Stern Marshal", 194, Rarity.RARE, mage.cards.s.SternMarshal.class)); - cards.add(new SetCardInfo("Stone Rain", 157, Rarity.COMMON, mage.cards.s.StoneRain.class)); - cards.add(new SetCardInfo("Storm Crow", 70, Rarity.COMMON, mage.cards.s.StormCrow.class)); - cards.add(new SetCardInfo("Summer Bloom", 113, Rarity.RARE, mage.cards.s.SummerBloom.class)); - cards.add(new SetCardInfo("Swamp", 219, Rarity.LAND, mage.cards.basiclands.Swamp.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Swamp", 220, Rarity.LAND, mage.cards.basiclands.Swamp.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Swamp", 221, Rarity.LAND, mage.cards.basiclands.Swamp.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Swamp", 222, Rarity.LAND, mage.cards.basiclands.Swamp.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Sylvan Tutor", 114, Rarity.RARE, mage.cards.s.SylvanTutor.class)); - cards.add(new SetCardInfo("Symbol of Unsummoning", 71, Rarity.COMMON, mage.cards.s.SymbolOfUnsummoning.class)); - cards.add(new SetCardInfo("Taunt", 72, Rarity.RARE, mage.cards.t.Taunt.class)); - cards.add(new SetCardInfo("Theft of Dreams", 73, Rarity.UNCOMMON, mage.cards.t.TheftOfDreams.class)); - cards.add(new SetCardInfo("Thing from the Deep", 74, Rarity.RARE, mage.cards.t.ThingFromTheDeep.class)); - cards.add(new SetCardInfo("Thundering Wurm", 115, Rarity.RARE, mage.cards.t.ThunderingWurm.class)); - cards.add(new SetCardInfo("Thundermare", 158, Rarity.RARE, mage.cards.t.Thundermare.class)); - cards.add(new SetCardInfo("Tidal Surge", 75, Rarity.COMMON, mage.cards.t.TidalSurge.class)); - cards.add(new SetCardInfo("Time Ebb", 76, Rarity.COMMON, mage.cards.t.TimeEbb.class)); - cards.add(new SetCardInfo("Touch of Brilliance", 77, Rarity.COMMON, mage.cards.t.TouchOfBrilliance.class)); - cards.add(new SetCardInfo("Undying Beast", 36, Rarity.COMMON, mage.cards.u.UndyingBeast.class)); - cards.add(new SetCardInfo("Untamed Wilds", 117, Rarity.UNCOMMON, mage.cards.u.UntamedWilds.class)); - cards.add(new SetCardInfo("Valorous Charge", 196, Rarity.UNCOMMON, mage.cards.v.ValorousCharge.class)); - cards.add(new SetCardInfo("Vampiric Feast", 37, Rarity.UNCOMMON, mage.cards.v.VampiricFeast.class)); - cards.add(new SetCardInfo("Vampiric Touch", 38, Rarity.COMMON, mage.cards.v.VampiricTouch.class)); - cards.add(new SetCardInfo("Venerable Monk", 197, Rarity.UNCOMMON, mage.cards.v.VenerableMonk.class)); - cards.add(new SetCardInfo("Vengeance", 198, Rarity.UNCOMMON, mage.cards.v.Vengeance.class)); - cards.add(new SetCardInfo("Virtue's Ruin", 39, Rarity.UNCOMMON, mage.cards.v.VirtuesRuin.class)); - cards.add(new SetCardInfo("Volcanic Dragon", 159, Rarity.RARE, mage.cards.v.VolcanicDragon.class)); - cards.add(new SetCardInfo("Volcanic Hammer", 160, Rarity.COMMON, mage.cards.v.VolcanicHammer.class)); - cards.add(new SetCardInfo("Wall of Granite", 161, Rarity.UNCOMMON, mage.cards.w.WallOfGranite.class)); - cards.add(new SetCardInfo("Wall of Swords", 199, Rarity.UNCOMMON, mage.cards.w.WallOfSwords.class)); - cards.add(new SetCardInfo("Warrior's Charge", 200, Rarity.COMMON, mage.cards.w.WarriorsCharge1.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Warrior's Charge", 201, Rarity.COMMON, mage.cards.w.WarriorsCharge1.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Whiptail Wurm", 118, Rarity.UNCOMMON, mage.cards.w.WhiptailWurm.class)); - cards.add(new SetCardInfo("Wicked Pact", 40, Rarity.RARE, mage.cards.w.WickedPact.class)); - cards.add(new SetCardInfo("Willow Dryad", 119, Rarity.COMMON, mage.cards.w.WillowDryad.class)); - cards.add(new SetCardInfo("Wind Drake", 78, Rarity.COMMON, mage.cards.w.WindDrake.class)); - cards.add(new SetCardInfo("Winds of Change", 162, Rarity.RARE, mage.cards.w.WindsOfChange.class)); - cards.add(new SetCardInfo("Winter's Grasp", 120, Rarity.UNCOMMON, mage.cards.w.WintersGrasp.class)); - cards.add(new SetCardInfo("Withering Gaze", 79, Rarity.UNCOMMON, mage.cards.w.WitheringGaze.class)); - cards.add(new SetCardInfo("Wood Elves", 121, Rarity.RARE, mage.cards.w.WoodElves.class)); - cards.add(new SetCardInfo("Wrath of God", 202, Rarity.RARE, mage.cards.w.WrathOfGod.class)); - } +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.SetType; +import mage.constants.Rarity; +import mage.cards.CardGraphicInfo; + +/** + * + * @author Plopman + */ + +public class Portal extends ExpansionSet { + + private static final Portal fINSTANCE = new Portal(); + + /** + * + * @return + */ + public static Portal getInstance() { + return fINSTANCE; + } + + private Portal() { + super("Portal", "POR", ExpansionSet.buildDate(1997, 5, 1), SetType.SUPPLEMENTAL); + this.blockName = "Beginner"; + this.hasBasicLands = true; + this.hasBoosters = true; + this.numBoosterLands = 0; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + cards.add(new SetCardInfo("Alabaster Dragon", 163, Rarity.RARE, mage.cards.a.AlabasterDragon.class)); + cards.add(new SetCardInfo("Alluring Scent", 80, Rarity.RARE, mage.cards.a.AlluringScent.class)); + cards.add(new SetCardInfo("Anaconda", 81, Rarity.UNCOMMON, mage.cards.a.Anaconda.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Anaconda", 82, Rarity.UNCOMMON, mage.cards.a.Anaconda.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Ancestral Memories", 41, Rarity.RARE, mage.cards.a.AncestralMemories.class)); + cards.add(new SetCardInfo("Angelic Blessing", 164, Rarity.COMMON, mage.cards.a.AngelicBlessing.class)); + cards.add(new SetCardInfo("Archangel", 165, Rarity.RARE, mage.cards.a.Archangel.class)); + cards.add(new SetCardInfo("Ardent Militia", 166, Rarity.UNCOMMON, mage.cards.a.ArdentMilitia.class)); + cards.add(new SetCardInfo("Armageddon", 167, Rarity.RARE, mage.cards.a.Armageddon.class)); + cards.add(new SetCardInfo("Armored Pegasus", 168, Rarity.COMMON, mage.cards.a.ArmoredPegasus.class)); + cards.add(new SetCardInfo("Arrogant Vampire", 1, Rarity.UNCOMMON, mage.cards.a.ArrogantVampire.class)); + cards.add(new SetCardInfo("Balance of Power", 42, Rarity.RARE, mage.cards.b.BalanceOfPower.class)); + cards.add(new SetCardInfo("Baleful Stare", 43, Rarity.UNCOMMON, mage.cards.b.BalefulStare.class)); + cards.add(new SetCardInfo("Bee Sting", 83, Rarity.UNCOMMON, mage.cards.b.BeeSting.class)); + cards.add(new SetCardInfo("Blaze", 122, Rarity.UNCOMMON, mage.cards.b.Blaze.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Blaze", 123, Rarity.UNCOMMON, mage.cards.b.Blaze.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Blessed Reversal", 169, Rarity.RARE, mage.cards.b.BlessedReversal.class)); + cards.add(new SetCardInfo("Blinding Light", 170, Rarity.RARE, mage.cards.b.BlindingLight.class)); + cards.add(new SetCardInfo("Bog Imp", 3, Rarity.COMMON, mage.cards.b.BogImp.class)); + cards.add(new SetCardInfo("Bog Raiders", 4, Rarity.COMMON, mage.cards.b.BogRaiders.class)); + cards.add(new SetCardInfo("Bog Wraith", 5, Rarity.UNCOMMON, mage.cards.b.BogWraith.class)); + cards.add(new SetCardInfo("Boiling Seas", 124, Rarity.UNCOMMON, mage.cards.b.BoilingSeas.class)); + cards.add(new SetCardInfo("Border Guard", 171, Rarity.COMMON, mage.cards.b.BorderGuard.class)); + cards.add(new SetCardInfo("Breath of Life", 172, Rarity.COMMON, mage.cards.b.BreathOfLife.class)); + cards.add(new SetCardInfo("Bull Hippo", 84, Rarity.UNCOMMON, mage.cards.b.BullHippo.class)); + cards.add(new SetCardInfo("Burning Cloak", 125, Rarity.COMMON, mage.cards.b.BurningCloak.class)); + cards.add(new SetCardInfo("Capricious Sorcerer", 44, Rarity.RARE, mage.cards.c.CapriciousSorcerer.class)); + cards.add(new SetCardInfo("Charging Bandits", 6, Rarity.UNCOMMON, mage.cards.c.ChargingBandits.class)); + cards.add(new SetCardInfo("Charging Paladin", 173, Rarity.UNCOMMON, mage.cards.c.ChargingPaladin.class)); + cards.add(new SetCardInfo("Charging Rhino", 85, Rarity.RARE, mage.cards.c.ChargingRhino.class)); + cards.add(new SetCardInfo("Cloak of Feathers", 45, Rarity.COMMON, mage.cards.c.CloakOfFeathers.class)); + cards.add(new SetCardInfo("Cloud Dragon", 46, Rarity.RARE, mage.cards.c.CloudDragon.class)); + cards.add(new SetCardInfo("Cloud Pirates", 47, Rarity.COMMON, mage.cards.c.CloudPirates.class)); + cards.add(new SetCardInfo("Cloud Spirit", 48, Rarity.UNCOMMON, mage.cards.c.CloudSpirit.class)); + cards.add(new SetCardInfo("Coral Eel", 50, Rarity.COMMON, mage.cards.c.CoralEel.class)); + cards.add(new SetCardInfo("Craven Giant", 126, Rarity.COMMON, mage.cards.c.CravenGiant.class)); + cards.add(new SetCardInfo("Craven Knight", 7, Rarity.COMMON, mage.cards.c.CravenKnight.class)); + cards.add(new SetCardInfo("Cruel Bargain", 8, Rarity.RARE, mage.cards.c.CruelBargain.class)); + cards.add(new SetCardInfo("Cruel Tutor", 9, Rarity.RARE, mage.cards.c.CruelTutor.class)); + cards.add(new SetCardInfo("Deep-Sea Serpent", 52, Rarity.UNCOMMON, mage.cards.d.DeepSeaSerpent.class)); + cards.add(new SetCardInfo("Deja Vu", 53, Rarity.COMMON, mage.cards.d.DejaVu.class)); + cards.add(new SetCardInfo("Desert Drake", 127, Rarity.UNCOMMON, mage.cards.d.DesertDrake.class)); + cards.add(new SetCardInfo("Devastation", 128, Rarity.RARE, mage.cards.d.Devastation.class)); + cards.add(new SetCardInfo("Devoted Hero", 175, Rarity.COMMON, mage.cards.d.DevotedHero.class)); + cards.add(new SetCardInfo("Djinn of the Lamp", 54, Rarity.RARE, mage.cards.d.DjinnOfTheLamp.class)); + cards.add(new SetCardInfo("Dread Reaper", 11, Rarity.RARE, mage.cards.d.DreadReaper.class)); + cards.add(new SetCardInfo("Dry Spell", 12, Rarity.UNCOMMON, mage.cards.d.DrySpell1.class)); + cards.add(new SetCardInfo("Earthquake", 129, Rarity.RARE, mage.cards.e.Earthquake.class)); + cards.add(new SetCardInfo("Ebon Dragon", 13, Rarity.RARE, mage.cards.e.EbonDragon.class)); + cards.add(new SetCardInfo("Elite Cat Warrior", 87, Rarity.COMMON, mage.cards.e.EliteCatWarrior1.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Elite Cat Warrior", 88, Rarity.COMMON, mage.cards.e.EliteCatWarrior1.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Elven Cache", 89, Rarity.COMMON, mage.cards.e.ElvenCache.class)); + cards.add(new SetCardInfo("Elvish Ranger", 90, Rarity.COMMON, mage.cards.e.ElvishRanger.class)); + cards.add(new SetCardInfo("Endless Cockroaches", 14, Rarity.RARE, mage.cards.e.EndlessCockroaches.class)); + cards.add(new SetCardInfo("Exhaustion", 55, Rarity.RARE, mage.cards.e.Exhaustion.class)); + cards.add(new SetCardInfo("False Peace", 176, Rarity.COMMON, mage.cards.f.FalsePeace.class)); + cards.add(new SetCardInfo("Feral Shadow", 15, Rarity.COMMON, mage.cards.f.FeralShadow.class)); + cards.add(new SetCardInfo("Final Strike", 16, Rarity.RARE, mage.cards.f.FinalStrike.class)); + cards.add(new SetCardInfo("Fire Dragon", 130, Rarity.RARE, mage.cards.f.FireDragon.class)); + cards.add(new SetCardInfo("Fire Imp", 131, Rarity.UNCOMMON, mage.cards.f.FireImp.class)); + cards.add(new SetCardInfo("Fire Snake", 132, Rarity.COMMON, mage.cards.f.FireSnake.class)); + cards.add(new SetCardInfo("Fire Tempest", 133, Rarity.RARE, mage.cards.f.FireTempest.class)); + cards.add(new SetCardInfo("Flashfires", 134, Rarity.UNCOMMON, mage.cards.f.Flashfires.class)); + cards.add(new SetCardInfo("Fleet-Footed Monk", 177, Rarity.COMMON, mage.cards.f.FleetFootedMonk.class)); + cards.add(new SetCardInfo("Flux", 56, Rarity.UNCOMMON, mage.cards.f.Flux.class)); + cards.add(new SetCardInfo("Foot Soldiers", 178, Rarity.COMMON, mage.cards.f.FootSoldiers.class)); + cards.add(new SetCardInfo("Forest", 203, Rarity.LAND, mage.cards.basiclands.Forest.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Forest", 204, Rarity.LAND, mage.cards.basiclands.Forest.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Forest", 205, Rarity.LAND, mage.cards.basiclands.Forest.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Forest", 206, Rarity.LAND, mage.cards.basiclands.Forest.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Fruition", 91, Rarity.COMMON, mage.cards.f.Fruition.class)); + cards.add(new SetCardInfo("Giant Octopus", 57, Rarity.COMMON, mage.cards.g.GiantOctopus.class)); + cards.add(new SetCardInfo("Giant Spider", 92, Rarity.COMMON, mage.cards.g.GiantSpider.class)); + cards.add(new SetCardInfo("Gift of Estates", 179, Rarity.RARE, mage.cards.g.GiftOfEstates.class)); + cards.add(new SetCardInfo("Goblin Bully", 136, Rarity.COMMON, mage.cards.g.GoblinBully.class)); + cards.add(new SetCardInfo("Gorilla Warrior", 93, Rarity.COMMON, mage.cards.g.GorillaWarrior.class)); + cards.add(new SetCardInfo("Gravedigger", 17, Rarity.UNCOMMON, mage.cards.g.Gravedigger.class)); + cards.add(new SetCardInfo("Grizzly Bears", 94, Rarity.COMMON, mage.cards.g.GrizzlyBears.class)); + cards.add(new SetCardInfo("Hand of Death", 18, Rarity.COMMON, mage.cards.h.HandOfDeath.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Hand of Death", 19, Rarity.COMMON, mage.cards.h.HandOfDeath.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Highland Giant", 137, Rarity.COMMON, mage.cards.h.HighlandGiant.class)); + cards.add(new SetCardInfo("Hill Giant", 138, Rarity.COMMON, mage.cards.h.HillGiant.class)); + cards.add(new SetCardInfo("Horned Turtle", 58, Rarity.COMMON, mage.cards.h.HornedTurtle.class)); + cards.add(new SetCardInfo("Howling Fury", 20, Rarity.COMMON, mage.cards.h.HowlingFury.class)); + cards.add(new SetCardInfo("Hulking Cyclops", 139, Rarity.UNCOMMON, mage.cards.h.HulkingCyclops.class)); + cards.add(new SetCardInfo("Hulking Goblin", 140, Rarity.COMMON, mage.cards.h.HulkingGoblin.class)); + cards.add(new SetCardInfo("Hurricane", 95, Rarity.RARE, mage.cards.h.Hurricane.class)); + cards.add(new SetCardInfo("Ingenious Thief", 59, Rarity.UNCOMMON, mage.cards.i.IngeniousThief.class)); + cards.add(new SetCardInfo("Island", 207, Rarity.LAND, mage.cards.basiclands.Island.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Island", 208, Rarity.LAND, mage.cards.basiclands.Island.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Island", 209, Rarity.LAND, mage.cards.basiclands.Island.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Island", 210, Rarity.LAND, mage.cards.basiclands.Island.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Jungle Lion", 96, Rarity.COMMON, mage.cards.j.JungleLion.class)); + cards.add(new SetCardInfo("Keen-Eyed Archers", 181, Rarity.COMMON, mage.cards.k.KeenEyedArchers.class)); + cards.add(new SetCardInfo("King's Assassin", 21, Rarity.RARE, mage.cards.k.KingsAssassin.class)); + cards.add(new SetCardInfo("Knight Errant", 182, Rarity.COMMON, mage.cards.k.KnightErrant.class)); + cards.add(new SetCardInfo("Last Chance", 141, Rarity.RARE, mage.cards.l.LastChance.class)); + cards.add(new SetCardInfo("Lava Axe", 142, Rarity.COMMON, mage.cards.l.LavaAxe.class)); + cards.add(new SetCardInfo("Lava Flow", 143, Rarity.UNCOMMON, mage.cards.l.LavaFlow.class)); + cards.add(new SetCardInfo("Lizard Warrior", 144, Rarity.COMMON, mage.cards.l.LizardWarrior.class)); + cards.add(new SetCardInfo("Man-o'-War", 60, Rarity.UNCOMMON, mage.cards.m.ManOWar.class)); + cards.add(new SetCardInfo("Mercenary Knight", 22, Rarity.RARE, mage.cards.m.MercenaryKnight.class)); + cards.add(new SetCardInfo("Merfolk of the Pearl Trident", 61, Rarity.COMMON, mage.cards.m.MerfolkOfThePearlTrident.class)); + cards.add(new SetCardInfo("Mind Knives", 23, Rarity.COMMON, mage.cards.m.MindKnives.class)); + cards.add(new SetCardInfo("Mind Rot", 24, Rarity.COMMON, mage.cards.m.MindRot.class)); + cards.add(new SetCardInfo("Minotaur Warrior", 145, Rarity.COMMON, mage.cards.m.MinotaurWarrior.class)); + cards.add(new SetCardInfo("Mobilize", 97, Rarity.COMMON, mage.cards.m.Mobilize.class)); + cards.add(new SetCardInfo("Monstrous Growth", 98, Rarity.COMMON, mage.cards.m.MonstrousGrowth.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Monstrous Growth", 99, Rarity.COMMON, mage.cards.m.MonstrousGrowth.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Moon Sprite", 100, Rarity.UNCOMMON, mage.cards.m.MoonSprite.class)); + cards.add(new SetCardInfo("Mountain", 211, Rarity.LAND, mage.cards.basiclands.Mountain.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Mountain", 212, Rarity.LAND, mage.cards.basiclands.Mountain.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Mountain", 213, Rarity.LAND, mage.cards.basiclands.Mountain.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Mountain", 214, Rarity.LAND, mage.cards.basiclands.Mountain.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Mountain Goat", 146, Rarity.UNCOMMON, mage.cards.m.MountainGoat.class)); + cards.add(new SetCardInfo("Muck Rats", 25, Rarity.COMMON, mage.cards.m.MuckRats.class)); + cards.add(new SetCardInfo("Mystic Denial", 62, Rarity.UNCOMMON, mage.cards.m.MysticDenial.class)); + cards.add(new SetCardInfo("Natural Order", 101, Rarity.RARE, mage.cards.n.NaturalOrder.class)); + cards.add(new SetCardInfo("Natural Spring", 102, Rarity.UNCOMMON, mage.cards.n.NaturalSpring.class)); + cards.add(new SetCardInfo("Nature's Cloak", 103, Rarity.RARE, mage.cards.n.NaturesCloak.class)); + cards.add(new SetCardInfo("Nature's Lore", 104, Rarity.COMMON, mage.cards.n.NaturesLore.class)); + cards.add(new SetCardInfo("Nature's Ruin", 26, Rarity.UNCOMMON, mage.cards.n.NaturesRuin.class)); + cards.add(new SetCardInfo("Needle Storm", 105, Rarity.UNCOMMON, mage.cards.n.NeedleStorm.class)); + cards.add(new SetCardInfo("Noxious Toad", 27, Rarity.UNCOMMON, mage.cards.n.NoxiousToad.class)); + cards.add(new SetCardInfo("Omen", 63, Rarity.COMMON, mage.cards.o.Omen.class)); + cards.add(new SetCardInfo("Owl Familiar", 64, Rarity.COMMON, mage.cards.o.OwlFamiliar.class)); + cards.add(new SetCardInfo("Panther Warriors", 106, Rarity.COMMON, mage.cards.p.PantherWarriors.class)); + cards.add(new SetCardInfo("Personal Tutor", 65, Rarity.UNCOMMON, mage.cards.p.PersonalTutor.class)); + cards.add(new SetCardInfo("Phantom Warrior", 66, Rarity.RARE, mage.cards.p.PhantomWarrior.class)); + cards.add(new SetCardInfo("Pillaging Horde", 147, Rarity.RARE, mage.cards.p.PillagingHorde.class)); + cards.add(new SetCardInfo("Plains", 215, Rarity.LAND, mage.cards.basiclands.Plains.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Plains", 216, Rarity.LAND, mage.cards.basiclands.Plains.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Plains", 217, Rarity.LAND, mage.cards.basiclands.Plains.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Plains", 218, Rarity.LAND, mage.cards.basiclands.Plains.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Plant Elemental", 107, Rarity.UNCOMMON, mage.cards.p.PlantElemental.class)); + cards.add(new SetCardInfo("Primeval Force", 108, Rarity.RARE, mage.cards.p.PrimevalForce.class)); + cards.add(new SetCardInfo("Prosperity", 67, Rarity.RARE, mage.cards.p.Prosperity.class)); + cards.add(new SetCardInfo("Pyroclasm", 148, Rarity.RARE, mage.cards.p.Pyroclasm.class)); + cards.add(new SetCardInfo("Python", 28, Rarity.COMMON, mage.cards.p.Python.class)); + cards.add(new SetCardInfo("Raging Cougar", 149, Rarity.COMMON, mage.cards.r.RagingCougar.class)); + cards.add(new SetCardInfo("Raging Goblin", 150, Rarity.COMMON, mage.cards.r.RagingGoblin.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Raging Goblin", 151, Rarity.COMMON, mage.cards.r.RagingGoblin.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Raging Minotaur", 152, Rarity.COMMON, mage.cards.r.RagingMinotaur.class)); + cards.add(new SetCardInfo("Rain of Salt", 153, Rarity.UNCOMMON, mage.cards.r.RainOfSalt.class)); + cards.add(new SetCardInfo("Rain of Tears", 29, Rarity.UNCOMMON, mage.cards.r.RainOfTears.class)); + cards.add(new SetCardInfo("Raise Dead", 30, Rarity.COMMON, mage.cards.r.RaiseDead.class)); + cards.add(new SetCardInfo("Redwood Treefolk", 109, Rarity.COMMON, mage.cards.r.RedwoodTreefolk.class)); + cards.add(new SetCardInfo("Regal Unicorn", 184, Rarity.COMMON, mage.cards.r.RegalUnicorn.class)); + cards.add(new SetCardInfo("Renewing Dawn", 185, Rarity.UNCOMMON, mage.cards.r.RenewingDawn.class)); + cards.add(new SetCardInfo("Rowan Treefolk", 110, Rarity.COMMON, mage.cards.r.RowanTreefolk.class)); + cards.add(new SetCardInfo("Sacred Knight", 186, Rarity.COMMON, mage.cards.s.SacredKnight.class)); + cards.add(new SetCardInfo("Sacred Nectar", 187, Rarity.COMMON, mage.cards.s.SacredNectar.class)); + cards.add(new SetCardInfo("Scorching Spear", 154, Rarity.COMMON, mage.cards.s.ScorchingSpear.class)); + cards.add(new SetCardInfo("Seasoned Marshal", 188, Rarity.UNCOMMON, mage.cards.s.SeasonedMarshal.class)); + cards.add(new SetCardInfo("Serpent Assassin", 31, Rarity.RARE, mage.cards.s.SerpentAssassin.class)); + cards.add(new SetCardInfo("Serpent Warrior", 32, Rarity.COMMON, mage.cards.s.SerpentWarrior.class)); + cards.add(new SetCardInfo("Skeletal Crocodile", 33, Rarity.COMMON, mage.cards.s.SkeletalCrocodile.class)); + cards.add(new SetCardInfo("Skeletal Snake", 34, Rarity.COMMON, mage.cards.s.SkeletalSnake.class)); + cards.add(new SetCardInfo("Snapping Drake", 68, Rarity.COMMON, mage.cards.s.SnappingDrake.class)); + cards.add(new SetCardInfo("Sorcerous Sight", 69, Rarity.COMMON, mage.cards.s.SorcerousSight.class)); + cards.add(new SetCardInfo("Soul Shred", 35, Rarity.COMMON, mage.cards.s.SoulShred.class)); + cards.add(new SetCardInfo("Spined Wurm", 111, Rarity.COMMON, mage.cards.s.SpinedWurm.class)); + cards.add(new SetCardInfo("Spiritual Guardian", 189, Rarity.RARE, mage.cards.s.SpiritualGuardian.class)); + cards.add(new SetCardInfo("Spitting Earth", 156, Rarity.COMMON, mage.cards.s.SpittingEarth.class)); + cards.add(new SetCardInfo("Spotted Griffin", 190, Rarity.COMMON, mage.cards.s.SpottedGriffin.class)); + cards.add(new SetCardInfo("Stalking Tiger", 112, Rarity.COMMON, mage.cards.s.StalkingTiger.class)); + cards.add(new SetCardInfo("Starlight", 191, Rarity.UNCOMMON, mage.cards.s.Starlight.class)); + cards.add(new SetCardInfo("Starlit Angel", 192, Rarity.UNCOMMON, mage.cards.s.StarlitAngel.class)); + cards.add(new SetCardInfo("Steadfastness", 193, Rarity.COMMON, mage.cards.s.Steadfastness.class)); + cards.add(new SetCardInfo("Stern Marshal", 194, Rarity.RARE, mage.cards.s.SternMarshal.class)); + cards.add(new SetCardInfo("Stone Rain", 157, Rarity.COMMON, mage.cards.s.StoneRain.class)); + cards.add(new SetCardInfo("Storm Crow", 70, Rarity.COMMON, mage.cards.s.StormCrow.class)); + cards.add(new SetCardInfo("Summer Bloom", 113, Rarity.RARE, mage.cards.s.SummerBloom.class)); + cards.add(new SetCardInfo("Swamp", 219, Rarity.LAND, mage.cards.basiclands.Swamp.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Swamp", 220, Rarity.LAND, mage.cards.basiclands.Swamp.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Swamp", 221, Rarity.LAND, mage.cards.basiclands.Swamp.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Swamp", 222, Rarity.LAND, mage.cards.basiclands.Swamp.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Sylvan Tutor", 114, Rarity.RARE, mage.cards.s.SylvanTutor.class)); + cards.add(new SetCardInfo("Symbol of Unsummoning", 71, Rarity.COMMON, mage.cards.s.SymbolOfUnsummoning.class)); + cards.add(new SetCardInfo("Taunt", 72, Rarity.RARE, mage.cards.t.Taunt.class)); + cards.add(new SetCardInfo("Theft of Dreams", 73, Rarity.UNCOMMON, mage.cards.t.TheftOfDreams.class)); + cards.add(new SetCardInfo("Thing from the Deep", 74, Rarity.RARE, mage.cards.t.ThingFromTheDeep.class)); + cards.add(new SetCardInfo("Thundering Wurm", 115, Rarity.RARE, mage.cards.t.ThunderingWurm.class)); + cards.add(new SetCardInfo("Thundermare", 158, Rarity.RARE, mage.cards.t.Thundermare.class)); + cards.add(new SetCardInfo("Tidal Surge", 75, Rarity.COMMON, mage.cards.t.TidalSurge.class)); + cards.add(new SetCardInfo("Time Ebb", 76, Rarity.COMMON, mage.cards.t.TimeEbb.class)); + cards.add(new SetCardInfo("Touch of Brilliance", 77, Rarity.COMMON, mage.cards.t.TouchOfBrilliance.class)); + cards.add(new SetCardInfo("Undying Beast", 36, Rarity.COMMON, mage.cards.u.UndyingBeast.class)); + cards.add(new SetCardInfo("Untamed Wilds", 117, Rarity.UNCOMMON, mage.cards.u.UntamedWilds.class)); + cards.add(new SetCardInfo("Valorous Charge", 196, Rarity.UNCOMMON, mage.cards.v.ValorousCharge.class)); + cards.add(new SetCardInfo("Vampiric Feast", 37, Rarity.UNCOMMON, mage.cards.v.VampiricFeast.class)); + cards.add(new SetCardInfo("Vampiric Touch", 38, Rarity.COMMON, mage.cards.v.VampiricTouch.class)); + cards.add(new SetCardInfo("Venerable Monk", 197, Rarity.UNCOMMON, mage.cards.v.VenerableMonk.class)); + cards.add(new SetCardInfo("Vengeance", 198, Rarity.UNCOMMON, mage.cards.v.Vengeance.class)); + cards.add(new SetCardInfo("Virtue's Ruin", 39, Rarity.UNCOMMON, mage.cards.v.VirtuesRuin.class)); + cards.add(new SetCardInfo("Volcanic Dragon", 159, Rarity.RARE, mage.cards.v.VolcanicDragon.class)); + cards.add(new SetCardInfo("Volcanic Hammer", 160, Rarity.COMMON, mage.cards.v.VolcanicHammer.class)); + cards.add(new SetCardInfo("Wall of Granite", 161, Rarity.UNCOMMON, mage.cards.w.WallOfGranite.class)); + cards.add(new SetCardInfo("Wall of Swords", 199, Rarity.UNCOMMON, mage.cards.w.WallOfSwords.class)); + cards.add(new SetCardInfo("Warrior's Charge", 200, Rarity.COMMON, mage.cards.w.WarriorsCharge1.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Warrior's Charge", 201, Rarity.COMMON, mage.cards.w.WarriorsCharge1.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Whiptail Wurm", 118, Rarity.UNCOMMON, mage.cards.w.WhiptailWurm.class)); + cards.add(new SetCardInfo("Wicked Pact", 40, Rarity.RARE, mage.cards.w.WickedPact.class)); + cards.add(new SetCardInfo("Willow Dryad", 119, Rarity.COMMON, mage.cards.w.WillowDryad.class)); + cards.add(new SetCardInfo("Wind Drake", 78, Rarity.COMMON, mage.cards.w.WindDrake.class)); + cards.add(new SetCardInfo("Winds of Change", 162, Rarity.RARE, mage.cards.w.WindsOfChange.class)); + cards.add(new SetCardInfo("Winter's Grasp", 120, Rarity.UNCOMMON, mage.cards.w.WintersGrasp.class)); + cards.add(new SetCardInfo("Withering Gaze", 79, Rarity.UNCOMMON, mage.cards.w.WitheringGaze.class)); + cards.add(new SetCardInfo("Wood Elves", 121, Rarity.RARE, mage.cards.w.WoodElves.class)); + cards.add(new SetCardInfo("Wrath of God", 202, Rarity.RARE, mage.cards.w.WrathOfGod.class)); + } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/Prophecy.java b/Mage.Sets/src/mage/sets/Prophecy.java index e4a7e8f3bcf..de90cb1fc1f 100644 --- a/Mage.Sets/src/mage/sets/Prophecy.java +++ b/Mage.Sets/src/mage/sets/Prophecy.java @@ -1,153 +1,154 @@ -/* - * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of BetaSteward_at_googlemail.com. - */ -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.SetType; -import mage.constants.Rarity; - -/** - * - * @author North - */ -public class Prophecy extends ExpansionSet { - - private static final Prophecy fINSTANCE = new Prophecy(); - - public static Prophecy getInstance() { - return fINSTANCE; - } - - private Prophecy() { - super("Prophecy", "PCY", ExpansionSet.buildDate(2000, 4, 27), SetType.EXPANSION); - this.blockName = "Masques"; - this.parentSet = MercadianMasques.getInstance(); - this.hasBasicLands = false; - this.hasBoosters = true; - this.numBoosterLands = 0; - this.numBoosterCommon = 11; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - cards.add(new SetCardInfo("Abolish", 1, Rarity.UNCOMMON, mage.cards.a.Abolish.class)); - cards.add(new SetCardInfo("Agent of Shauku", 55, Rarity.COMMON, mage.cards.a.AgentOfShauku.class)); - cards.add(new SetCardInfo("Alexi's Cloak", 29, Rarity.COMMON, mage.cards.a.AlexisCloak.class)); - cards.add(new SetCardInfo("Alexi, Zephyr Mage", 28, Rarity.RARE, mage.cards.a.AlexiZephyrMage.class)); - cards.add(new SetCardInfo("Aura Fracture", 2, Rarity.COMMON, mage.cards.a.AuraFracture.class)); - cards.add(new SetCardInfo("Avatar of Fury", 82, Rarity.RARE, mage.cards.a.AvatarOfFury.class)); - cards.add(new SetCardInfo("Avatar of Hope", 3, Rarity.RARE, mage.cards.a.AvatarOfHope.class)); - cards.add(new SetCardInfo("Avatar of Might", 109, Rarity.RARE, mage.cards.a.AvatarOfMight.class)); - cards.add(new SetCardInfo("Avatar of Will", 30, Rarity.RARE, mage.cards.a.AvatarOfWill.class)); - cards.add(new SetCardInfo("Avatar of Woe", 56, Rarity.RARE, mage.cards.a.AvatarOfWoe.class)); - cards.add(new SetCardInfo("Barbed Field", 83, Rarity.UNCOMMON, mage.cards.b.BarbedField.class)); - cards.add(new SetCardInfo("Blessed Wind", 4, Rarity.RARE, mage.cards.b.BlessedWind.class)); - cards.add(new SetCardInfo("Bog Elemental", 57, Rarity.RARE, mage.cards.b.BogElemental.class)); - cards.add(new SetCardInfo("Bog Glider", 58, Rarity.COMMON, mage.cards.b.BogGlider.class)); - cards.add(new SetCardInfo("Calming Verse", 110, Rarity.COMMON, mage.cards.c.CalmingVerse.class)); - cards.add(new SetCardInfo("Chilling Apparition", 59, Rarity.UNCOMMON, mage.cards.c.ChillingApparition.class)); - cards.add(new SetCardInfo("Chimeric Idol", 136, Rarity.UNCOMMON, mage.cards.c.ChimericIdol.class)); - cards.add(new SetCardInfo("Coastal Hornclaw", 31, Rarity.COMMON, mage.cards.c.CoastalHornclaw.class)); - cards.add(new SetCardInfo("Darba", 111, Rarity.UNCOMMON, mage.cards.d.Darba.class)); - cards.add(new SetCardInfo("Denying Wind", 32, Rarity.RARE, mage.cards.d.DenyingWind.class)); - cards.add(new SetCardInfo("Despoil", 62, Rarity.COMMON, mage.cards.d.Despoil.class)); - cards.add(new SetCardInfo("Devastate", 87, Rarity.COMMON, mage.cards.d.Devastate.class)); - cards.add(new SetCardInfo("Diving Griffin", 6, Rarity.COMMON, mage.cards.d.DivingGriffin.class)); - cards.add(new SetCardInfo("Excavation", 33, Rarity.UNCOMMON, mage.cards.e.Excavation.class)); - cards.add(new SetCardInfo("Fault Riders", 88, Rarity.COMMON, mage.cards.f.FaultRiders.class)); - cards.add(new SetCardInfo("Fen Stalker", 64, Rarity.COMMON, mage.cards.f.FenStalker.class)); - cards.add(new SetCardInfo("Flameshot", 90, Rarity.UNCOMMON, mage.cards.f.Flameshot.class)); - cards.add(new SetCardInfo("Flowering Field", 9, Rarity.UNCOMMON, mage.cards.f.FloweringField.class)); - cards.add(new SetCardInfo("Foil", 34, Rarity.UNCOMMON, mage.cards.f.Foil.class)); - cards.add(new SetCardInfo("Greel's Caress", 67, Rarity.COMMON, mage.cards.g.GreelsCaress.class)); - cards.add(new SetCardInfo("Gulf Squid", 35, Rarity.COMMON, mage.cards.g.GulfSquid.class)); - cards.add(new SetCardInfo("Hazy Homunculus", 36, Rarity.COMMON, mage.cards.h.HazyHomunculus.class)); - cards.add(new SetCardInfo("Heightened Awareness", 37, Rarity.RARE, mage.cards.h.HeightenedAwareness.class)); - cards.add(new SetCardInfo("Infernal Genesis", 68, Rarity.RARE, mage.cards.i.InfernalGenesis.class)); - cards.add(new SetCardInfo("Inflame", 91, Rarity.COMMON, mage.cards.i.Inflame.class)); - cards.add(new SetCardInfo("Jeweled Spirit", 12, Rarity.RARE, mage.cards.j.JeweledSpirit.class)); - cards.add(new SetCardInfo("Jolrael, Empress of Beasts", 115, Rarity.RARE, mage.cards.j.JolraelEmpressOfBeasts.class)); - cards.add(new SetCardInfo("Jolrael's Favor", 116, Rarity.COMMON, mage.cards.j.JolraelsFavor.class)); - cards.add(new SetCardInfo("Keldon Arsonist", 92, Rarity.UNCOMMON, mage.cards.k.KeldonArsonist.class)); - cards.add(new SetCardInfo("Latulla, Keldon Overseer", 95, Rarity.RARE, mage.cards.l.LatullaKeldonOverseer.class)); - cards.add(new SetCardInfo("Lesser Gargadon", 97, Rarity.UNCOMMON, mage.cards.l.LesserGargadon.class)); - cards.add(new SetCardInfo("Living Terrain", 117, Rarity.UNCOMMON, mage.cards.l.LivingTerrain.class)); - cards.add(new SetCardInfo("Mageta's Boon", 14, Rarity.COMMON, mage.cards.m.MagetasBoon.class)); - cards.add(new SetCardInfo("Mageta the Lion", 13, Rarity.RARE, mage.cards.m.MagetaTheLion.class)); - cards.add(new SetCardInfo("Marsh Boa", 118, Rarity.COMMON, mage.cards.m.MarshBoa.class)); - cards.add(new SetCardInfo("Mercenary Informer", 15, Rarity.RARE, mage.cards.m.MercenaryInformer.class)); - cards.add(new SetCardInfo("Mine Bearer", 16, Rarity.COMMON, mage.cards.m.MineBearer.class)); - cards.add(new SetCardInfo("Mungha Wurm", 119, Rarity.RARE, mage.cards.m.MunghaWurm.class)); - cards.add(new SetCardInfo("Nakaya Shade", 69, Rarity.UNCOMMON, mage.cards.n.NakayaShade.class)); - cards.add(new SetCardInfo("Noxious Field", 70, Rarity.UNCOMMON, mage.cards.n.NoxiousField.class)); - cards.add(new SetCardInfo("Outbreak", 71, Rarity.UNCOMMON, mage.cards.o.Outbreak.class)); - cards.add(new SetCardInfo("Overburden", 39, Rarity.RARE, mage.cards.o.Overburden.class)); - cards.add(new SetCardInfo("Panic Attack", 98, Rarity.COMMON, mage.cards.p.PanicAttack.class)); - cards.add(new SetCardInfo("Pit Raptor", 72, Rarity.UNCOMMON, mage.cards.p.PitRaptor.class)); - cards.add(new SetCardInfo("Plague Fiend", 73, Rarity.COMMON, mage.cards.p.PlagueFiend.class)); - cards.add(new SetCardInfo("Plague Wind", 74, Rarity.RARE, mage.cards.p.PlagueWind.class)); - cards.add(new SetCardInfo("Pygmy Razorback", 120, Rarity.COMMON, mage.cards.p.PygmyRazorback.class)); - cards.add(new SetCardInfo("Quicksilver Wall", 41, Rarity.UNCOMMON, mage.cards.q.QuicksilverWall.class)); - cards.add(new SetCardInfo("Rebel Informer", 75, Rarity.RARE, mage.cards.r.RebelInformer.class)); - cards.add(new SetCardInfo("Rethink", 42, Rarity.COMMON, mage.cards.r.Rethink.class)); - cards.add(new SetCardInfo("Rhystic Circle", 19, Rarity.COMMON, mage.cards.r.RhysticCircle.class)); - cards.add(new SetCardInfo("Rhystic Study", 45, Rarity.COMMON, mage.cards.r.RhysticStudy.class)); - cards.add(new SetCardInfo("Rhystic Tutor", 77, Rarity.RARE, mage.cards.r.RhysticTutor.class)); - cards.add(new SetCardInfo("Ribbon Snake", 46, Rarity.COMMON, mage.cards.r.RibbonSnake.class)); - cards.add(new SetCardInfo("Rib Cage Spider", 121, Rarity.COMMON, mage.cards.r.RibCageSpider.class)); - cards.add(new SetCardInfo("Ridgeline Rager", 100, Rarity.COMMON, mage.cards.r.RidgelineRager.class)); - cards.add(new SetCardInfo("Root Cage", 122, Rarity.UNCOMMON, mage.cards.r.RootCage.class)); - cards.add(new SetCardInfo("Scoria Cat", 101, Rarity.UNCOMMON, mage.cards.s.ScoriaCat.class)); - cards.add(new SetCardInfo("Searing Wind", 103, Rarity.RARE, mage.cards.s.SearingWind.class)); - cards.add(new SetCardInfo("Shield Dancer", 23, Rarity.UNCOMMON, mage.cards.s.ShieldDancer.class)); - cards.add(new SetCardInfo("Silt Crawler", 123, Rarity.COMMON, mage.cards.s.SiltCrawler.class)); - cards.add(new SetCardInfo("Spiketail Drake", 48, Rarity.UNCOMMON, mage.cards.s.SpiketailDrake.class)); - cards.add(new SetCardInfo("Spiketail Hatchling", 49, Rarity.COMMON, mage.cards.s.SpiketailHatchling.class)); - cards.add(new SetCardInfo("Spitting Spider", 125, Rarity.UNCOMMON, mage.cards.s.SpittingSpider.class)); - cards.add(new SetCardInfo("Spore Frog", 126, Rarity.COMMON, mage.cards.s.SporeFrog.class)); - cards.add(new SetCardInfo("Spur Grappler", 104, Rarity.COMMON, mage.cards.s.SpurGrappler.class)); - cards.add(new SetCardInfo("Squirrel Wrangler", 127, Rarity.RARE, mage.cards.s.SquirrelWrangler.class)); - cards.add(new SetCardInfo("Steal Strength", 79, Rarity.COMMON, mage.cards.s.StealStrength.class)); - cards.add(new SetCardInfo("Stormwatch Eagle", 50, Rarity.COMMON, mage.cards.s.StormwatchEagle.class)); - cards.add(new SetCardInfo("Sunken Field", 51, Rarity.UNCOMMON, mage.cards.s.SunkenField.class)); - cards.add(new SetCardInfo("Sword Dancer", 25, Rarity.UNCOMMON, mage.cards.s.SwordDancer.class)); - cards.add(new SetCardInfo("Thrive", 129, Rarity.COMMON, mage.cards.t.Thrive.class)); - cards.add(new SetCardInfo("Trenching Steed", 26, Rarity.COMMON, mage.cards.t.TrenchingSteed.class)); - cards.add(new SetCardInfo("Troubled Healer", 27, Rarity.COMMON, mage.cards.t.TroubledHealer.class)); - cards.add(new SetCardInfo("Troublesome Spirit", 52, Rarity.RARE, mage.cards.t.TroublesomeSpirit.class)); - cards.add(new SetCardInfo("Verdant Field", 130, Rarity.UNCOMMON, mage.cards.v.VerdantField.class)); - cards.add(new SetCardInfo("Vintara Elephant", 131, Rarity.COMMON, mage.cards.v.VintaraElephant.class)); - cards.add(new SetCardInfo("Vintara Snapper", 132, Rarity.UNCOMMON, mage.cards.v.VintaraSnapper.class)); - cards.add(new SetCardInfo("Well of Discovery", 140, Rarity.RARE, mage.cards.w.WellOfDiscovery.class)); - cards.add(new SetCardInfo("Well of Life", 141, Rarity.UNCOMMON, mage.cards.w.WellOfLife.class)); - cards.add(new SetCardInfo("Whip Sergeant", 107, Rarity.UNCOMMON, mage.cards.w.WhipSergeant.class)); - cards.add(new SetCardInfo("Whipstitched Zombie", 81, Rarity.COMMON, mage.cards.w.WhipstitchedZombie.class)); - cards.add(new SetCardInfo("Wild Might", 134, Rarity.COMMON, mage.cards.w.WildMight.class)); - cards.add(new SetCardInfo("Wintermoon Mesa", 143, Rarity.RARE, mage.cards.w.WintermoonMesa.class)); - cards.add(new SetCardInfo("Zerapa Minotaur", 108, Rarity.COMMON, mage.cards.z.ZerapaMinotaur.class)); - } -} +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * + * @author North + */ +public class Prophecy extends ExpansionSet { + + private static final Prophecy fINSTANCE = new Prophecy(); + + public static Prophecy getInstance() { + return fINSTANCE; + } + + private Prophecy() { + super("Prophecy", "PCY", ExpansionSet.buildDate(2000, 4, 27), SetType.EXPANSION); + this.blockName = "Masques"; + this.parentSet = MercadianMasques.getInstance(); + this.hasBasicLands = false; + this.hasBoosters = true; + this.numBoosterLands = 0; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + cards.add(new SetCardInfo("Abolish", 1, Rarity.UNCOMMON, mage.cards.a.Abolish.class)); + cards.add(new SetCardInfo("Agent of Shauku", 55, Rarity.COMMON, mage.cards.a.AgentOfShauku.class)); + cards.add(new SetCardInfo("Alexi's Cloak", 29, Rarity.COMMON, mage.cards.a.AlexisCloak.class)); + cards.add(new SetCardInfo("Alexi, Zephyr Mage", 28, Rarity.RARE, mage.cards.a.AlexiZephyrMage.class)); + cards.add(new SetCardInfo("Aura Fracture", 2, Rarity.COMMON, mage.cards.a.AuraFracture.class)); + cards.add(new SetCardInfo("Avatar of Fury", 82, Rarity.RARE, mage.cards.a.AvatarOfFury.class)); + cards.add(new SetCardInfo("Avatar of Hope", 3, Rarity.RARE, mage.cards.a.AvatarOfHope.class)); + cards.add(new SetCardInfo("Avatar of Might", 109, Rarity.RARE, mage.cards.a.AvatarOfMight.class)); + cards.add(new SetCardInfo("Avatar of Will", 30, Rarity.RARE, mage.cards.a.AvatarOfWill.class)); + cards.add(new SetCardInfo("Avatar of Woe", 56, Rarity.RARE, mage.cards.a.AvatarOfWoe.class)); + cards.add(new SetCardInfo("Barbed Field", 83, Rarity.UNCOMMON, mage.cards.b.BarbedField.class)); + cards.add(new SetCardInfo("Blessed Wind", 4, Rarity.RARE, mage.cards.b.BlessedWind.class)); + cards.add(new SetCardInfo("Bog Elemental", 57, Rarity.RARE, mage.cards.b.BogElemental.class)); + cards.add(new SetCardInfo("Bog Glider", 58, Rarity.COMMON, mage.cards.b.BogGlider.class)); + cards.add(new SetCardInfo("Calming Verse", 110, Rarity.COMMON, mage.cards.c.CalmingVerse.class)); + cards.add(new SetCardInfo("Chilling Apparition", 59, Rarity.UNCOMMON, mage.cards.c.ChillingApparition.class)); + cards.add(new SetCardInfo("Chimeric Idol", 136, Rarity.UNCOMMON, mage.cards.c.ChimericIdol.class)); + cards.add(new SetCardInfo("Coastal Hornclaw", 31, Rarity.COMMON, mage.cards.c.CoastalHornclaw.class)); + cards.add(new SetCardInfo("Darba", 111, Rarity.UNCOMMON, mage.cards.d.Darba.class)); + cards.add(new SetCardInfo("Denying Wind", 32, Rarity.RARE, mage.cards.d.DenyingWind.class)); + cards.add(new SetCardInfo("Despoil", 62, Rarity.COMMON, mage.cards.d.Despoil.class)); + cards.add(new SetCardInfo("Devastate", 87, Rarity.COMMON, mage.cards.d.Devastate.class)); + cards.add(new SetCardInfo("Diving Griffin", 6, Rarity.COMMON, mage.cards.d.DivingGriffin.class)); + cards.add(new SetCardInfo("Excavation", 33, Rarity.UNCOMMON, mage.cards.e.Excavation.class)); + cards.add(new SetCardInfo("Fault Riders", 88, Rarity.COMMON, mage.cards.f.FaultRiders.class)); + cards.add(new SetCardInfo("Fen Stalker", 64, Rarity.COMMON, mage.cards.f.FenStalker.class)); + cards.add(new SetCardInfo("Flameshot", 90, Rarity.UNCOMMON, mage.cards.f.Flameshot.class)); + cards.add(new SetCardInfo("Flowering Field", 9, Rarity.UNCOMMON, mage.cards.f.FloweringField.class)); + cards.add(new SetCardInfo("Foil", 34, Rarity.UNCOMMON, mage.cards.f.Foil.class)); + cards.add(new SetCardInfo("Greel's Caress", 67, Rarity.COMMON, mage.cards.g.GreelsCaress.class)); + cards.add(new SetCardInfo("Gulf Squid", 35, Rarity.COMMON, mage.cards.g.GulfSquid.class)); + cards.add(new SetCardInfo("Hazy Homunculus", 36, Rarity.COMMON, mage.cards.h.HazyHomunculus.class)); + cards.add(new SetCardInfo("Heightened Awareness", 37, Rarity.RARE, mage.cards.h.HeightenedAwareness.class)); + cards.add(new SetCardInfo("Infernal Genesis", 68, Rarity.RARE, mage.cards.i.InfernalGenesis.class)); + cards.add(new SetCardInfo("Inflame", 91, Rarity.COMMON, mage.cards.i.Inflame.class)); + cards.add(new SetCardInfo("Jeweled Spirit", 12, Rarity.RARE, mage.cards.j.JeweledSpirit.class)); + cards.add(new SetCardInfo("Jolrael, Empress of Beasts", 115, Rarity.RARE, mage.cards.j.JolraelEmpressOfBeasts.class)); + cards.add(new SetCardInfo("Jolrael's Favor", 116, Rarity.COMMON, mage.cards.j.JolraelsFavor.class)); + cards.add(new SetCardInfo("Keldon Arsonist", 92, Rarity.UNCOMMON, mage.cards.k.KeldonArsonist.class)); + cards.add(new SetCardInfo("Latulla, Keldon Overseer", 95, Rarity.RARE, mage.cards.l.LatullaKeldonOverseer.class)); + cards.add(new SetCardInfo("Lesser Gargadon", 97, Rarity.UNCOMMON, mage.cards.l.LesserGargadon.class)); + cards.add(new SetCardInfo("Living Terrain", 117, Rarity.UNCOMMON, mage.cards.l.LivingTerrain.class)); + cards.add(new SetCardInfo("Mageta's Boon", 14, Rarity.COMMON, mage.cards.m.MagetasBoon.class)); + cards.add(new SetCardInfo("Mageta the Lion", 13, Rarity.RARE, mage.cards.m.MagetaTheLion.class)); + cards.add(new SetCardInfo("Marsh Boa", 118, Rarity.COMMON, mage.cards.m.MarshBoa.class)); + cards.add(new SetCardInfo("Mercenary Informer", 15, Rarity.RARE, mage.cards.m.MercenaryInformer.class)); + cards.add(new SetCardInfo("Mine Bearer", 16, Rarity.COMMON, mage.cards.m.MineBearer.class)); + cards.add(new SetCardInfo("Mungha Wurm", 119, Rarity.RARE, mage.cards.m.MunghaWurm.class)); + cards.add(new SetCardInfo("Nakaya Shade", 69, Rarity.UNCOMMON, mage.cards.n.NakayaShade.class)); + cards.add(new SetCardInfo("Noxious Field", 70, Rarity.UNCOMMON, mage.cards.n.NoxiousField.class)); + cards.add(new SetCardInfo("Outbreak", 71, Rarity.UNCOMMON, mage.cards.o.Outbreak.class)); + cards.add(new SetCardInfo("Overburden", 39, Rarity.RARE, mage.cards.o.Overburden.class)); + cards.add(new SetCardInfo("Panic Attack", 98, Rarity.COMMON, mage.cards.p.PanicAttack.class)); + cards.add(new SetCardInfo("Pit Raptor", 72, Rarity.UNCOMMON, mage.cards.p.PitRaptor.class)); + cards.add(new SetCardInfo("Plague Fiend", 73, Rarity.COMMON, mage.cards.p.PlagueFiend.class)); + cards.add(new SetCardInfo("Plague Wind", 74, Rarity.RARE, mage.cards.p.PlagueWind.class)); + cards.add(new SetCardInfo("Pygmy Razorback", 120, Rarity.COMMON, mage.cards.p.PygmyRazorback.class)); + cards.add(new SetCardInfo("Quicksilver Wall", 41, Rarity.UNCOMMON, mage.cards.q.QuicksilverWall.class)); + cards.add(new SetCardInfo("Rebel Informer", 75, Rarity.RARE, mage.cards.r.RebelInformer.class)); + cards.add(new SetCardInfo("Rethink", 42, Rarity.COMMON, mage.cards.r.Rethink.class)); + cards.add(new SetCardInfo("Rhystic Circle", 19, Rarity.COMMON, mage.cards.r.RhysticCircle.class)); + cards.add(new SetCardInfo("Rhystic Study", 45, Rarity.COMMON, mage.cards.r.RhysticStudy.class)); + cards.add(new SetCardInfo("Rhystic Tutor", 77, Rarity.RARE, mage.cards.r.RhysticTutor.class)); + cards.add(new SetCardInfo("Ribbon Snake", 46, Rarity.COMMON, mage.cards.r.RibbonSnake.class)); + cards.add(new SetCardInfo("Rib Cage Spider", 121, Rarity.COMMON, mage.cards.r.RibCageSpider.class)); + cards.add(new SetCardInfo("Ridgeline Rager", 100, Rarity.COMMON, mage.cards.r.RidgelineRager.class)); + cards.add(new SetCardInfo("Root Cage", 122, Rarity.UNCOMMON, mage.cards.r.RootCage.class)); + cards.add(new SetCardInfo("Scoria Cat", 101, Rarity.UNCOMMON, mage.cards.s.ScoriaCat.class)); + cards.add(new SetCardInfo("Searing Wind", 103, Rarity.RARE, mage.cards.s.SearingWind.class)); + cards.add(new SetCardInfo("Shield Dancer", 23, Rarity.UNCOMMON, mage.cards.s.ShieldDancer.class)); + cards.add(new SetCardInfo("Silt Crawler", 123, Rarity.COMMON, mage.cards.s.SiltCrawler.class)); + cards.add(new SetCardInfo("Spiketail Drake", 48, Rarity.UNCOMMON, mage.cards.s.SpiketailDrake.class)); + cards.add(new SetCardInfo("Spiketail Hatchling", 49, Rarity.COMMON, mage.cards.s.SpiketailHatchling.class)); + cards.add(new SetCardInfo("Spitting Spider", 125, Rarity.UNCOMMON, mage.cards.s.SpittingSpider.class)); + cards.add(new SetCardInfo("Spore Frog", 126, Rarity.COMMON, mage.cards.s.SporeFrog.class)); + cards.add(new SetCardInfo("Spur Grappler", 104, Rarity.COMMON, mage.cards.s.SpurGrappler.class)); + cards.add(new SetCardInfo("Squirrel Wrangler", 127, Rarity.RARE, mage.cards.s.SquirrelWrangler.class)); + cards.add(new SetCardInfo("Steal Strength", 79, Rarity.COMMON, mage.cards.s.StealStrength.class)); + cards.add(new SetCardInfo("Stormwatch Eagle", 50, Rarity.COMMON, mage.cards.s.StormwatchEagle.class)); + cards.add(new SetCardInfo("Sunken Field", 51, Rarity.UNCOMMON, mage.cards.s.SunkenField.class)); + cards.add(new SetCardInfo("Sword Dancer", 25, Rarity.UNCOMMON, mage.cards.s.SwordDancer.class)); + cards.add(new SetCardInfo("Thrive", 129, Rarity.COMMON, mage.cards.t.Thrive.class)); + cards.add(new SetCardInfo("Trenching Steed", 26, Rarity.COMMON, mage.cards.t.TrenchingSteed.class)); + cards.add(new SetCardInfo("Troubled Healer", 27, Rarity.COMMON, mage.cards.t.TroubledHealer.class)); + cards.add(new SetCardInfo("Troublesome Spirit", 52, Rarity.RARE, mage.cards.t.TroublesomeSpirit.class)); + cards.add(new SetCardInfo("Verdant Field", 130, Rarity.UNCOMMON, mage.cards.v.VerdantField.class)); + cards.add(new SetCardInfo("Vintara Elephant", 131, Rarity.COMMON, mage.cards.v.VintaraElephant.class)); + cards.add(new SetCardInfo("Vintara Snapper", 132, Rarity.UNCOMMON, mage.cards.v.VintaraSnapper.class)); + cards.add(new SetCardInfo("Well of Discovery", 140, Rarity.RARE, mage.cards.w.WellOfDiscovery.class)); + cards.add(new SetCardInfo("Well of Life", 141, Rarity.UNCOMMON, mage.cards.w.WellOfLife.class)); + cards.add(new SetCardInfo("Whip Sergeant", 107, Rarity.UNCOMMON, mage.cards.w.WhipSergeant.class)); + cards.add(new SetCardInfo("Whipstitched Zombie", 81, Rarity.COMMON, mage.cards.w.WhipstitchedZombie.class)); + cards.add(new SetCardInfo("Wild Might", 134, Rarity.COMMON, mage.cards.w.WildMight.class)); + cards.add(new SetCardInfo("Wintermoon Mesa", 143, Rarity.RARE, mage.cards.w.WintermoonMesa.class)); + cards.add(new SetCardInfo("Withdraw", 54, Rarity.COMMON, mage.cards.w.Withdraw.class)); + cards.add(new SetCardInfo("Zerapa Minotaur", 108, Rarity.COMMON, mage.cards.z.ZerapaMinotaur.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/Weatherlight.java b/Mage.Sets/src/mage/sets/Weatherlight.java index fe13584ad56..d87b3a3450a 100644 --- a/Mage.Sets/src/mage/sets/Weatherlight.java +++ b/Mage.Sets/src/mage/sets/Weatherlight.java @@ -1,193 +1,194 @@ -/* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - -package mage.sets; - -import mage.constants.SetType; -import mage.cards.ExpansionSet; - -import mage.constants.Rarity; - -/** - * - * @author noxx - */ -public class Weatherlight extends ExpansionSet { - - private static final Weatherlight fINSTANCE = new Weatherlight(); - - public static Weatherlight getInstance() { - return fINSTANCE; - } - - private Weatherlight() { - super("Weatherlight", "WTH", ExpansionSet.buildDate(1997, 5, 31), SetType.EXPANSION); - this.blockName = "Mirage"; - this.parentSet = Mirage.getInstance(); - this.hasBasicLands = false; - this.hasBoosters = true; - this.numBoosterLands = 0; - this.numBoosterCommon = 11; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - cards.add(new SetCardInfo("Abduction", 30, Rarity.UNCOMMON, mage.cards.a.Abduction.class)); - cards.add(new SetCardInfo("Abeyance", 117, Rarity.RARE, mage.cards.a.Abeyance.class)); - cards.add(new SetCardInfo("Abjure", 31, Rarity.COMMON, mage.cards.a.Abjure.class)); - cards.add(new SetCardInfo("Abyssal Gatekeeper", 1, Rarity.COMMON, mage.cards.a.AbyssalGatekeeper.class)); - cards.add(new SetCardInfo("Aether Flash", 88, Rarity.UNCOMMON, mage.cards.a.AetherFlash.class)); - cards.add(new SetCardInfo("Agonizing Memories", 2, Rarity.UNCOMMON, mage.cards.a.AgonizingMemories.class)); - cards.add(new SetCardInfo("Alabaster Dragon", 118, Rarity.RARE, mage.cards.a.AlabasterDragon.class)); - cards.add(new SetCardInfo("Alms", 119, Rarity.COMMON, mage.cards.a.Alms.class)); - cards.add(new SetCardInfo("Ancestral Knowledge", 32, Rarity.RARE, mage.cards.a.AncestralKnowledge.class)); - cards.add(new SetCardInfo("Angelic Renewal", 120, Rarity.COMMON, mage.cards.a.AngelicRenewal.class)); - cards.add(new SetCardInfo("Arctic Wolves", 60, Rarity.UNCOMMON, mage.cards.a.ArcticWolves.class)); - cards.add(new SetCardInfo("Ardent Militia", 121, Rarity.COMMON, mage.cards.a.ArdentMilitia.class)); - cards.add(new SetCardInfo("Argivian Find", 122, Rarity.UNCOMMON, mage.cards.a.ArgivianFind.class)); - cards.add(new SetCardInfo("Argivian Restoration", 34, Rarity.UNCOMMON, mage.cards.a.ArgivianRestoration.class)); - cards.add(new SetCardInfo("Aura of Silence", 123, Rarity.UNCOMMON, mage.cards.a.AuraOfSilence.class)); - cards.add(new SetCardInfo("Barrow Ghoul", 3, Rarity.COMMON, mage.cards.b.BarrowGhoul.class)); - cards.add(new SetCardInfo("Benalish Knight", 125, Rarity.COMMON, mage.cards.b.BenalishKnight.class)); - cards.add(new SetCardInfo("Benalish Missionary", 126, Rarity.COMMON, mage.cards.b.BenalishMissionary.class)); - cards.add(new SetCardInfo("Bloodrock Cyclops", 90, Rarity.COMMON, mage.cards.b.BloodrockCyclops.class)); - cards.add(new SetCardInfo("Blossoming Wreath", 62, Rarity.COMMON, mage.cards.b.BlossomingWreath.class)); - cards.add(new SetCardInfo("Bogardan Firefiend", 91, Rarity.COMMON, mage.cards.b.BogardanFirefiend.class)); - cards.add(new SetCardInfo("Boiling Blood", 92, Rarity.COMMON, mage.cards.b.BoilingBlood.class)); - cards.add(new SetCardInfo("Bone Dancer", 4, Rarity.RARE, mage.cards.b.BoneDancer.class)); - cards.add(new SetCardInfo("Briar Shield", 63, Rarity.COMMON, mage.cards.b.BriarShield.class)); - cards.add(new SetCardInfo("Bubble Matrix", 147, Rarity.RARE, mage.cards.b.BubbleMatrix.class)); - cards.add(new SetCardInfo("Buried Alive", 5, Rarity.UNCOMMON, mage.cards.b.BuriedAlive.class)); - cards.add(new SetCardInfo("Call of the Wild", 64, Rarity.RARE, mage.cards.c.CallOfTheWild.class)); - cards.add(new SetCardInfo("Chimeric Sphere", 148, Rarity.UNCOMMON, mage.cards.c.ChimericSphere.class)); - cards.add(new SetCardInfo("Cinder Giant", 93, Rarity.UNCOMMON, mage.cards.c.CinderGiant.class)); - cards.add(new SetCardInfo("Cinder Wall", 94, Rarity.COMMON, mage.cards.c.CinderWall.class)); - cards.add(new SetCardInfo("Cloud Djinn", 36, Rarity.UNCOMMON, mage.cards.c.CloudDjinn.class)); - cards.add(new SetCardInfo("Cone of Flame", 95, Rarity.UNCOMMON, mage.cards.c.ConeOfFlame.class)); - cards.add(new SetCardInfo("Debt of Loyalty", 127, Rarity.RARE, mage.cards.d.DebtOfLoyalty.class)); - cards.add(new SetCardInfo("Dense Foliage", 66, Rarity.RARE, mage.cards.d.DenseFoliage.class)); - cards.add(new SetCardInfo("Disrupt", 37, Rarity.COMMON, mage.cards.d.Disrupt.class)); - cards.add(new SetCardInfo("Doomsday", 8, Rarity.RARE, mage.cards.d.Doomsday.class)); - cards.add(new SetCardInfo("Downdraft", 67, Rarity.UNCOMMON, mage.cards.d.Downdraft.class)); - cards.add(new SetCardInfo("Duskrider Falcon", 128, Rarity.COMMON, mage.cards.d.DuskriderFalcon.class)); - cards.add(new SetCardInfo("Dwarven Berserker", 97, Rarity.COMMON, mage.cards.d.DwarvenBerserker.class)); - cards.add(new SetCardInfo("Dwarven Thaumaturgist", 98, Rarity.RARE, mage.cards.d.DwarvenThaumaturgist.class)); - cards.add(new SetCardInfo("Empyrial Armor", 129, Rarity.COMMON, mage.cards.e.EmpyrialArmor.class)); - cards.add(new SetCardInfo("Fallow Wurm", 68, Rarity.UNCOMMON, mage.cards.f.FallowWurm.class)); - cards.add(new SetCardInfo("Familiar Ground", 69, Rarity.UNCOMMON, mage.cards.f.FamiliarGround.class)); - cards.add(new SetCardInfo("Fatal Blow", 9, Rarity.COMMON, mage.cards.f.FatalBlow.class)); - cards.add(new SetCardInfo("Fervor", 99, Rarity.RARE, mage.cards.f.Fervor.class)); - cards.add(new SetCardInfo("Festering Evil", 10, Rarity.UNCOMMON, mage.cards.f.FesteringEvil.class)); - cards.add(new SetCardInfo("Firestorm", 101, Rarity.RARE, mage.cards.f.Firestorm.class)); - cards.add(new SetCardInfo("Fire Whip", 100, Rarity.COMMON, mage.cards.f.FireWhip.class)); - cards.add(new SetCardInfo("Fit of Rage", 102, Rarity.COMMON, mage.cards.f.FitOfRage.class)); - cards.add(new SetCardInfo("Fledgling Djinn", 11, Rarity.COMMON, mage.cards.f.FledglingDjinn.class)); - cards.add(new SetCardInfo("Fog Elemental", 40, Rarity.COMMON, mage.cards.f.FogElemental.class)); - cards.add(new SetCardInfo("Foriysian Brigade", 130, Rarity.UNCOMMON, mage.cards.f.ForiysianBrigade.class)); - cards.add(new SetCardInfo("Gaea's Blessing", 71, Rarity.UNCOMMON, mage.cards.g.GaeasBlessing.class)); - cards.add(new SetCardInfo("Gallowbraid", 12, Rarity.RARE, mage.cards.g.Gallowbraid.class)); - cards.add(new SetCardInfo("Gemstone Mine", 164, Rarity.UNCOMMON, mage.cards.g.GemstoneMine.class)); - cards.add(new SetCardInfo("Gerrard's Wisdom", 131, Rarity.UNCOMMON, mage.cards.g.GerrardsWisdom.class)); - cards.add(new SetCardInfo("Goblin Bomb", 103, Rarity.RARE, mage.cards.g.GoblinBomb.class)); - cards.add(new SetCardInfo("Goblin Grenadiers", 104, Rarity.UNCOMMON, mage.cards.g.GoblinGrenadiers.class)); - cards.add(new SetCardInfo("Goblin Vandal", 105, Rarity.COMMON, mage.cards.g.GoblinVandal.class)); - cards.add(new SetCardInfo("Guided Strike", 132, Rarity.COMMON, mage.cards.g.GuidedStrike.class)); - cards.add(new SetCardInfo("Harvest Wurm", 72, Rarity.COMMON, mage.cards.h.HarvestWurm.class)); - cards.add(new SetCardInfo("Haunting Misery", 13, Rarity.COMMON, mage.cards.h.HauntingMisery.class)); - cards.add(new SetCardInfo("Heavy Ballista", 133, Rarity.COMMON, mage.cards.h.HeavyBallista.class)); - cards.add(new SetCardInfo("Hidden Horror", 14, Rarity.UNCOMMON, mage.cards.h.HiddenHorror.class)); - cards.add(new SetCardInfo("Hurloon Shaman", 108, Rarity.UNCOMMON, mage.cards.h.HurloonShaman.class)); - cards.add(new SetCardInfo("Jabari's Banner", 150, Rarity.UNCOMMON, mage.cards.j.JabarisBanner.class)); - cards.add(new SetCardInfo("Lava Hounds", 109, Rarity.UNCOMMON, mage.cards.l.LavaHounds.class)); - cards.add(new SetCardInfo("Llanowar Behemoth", 74, Rarity.UNCOMMON, mage.cards.l.LlanowarBehemoth.class)); - cards.add(new SetCardInfo("Llanowar Druid", 75, Rarity.COMMON, mage.cards.l.LlanowarDruid.class)); - cards.add(new SetCardInfo("Llanowar Sentinel", 76, Rarity.COMMON, mage.cards.l.LlanowarSentinel.class)); - cards.add(new SetCardInfo("Lotus Vale", 165, Rarity.RARE, mage.cards.l.LotusVale.class)); - cards.add(new SetCardInfo("Mana Chains", 41, Rarity.COMMON, mage.cards.m.ManaChains.class)); - cards.add(new SetCardInfo("Mana Web", 152, Rarity.RARE, mage.cards.m.ManaWeb.class)); - cards.add(new SetCardInfo("Manta Ray", 42, Rarity.COMMON, mage.cards.m.MantaRay.class)); - cards.add(new SetCardInfo("Maraxus of Keld", 111, Rarity.RARE, mage.cards.m.MaraxusOfKeld.class)); - cards.add(new SetCardInfo("Master of Arms", 136, Rarity.UNCOMMON, mage.cards.m.MasterOfArms.class)); - cards.add(new SetCardInfo("Merfolk Traders", 43, Rarity.COMMON, mage.cards.m.MerfolkTraders.class)); - cards.add(new SetCardInfo("Mind Stone", 153, Rarity.COMMON, mage.cards.m.MindStone.class)); - cards.add(new SetCardInfo("Mischievous Poltergeist", 16, Rarity.UNCOMMON, mage.cards.m.MischievousPoltergeist.class)); - cards.add(new SetCardInfo("Mistmoon Griffin", 137, Rarity.UNCOMMON, mage.cards.m.MistmoonGriffin.class)); - cards.add(new SetCardInfo("Morinfen", 17, Rarity.RARE, mage.cards.m.Morinfen.class)); - cards.add(new SetCardInfo("Mwonvuli Ooze", 77, Rarity.RARE, mage.cards.m.MwonvuliOoze.class)); - cards.add(new SetCardInfo("Nature's Kiss", 78, Rarity.COMMON, mage.cards.n.NaturesKiss.class)); - cards.add(new SetCardInfo("Nature's Resurgence", 79, Rarity.RARE, mage.cards.n.NaturesResurgence.class)); - cards.add(new SetCardInfo("Necratog", 18, Rarity.UNCOMMON, mage.cards.n.Necratog.class)); - cards.add(new SetCardInfo("Null Rod", 154, Rarity.RARE, mage.cards.n.NullRod.class)); - cards.add(new SetCardInfo("Odylic Wraith", 19, Rarity.UNCOMMON, mage.cards.o.OdylicWraith.class)); - cards.add(new SetCardInfo("Ophidian", 45, Rarity.COMMON, mage.cards.o.Ophidian.class)); - cards.add(new SetCardInfo("Orcish Settlers", 112, Rarity.UNCOMMON, mage.cards.o.OrcishSettlers.class)); - cards.add(new SetCardInfo("Paradigm Shift", 46, Rarity.RARE, mage.cards.p.ParadigmShift.class)); - cards.add(new SetCardInfo("Peacekeeper", 138, Rarity.RARE, mage.cards.p.Peacekeeper.class)); - cards.add(new SetCardInfo("Pendrell Mists", 47, Rarity.RARE, mage.cards.p.PendrellMists.class)); - cards.add(new SetCardInfo("Phantom Warrior", 48, Rarity.UNCOMMON, mage.cards.p.PhantomWarrior.class)); - cards.add(new SetCardInfo("Phantom Wings", 49, Rarity.COMMON, mage.cards.p.PhantomWings.class)); - cards.add(new SetCardInfo("Phyrexian Furnace", 155, Rarity.UNCOMMON, mage.cards.p.PhyrexianFurnace.class)); - cards.add(new SetCardInfo("Psychic Vortex", 50, Rarity.RARE, mage.cards.p.PsychicVortex.class)); - cards.add(new SetCardInfo("Razortooth Rats", 20, Rarity.COMMON, mage.cards.r.RazortoothRats.class)); - cards.add(new SetCardInfo("Redwood Treefolk", 80, Rarity.COMMON, mage.cards.r.RedwoodTreefolk.class)); - cards.add(new SetCardInfo("Relearn", 51, Rarity.UNCOMMON, mage.cards.r.Relearn.class)); - cards.add(new SetCardInfo("Revered Unicorn", 139, Rarity.UNCOMMON, mage.cards.r.ReveredUnicorn.class)); - cards.add(new SetCardInfo("Roc Hatchling", 113, Rarity.UNCOMMON, mage.cards.r.RocHatchling.class)); - cards.add(new SetCardInfo("Rogue Elephant", 81, Rarity.COMMON, mage.cards.r.RogueElephant.class)); - cards.add(new SetCardInfo("Sage Owl", 52, Rarity.COMMON, mage.cards.s.SageOwl.class)); - cards.add(new SetCardInfo("Scorched Ruins", 166, Rarity.RARE, mage.cards.s.ScorchedRuins.class)); - cards.add(new SetCardInfo("Serenity", 140, Rarity.RARE, mage.cards.s.Serenity.class)); - cards.add(new SetCardInfo("Serra's Blessing", 141, Rarity.UNCOMMON, mage.cards.s.SerrasBlessing.class)); - cards.add(new SetCardInfo("Serrated Biskelion", 156, Rarity.UNCOMMON, mage.cards.s.SerratedBiskelion.class)); - cards.add(new SetCardInfo("Shadow Rider", 21, Rarity.COMMON, mage.cards.s.ShadowRider.class)); - cards.add(new SetCardInfo("Soul Shepherd", 142, Rarity.COMMON, mage.cards.s.SoulShepherd.class)); - cards.add(new SetCardInfo("Southern Paladin", 143, Rarity.RARE, mage.cards.s.SouthernPaladin.class)); - cards.add(new SetCardInfo("Spinning Darkness", 23, Rarity.COMMON, mage.cards.s.SpinningDarkness.class)); - cards.add(new SetCardInfo("Steel Golem", 157, Rarity.UNCOMMON, mage.cards.s.SteelGolem.class)); - cards.add(new SetCardInfo("Strands of Night", 24, Rarity.UNCOMMON, mage.cards.s.StrandsOfNight.class)); - cards.add(new SetCardInfo("Straw Golem", 158, Rarity.UNCOMMON, mage.cards.s.StrawGolem.class)); - cards.add(new SetCardInfo("Striped Bears", 82, Rarity.COMMON, mage.cards.s.StripedBears.class)); - cards.add(new SetCardInfo("Tariff", 144, Rarity.RARE, mage.cards.t.Tariff.class)); - cards.add(new SetCardInfo("Tendrils of Despair", 25, Rarity.COMMON, mage.cards.t.TendrilsOfDespair.class)); - cards.add(new SetCardInfo("Thunderbolt", 115, Rarity.COMMON, mage.cards.t.Thunderbolt.class)); - cards.add(new SetCardInfo("Thundermare", 116, Rarity.RARE, mage.cards.t.Thundermare.class)); - cards.add(new SetCardInfo("Tolarian Drake", 55, Rarity.COMMON, mage.cards.t.TolarianDrake.class)); - cards.add(new SetCardInfo("Tolarian Entrancer", 56, Rarity.RARE, mage.cards.t.TolarianEntrancer.class)); - cards.add(new SetCardInfo("Tolarian Serpent", 57, Rarity.RARE, mage.cards.t.TolarianSerpent.class)); - cards.add(new SetCardInfo("Touchstone", 161, Rarity.UNCOMMON, mage.cards.t.Touchstone.class)); - cards.add(new SetCardInfo("Tranquil Grove", 84, Rarity.RARE, mage.cards.t.TranquilGrove.class)); - cards.add(new SetCardInfo("Uktabi Efreet", 85, Rarity.COMMON, mage.cards.u.UktabiEfreet.class)); - cards.add(new SetCardInfo("Urborg Justice", 26, Rarity.RARE, mage.cards.u.UrborgJustice.class)); - cards.add(new SetCardInfo("Veteran Explorer", 86, Rarity.UNCOMMON, mage.cards.v.VeteranExplorer.class)); - cards.add(new SetCardInfo("Vitalize", 87, Rarity.COMMON, mage.cards.v.Vitalize.class)); - cards.add(new SetCardInfo("Vodalian Illusionist", 58, Rarity.UNCOMMON, mage.cards.v.VodalianIllusionist.class)); - cards.add(new SetCardInfo("Winding Canyons", 167, Rarity.RARE, mage.cards.w.WindingCanyons.class)); - cards.add(new SetCardInfo("Xanthic Statue", 163, Rarity.RARE, mage.cards.x.XanthicStatue.class)); - cards.add(new SetCardInfo("Zombie Scavengers", 29, Rarity.COMMON, mage.cards.z.ZombieScavengers.class)); - } - -} +/* +* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are +* permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, this list +* of conditions and the following disclaimer in the documentation and/or other materials +* provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR +* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +* The views and conclusions contained in the software and documentation are those of the +* authors and should not be interpreted as representing official policies, either expressed +* or implied, of BetaSteward_at_googlemail.com. +*/ + +package mage.sets; + +import mage.constants.SetType; +import mage.cards.ExpansionSet; + +import mage.constants.Rarity; + +/** + * + * @author noxx + */ +public class Weatherlight extends ExpansionSet { + + private static final Weatherlight fINSTANCE = new Weatherlight(); + + public static Weatherlight getInstance() { + return fINSTANCE; + } + + private Weatherlight() { + super("Weatherlight", "WTH", ExpansionSet.buildDate(1997, 5, 31), SetType.EXPANSION); + this.blockName = "Mirage"; + this.parentSet = Mirage.getInstance(); + this.hasBasicLands = false; + this.hasBoosters = true; + this.numBoosterLands = 0; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + cards.add(new SetCardInfo("Abduction", 30, Rarity.UNCOMMON, mage.cards.a.Abduction.class)); + cards.add(new SetCardInfo("Abeyance", 117, Rarity.RARE, mage.cards.a.Abeyance.class)); + cards.add(new SetCardInfo("Abjure", 31, Rarity.COMMON, mage.cards.a.Abjure.class)); + cards.add(new SetCardInfo("Abyssal Gatekeeper", 1, Rarity.COMMON, mage.cards.a.AbyssalGatekeeper.class)); + cards.add(new SetCardInfo("Aether Flash", 88, Rarity.UNCOMMON, mage.cards.a.AetherFlash.class)); + cards.add(new SetCardInfo("Agonizing Memories", 2, Rarity.UNCOMMON, mage.cards.a.AgonizingMemories.class)); + cards.add(new SetCardInfo("Alabaster Dragon", 118, Rarity.RARE, mage.cards.a.AlabasterDragon.class)); + cards.add(new SetCardInfo("Alms", 119, Rarity.COMMON, mage.cards.a.Alms.class)); + cards.add(new SetCardInfo("Ancestral Knowledge", 32, Rarity.RARE, mage.cards.a.AncestralKnowledge.class)); + cards.add(new SetCardInfo("Angelic Renewal", 120, Rarity.COMMON, mage.cards.a.AngelicRenewal.class)); + cards.add(new SetCardInfo("Arctic Wolves", 60, Rarity.UNCOMMON, mage.cards.a.ArcticWolves.class)); + cards.add(new SetCardInfo("Ardent Militia", 121, Rarity.COMMON, mage.cards.a.ArdentMilitia.class)); + cards.add(new SetCardInfo("Argivian Find", 122, Rarity.UNCOMMON, mage.cards.a.ArgivianFind.class)); + cards.add(new SetCardInfo("Argivian Restoration", 34, Rarity.UNCOMMON, mage.cards.a.ArgivianRestoration.class)); + cards.add(new SetCardInfo("Aura of Silence", 123, Rarity.UNCOMMON, mage.cards.a.AuraOfSilence.class)); + cards.add(new SetCardInfo("Barrow Ghoul", 3, Rarity.COMMON, mage.cards.b.BarrowGhoul.class)); + cards.add(new SetCardInfo("Benalish Knight", 125, Rarity.COMMON, mage.cards.b.BenalishKnight.class)); + cards.add(new SetCardInfo("Benalish Missionary", 126, Rarity.COMMON, mage.cards.b.BenalishMissionary.class)); + cards.add(new SetCardInfo("Bloodrock Cyclops", 90, Rarity.COMMON, mage.cards.b.BloodrockCyclops.class)); + cards.add(new SetCardInfo("Blossoming Wreath", 62, Rarity.COMMON, mage.cards.b.BlossomingWreath.class)); + cards.add(new SetCardInfo("Bogardan Firefiend", 91, Rarity.COMMON, mage.cards.b.BogardanFirefiend.class)); + cards.add(new SetCardInfo("Boiling Blood", 92, Rarity.COMMON, mage.cards.b.BoilingBlood.class)); + cards.add(new SetCardInfo("Bone Dancer", 4, Rarity.RARE, mage.cards.b.BoneDancer.class)); + cards.add(new SetCardInfo("Briar Shield", 63, Rarity.COMMON, mage.cards.b.BriarShield.class)); + cards.add(new SetCardInfo("Bubble Matrix", 147, Rarity.RARE, mage.cards.b.BubbleMatrix.class)); + cards.add(new SetCardInfo("Buried Alive", 5, Rarity.UNCOMMON, mage.cards.b.BuriedAlive.class)); + cards.add(new SetCardInfo("Call of the Wild", 64, Rarity.RARE, mage.cards.c.CallOfTheWild.class)); + cards.add(new SetCardInfo("Chimeric Sphere", 148, Rarity.UNCOMMON, mage.cards.c.ChimericSphere.class)); + cards.add(new SetCardInfo("Cinder Giant", 93, Rarity.UNCOMMON, mage.cards.c.CinderGiant.class)); + cards.add(new SetCardInfo("Cinder Wall", 94, Rarity.COMMON, mage.cards.c.CinderWall.class)); + cards.add(new SetCardInfo("Cloud Djinn", 36, Rarity.UNCOMMON, mage.cards.c.CloudDjinn.class)); + cards.add(new SetCardInfo("Cone of Flame", 95, Rarity.UNCOMMON, mage.cards.c.ConeOfFlame.class)); + cards.add(new SetCardInfo("Debt of Loyalty", 127, Rarity.RARE, mage.cards.d.DebtOfLoyalty.class)); + cards.add(new SetCardInfo("Dense Foliage", 66, Rarity.RARE, mage.cards.d.DenseFoliage.class)); + cards.add(new SetCardInfo("Disrupt", 37, Rarity.COMMON, mage.cards.d.Disrupt.class)); + cards.add(new SetCardInfo("Doomsday", 8, Rarity.RARE, mage.cards.d.Doomsday.class)); + cards.add(new SetCardInfo("Downdraft", 67, Rarity.UNCOMMON, mage.cards.d.Downdraft.class)); + cards.add(new SetCardInfo("Duskrider Falcon", 128, Rarity.COMMON, mage.cards.d.DuskriderFalcon.class)); + cards.add(new SetCardInfo("Dwarven Berserker", 97, Rarity.COMMON, mage.cards.d.DwarvenBerserker.class)); + cards.add(new SetCardInfo("Dwarven Thaumaturgist", 98, Rarity.RARE, mage.cards.d.DwarvenThaumaturgist.class)); + cards.add(new SetCardInfo("Empyrial Armor", 129, Rarity.COMMON, mage.cards.e.EmpyrialArmor.class)); + cards.add(new SetCardInfo("Fallow Wurm", 68, Rarity.UNCOMMON, mage.cards.f.FallowWurm.class)); + cards.add(new SetCardInfo("Familiar Ground", 69, Rarity.UNCOMMON, mage.cards.f.FamiliarGround.class)); + cards.add(new SetCardInfo("Fatal Blow", 9, Rarity.COMMON, mage.cards.f.FatalBlow.class)); + cards.add(new SetCardInfo("Fervor", 99, Rarity.RARE, mage.cards.f.Fervor.class)); + cards.add(new SetCardInfo("Festering Evil", 10, Rarity.UNCOMMON, mage.cards.f.FesteringEvil.class)); + cards.add(new SetCardInfo("Firestorm", 101, Rarity.RARE, mage.cards.f.Firestorm.class)); + cards.add(new SetCardInfo("Fire Whip", 100, Rarity.COMMON, mage.cards.f.FireWhip.class)); + cards.add(new SetCardInfo("Fit of Rage", 102, Rarity.COMMON, mage.cards.f.FitOfRage.class)); + cards.add(new SetCardInfo("Fledgling Djinn", 11, Rarity.COMMON, mage.cards.f.FledglingDjinn.class)); + cards.add(new SetCardInfo("Flux", 27, Rarity.COMMON, mage.cards.f.Flux.class)); + cards.add(new SetCardInfo("Fog Elemental", 40, Rarity.COMMON, mage.cards.f.FogElemental.class)); + cards.add(new SetCardInfo("Foriysian Brigade", 130, Rarity.UNCOMMON, mage.cards.f.ForiysianBrigade.class)); + cards.add(new SetCardInfo("Gaea's Blessing", 71, Rarity.UNCOMMON, mage.cards.g.GaeasBlessing.class)); + cards.add(new SetCardInfo("Gallowbraid", 12, Rarity.RARE, mage.cards.g.Gallowbraid.class)); + cards.add(new SetCardInfo("Gemstone Mine", 164, Rarity.UNCOMMON, mage.cards.g.GemstoneMine.class)); + cards.add(new SetCardInfo("Gerrard's Wisdom", 131, Rarity.UNCOMMON, mage.cards.g.GerrardsWisdom.class)); + cards.add(new SetCardInfo("Goblin Bomb", 103, Rarity.RARE, mage.cards.g.GoblinBomb.class)); + cards.add(new SetCardInfo("Goblin Grenadiers", 104, Rarity.UNCOMMON, mage.cards.g.GoblinGrenadiers.class)); + cards.add(new SetCardInfo("Goblin Vandal", 105, Rarity.COMMON, mage.cards.g.GoblinVandal.class)); + cards.add(new SetCardInfo("Guided Strike", 132, Rarity.COMMON, mage.cards.g.GuidedStrike.class)); + cards.add(new SetCardInfo("Harvest Wurm", 72, Rarity.COMMON, mage.cards.h.HarvestWurm.class)); + cards.add(new SetCardInfo("Haunting Misery", 13, Rarity.COMMON, mage.cards.h.HauntingMisery.class)); + cards.add(new SetCardInfo("Heavy Ballista", 133, Rarity.COMMON, mage.cards.h.HeavyBallista.class)); + cards.add(new SetCardInfo("Hidden Horror", 14, Rarity.UNCOMMON, mage.cards.h.HiddenHorror.class)); + cards.add(new SetCardInfo("Hurloon Shaman", 108, Rarity.UNCOMMON, mage.cards.h.HurloonShaman.class)); + cards.add(new SetCardInfo("Jabari's Banner", 150, Rarity.UNCOMMON, mage.cards.j.JabarisBanner.class)); + cards.add(new SetCardInfo("Lava Hounds", 109, Rarity.UNCOMMON, mage.cards.l.LavaHounds.class)); + cards.add(new SetCardInfo("Llanowar Behemoth", 74, Rarity.UNCOMMON, mage.cards.l.LlanowarBehemoth.class)); + cards.add(new SetCardInfo("Llanowar Druid", 75, Rarity.COMMON, mage.cards.l.LlanowarDruid.class)); + cards.add(new SetCardInfo("Llanowar Sentinel", 76, Rarity.COMMON, mage.cards.l.LlanowarSentinel.class)); + cards.add(new SetCardInfo("Lotus Vale", 165, Rarity.RARE, mage.cards.l.LotusVale.class)); + cards.add(new SetCardInfo("Mana Chains", 41, Rarity.COMMON, mage.cards.m.ManaChains.class)); + cards.add(new SetCardInfo("Mana Web", 152, Rarity.RARE, mage.cards.m.ManaWeb.class)); + cards.add(new SetCardInfo("Manta Ray", 42, Rarity.COMMON, mage.cards.m.MantaRay.class)); + cards.add(new SetCardInfo("Maraxus of Keld", 111, Rarity.RARE, mage.cards.m.MaraxusOfKeld.class)); + cards.add(new SetCardInfo("Master of Arms", 136, Rarity.UNCOMMON, mage.cards.m.MasterOfArms.class)); + cards.add(new SetCardInfo("Merfolk Traders", 43, Rarity.COMMON, mage.cards.m.MerfolkTraders.class)); + cards.add(new SetCardInfo("Mind Stone", 153, Rarity.COMMON, mage.cards.m.MindStone.class)); + cards.add(new SetCardInfo("Mischievous Poltergeist", 16, Rarity.UNCOMMON, mage.cards.m.MischievousPoltergeist.class)); + cards.add(new SetCardInfo("Mistmoon Griffin", 137, Rarity.UNCOMMON, mage.cards.m.MistmoonGriffin.class)); + cards.add(new SetCardInfo("Morinfen", 17, Rarity.RARE, mage.cards.m.Morinfen.class)); + cards.add(new SetCardInfo("Mwonvuli Ooze", 77, Rarity.RARE, mage.cards.m.MwonvuliOoze.class)); + cards.add(new SetCardInfo("Nature's Kiss", 78, Rarity.COMMON, mage.cards.n.NaturesKiss.class)); + cards.add(new SetCardInfo("Nature's Resurgence", 79, Rarity.RARE, mage.cards.n.NaturesResurgence.class)); + cards.add(new SetCardInfo("Necratog", 18, Rarity.UNCOMMON, mage.cards.n.Necratog.class)); + cards.add(new SetCardInfo("Null Rod", 154, Rarity.RARE, mage.cards.n.NullRod.class)); + cards.add(new SetCardInfo("Odylic Wraith", 19, Rarity.UNCOMMON, mage.cards.o.OdylicWraith.class)); + cards.add(new SetCardInfo("Ophidian", 45, Rarity.COMMON, mage.cards.o.Ophidian.class)); + cards.add(new SetCardInfo("Orcish Settlers", 112, Rarity.UNCOMMON, mage.cards.o.OrcishSettlers.class)); + cards.add(new SetCardInfo("Paradigm Shift", 46, Rarity.RARE, mage.cards.p.ParadigmShift.class)); + cards.add(new SetCardInfo("Peacekeeper", 138, Rarity.RARE, mage.cards.p.Peacekeeper.class)); + cards.add(new SetCardInfo("Pendrell Mists", 47, Rarity.RARE, mage.cards.p.PendrellMists.class)); + cards.add(new SetCardInfo("Phantom Warrior", 48, Rarity.UNCOMMON, mage.cards.p.PhantomWarrior.class)); + cards.add(new SetCardInfo("Phantom Wings", 49, Rarity.COMMON, mage.cards.p.PhantomWings.class)); + cards.add(new SetCardInfo("Phyrexian Furnace", 155, Rarity.UNCOMMON, mage.cards.p.PhyrexianFurnace.class)); + cards.add(new SetCardInfo("Psychic Vortex", 50, Rarity.RARE, mage.cards.p.PsychicVortex.class)); + cards.add(new SetCardInfo("Razortooth Rats", 20, Rarity.COMMON, mage.cards.r.RazortoothRats.class)); + cards.add(new SetCardInfo("Redwood Treefolk", 80, Rarity.COMMON, mage.cards.r.RedwoodTreefolk.class)); + cards.add(new SetCardInfo("Relearn", 51, Rarity.UNCOMMON, mage.cards.r.Relearn.class)); + cards.add(new SetCardInfo("Revered Unicorn", 139, Rarity.UNCOMMON, mage.cards.r.ReveredUnicorn.class)); + cards.add(new SetCardInfo("Roc Hatchling", 113, Rarity.UNCOMMON, mage.cards.r.RocHatchling.class)); + cards.add(new SetCardInfo("Rogue Elephant", 81, Rarity.COMMON, mage.cards.r.RogueElephant.class)); + cards.add(new SetCardInfo("Sage Owl", 52, Rarity.COMMON, mage.cards.s.SageOwl.class)); + cards.add(new SetCardInfo("Scorched Ruins", 166, Rarity.RARE, mage.cards.s.ScorchedRuins.class)); + cards.add(new SetCardInfo("Serenity", 140, Rarity.RARE, mage.cards.s.Serenity.class)); + cards.add(new SetCardInfo("Serra's Blessing", 141, Rarity.UNCOMMON, mage.cards.s.SerrasBlessing.class)); + cards.add(new SetCardInfo("Serrated Biskelion", 156, Rarity.UNCOMMON, mage.cards.s.SerratedBiskelion.class)); + cards.add(new SetCardInfo("Shadow Rider", 21, Rarity.COMMON, mage.cards.s.ShadowRider.class)); + cards.add(new SetCardInfo("Soul Shepherd", 142, Rarity.COMMON, mage.cards.s.SoulShepherd.class)); + cards.add(new SetCardInfo("Southern Paladin", 143, Rarity.RARE, mage.cards.s.SouthernPaladin.class)); + cards.add(new SetCardInfo("Spinning Darkness", 23, Rarity.COMMON, mage.cards.s.SpinningDarkness.class)); + cards.add(new SetCardInfo("Steel Golem", 157, Rarity.UNCOMMON, mage.cards.s.SteelGolem.class)); + cards.add(new SetCardInfo("Strands of Night", 24, Rarity.UNCOMMON, mage.cards.s.StrandsOfNight.class)); + cards.add(new SetCardInfo("Straw Golem", 158, Rarity.UNCOMMON, mage.cards.s.StrawGolem.class)); + cards.add(new SetCardInfo("Striped Bears", 82, Rarity.COMMON, mage.cards.s.StripedBears.class)); + cards.add(new SetCardInfo("Tariff", 144, Rarity.RARE, mage.cards.t.Tariff.class)); + cards.add(new SetCardInfo("Tendrils of Despair", 25, Rarity.COMMON, mage.cards.t.TendrilsOfDespair.class)); + cards.add(new SetCardInfo("Thunderbolt", 115, Rarity.COMMON, mage.cards.t.Thunderbolt.class)); + cards.add(new SetCardInfo("Thundermare", 116, Rarity.RARE, mage.cards.t.Thundermare.class)); + cards.add(new SetCardInfo("Tolarian Drake", 55, Rarity.COMMON, mage.cards.t.TolarianDrake.class)); + cards.add(new SetCardInfo("Tolarian Entrancer", 56, Rarity.RARE, mage.cards.t.TolarianEntrancer.class)); + cards.add(new SetCardInfo("Tolarian Serpent", 57, Rarity.RARE, mage.cards.t.TolarianSerpent.class)); + cards.add(new SetCardInfo("Touchstone", 161, Rarity.UNCOMMON, mage.cards.t.Touchstone.class)); + cards.add(new SetCardInfo("Tranquil Grove", 84, Rarity.RARE, mage.cards.t.TranquilGrove.class)); + cards.add(new SetCardInfo("Uktabi Efreet", 85, Rarity.COMMON, mage.cards.u.UktabiEfreet.class)); + cards.add(new SetCardInfo("Urborg Justice", 26, Rarity.RARE, mage.cards.u.UrborgJustice.class)); + cards.add(new SetCardInfo("Veteran Explorer", 86, Rarity.UNCOMMON, mage.cards.v.VeteranExplorer.class)); + cards.add(new SetCardInfo("Vitalize", 87, Rarity.COMMON, mage.cards.v.Vitalize.class)); + cards.add(new SetCardInfo("Vodalian Illusionist", 58, Rarity.UNCOMMON, mage.cards.v.VodalianIllusionist.class)); + cards.add(new SetCardInfo("Winding Canyons", 167, Rarity.RARE, mage.cards.w.WindingCanyons.class)); + cards.add(new SetCardInfo("Xanthic Statue", 163, Rarity.RARE, mage.cards.x.XanthicStatue.class)); + cards.add(new SetCardInfo("Zombie Scavengers", 29, Rarity.COMMON, mage.cards.z.ZombieScavengers.class)); + } + +} From 54d5599e067871345e3e26fd697def66997f0d2a Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 19 Oct 2016 23:24:02 +0200 Subject: [PATCH 08/35] [SWS] Fixed Exogorth's block ability. --- Mage.Sets/src/mage/cards/e/Exogorth.java | 43 ++----------------- .../keyword/CanBlockSpaceflightAbility.java | 43 +++++++++++++++++++ .../abilities/keyword/SpaceflightAbility.java | 3 +- 3 files changed, 49 insertions(+), 40 deletions(-) create mode 100644 Mage/src/main/java/mage/abilities/keyword/CanBlockSpaceflightAbility.java diff --git a/Mage.Sets/src/mage/cards/e/Exogorth.java b/Mage.Sets/src/mage/cards/e/Exogorth.java index 165f16787b0..dcbe49f4ee3 100644 --- a/Mage.Sets/src/mage/cards/e/Exogorth.java +++ b/Mage.Sets/src/mage/cards/e/Exogorth.java @@ -29,19 +29,12 @@ package mage.cards.e; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.RestrictionEffect; +import mage.abilities.keyword.CanBlockSpaceflightAbility; import mage.abilities.keyword.FlashAbility; -import mage.abilities.keyword.SpaceflightAbility; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.permanent.Permanent; /** * @@ -50,7 +43,7 @@ import mage.game.permanent.Permanent; public class Exogorth extends CardImpl { public Exogorth(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{G}{G}"); this.subtype.add("Slug"); this.power = new MageInt(7); this.toughness = new MageInt(7); @@ -61,8 +54,8 @@ public class Exogorth extends CardImpl { // Trample this.addAbility(TrampleAbility.getInstance()); - // Exogorth can block only creatures with spaceflight. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CanBlockOnlySpaceflightEffect())); + // Exogorth can block creatures with spaceflight. + this.addAbility(CanBlockSpaceflightAbility.getInstance()); } public Exogorth(final Exogorth card) { @@ -74,31 +67,3 @@ public class Exogorth extends CardImpl { return new Exogorth(this); } } - -class CanBlockOnlySpaceflightEffect extends RestrictionEffect { - - public CanBlockOnlySpaceflightEffect() { - super(Duration.EndOfTurn); - this.staticText = "{this} can block only creatures with spaceflight"; - } - - public CanBlockOnlySpaceflightEffect(final CanBlockOnlySpaceflightEffect effect) { - super(effect); - } - - @Override - public boolean applies(Permanent permanent, Ability source, Game game) { - return permanent.getId().equals(source.getSourceId()); - } - - @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { - return attacker.getAbilities().contains(SpaceflightAbility.getInstance()); - } - - @Override - public CanBlockOnlySpaceflightEffect copy() { - return new CanBlockOnlySpaceflightEffect(this); - } - -} diff --git a/Mage/src/main/java/mage/abilities/keyword/CanBlockSpaceflightAbility.java b/Mage/src/main/java/mage/abilities/keyword/CanBlockSpaceflightAbility.java new file mode 100644 index 00000000000..b65edc61292 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/CanBlockSpaceflightAbility.java @@ -0,0 +1,43 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.abilities.keyword; + +import java.io.ObjectStreamException; +import mage.abilities.MageSingleton; +import mage.abilities.StaticAbility; +import mage.constants.Zone; + +/** + * + * @author LevelX2 + */ +public class CanBlockSpaceflightAbility extends StaticAbility implements MageSingleton { + + private static final CanBlockSpaceflightAbility fINSTANCE = new CanBlockSpaceflightAbility(); + + private Object readResolve() throws ObjectStreamException { + return fINSTANCE; + } + + public static CanBlockSpaceflightAbility getInstance() { + return fINSTANCE; + } + + private CanBlockSpaceflightAbility() { + super(Zone.ALL, null); + } + + @Override + public String getRule() { + return "{this} can block creatures with spaceflight."; + } + + @Override + public CanBlockSpaceflightAbility copy() { + return fINSTANCE; + } + +} diff --git a/Mage/src/main/java/mage/abilities/keyword/SpaceflightAbility.java b/Mage/src/main/java/mage/abilities/keyword/SpaceflightAbility.java index c0e080ad1af..f4a84542c02 100644 --- a/Mage/src/main/java/mage/abilities/keyword/SpaceflightAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/SpaceflightAbility.java @@ -90,7 +90,8 @@ class SpaceFlightEffect extends RestrictionEffect implements MageSingleton { @Override public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { - return blocker.getAbilities().containsKey(SpaceflightAbility.getInstance().getId()); + return blocker.getAbilities().containsKey(SpaceflightAbility.getInstance().getId()) + || blocker.getAbilities().containsKey(CanBlockSpaceflightAbility.getInstance().getId()); } @Override From a47aa158f0a734d86cfcbcbdca6ee2703b946ce3 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 19 Oct 2016 23:31:53 +0200 Subject: [PATCH 09/35] [SWS] Fixed a bug of the watcher used for the hate ability. --- Mage.Sets/src/mage/cards/s/SithMarauder.java | 4 ++-- Mage.Sets/src/mage/cards/v/VaporSnag.java | 11 ++++------- .../common/LifeLossOtherFromCombatWatcher.java | 1 + 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Mage.Sets/src/mage/cards/s/SithMarauder.java b/Mage.Sets/src/mage/cards/s/SithMarauder.java index b3520da7799..73817f9334a 100644 --- a/Mage.Sets/src/mage/cards/s/SithMarauder.java +++ b/Mage.Sets/src/mage/cards/s/SithMarauder.java @@ -47,13 +47,13 @@ import mage.watchers.common.LifeLossOtherFromCombatWatcher; public class SithMarauder extends CardImpl { public SithMarauder(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); this.subtype.add("Human"); this.subtype.add("Sith"); this.power = new MageInt(5); this.toughness = new MageInt(4); - // Hate — When Sith Marauder enters the battlefield, if opponent lost life from source other than combat damage this turn, Sith Marauder deals 3 damage to target creature or player. + // Hate — When Sith Marauder enters the battlefield, if an opponent lost life from a source other than combat damage this turn, Sith Marauder deals 3 damage to target creature or player. Ability ability = new ConditionalTriggeredAbility( new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(3)), HateCondition.getInstance(), diff --git a/Mage.Sets/src/mage/cards/v/VaporSnag.java b/Mage.Sets/src/mage/cards/v/VaporSnag.java index 40506bc8d15..53357b11c8f 100644 --- a/Mage.Sets/src/mage/cards/v/VaporSnag.java +++ b/Mage.Sets/src/mage/cards/v/VaporSnag.java @@ -25,16 +25,14 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.cards.v; import java.util.UUID; - -import mage.constants.CardType; import mage.abilities.effects.common.LoseLifeTargetControllerEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.CardType; import mage.target.common.TargetCreaturePermanent; /** @@ -43,17 +41,16 @@ import mage.target.common.TargetCreaturePermanent; */ public class VaporSnag extends CardImpl { - public VaporSnag (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{U}"); + public VaporSnag(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}"); - // Return target creature to its owner's hand. Its controller loses 1 life. this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); this.getSpellAbility().addEffect(new LoseLifeTargetControllerEffect(1)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } - public VaporSnag (final VaporSnag card) { + public VaporSnag(final VaporSnag card) { super(card); } diff --git a/Mage/src/main/java/mage/watchers/common/LifeLossOtherFromCombatWatcher.java b/Mage/src/main/java/mage/watchers/common/LifeLossOtherFromCombatWatcher.java index c409d1a977f..ebf698bdd45 100644 --- a/Mage/src/main/java/mage/watchers/common/LifeLossOtherFromCombatWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/LifeLossOtherFromCombatWatcher.java @@ -50,6 +50,7 @@ public class LifeLossOtherFromCombatWatcher extends Watcher { public LifeLossOtherFromCombatWatcher(final LifeLossOtherFromCombatWatcher watcher) { super(watcher); + this.players.addAll(watcher.players); } @Override From cfb4eea2676a070b052f14d936f08b0423769a0b Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 19 Oct 2016 23:35:51 +0200 Subject: [PATCH 10/35] [SWS] Fixed wrong p/t of Trade Federation Battleship. --- Mage.Sets/src/mage/cards/t/TradeFederationBattleship.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Mage.Sets/src/mage/cards/t/TradeFederationBattleship.java b/Mage.Sets/src/mage/cards/t/TradeFederationBattleship.java index 7b126eee537..4cfac14e8db 100644 --- a/Mage.Sets/src/mage/cards/t/TradeFederationBattleship.java +++ b/Mage.Sets/src/mage/cards/t/TradeFederationBattleship.java @@ -62,10 +62,10 @@ public class TradeFederationBattleship extends CardImpl { } public TradeFederationBattleship(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{3}{W}{U}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}{W}{U}{B}"); this.subtype.add("Starship"); - this.power = new MageInt(2); - this.toughness = new MageInt(2); + this.power = new MageInt(0); + this.toughness = new MageInt(6); // Spaceflight this.addAbility(SpaceflightAbility.getInstance()); From 5242eff1827e76fdae31cb5168dfe8a9f6046b3e Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 19 Oct 2016 23:38:02 +0200 Subject: [PATCH 11/35] [SWS] Fixed wrong casting costs of Gungan Captain. --- Mage.Sets/src/mage/cards/g/GunganCaptain.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/cards/g/GunganCaptain.java b/Mage.Sets/src/mage/cards/g/GunganCaptain.java index b74a9f328bd..19faa03e27e 100644 --- a/Mage.Sets/src/mage/cards/g/GunganCaptain.java +++ b/Mage.Sets/src/mage/cards/g/GunganCaptain.java @@ -44,7 +44,7 @@ import mage.constants.CardType; public class GunganCaptain extends CardImpl { public GunganCaptain(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); this.subtype.add("Gungan"); this.subtype.add("Warrior"); this.power = new MageInt(1); From 5882b50898b76d580394ad131bad305a1739ca0c Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 19 Oct 2016 23:47:56 +0200 Subject: [PATCH 12/35] [SWS] Cloaking Device - fixed that defending player did not lose life. --- .../src/mage/cards/c/CloakingDevice.java | 62 +++++++++++++++++-- 1 file changed, 56 insertions(+), 6 deletions(-) diff --git a/Mage.Sets/src/mage/cards/c/CloakingDevice.java b/Mage.Sets/src/mage/cards/c/CloakingDevice.java index 5db33ff4a7e..a5126fcff8a 100644 --- a/Mage.Sets/src/mage/cards/c/CloakingDevice.java +++ b/Mage.Sets/src/mage/cards/c/CloakingDevice.java @@ -28,13 +28,14 @@ package mage.cards.c; import java.util.UUID; -import mage.MageObject; import mage.abilities.Ability; +import mage.abilities.Mode; import mage.abilities.common.AttacksAttachedTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.AttachEffect; -import mage.abilities.effects.common.LoseLifeDefendingPlayerEffect; import mage.abilities.effects.common.combat.CantBeBlockedAttachedEffect; import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; @@ -43,8 +44,6 @@ import mage.constants.AttachmentType; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; -import mage.counters.Counter; -import mage.filter.FilterPermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -58,7 +57,7 @@ import mage.target.common.TargetCreaturePermanent; public class CloakingDevice extends CardImpl { public CloakingDevice(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); this.subtype.add("Aura"); // Enchant creature @@ -72,7 +71,7 @@ public class CloakingDevice extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantBeBlockedAttachedEffect(AttachmentType.AURA))); // Whenever enchanted creature attacks, defending player loses 1 life. - this.addAbility(new AttacksAttachedTriggeredAbility(new LoseLifeDefendingPlayerEffect(1, true), AttachmentType.AURA, false)); + this.addAbility(new AttacksAttachedTriggeredAbility(new CloakingDeviceLoseLifeDefendingPlayerEffect(1, true), AttachmentType.AURA, false)); } @@ -85,3 +84,54 @@ public class CloakingDevice extends CardImpl { return new CloakingDevice(this); } } + +class CloakingDeviceLoseLifeDefendingPlayerEffect extends OneShotEffect { + + private DynamicValue amount; + private boolean attackerIsSource; + + /** + * + * @param amount + * @param attackerIsSource true if the source.getSourceId() contains the + * attacker false if attacker has to be taken from targetPointer + */ + public CloakingDeviceLoseLifeDefendingPlayerEffect(int amount, boolean attackerIsSource) { + this(new StaticValue(amount), attackerIsSource); + } + + public CloakingDeviceLoseLifeDefendingPlayerEffect(DynamicValue amount, boolean attackerIsSource) { + super(Outcome.Damage); + this.amount = amount; + this.attackerIsSource = attackerIsSource; + } + + public CloakingDeviceLoseLifeDefendingPlayerEffect(final CloakingDeviceLoseLifeDefendingPlayerEffect effect) { + super(effect); + this.amount = effect.amount.copy(); + this.attackerIsSource = effect.attackerIsSource; + } + + @Override + public CloakingDeviceLoseLifeDefendingPlayerEffect copy() { + return new CloakingDeviceLoseLifeDefendingPlayerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent enchantment = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (enchantment != null && enchantment.getAttachedTo() != null) { + Player defender = game.getPlayer(game.getCombat().getDefendingPlayerId(enchantment.getAttachedTo(), game)); + if (defender != null) { + defender.loseLife(amount.calculate(game, source, this), game, false); + } + } + return true; + } + + @Override + public String getText(Mode mode) { + return "defending player loses " + amount + " life"; + } + +} From aa5ab9ea18fe1fc0c5bbff588bbbad875abcfb21 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 19 Oct 2016 23:51:18 +0200 Subject: [PATCH 13/35] [SWS] Force Adept - Fixed missing targets. --- Mage.Sets/src/mage/cards/f/ForceAdept.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Mage.Sets/src/mage/cards/f/ForceAdept.java b/Mage.Sets/src/mage/cards/f/ForceAdept.java index 553622b1866..7d0b1b83e57 100644 --- a/Mage.Sets/src/mage/cards/f/ForceAdept.java +++ b/Mage.Sets/src/mage/cards/f/ForceAdept.java @@ -63,7 +63,7 @@ public class ForceAdept extends CardImpl { } public ForceAdept(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{G}{U}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{U}{W}"); this.subtype.add("Mirialan"); this.subtype.add("Jedi"); this.power = new MageInt(2); @@ -74,8 +74,8 @@ public class ForceAdept extends CardImpl { // When Force Adept enters the battlefield, return another target creature you control and target creature you don't control to their owner's hands. Ability ability = new EntersBattlefieldTriggeredAbility(new ForceAdeptEffect()); - this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(filter1)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter2)); + ability.addTarget(new TargetControlledCreaturePermanent(filter1)); + ability.addTarget(new TargetCreaturePermanent(filter2)); this.addAbility(ability); } From 6d099312dfd33a939e0b77fe2dd3a2105d572cf3 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 19 Oct 2016 23:58:07 +0200 Subject: [PATCH 14/35] [SWS] Dark Decision - Fixed that the exiled card could not be cast. --- Mage.Sets/src/mage/cards/d/DarkDecision.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Mage.Sets/src/mage/cards/d/DarkDecision.java b/Mage.Sets/src/mage/cards/d/DarkDecision.java index 73ae0adcd39..b4f402f3497 100644 --- a/Mage.Sets/src/mage/cards/d/DarkDecision.java +++ b/Mage.Sets/src/mage/cards/d/DarkDecision.java @@ -55,7 +55,7 @@ import mage.target.targetpointer.FixedTarget; public class DarkDecision extends CardImpl { public DarkDecision(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{B}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}{R}"); // As an additional cost to cast Dark Decision, pay 1 life. this.getSpellAbility().addCost(new PayLifeCost(1)); @@ -103,7 +103,7 @@ class DarkDecisionEffect extends OneShotEffect { if (card != null) { controller.moveCardsToExile(card, source, game, true, source.getSourceId(), sourceObject.getIdName()); ContinuousEffect effect = new DarkDecisionMayPlayExiledEffect(); - effect.setTargetPointer(new FixedTarget(card.getId())); + effect.setTargetPointer(new FixedTarget(card.getId(), game)); game.addEffect(effect, source); } controller.shuffleLibrary(source, game); @@ -137,7 +137,7 @@ class DarkDecisionMayPlayExiledEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - if (objectId.equals(getTargetPointer().getFirst(game, source)) && affectedControllerId.equals(source.getSourceId())) { + if (objectId.equals(getTargetPointer().getFirst(game, source)) && affectedControllerId.equals(source.getControllerId())) { ExileZone exileZone = game.getExile().getExileZone(source.getSourceId()); return exileZone != null && exileZone.contains(getTargetPointer().getFirst(game, source)); } From d7a39045693b81086fd40ea9179a3db5e6e1ea32 Mon Sep 17 00:00:00 2001 From: Campbell Suter Date: Fri, 14 Oct 2016 09:46:45 +1300 Subject: [PATCH 15/35] Add key options to prefs dialog --- .../mage/client/components/KeyBindButton.java | 68 + .../mage/client/dialog/PreferencesDialog.form | 153 ++ .../mage/client/dialog/PreferencesDialog.java | 2191 +++++++++-------- 3 files changed, 1398 insertions(+), 1014 deletions(-) create mode 100644 Mage.Client/src/main/java/mage/client/components/KeyBindButton.java diff --git a/Mage.Client/src/main/java/mage/client/components/KeyBindButton.java b/Mage.Client/src/main/java/mage/client/components/KeyBindButton.java new file mode 100644 index 00000000000..12f332859b2 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/components/KeyBindButton.java @@ -0,0 +1,68 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.client.components; + +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import javax.swing.JToggleButton; + +/** + * + * @author Campbell Suter + */ +public class KeyBindButton extends JToggleButton implements KeyListener { + + private int keyCode; + private String text; + + public KeyBindButton() { + fixText(); + addKeyListener(this); + } + + @Override + public void keyTyped(KeyEvent e) { + } + + @Override + public void keyPressed(KeyEvent e) { + } + + @Override + public void keyReleased(KeyEvent e) { + if (!isSelected()) { + return; + } + keyCode = e.getKeyCode(); + fixText(); + setSelected(false); + System.out.println("text: " + text); + } + + private void fixText() { + if (keyCode == 0) { + text = ""; + } else { + text = KeyEvent.getKeyText(keyCode); + } + repaint(); + } + + public void setKeyCode(int keyCode) { + this.keyCode = keyCode; + fixText(); + } + + public int getKeyCode() { + return keyCode; + } + + @Override + public String getText() { + return text; + } + +} diff --git a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form index 4cf0b3303cc..02e5d4b84bb 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form +++ b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form @@ -5874,6 +5874,159 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java index 57ab43e6e32..d43ec0b5557 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java @@ -37,6 +37,7 @@ import java.awt.BorderLayout; import java.awt.Color; import java.awt.Image; import java.awt.Rectangle; +import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; @@ -60,6 +61,7 @@ import javax.swing.border.Border; import javax.swing.filechooser.FileFilter; import mage.client.MageFrame; import mage.client.SessionHandler; +import mage.client.components.KeyBindButton; import mage.client.util.Config; import mage.client.util.GUISizeHelper; import mage.client.util.ImageHelper; @@ -82,297 +84,306 @@ import org.apache.log4j.Logger; */ public class PreferencesDialog extends javax.swing.JDialog { - private static final Logger logger = Logger.getLogger(PreferencesDialog.class); + private static final Logger logger = Logger.getLogger(PreferencesDialog.class); - public static final String KEY_SHOW_TOOLTIPS_DELAY = "showTooltipsDelay"; - public static final String KEY_SHOW_CARD_NAMES = "showCardNames"; - public static final String KEY_PERMANENTS_IN_ONE_PILE = "nonLandPermanentsInOnePile"; - public static final String KEY_SHOW_PLAYER_NAMES_PERMANENTLY = "showPlayerNamesPermanently"; - public static final String KEY_SHOW_ABILITY_PICKER_FORCED = "showAbilityPicker"; - public static final String KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS = "gameAllowRequestShowHandCards"; - public static final String KEY_GAME_SHOW_STORM_COUNTER = "gameShowStormCounter"; - public static final String KEY_GAME_CONFIRM_EMPTY_MANA_POOL = "gameConfirmEmptyManaPool"; - public static final String KEY_GAME_ASK_MOVE_TO_GRAVE_ORDER = "gameAskMoveToGraveORder"; + public static final String KEY_SHOW_TOOLTIPS_DELAY = "showTooltipsDelay"; + public static final String KEY_SHOW_CARD_NAMES = "showCardNames"; + public static final String KEY_PERMANENTS_IN_ONE_PILE = "nonLandPermanentsInOnePile"; + public static final String KEY_SHOW_PLAYER_NAMES_PERMANENTLY = "showPlayerNamesPermanently"; + public static final String KEY_SHOW_ABILITY_PICKER_FORCED = "showAbilityPicker"; + public static final String KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS = "gameAllowRequestShowHandCards"; + public static final String KEY_GAME_SHOW_STORM_COUNTER = "gameShowStormCounter"; + public static final String KEY_GAME_CONFIRM_EMPTY_MANA_POOL = "gameConfirmEmptyManaPool"; + public static final String KEY_GAME_ASK_MOVE_TO_GRAVE_ORDER = "gameAskMoveToGraveORder"; - public static final String KEY_GUI_TABLE_FONT_SIZE = "guiTableFontSize"; - public static final String KEY_GUI_CHAT_FONT_SIZE = "guiChatFontSize"; - public static final String KEY_GUI_CARD_HAND_SIZE = "guiCardHandSize"; - public static final String KEY_GUI_CARD_EDITOR_SIZE = "guiCardEditorSize"; - public static final String KEY_GUI_CARD_OFFSET_SIZE = "guiCardOffsetSize"; - public static final String KEY_GUI_ENLARGED_IMAGE_SIZE = "guiEnlargedImageSize"; + public static final String KEY_GUI_TABLE_FONT_SIZE = "guiTableFontSize"; + public static final String KEY_GUI_CHAT_FONT_SIZE = "guiChatFontSize"; + public static final String KEY_GUI_CARD_HAND_SIZE = "guiCardHandSize"; + public static final String KEY_GUI_CARD_EDITOR_SIZE = "guiCardEditorSize"; + public static final String KEY_GUI_CARD_OFFSET_SIZE = "guiCardOffsetSize"; + public static final String KEY_GUI_ENLARGED_IMAGE_SIZE = "guiEnlargedImageSize"; - public static final String KEY_GUI_STACK_WIDTH = "guiStackWidth"; - public static final String KEY_GUI_TOOLTIP_SIZE = "guiTooltipSize"; - public static final String KEY_GUI_DIALOG_FONT_SIZE = "guiDialogFontSize"; - public static final String KEY_GUI_FEEDBACK_AREA_SIZE = "guiFeedbackAreaSize"; - public static final String KEY_GUI_CARD_OTHER_ZONES_SIZE = "guiCardOtherZonesSize"; - public static final String KEY_GUI_CARD_BATTLEFIELD_MIN_SIZE = "guiCardBattlefieldMinSize"; - public static final String KEY_GUI_CARD_BATTLEFIELD_MAX_SIZE = "guiCardBattlefieldMaxSize"; + public static final String KEY_GUI_STACK_WIDTH = "guiStackWidth"; + public static final String KEY_GUI_TOOLTIP_SIZE = "guiTooltipSize"; + public static final String KEY_GUI_DIALOG_FONT_SIZE = "guiDialogFontSize"; + public static final String KEY_GUI_FEEDBACK_AREA_SIZE = "guiFeedbackAreaSize"; + public static final String KEY_GUI_CARD_OTHER_ZONES_SIZE = "guiCardOtherZonesSize"; + public static final String KEY_GUI_CARD_BATTLEFIELD_MIN_SIZE = "guiCardBattlefieldMinSize"; + public static final String KEY_GUI_CARD_BATTLEFIELD_MAX_SIZE = "guiCardBattlefieldMaxSize"; - public static final String KEY_GAME_LOG_AUTO_SAVE = "gameLogAutoSave"; - public static final String KEY_DRAFT_LOG_AUTO_SAVE = "draftLogAutoSave"; + public static final String KEY_GAME_LOG_AUTO_SAVE = "gameLogAutoSave"; + public static final String KEY_DRAFT_LOG_AUTO_SAVE = "draftLogAutoSave"; - public static final String KEY_CARD_IMAGES_USE_DEFAULT = "cardImagesUseDefault"; - public static final String KEY_CARD_IMAGES_PATH = "cardImagesPath"; - public static final String KEY_CARD_IMAGES_THREADS = "cardImagesThreads"; - public static final String KEY_CARD_IMAGES_CHECK = "cardImagesCheck"; - public static final String KEY_CARD_IMAGES_SAVE_TO_ZIP = "cardImagesSaveToZip"; - public static final String KEY_CARD_IMAGES_PREF_LANGUAGE = "cardImagesPreferedImageLaguage"; + public static final String KEY_CARD_IMAGES_USE_DEFAULT = "cardImagesUseDefault"; + public static final String KEY_CARD_IMAGES_PATH = "cardImagesPath"; + public static final String KEY_CARD_IMAGES_THREADS = "cardImagesThreads"; + public static final String KEY_CARD_IMAGES_CHECK = "cardImagesCheck"; + public static final String KEY_CARD_IMAGES_SAVE_TO_ZIP = "cardImagesSaveToZip"; + public static final String KEY_CARD_IMAGES_PREF_LANGUAGE = "cardImagesPreferedImageLaguage"; - public static final String KEY_CARD_RENDERING_FALLBACK = "cardRenderingFallback"; - public static final String KEY_CARD_RENDERING_REMINDER_TEXT = "cardRenderingReminderText"; - public static final String KEY_CARD_RENDERING_SET_SYMBOL = "cardRenderingSetSymbol"; - - public static final String KEY_BACKGROUND_IMAGE = "backgroundImage"; - public static final String KEY_BATTLEFIELD_IMAGE = "battlefieldImage"; - public static final String KEY_BACKGROUND_IMAGE_DEFAULT = "backgroundImagedDefault"; - public static final String KEY_BATTLEFIELD_IMAGE_RANDOM = "battlefieldImagerandom"; - public static final String KEY_BATTLEFIELD_IMAGE_DEFAULT = "battlefieldImageDefault"; + public static final String KEY_CARD_RENDERING_FALLBACK = "cardRenderingFallback"; + public static final String KEY_CARD_RENDERING_REMINDER_TEXT = "cardRenderingReminderText"; + public static final String KEY_CARD_RENDERING_SET_SYMBOL = "cardRenderingSetSymbol"; - public static final String KEY_SOUNDS_GAME_ON = "soundsOn"; - public static final String KEY_SOUNDS_DRAFT_ON = "soundsDraftOn"; - public static final String KEY_SOUNDS_SKIP_BUTTONS_ON = "soundsSkipButtonsOn"; - public static final String KEY_SOUNDS_OTHER_ON = "soundsOtherOn"; - public static final String KEY_SOUNDS_MATCH_MUSIC_ON = "soundsMatchMusicOn"; - public static final String KEY_SOUNDS_MATCH_MUSIC_PATH = "soundsMatchMusicPath"; + public static final String KEY_BACKGROUND_IMAGE = "backgroundImage"; + public static final String KEY_BATTLEFIELD_IMAGE = "battlefieldImage"; + public static final String KEY_BACKGROUND_IMAGE_DEFAULT = "backgroundImagedDefault"; + public static final String KEY_BATTLEFIELD_IMAGE_RANDOM = "battlefieldImagerandom"; + public static final String KEY_BATTLEFIELD_IMAGE_DEFAULT = "battlefieldImageDefault"; - public static final String KEY_BIG_CARD_TOGGLED = "bigCardToggled"; + public static final String KEY_SOUNDS_GAME_ON = "soundsOn"; + public static final String KEY_SOUNDS_DRAFT_ON = "soundsDraftOn"; + public static final String KEY_SOUNDS_SKIP_BUTTONS_ON = "soundsSkipButtonsOn"; + public static final String KEY_SOUNDS_OTHER_ON = "soundsOtherOn"; + public static final String KEY_SOUNDS_MATCH_MUSIC_ON = "soundsMatchMusicOn"; + public static final String KEY_SOUNDS_MATCH_MUSIC_PATH = "soundsMatchMusicPath"; - // Phases - public static final String UPKEEP_YOU = "upkeepYou"; - public static final String DRAW_YOU = "drawYou"; - public static final String MAIN_YOU = "mainYou"; - public static final String BEFORE_COMBAT_YOU = "beforeCombatYou"; - public static final String END_OF_COMBAT_YOU = "endOfCombatYou"; - public static final String MAIN_TWO_YOU = "main2You"; - public static final String END_OF_TURN_YOU = "endOfTurnYou"; + public static final String KEY_BIG_CARD_TOGGLED = "bigCardToggled"; - public static final String UPKEEP_OTHERS = "upkeepOthers"; - public static final String DRAW_OTHERS = "drawOthers"; - public static final String MAIN_OTHERS = "mainOthers"; - public static final String BEFORE_COMBAT_OTHERS = "beforeCombatOthers"; - public static final String END_OF_COMBAT_OTHERS = "endOfCombatOthers"; - public static final String MAIN_TWO_OTHERS = "main2Others"; - public static final String END_OF_TURN_OTHERS = "endOfTurnOthers"; + // Phases + public static final String UPKEEP_YOU = "upkeepYou"; + public static final String DRAW_YOU = "drawYou"; + public static final String MAIN_YOU = "mainYou"; + public static final String BEFORE_COMBAT_YOU = "beforeCombatYou"; + public static final String END_OF_COMBAT_YOU = "endOfCombatYou"; + public static final String MAIN_TWO_YOU = "main2You"; + public static final String END_OF_TURN_YOU = "endOfTurnYou"; - public static final String KEY_STOP_ATTACK = "stopDeclareAttacksStep"; - public static final String KEY_STOP_BLOCK = "stopDeclareBlockersStep"; - public static final String KEY_STOP_ALL_MAIN_PHASES = "stopOnAllMainPhases"; - public static final String KEY_STOP_ALL_END_PHASES = "stopOnAllEndPhases"; - public static final String KEY_PASS_PRIORITY_CAST = "passPriorityCast"; - public static final String KEY_PASS_PRIORITY_ACTIVATION = "passPriorityActivation"; - public static final String KEY_AUTO_ORDER_TRIGGER = "autoOrderTrigger"; - public static final String KEY_USE_FIRST_MANA_ABILITY = "useFirstManaAbility"; + public static final String UPKEEP_OTHERS = "upkeepOthers"; + public static final String DRAW_OTHERS = "drawOthers"; + public static final String MAIN_OTHERS = "mainOthers"; + public static final String BEFORE_COMBAT_OTHERS = "beforeCombatOthers"; + public static final String END_OF_COMBAT_OTHERS = "endOfCombatOthers"; + public static final String MAIN_TWO_OTHERS = "main2Others"; + public static final String END_OF_TURN_OTHERS = "endOfTurnOthers"; - // mana auto payment - public static final String KEY_GAME_MANA_AUTOPAYMENT = "gameManaAutopayment"; - public static final String KEY_GAME_MANA_AUTOPAYMENT_ONLY_ONE = "gameManaAutopaymentOnlyOne"; + public static final String KEY_STOP_ATTACK = "stopDeclareAttacksStep"; + public static final String KEY_STOP_BLOCK = "stopDeclareBlockersStep"; + public static final String KEY_STOP_ALL_MAIN_PHASES = "stopOnAllMainPhases"; + public static final String KEY_STOP_ALL_END_PHASES = "stopOnAllEndPhases"; + public static final String KEY_PASS_PRIORITY_CAST = "passPriorityCast"; + public static final String KEY_PASS_PRIORITY_ACTIVATION = "passPriorityActivation"; + public static final String KEY_AUTO_ORDER_TRIGGER = "autoOrderTrigger"; + public static final String KEY_USE_FIRST_MANA_ABILITY = "useFirstManaAbility"; - // Size of frame to check if divider locations should be used - public static final String KEY_MAGE_PANEL_LAST_SIZE = "gamepanelLastSize"; + // mana auto payment + public static final String KEY_GAME_MANA_AUTOPAYMENT = "gameManaAutopayment"; + public static final String KEY_GAME_MANA_AUTOPAYMENT_ONLY_ONE = "gameManaAutopaymentOnlyOne"; - // pref settings of table settings and filtering - public static final String KEY_TABLES_FILTER_SETTINGS = "tablePanelFilterSettings"; - public static final String KEY_TABLES_COLUMNS_WIDTH = "tablePanelColumnWidth"; - public static final String KEY_TABLES_COLUMNS_ORDER = "tablePanelColumnSort"; + // Size of frame to check if divider locations should be used + public static final String KEY_MAGE_PANEL_LAST_SIZE = "gamepanelLastSize"; - // last sort settings used in deck editor - public static final String KEY_DECK_EDITOR_LAST_SORT = "deckEditorLastSort"; - public static final String KEY_DECK_EDITOR_LAST_SEPARATE_CREATURES = "deckEditorLastSeparateCreatures"; + // pref settings of table settings and filtering + public static final String KEY_TABLES_FILTER_SETTINGS = "tablePanelFilterSettings"; + public static final String KEY_TABLES_COLUMNS_WIDTH = "tablePanelColumnWidth"; + public static final String KEY_TABLES_COLUMNS_ORDER = "tablePanelColumnSort"; - // positions of divider bars - public static final String KEY_TABLES_DIVIDER_LOCATION_1 = "tablePanelDividerLocation1"; - public static final String KEY_TABLES_DIVIDER_LOCATION_2 = "tablePanelDividerLocation2"; - public static final String KEY_TABLES_DIVIDER_LOCATION_3 = "tablePanelDividerLocation3"; + // last sort settings used in deck editor + public static final String KEY_DECK_EDITOR_LAST_SORT = "deckEditorLastSort"; + public static final String KEY_DECK_EDITOR_LAST_SEPARATE_CREATURES = "deckEditorLastSeparateCreatures"; - // Positions of deck editor divider bars - public static final String KEY_EDITOR_HORIZONTAL_DIVIDER_LOCATION = "editorHorizontalDividerLocation"; - public static final String KEY_EDITOR_DECKAREA_SETTINGS = "editorDeckAreaSettings"; + // positions of divider bars + public static final String KEY_TABLES_DIVIDER_LOCATION_1 = "tablePanelDividerLocation1"; + public static final String KEY_TABLES_DIVIDER_LOCATION_2 = "tablePanelDividerLocation2"; + public static final String KEY_TABLES_DIVIDER_LOCATION_3 = "tablePanelDividerLocation3"; - // user list - public static final String KEY_USERS_COLUMNS_WIDTH = "userPanelColumnWidth"; - public static final String KEY_USERS_COLUMNS_ORDER = "userPanelColumnSort"; - // table waiting dialog - public static final String KEY_TABLE_WAITING_WIDTH = "tableWaitingPanelWidth"; - public static final String KEY_TABLE_WAITING_HEIGHT = "tableWaitingPanelHeight"; - public static final String KEY_TABLE_WAITING_COLUMNS_WIDTH = "tableWaitingPanelColumnWidth"; - public static final String KEY_TABLE_WAITING_COLUMNS_ORDER = "tableWaitingPanelColumnSort"; + // Positions of deck editor divider bars + public static final String KEY_EDITOR_HORIZONTAL_DIVIDER_LOCATION = "editorHorizontalDividerLocation"; + public static final String KEY_EDITOR_DECKAREA_SETTINGS = "editorDeckAreaSettings"; - public static final String KEY_GAMEPANEL_DIVIDER_LOCATION_0 = "gamepanelDividerLocation0"; - public static final String KEY_GAMEPANEL_DIVIDER_LOCATION_1 = "gamepanelDividerLocation1"; - public static final String KEY_GAMEPANEL_DIVIDER_LOCATION_2 = "gamepanelDividerLocation2"; + // user list + public static final String KEY_USERS_COLUMNS_WIDTH = "userPanelColumnWidth"; + public static final String KEY_USERS_COLUMNS_ORDER = "userPanelColumnSort"; + // table waiting dialog + public static final String KEY_TABLE_WAITING_WIDTH = "tableWaitingPanelWidth"; + public static final String KEY_TABLE_WAITING_HEIGHT = "tableWaitingPanelHeight"; + public static final String KEY_TABLE_WAITING_COLUMNS_WIDTH = "tableWaitingPanelColumnWidth"; + public static final String KEY_TABLE_WAITING_COLUMNS_ORDER = "tableWaitingPanelColumnSort"; - public static final String KEY_TOURNAMENT_PLAYER_COLUMNS_WIDTH = "tournamentPlayerPanelColumnWidth"; - public static final String KEY_TOURNAMENT_PLAYER_COLUMNS_ORDER = "tournamentPlayerPanelColumnSort"; - public static final String KEY_TOURNAMENT_MATCH_COLUMNS_WIDTH = "tournamentMatchPanelColumnWidth"; - public static final String KEY_TOURNAMENT_MATCH_COLUMNS_ORDER = "tournamentMatchPanelColumnSort"; - public static final String KEY_TOURNAMENT_DIVIDER_LOCATION_1 = "tournamentPanelDividerLocation1"; - public static final String KEY_TOURNAMENT_DIVIDER_LOCATION_2 = "tournamentPanelDividerLocation2"; + public static final String KEY_GAMEPANEL_DIVIDER_LOCATION_0 = "gamepanelDividerLocation0"; + public static final String KEY_GAMEPANEL_DIVIDER_LOCATION_1 = "gamepanelDividerLocation1"; + public static final String KEY_GAMEPANEL_DIVIDER_LOCATION_2 = "gamepanelDividerLocation2"; - // pref setting for new table dialog - public static final String KEY_NEW_TABLE_NAME = "newTableName"; - public static final String KEY_NEW_TABLE_PASSWORD = "newTablePassword"; - public static final String KEY_NEW_TABLE_PASSWORD_JOIN = "newTablePasswordJoin"; - public static final String KEY_NEW_TABLE_DECK_TYPE = "newTableDeckType"; - public static final String KEY_NEW_TABLE_TIME_LIMIT = "newTableTimeLimit"; - public static final String KEY_NEW_TABLE_GAME_TYPE = "newTableGameType"; - public static final String KEY_NEW_TABLE_NUMBER_OF_WINS = "newTableNumberOfWins"; - public static final String KEY_NEW_TABLE_ROLLBACK_TURNS_ALLOWED = "newTableRollbackTurnsAllowed"; - public static final String KEY_NEW_TABLE_NUMBER_OF_FREE_MULLIGANS = "newTableNumberOfFreeMulligans"; - public static final String KEY_NEW_TABLE_DECK_FILE = "newTableDeckFile"; - public static final String KEY_NEW_TABLE_RANGE = "newTableRange"; - public static final String KEY_NEW_TABLE_ATTACK_OPTION = "newTableAttackOption"; - public static final String KEY_NEW_TABLE_SKILL_LEVEL = "newTableSkillLevel"; - public static final String KEY_NEW_TABLE_NUMBER_PLAYERS = "newTableNumberPlayers"; - public static final String KEY_NEW_TABLE_PLAYER_TYPES = "newTablePlayerTypes"; - public static final String KEY_NEW_TABLE_QUIT_RATIO = "newTableQuitRatio"; - public static final String KEY_NEW_TABLE_RATED = "newTableRated"; + public static final String KEY_TOURNAMENT_PLAYER_COLUMNS_WIDTH = "tournamentPlayerPanelColumnWidth"; + public static final String KEY_TOURNAMENT_PLAYER_COLUMNS_ORDER = "tournamentPlayerPanelColumnSort"; + public static final String KEY_TOURNAMENT_MATCH_COLUMNS_WIDTH = "tournamentMatchPanelColumnWidth"; + public static final String KEY_TOURNAMENT_MATCH_COLUMNS_ORDER = "tournamentMatchPanelColumnSort"; + public static final String KEY_TOURNAMENT_DIVIDER_LOCATION_1 = "tournamentPanelDividerLocation1"; + public static final String KEY_TOURNAMENT_DIVIDER_LOCATION_2 = "tournamentPanelDividerLocation2"; - // pref setting for new tournament dialog - public static final String KEY_NEW_TOURNAMENT_NAME = "newTournamentName"; - public static final String KEY_NEW_TOURNAMENT_PASSWORD = "newTournamentPassword"; - public static final String KEY_NEW_TOURNAMENT_TIME_LIMIT = "newTournamentTimeLimit"; - public static final String KEY_NEW_TOURNAMENT_CONSTR_TIME = "newTournamentConstructionTime"; - public static final String KEY_NEW_TOURNAMENT_TYPE = "newTournamentType"; - public static final String KEY_NEW_TOURNAMENT_NUMBER_OF_FREE_MULLIGANS = "newTournamentNumberOfFreeMulligans"; - public static final String KEY_NEW_TOURNAMENT_NUMBER_OF_WINS = "newTournamentNumberOfWins"; - public static final String KEY_NEW_TOURNAMENT_PACKS_SEALED = "newTournamentPacksSealed"; - public static final String KEY_NEW_TOURNAMENT_PACKS_DRAFT = "newTournamentPacksDraft"; - public static final String KEY_NEW_TOURNAMENT_PACKS_RANDOM_DRAFT = "newTournamentPacksRandomDraft"; - public static final String KEY_NEW_TOURNAMENT_PLAYERS_SEALED = "newTournamentPlayersSealed"; - public static final String KEY_NEW_TOURNAMENT_PLAYERS_DRAFT = "newTournamentPlayersDraft"; - public static final String KEY_NEW_TOURNAMENT_DRAFT_TIMING = "newTournamentDraftTiming"; - public static final String KEY_NEW_TOURNAMENT_ALLOW_SPECTATORS = "newTournamentAllowSpectators"; - public static final String KEY_NEW_TOURNAMENT_ALLOW_ROLLBACKS = "newTournamentAllowRollbacks"; - public static final String KEY_NEW_TOURNAMENT_DECK_FILE = "newTournamentDeckFile"; - public static final String KEY_NEW_TOURNAMENT_QUIT_RATIO = "newTournamentQuitRatio"; - public static final String KEY_NEW_TOURNAMENT_RATED = "newTournamentRated"; + // pref setting for new table dialog + public static final String KEY_NEW_TABLE_NAME = "newTableName"; + public static final String KEY_NEW_TABLE_PASSWORD = "newTablePassword"; + public static final String KEY_NEW_TABLE_PASSWORD_JOIN = "newTablePasswordJoin"; + public static final String KEY_NEW_TABLE_DECK_TYPE = "newTableDeckType"; + public static final String KEY_NEW_TABLE_TIME_LIMIT = "newTableTimeLimit"; + public static final String KEY_NEW_TABLE_GAME_TYPE = "newTableGameType"; + public static final String KEY_NEW_TABLE_NUMBER_OF_WINS = "newTableNumberOfWins"; + public static final String KEY_NEW_TABLE_ROLLBACK_TURNS_ALLOWED = "newTableRollbackTurnsAllowed"; + public static final String KEY_NEW_TABLE_NUMBER_OF_FREE_MULLIGANS = "newTableNumberOfFreeMulligans"; + public static final String KEY_NEW_TABLE_DECK_FILE = "newTableDeckFile"; + public static final String KEY_NEW_TABLE_RANGE = "newTableRange"; + public static final String KEY_NEW_TABLE_ATTACK_OPTION = "newTableAttackOption"; + public static final String KEY_NEW_TABLE_SKILL_LEVEL = "newTableSkillLevel"; + public static final String KEY_NEW_TABLE_NUMBER_PLAYERS = "newTableNumberPlayers"; + public static final String KEY_NEW_TABLE_PLAYER_TYPES = "newTablePlayerTypes"; + public static final String KEY_NEW_TABLE_QUIT_RATIO = "newTableQuitRatio"; + public static final String KEY_NEW_TABLE_RATED = "newTableRated"; - // pref setting for deck generator - public static final String KEY_NEW_DECK_GENERATOR_DECK_SIZE = "newDeckGeneratorDeckSize"; - public static final String KEY_NEW_DECK_GENERATOR_SET = "newDeckGeneratorSet"; - public static final String KEY_NEW_DECK_GENERATOR_SINGLETON = "newDeckGeneratorSingleton"; - public static final String KEY_NEW_DECK_GENERATOR_ARTIFACTS = "newDeckGeneratorArtifacts"; - public static final String KEY_NEW_DECK_GENERATOR_NON_BASIC_LANDS = "newDeckGeneratorNonBasicLands"; - public static final String KEY_NEW_DECK_GENERATOR_COLORLESS = "newDeckGeneratorColorless"; - public static final String KEY_NEW_DECK_GENERATOR_ADVANCED = "newDeckGeneratorAdvanced"; - public static final String KEY_NEW_DECK_GENERATOR_CREATURE_PERCENTAGE = "newDeckGeneratorCreaturePercentage"; - public static final String KEY_NEW_DECK_GENERATOR_NON_CREATURE_PERCENTAGE = "newDeckGeneratorNonCreaturePercentage"; - public static final String KEY_NEW_DECK_GENERATOR_LAND_PERCENTAGE = "newDeckGeneratorLandPercentage"; - public static final String KEY_NEW_DECK_GENERATOR_ADVANCED_CMC = "newDeckGeneratorAdvancedCMC"; + // pref setting for new tournament dialog + public static final String KEY_NEW_TOURNAMENT_NAME = "newTournamentName"; + public static final String KEY_NEW_TOURNAMENT_PASSWORD = "newTournamentPassword"; + public static final String KEY_NEW_TOURNAMENT_TIME_LIMIT = "newTournamentTimeLimit"; + public static final String KEY_NEW_TOURNAMENT_CONSTR_TIME = "newTournamentConstructionTime"; + public static final String KEY_NEW_TOURNAMENT_TYPE = "newTournamentType"; + public static final String KEY_NEW_TOURNAMENT_NUMBER_OF_FREE_MULLIGANS = "newTournamentNumberOfFreeMulligans"; + public static final String KEY_NEW_TOURNAMENT_NUMBER_OF_WINS = "newTournamentNumberOfWins"; + public static final String KEY_NEW_TOURNAMENT_PACKS_SEALED = "newTournamentPacksSealed"; + public static final String KEY_NEW_TOURNAMENT_PACKS_DRAFT = "newTournamentPacksDraft"; + public static final String KEY_NEW_TOURNAMENT_PACKS_RANDOM_DRAFT = "newTournamentPacksRandomDraft"; + public static final String KEY_NEW_TOURNAMENT_PLAYERS_SEALED = "newTournamentPlayersSealed"; + public static final String KEY_NEW_TOURNAMENT_PLAYERS_DRAFT = "newTournamentPlayersDraft"; + public static final String KEY_NEW_TOURNAMENT_DRAFT_TIMING = "newTournamentDraftTiming"; + public static final String KEY_NEW_TOURNAMENT_ALLOW_SPECTATORS = "newTournamentAllowSpectators"; + public static final String KEY_NEW_TOURNAMENT_ALLOW_ROLLBACKS = "newTournamentAllowRollbacks"; + public static final String KEY_NEW_TOURNAMENT_DECK_FILE = "newTournamentDeckFile"; + public static final String KEY_NEW_TOURNAMENT_QUIT_RATIO = "newTournamentQuitRatio"; + public static final String KEY_NEW_TOURNAMENT_RATED = "newTournamentRated"; - // used to save and restore the settings for the cardArea (draft, sideboarding, deck builder) - public static final String KEY_DRAFT_VIEW = "draftView"; + // pref setting for deck generator + public static final String KEY_NEW_DECK_GENERATOR_DECK_SIZE = "newDeckGeneratorDeckSize"; + public static final String KEY_NEW_DECK_GENERATOR_SET = "newDeckGeneratorSet"; + public static final String KEY_NEW_DECK_GENERATOR_SINGLETON = "newDeckGeneratorSingleton"; + public static final String KEY_NEW_DECK_GENERATOR_ARTIFACTS = "newDeckGeneratorArtifacts"; + public static final String KEY_NEW_DECK_GENERATOR_NON_BASIC_LANDS = "newDeckGeneratorNonBasicLands"; + public static final String KEY_NEW_DECK_GENERATOR_COLORLESS = "newDeckGeneratorColorless"; + public static final String KEY_NEW_DECK_GENERATOR_ADVANCED = "newDeckGeneratorAdvanced"; + public static final String KEY_NEW_DECK_GENERATOR_CREATURE_PERCENTAGE = "newDeckGeneratorCreaturePercentage"; + public static final String KEY_NEW_DECK_GENERATOR_NON_CREATURE_PERCENTAGE = "newDeckGeneratorNonCreaturePercentage"; + public static final String KEY_NEW_DECK_GENERATOR_LAND_PERCENTAGE = "newDeckGeneratorLandPercentage"; + public static final String KEY_NEW_DECK_GENERATOR_ADVANCED_CMC = "newDeckGeneratorAdvancedCMC"; - public static final String KEY_DRAFT_SORT_BY = "draftSortBy"; - public static final String KEY_DRAFT_SORT_INDEX = "draftSortIndex"; - public static final String KEY_DRAFT_SORT_ASCENDING = "draftSortAscending"; - public static final String KEY_DRAFT_PILES_TOGGLE = "draftPilesToggle"; + // used to save and restore the settings for the cardArea (draft, sideboarding, deck builder) + public static final String KEY_DRAFT_VIEW = "draftView"; - public static final String KEY_BASE_SORT_BY = "baseSortBy"; - public static final String KEY_BASE_SORT_INDEX = "baseSortIndex"; - public static final String KEY_BASE_SORT_ASCENDING = "baseSortAscending"; - public static final String KEY_BASE_PILES_TOGGLE = "basePilesToggle"; + public static final String KEY_DRAFT_SORT_BY = "draftSortBy"; + public static final String KEY_DRAFT_SORT_INDEX = "draftSortIndex"; + public static final String KEY_DRAFT_SORT_ASCENDING = "draftSortAscending"; + public static final String KEY_DRAFT_PILES_TOGGLE = "draftPilesToggle"; - public static final String KEY_SIDEBOARD_SORT_BY = "sideboardSortBy"; - public static final String KEY_SIDEBOARD_SORT_INDEX = "sideboardSortIndex"; - public static final String KEY_SIDEBOARD_SORT_ASCENDING = "sideboardSortAscending"; - public static final String KEY_SIDEBOARD_PILES_TOGGLE = "sideboardPilesToggle"; + public static final String KEY_BASE_SORT_BY = "baseSortBy"; + public static final String KEY_BASE_SORT_INDEX = "baseSortIndex"; + public static final String KEY_BASE_SORT_ASCENDING = "baseSortAscending"; + public static final String KEY_BASE_PILES_TOGGLE = "basePilesToggle"; - public static final String KEY_DECK_SORT_BY = "deckSortBy"; - public static final String KEY_DECK_SORT_INDEX = "deckSortIndex"; - public static final String KEY_DECK_SORT_ASCENDING = "deckSortAscending"; - public static final String KEY_DECK_PILES_TOGGLE = "deckPilesToggle"; + public static final String KEY_SIDEBOARD_SORT_BY = "sideboardSortBy"; + public static final String KEY_SIDEBOARD_SORT_INDEX = "sideboardSortIndex"; + public static final String KEY_SIDEBOARD_SORT_ASCENDING = "sideboardSortAscending"; + public static final String KEY_SIDEBOARD_PILES_TOGGLE = "sideboardPilesToggle"; - public static final String KEY_PROXY_ADDRESS = "proxyAddress"; - public static final String KEY_PROXY_PORT = "proxyPort"; - public static final String KEY_PROXY_USERNAME = "proxyUsername"; - public static final String KEY_PROXY_REMEMBER = "proxyRemember"; - public static final String KEY_PROXY_TYPE = "proxyType"; - public static final String KEY_PROXY_PSWD = "proxyPassword"; - public static final String KEY_CONNECTION_URL_SERVER_LIST = "connectionURLServerList"; + public static final String KEY_DECK_SORT_BY = "deckSortBy"; + public static final String KEY_DECK_SORT_INDEX = "deckSortIndex"; + public static final String KEY_DECK_SORT_ASCENDING = "deckSortAscending"; + public static final String KEY_DECK_PILES_TOGGLE = "deckPilesToggle"; - public static final String KEY_AVATAR = "selectedId"; + public static final String KEY_PROXY_ADDRESS = "proxyAddress"; + public static final String KEY_PROXY_PORT = "proxyPort"; + public static final String KEY_PROXY_USERNAME = "proxyUsername"; + public static final String KEY_PROXY_REMEMBER = "proxyRemember"; + public static final String KEY_PROXY_TYPE = "proxyType"; + public static final String KEY_PROXY_PSWD = "proxyPassword"; + public static final String KEY_CONNECTION_URL_SERVER_LIST = "connectionURLServerList"; - public static final String KEY_CONNECT_AUTO_CONNECT = "autoConnect"; - public static final String KEY_CONNECT_FLAG = "connectFlag"; + // controls + public static final String KEY_CONTROL_CANCEL_SKIP = "controlCancelSkip"; + public static final String KEY_CONTROL_NEXT_TURN = "controlNextTurn"; + public static final String KEY_CONTROL_END_STEP = "controlEndStep"; + public static final String KEY_CONTROL_MAIN_STEP = "controlMainStep"; + public static final String KEY_CONTROL_YOUR_TURN = "controlYourTurn"; + public static final String KEY_CONTROL_SKIP_STACK = "controlSkipStack"; + public static final String KEY_CONTROL_PRIOR_END = "controlPriorEnd"; - private static final Map CACHE = new HashMap<>(); + public static final String KEY_AVATAR = "selectedId"; - private static final Boolean UPDATE_CACHE_POLICY = Boolean.TRUE; + public static final String KEY_CONNECT_AUTO_CONNECT = "autoConnect"; + public static final String KEY_CONNECT_FLAG = "connectFlag"; - public static final String OPEN_CONNECTION_TAB = "Open-Connection-Tab"; - public static final String OPEN_PHASES_TAB = "Open-Phases-Tab"; + private static final Map CACHE = new HashMap<>(); - public static String PHASE_ON = "on"; - public static String PHASE_OFF = "off"; + private static final Boolean UPDATE_CACHE_POLICY = Boolean.TRUE; - private static final Map PANELS = new HashMap<>(); + public static final String OPEN_CONNECTION_TAB = "Open-Connection-Tab"; + public static final String OPEN_PHASES_TAB = "Open-Phases-Tab"; - private static final Border GREEN_BORDER = BorderFactory.createLineBorder(Color.GREEN, 3); - private static final Border BLACK_BORDER = BorderFactory.createLineBorder(Color.BLACK, 3); + public static String PHASE_ON = "on"; + public static String PHASE_OFF = "off"; - private static int selectedAvatarId; + private static final Map PANELS = new HashMap<>(); - private final JFileChooser fc = new JFileChooser(); + private static final Border GREEN_BORDER = BorderFactory.createLineBorder(Color.GREEN, 3); + private static final Border BLACK_BORDER = BorderFactory.createLineBorder(Color.BLACK, 3); - { - fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); - } + private static int selectedAvatarId; - private final JFileChooser fc_i = new JFileChooser(); + private final JFileChooser fc = new JFileChooser(); - { - fc_i.setAcceptAllFileFilterUsed(false); - fc_i.addChoosableFileFilter(new ImageFileFilter()); - } + { + fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + } - private static class ImageFileFilter extends FileFilter { + private final JFileChooser fc_i = new JFileChooser(); - @Override - public boolean accept(File f) { - String filename = f.getName(); - if (f.isDirectory()) { - return true; - } - if (filename != null) { - if (filename.endsWith(".jpg") || filename.endsWith(".jpeg") - || filename.endsWith(".png") || filename.endsWith(".bmp")) { - return true; - } - } - return false; - } + { + fc_i.setAcceptAllFileFilterUsed(false); + fc_i.addChoosableFileFilter(new ImageFileFilter()); + } - @Override - public String getDescription() { - return "*.png | *.bmp |*.jpg | *.jpeg"; - } - } + private static class ImageFileFilter extends FileFilter { - /** - * Creates new form PreferencesDialog - * - * @param parent - * @param modal - */ - public PreferencesDialog(java.awt.Frame parent, boolean modal) { - super(parent, modal); - initComponents(); - txtImageFolderPath.setEditable(false); - cbProxyType.setModel(new DefaultComboBoxModel<>(Connection.ProxyType.values())); - addAvatars(); + @Override + public boolean accept(File f) { + String filename = f.getName(); + if (f.isDirectory()) { + return true; + } + if (filename != null) { + if (filename.endsWith(".jpg") || filename.endsWith(".jpeg") + || filename.endsWith(".png") || filename.endsWith(".bmp")) { + return true; + } + } + return false; + } - cbPreferedImageLanguage.setModel(new DefaultComboBoxModel<>(new String[]{"en", "de", "fr", "it", "es", "pt", "jp", "cn", "ru", "tw", "ko"})); - cbNumberOfDownloadThreads.setModel(new DefaultComboBoxModel<>(new String[]{"10", "9", "8", "7", "6", "5", "4", "3", "2", "1"})); - } + @Override + public String getDescription() { + return "*.png | *.bmp |*.jpg | *.jpeg"; + } + } - /** - * This method is called from within the constructor to initialize the form. - * WARNING: Do NOT modify this code. The content of this method is always - * regenerated by the Form Editor. - */ - @SuppressWarnings("unchecked") + /** + * Creates new form PreferencesDialog + * + * @param parent + * @param modal + */ + public PreferencesDialog(java.awt.Frame parent, boolean modal) { + super(parent, modal); + initComponents(); + txtImageFolderPath.setEditable(false); + cbProxyType.setModel(new DefaultComboBoxModel<>(Connection.ProxyType.values())); + addAvatars(); + + cbPreferedImageLanguage.setModel(new DefaultComboBoxModel<>(new String[]{"en", "de", "fr", "it", "es", "pt", "jp", "cn", "ru", "tw", "ko"})); + cbNumberOfDownloadThreads.setModel(new DefaultComboBoxModel<>(new String[]{"10", "9", "8", "7", "6", "5", "4", "3", "2", "1"})); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; @@ -538,6 +549,21 @@ public class PreferencesDialog extends javax.swing.JDialog { txtPasswordField = new javax.swing.JPasswordField(); rememberPswd = new javax.swing.JCheckBox(); jLabel11 = new javax.swing.JLabel(); + tabControls = new javax.swing.JPanel(); + labelNextTurn = new javax.swing.JLabel(); + labelEndStep = new javax.swing.JLabel(); + labelMainStep = new javax.swing.JLabel(); + labelYourTurn = new javax.swing.JLabel(); + lebelSkip = new javax.swing.JLabel(); + labelPriorEnd = new javax.swing.JLabel(); + labelCancel = new javax.swing.JLabel(); + keyCancelSkip = new mage.client.components.KeyBindButton(); + keyNextTurn = new mage.client.components.KeyBindButton(); + keyMainStep = new mage.client.components.KeyBindButton(); + keyEndStep = new mage.client.components.KeyBindButton(); + keyYourTurn = new mage.client.components.KeyBindButton(); + keySkipStack = new mage.client.components.KeyBindButton(); + keyPriorEnd = new mage.client.components.KeyBindButton(); saveButton = new javax.swing.JButton(); exitButton = new javax.swing.JButton(); @@ -579,7 +605,7 @@ public class PreferencesDialog extends javax.swing.JDialog { .add(main_cardLayout.createSequentialGroup() .add(6, 6, 6) .add(main_cardLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING, false) - .add(tooltipDelayLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 308, Short.MAX_VALUE) + .add(tooltipDelayLabel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 308, Short.MAX_VALUE) .add(org.jdesktop.layout.GroupLayout.LEADING, showCardName) .add(tooltipDelay, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) @@ -2440,6 +2466,95 @@ public class PreferencesDialog extends javax.swing.JDialog { tabsPanel.addTab("Connection", tabConnection); + labelNextTurn.setText("Next Turn"); + + labelEndStep.setText("End Step"); + + labelMainStep.setText("Main Step"); + + labelYourTurn.setText("Your Turn"); + + lebelSkip.setText("Skip Stack"); + + labelPriorEnd.setText("Prior End"); + + labelCancel.setText("Cancel Skip"); + + keyCancelSkip.setText("keyBindButton1"); + + keyNextTurn.setText("keyBindButton1"); + + keyMainStep.setText("keyBindButton1"); + + keyEndStep.setText("keyBindButton1"); + + keyYourTurn.setText("keyBindButton1"); + + keySkipStack.setText("keyBindButton1"); + + keyPriorEnd.setText("keyBindButton1"); + + org.jdesktop.layout.GroupLayout tabControlsLayout = new org.jdesktop.layout.GroupLayout(tabControls); + tabControls.setLayout(tabControlsLayout); + tabControlsLayout.setHorizontalGroup( + tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(tabControlsLayout.createSequentialGroup() + .addContainerGap() + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(labelCancel) + .add(labelNextTurn) + .add(labelEndStep) + .add(labelMainStep) + .add(labelYourTurn) + .add(lebelSkip) + .add(labelPriorEnd)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(keySkipStack, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(keyYourTurn, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(keyNextTurn, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(keyCancelSkip, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(keyEndStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(keyMainStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(keyPriorEnd, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(483, Short.MAX_VALUE)) + ); + tabControlsLayout.setVerticalGroup( + tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(tabControlsLayout.createSequentialGroup() + .addContainerGap() + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(labelCancel) + .add(keyCancelSkip, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(labelNextTurn) + .add(keyNextTurn, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(labelEndStep) + .add(keyEndStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(labelMainStep) + .add(keyMainStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(labelYourTurn) + .add(keyYourTurn, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(lebelSkip) + .add(keySkipStack, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(labelPriorEnd) + .add(keyPriorEnd, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(301, Short.MAX_VALUE)) + ); + + tabsPanel.addTab("Controls", tabControls); + saveButton.setLabel("Save"); saveButton.setMaximumSize(new java.awt.Dimension(100, 30)); saveButton.setMinimumSize(new java.awt.Dimension(100, 30)); @@ -2492,182 +2607,191 @@ public class PreferencesDialog extends javax.swing.JDialog { }// //GEN-END:initComponents private void saveButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveButtonActionPerformed - Preferences prefs = MageFrame.getPreferences(); + Preferences prefs = MageFrame.getPreferences(); - // main - save(prefs, dialog.tooltipDelay, KEY_SHOW_TOOLTIPS_DELAY, "true", "false", UPDATE_CACHE_POLICY); - save(prefs, dialog.showCardName, KEY_SHOW_CARD_NAMES, "true", "false", UPDATE_CACHE_POLICY); - save(prefs, dialog.nonLandPermanentsInOnePile, KEY_PERMANENTS_IN_ONE_PILE, "true", "false", UPDATE_CACHE_POLICY); - save(prefs, dialog.showPlayerNamesPermanently, KEY_SHOW_PLAYER_NAMES_PERMANENTLY, "true", "false", UPDATE_CACHE_POLICY); - save(prefs, dialog.showAbilityPickerForced, KEY_SHOW_ABILITY_PICKER_FORCED, "true", "false", UPDATE_CACHE_POLICY); - save(prefs, dialog.cbAllowRequestToShowHandCards, KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS, "true", "false", UPDATE_CACHE_POLICY); - save(prefs, dialog.cbShowStormCounter, KEY_GAME_SHOW_STORM_COUNTER, "true", "false", UPDATE_CACHE_POLICY); - save(prefs, dialog.cbConfirmEmptyManaPool, KEY_GAME_CONFIRM_EMPTY_MANA_POOL, "true", "false", UPDATE_CACHE_POLICY); - save(prefs, dialog.cbAskMoveToGraveOrder, KEY_GAME_ASK_MOVE_TO_GRAVE_ORDER, "true", "false", UPDATE_CACHE_POLICY); - save(prefs, dialog.cbGameLogAutoSave, KEY_GAME_LOG_AUTO_SAVE, "true", "false", UPDATE_CACHE_POLICY); - save(prefs, dialog.cbDraftLogAutoSave, KEY_DRAFT_LOG_AUTO_SAVE, "true", "false", UPDATE_CACHE_POLICY); + // main + save(prefs, dialog.tooltipDelay, KEY_SHOW_TOOLTIPS_DELAY, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.showCardName, KEY_SHOW_CARD_NAMES, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.nonLandPermanentsInOnePile, KEY_PERMANENTS_IN_ONE_PILE, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.showPlayerNamesPermanently, KEY_SHOW_PLAYER_NAMES_PERMANENTLY, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.showAbilityPickerForced, KEY_SHOW_ABILITY_PICKER_FORCED, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.cbAllowRequestToShowHandCards, KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.cbShowStormCounter, KEY_GAME_SHOW_STORM_COUNTER, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.cbConfirmEmptyManaPool, KEY_GAME_CONFIRM_EMPTY_MANA_POOL, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.cbAskMoveToGraveOrder, KEY_GAME_ASK_MOVE_TO_GRAVE_ORDER, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.cbGameLogAutoSave, KEY_GAME_LOG_AUTO_SAVE, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.cbDraftLogAutoSave, KEY_DRAFT_LOG_AUTO_SAVE, "true", "false", UPDATE_CACHE_POLICY); - // GUI Size - boolean sizeGUIChanged = false; - if (getCachedValue(KEY_GUI_TABLE_FONT_SIZE, 14) != dialog.sliderFontSize.getValue()) { - save(prefs, dialog.sliderFontSize, KEY_GUI_TABLE_FONT_SIZE, "true", "false", UPDATE_CACHE_POLICY); - sizeGUIChanged = true; - } - if (getCachedValue(KEY_GUI_CHAT_FONT_SIZE, 14) != dialog.sliderChatFontSize.getValue()) { - save(prefs, dialog.sliderChatFontSize, KEY_GUI_CHAT_FONT_SIZE, "true", "false", UPDATE_CACHE_POLICY); - sizeGUIChanged = true; - } - if (getCachedValue(KEY_GUI_CARD_HAND_SIZE, 14) != dialog.sliderCardSizeHand.getValue()) { - save(prefs, dialog.sliderCardSizeHand, KEY_GUI_CARD_HAND_SIZE, "true", "false", UPDATE_CACHE_POLICY); - sizeGUIChanged = true; - } - if (getCachedValue(KEY_GUI_CARD_EDITOR_SIZE, 14) != dialog.sliderEditorCardSize.getValue()) { - save(prefs, dialog.sliderEditorCardSize, KEY_GUI_CARD_EDITOR_SIZE, "true", "false", UPDATE_CACHE_POLICY); - sizeGUIChanged = true; - } - if (getCachedValue(KEY_GUI_CARD_OFFSET_SIZE, 14) != dialog.sliderEditorCardOffset.getValue()) { - save(prefs, dialog.sliderEditorCardOffset, KEY_GUI_CARD_OFFSET_SIZE, "true", "false", UPDATE_CACHE_POLICY); - sizeGUIChanged = true; - } - if (getCachedValue(KEY_GUI_ENLARGED_IMAGE_SIZE, 20) != dialog.sliderEnlargedImageSize.getValue()) { - save(prefs, dialog.sliderEnlargedImageSize, KEY_GUI_ENLARGED_IMAGE_SIZE, "true", "false", UPDATE_CACHE_POLICY); - sizeGUIChanged = true; - } - if (getCachedValue(KEY_GUI_STACK_WIDTH, 30) != dialog.sliderStackWidth.getValue()) { - save(prefs, dialog.sliderStackWidth, KEY_GUI_STACK_WIDTH, "true", "false", UPDATE_CACHE_POLICY); - sizeGUIChanged = true; - } - if (getCachedValue(KEY_GUI_TOOLTIP_SIZE, 14) != dialog.sliderTooltipSize.getValue()) { - save(prefs, dialog.sliderTooltipSize, KEY_GUI_TOOLTIP_SIZE, "true", "false", UPDATE_CACHE_POLICY); - sizeGUIChanged = true; - } - if (getCachedValue(KEY_GUI_DIALOG_FONT_SIZE, 14) != dialog.sliderDialogFont.getValue()) { - save(prefs, dialog.sliderDialogFont, KEY_GUI_DIALOG_FONT_SIZE, "true", "false", UPDATE_CACHE_POLICY); - sizeGUIChanged = true; - } - if (getCachedValue(KEY_GUI_FEEDBACK_AREA_SIZE, 14) != dialog.sliderGameFeedbackArea.getValue()) { - save(prefs, dialog.sliderGameFeedbackArea, KEY_GUI_FEEDBACK_AREA_SIZE, "true", "false", UPDATE_CACHE_POLICY); - sizeGUIChanged = true; - } - if (getCachedValue(KEY_GUI_CARD_OTHER_ZONES_SIZE, 14) != dialog.sliderCardSizeOtherZones.getValue()) { - save(prefs, dialog.sliderCardSizeOtherZones, KEY_GUI_CARD_OTHER_ZONES_SIZE, "true", "false", UPDATE_CACHE_POLICY); - sizeGUIChanged = true; - } - if (getCachedValue(KEY_GUI_CARD_BATTLEFIELD_MIN_SIZE, 10) != dialog.sliderCardSizeMaxBattlefield.getValue()) { - save(prefs, dialog.sliderCardSizeMinBattlefield, KEY_GUI_CARD_BATTLEFIELD_MIN_SIZE, "true", "false", UPDATE_CACHE_POLICY); - sizeGUIChanged = true; - } - if (getCachedValue(KEY_GUI_CARD_BATTLEFIELD_MAX_SIZE, 14) != dialog.sliderCardSizeMaxBattlefield.getValue()) { - save(prefs, dialog.sliderCardSizeMaxBattlefield, KEY_GUI_CARD_BATTLEFIELD_MAX_SIZE, "true", "false", UPDATE_CACHE_POLICY); - sizeGUIChanged = true; - } - if (sizeGUIChanged) { - // do as worker job - GUISizeHelper.changeGUISize(); - } + // GUI Size + boolean sizeGUIChanged = false; + if (getCachedValue(KEY_GUI_TABLE_FONT_SIZE, 14) != dialog.sliderFontSize.getValue()) { + save(prefs, dialog.sliderFontSize, KEY_GUI_TABLE_FONT_SIZE, "true", "false", UPDATE_CACHE_POLICY); + sizeGUIChanged = true; + } + if (getCachedValue(KEY_GUI_CHAT_FONT_SIZE, 14) != dialog.sliderChatFontSize.getValue()) { + save(prefs, dialog.sliderChatFontSize, KEY_GUI_CHAT_FONT_SIZE, "true", "false", UPDATE_CACHE_POLICY); + sizeGUIChanged = true; + } + if (getCachedValue(KEY_GUI_CARD_HAND_SIZE, 14) != dialog.sliderCardSizeHand.getValue()) { + save(prefs, dialog.sliderCardSizeHand, KEY_GUI_CARD_HAND_SIZE, "true", "false", UPDATE_CACHE_POLICY); + sizeGUIChanged = true; + } + if (getCachedValue(KEY_GUI_CARD_EDITOR_SIZE, 14) != dialog.sliderEditorCardSize.getValue()) { + save(prefs, dialog.sliderEditorCardSize, KEY_GUI_CARD_EDITOR_SIZE, "true", "false", UPDATE_CACHE_POLICY); + sizeGUIChanged = true; + } + if (getCachedValue(KEY_GUI_CARD_OFFSET_SIZE, 14) != dialog.sliderEditorCardOffset.getValue()) { + save(prefs, dialog.sliderEditorCardOffset, KEY_GUI_CARD_OFFSET_SIZE, "true", "false", UPDATE_CACHE_POLICY); + sizeGUIChanged = true; + } + if (getCachedValue(KEY_GUI_ENLARGED_IMAGE_SIZE, 20) != dialog.sliderEnlargedImageSize.getValue()) { + save(prefs, dialog.sliderEnlargedImageSize, KEY_GUI_ENLARGED_IMAGE_SIZE, "true", "false", UPDATE_CACHE_POLICY); + sizeGUIChanged = true; + } + if (getCachedValue(KEY_GUI_STACK_WIDTH, 30) != dialog.sliderStackWidth.getValue()) { + save(prefs, dialog.sliderStackWidth, KEY_GUI_STACK_WIDTH, "true", "false", UPDATE_CACHE_POLICY); + sizeGUIChanged = true; + } + if (getCachedValue(KEY_GUI_TOOLTIP_SIZE, 14) != dialog.sliderTooltipSize.getValue()) { + save(prefs, dialog.sliderTooltipSize, KEY_GUI_TOOLTIP_SIZE, "true", "false", UPDATE_CACHE_POLICY); + sizeGUIChanged = true; + } + if (getCachedValue(KEY_GUI_DIALOG_FONT_SIZE, 14) != dialog.sliderDialogFont.getValue()) { + save(prefs, dialog.sliderDialogFont, KEY_GUI_DIALOG_FONT_SIZE, "true", "false", UPDATE_CACHE_POLICY); + sizeGUIChanged = true; + } + if (getCachedValue(KEY_GUI_FEEDBACK_AREA_SIZE, 14) != dialog.sliderGameFeedbackArea.getValue()) { + save(prefs, dialog.sliderGameFeedbackArea, KEY_GUI_FEEDBACK_AREA_SIZE, "true", "false", UPDATE_CACHE_POLICY); + sizeGUIChanged = true; + } + if (getCachedValue(KEY_GUI_CARD_OTHER_ZONES_SIZE, 14) != dialog.sliderCardSizeOtherZones.getValue()) { + save(prefs, dialog.sliderCardSizeOtherZones, KEY_GUI_CARD_OTHER_ZONES_SIZE, "true", "false", UPDATE_CACHE_POLICY); + sizeGUIChanged = true; + } + if (getCachedValue(KEY_GUI_CARD_BATTLEFIELD_MIN_SIZE, 10) != dialog.sliderCardSizeMaxBattlefield.getValue()) { + save(prefs, dialog.sliderCardSizeMinBattlefield, KEY_GUI_CARD_BATTLEFIELD_MIN_SIZE, "true", "false", UPDATE_CACHE_POLICY); + sizeGUIChanged = true; + } + if (getCachedValue(KEY_GUI_CARD_BATTLEFIELD_MAX_SIZE, 14) != dialog.sliderCardSizeMaxBattlefield.getValue()) { + save(prefs, dialog.sliderCardSizeMaxBattlefield, KEY_GUI_CARD_BATTLEFIELD_MAX_SIZE, "true", "false", UPDATE_CACHE_POLICY); + sizeGUIChanged = true; + } + if (sizeGUIChanged) { + // do as worker job + GUISizeHelper.changeGUISize(); + } - // Phases & Priority - save(prefs, dialog.checkBoxUpkeepYou, UPKEEP_YOU); - save(prefs, dialog.checkBoxDrawYou, DRAW_YOU); - save(prefs, dialog.checkBoxMainYou, MAIN_YOU); - save(prefs, dialog.checkBoxBeforeCYou, BEFORE_COMBAT_YOU); - save(prefs, dialog.checkBoxEndOfCYou, END_OF_COMBAT_YOU); - save(prefs, dialog.checkBoxMain2You, MAIN_TWO_YOU); - save(prefs, dialog.checkBoxEndTurnYou, END_OF_TURN_YOU); + // Phases & Priority + save(prefs, dialog.checkBoxUpkeepYou, UPKEEP_YOU); + save(prefs, dialog.checkBoxDrawYou, DRAW_YOU); + save(prefs, dialog.checkBoxMainYou, MAIN_YOU); + save(prefs, dialog.checkBoxBeforeCYou, BEFORE_COMBAT_YOU); + save(prefs, dialog.checkBoxEndOfCYou, END_OF_COMBAT_YOU); + save(prefs, dialog.checkBoxMain2You, MAIN_TWO_YOU); + save(prefs, dialog.checkBoxEndTurnYou, END_OF_TURN_YOU); - save(prefs, dialog.checkBoxUpkeepOthers, UPKEEP_OTHERS); - save(prefs, dialog.checkBoxDrawOthers, DRAW_OTHERS); - save(prefs, dialog.checkBoxMainOthers, MAIN_OTHERS); - save(prefs, dialog.checkBoxBeforeCOthers, BEFORE_COMBAT_OTHERS); - save(prefs, dialog.checkBoxEndOfCOthers, END_OF_COMBAT_OTHERS); - save(prefs, dialog.checkBoxMain2Others, MAIN_TWO_OTHERS); - save(prefs, dialog.checkBoxEndTurnOthers, END_OF_TURN_OTHERS); + save(prefs, dialog.checkBoxUpkeepOthers, UPKEEP_OTHERS); + save(prefs, dialog.checkBoxDrawOthers, DRAW_OTHERS); + save(prefs, dialog.checkBoxMainOthers, MAIN_OTHERS); + save(prefs, dialog.checkBoxBeforeCOthers, BEFORE_COMBAT_OTHERS); + save(prefs, dialog.checkBoxEndOfCOthers, END_OF_COMBAT_OTHERS); + save(prefs, dialog.checkBoxMain2Others, MAIN_TWO_OTHERS); + save(prefs, dialog.checkBoxEndTurnOthers, END_OF_TURN_OTHERS); - save(prefs, dialog.cbStopAttack, KEY_STOP_ATTACK, "true", "false", UPDATE_CACHE_POLICY); - save(prefs, dialog.cbStopBlock, KEY_STOP_BLOCK, "true", "false", UPDATE_CACHE_POLICY); - save(prefs, dialog.cbStopOnAllMain, KEY_STOP_ALL_MAIN_PHASES, "true", "false", UPDATE_CACHE_POLICY); - save(prefs, dialog.cbStopOnAllEnd, KEY_STOP_ALL_END_PHASES, "true", "false", UPDATE_CACHE_POLICY); - save(prefs, dialog.cbPassPriorityCast, KEY_PASS_PRIORITY_CAST, "true", "false", UPDATE_CACHE_POLICY); - save(prefs, dialog.cbPassPriorityActivation, KEY_PASS_PRIORITY_ACTIVATION, "true", "false", UPDATE_CACHE_POLICY); - save(prefs, dialog.cbAutoOrderTrigger, KEY_AUTO_ORDER_TRIGGER, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.cbStopAttack, KEY_STOP_ATTACK, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.cbStopBlock, KEY_STOP_BLOCK, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.cbStopOnAllMain, KEY_STOP_ALL_MAIN_PHASES, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.cbStopOnAllEnd, KEY_STOP_ALL_END_PHASES, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.cbPassPriorityCast, KEY_PASS_PRIORITY_CAST, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.cbPassPriorityActivation, KEY_PASS_PRIORITY_ACTIVATION, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.cbAutoOrderTrigger, KEY_AUTO_ORDER_TRIGGER, "true", "false", UPDATE_CACHE_POLICY); - // images - save(prefs, dialog.cbUseDefaultImageFolder, KEY_CARD_IMAGES_USE_DEFAULT, "true", "false", UPDATE_CACHE_POLICY); - saveImagesPath(prefs); - save(prefs, dialog.cbCheckForNewImages, KEY_CARD_IMAGES_CHECK, "true", "false", UPDATE_CACHE_POLICY); - save(prefs, dialog.cbSaveToZipFiles, KEY_CARD_IMAGES_SAVE_TO_ZIP, "true", "false", UPDATE_CACHE_POLICY); - save(prefs, dialog.cbNumberOfDownloadThreads, KEY_CARD_IMAGES_THREADS); - save(prefs, dialog.cbPreferedImageLanguage, KEY_CARD_IMAGES_PREF_LANGUAGE); + // images + save(prefs, dialog.cbUseDefaultImageFolder, KEY_CARD_IMAGES_USE_DEFAULT, "true", "false", UPDATE_CACHE_POLICY); + saveImagesPath(prefs); + save(prefs, dialog.cbCheckForNewImages, KEY_CARD_IMAGES_CHECK, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.cbSaveToZipFiles, KEY_CARD_IMAGES_SAVE_TO_ZIP, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.cbNumberOfDownloadThreads, KEY_CARD_IMAGES_THREADS); + save(prefs, dialog.cbPreferedImageLanguage, KEY_CARD_IMAGES_PREF_LANGUAGE); - save(prefs, dialog.cbUseDefaultBackground, KEY_BACKGROUND_IMAGE_DEFAULT, "true", "false", UPDATE_CACHE_POLICY); - save(prefs, dialog.cbUseDefaultBattleImage, KEY_BATTLEFIELD_IMAGE_DEFAULT, "true", "false", UPDATE_CACHE_POLICY); - save(prefs, dialog.cbUseRandomBattleImage, KEY_BATTLEFIELD_IMAGE_RANDOM, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.cbUseDefaultBackground, KEY_BACKGROUND_IMAGE_DEFAULT, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.cbUseDefaultBattleImage, KEY_BATTLEFIELD_IMAGE_DEFAULT, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.cbUseRandomBattleImage, KEY_BATTLEFIELD_IMAGE_RANDOM, "true", "false", UPDATE_CACHE_POLICY); - // rendering - save(prefs, dialog.cbCardRenderImageFallback, KEY_CARD_RENDERING_FALLBACK, "true", "false", UPDATE_CACHE_POLICY); - save(prefs, dialog.cbCardRenderHideSetSymbol, KEY_CARD_RENDERING_SET_SYMBOL, "true", "false", UPDATE_CACHE_POLICY); - save(prefs, dialog.cbCardRenderShowReminderText, KEY_CARD_RENDERING_REMINDER_TEXT, "true", "false", UPDATE_CACHE_POLICY); - - // sounds - save(prefs, dialog.cbEnableGameSounds, KEY_SOUNDS_GAME_ON, "true", "false", UPDATE_CACHE_POLICY); - save(prefs, dialog.cbEnableDraftSounds, KEY_SOUNDS_DRAFT_ON, "true", "false", UPDATE_CACHE_POLICY); - save(prefs, dialog.cbEnableSkipButtonsSounds, KEY_SOUNDS_SKIP_BUTTONS_ON, "true", "false", UPDATE_CACHE_POLICY); - save(prefs, dialog.cbEnableOtherSounds, KEY_SOUNDS_OTHER_ON, "true", "false", UPDATE_CACHE_POLICY); - save(prefs, dialog.cbEnableBattlefieldBGM, KEY_SOUNDS_MATCH_MUSIC_ON, "true", "false", UPDATE_CACHE_POLICY); - saveSoundPath(prefs); + // rendering + save(prefs, dialog.cbCardRenderImageFallback, KEY_CARD_RENDERING_FALLBACK, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.cbCardRenderHideSetSymbol, KEY_CARD_RENDERING_SET_SYMBOL, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.cbCardRenderShowReminderText, KEY_CARD_RENDERING_REMINDER_TEXT, "true", "false", UPDATE_CACHE_POLICY); - // connection - save(prefs, dialog.cbProxyType, KEY_PROXY_TYPE); - save(prefs, dialog.txtProxyServer, KEY_PROXY_ADDRESS); - save(prefs, dialog.txtProxyPort, KEY_PROXY_PORT); - save(prefs, dialog.txtProxyUserName, KEY_PROXY_USERNAME); - save(prefs, dialog.rememberPswd, KEY_PROXY_REMEMBER, "true", "false", UPDATE_CACHE_POLICY); - if (dialog.rememberPswd.isSelected()) { - char[] input = txtPasswordField.getPassword(); - prefs.put(KEY_PROXY_PSWD, new String(input)); - } - save(prefs, dialog.txtURLServerList, KEY_CONNECTION_URL_SERVER_LIST); + // sounds + save(prefs, dialog.cbEnableGameSounds, KEY_SOUNDS_GAME_ON, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.cbEnableDraftSounds, KEY_SOUNDS_DRAFT_ON, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.cbEnableSkipButtonsSounds, KEY_SOUNDS_SKIP_BUTTONS_ON, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.cbEnableOtherSounds, KEY_SOUNDS_OTHER_ON, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.cbEnableBattlefieldBGM, KEY_SOUNDS_MATCH_MUSIC_ON, "true", "false", UPDATE_CACHE_POLICY); + saveSoundPath(prefs); - // Avatar - if (selectedAvatarId < MIN_AVATAR_ID || selectedAvatarId > MAX_AVATAR_ID) { - selectedAvatarId = DEFAULT_AVATAR_ID; - } - prefs.put(KEY_AVATAR, String.valueOf(selectedAvatarId)); - updateCache(KEY_AVATAR, String.valueOf(selectedAvatarId)); + // connection + save(prefs, dialog.cbProxyType, KEY_PROXY_TYPE); + save(prefs, dialog.txtProxyServer, KEY_PROXY_ADDRESS); + save(prefs, dialog.txtProxyPort, KEY_PROXY_PORT); + save(prefs, dialog.txtProxyUserName, KEY_PROXY_USERNAME); + save(prefs, dialog.rememberPswd, KEY_PROXY_REMEMBER, "true", "false", UPDATE_CACHE_POLICY); + if (dialog.rememberPswd.isSelected()) { + char[] input = txtPasswordField.getPassword(); + prefs.put(KEY_PROXY_PSWD, new String(input)); + } + save(prefs, dialog.txtURLServerList, KEY_CONNECTION_URL_SERVER_LIST); - try { - SessionHandler.updatePreferencesForServer(getUserData()); + // controls + save(prefs, dialog.keyCancelSkip, KEY_CONTROL_CANCEL_SKIP); + save(prefs, dialog.keyNextTurn, KEY_CONTROL_NEXT_TURN); + save(prefs, dialog.keyEndStep, KEY_CONTROL_END_STEP); + save(prefs, dialog.keyMainStep, KEY_CONTROL_MAIN_STEP); + save(prefs, dialog.keyYourTurn, KEY_CONTROL_YOUR_TURN); + save(prefs, dialog.keySkipStack, KEY_CONTROL_SKIP_STACK); + save(prefs, dialog.keyPriorEnd, KEY_CONTROL_PRIOR_END); - prefs.flush(); - } catch (BackingStoreException ex) { - logger.error("Error: couldn't save preferences", ex); - UserRequestMessage message = new UserRequestMessage("Error", "Error: couldn't save preferences. Please try once again."); - message.setButton1("OK", null); - MageFrame.getInstance().showUserRequestDialog(message); - } + // Avatar + if (selectedAvatarId < MIN_AVATAR_ID || selectedAvatarId > MAX_AVATAR_ID) { + selectedAvatarId = DEFAULT_AVATAR_ID; + } + prefs.put(KEY_AVATAR, String.valueOf(selectedAvatarId)); + updateCache(KEY_AVATAR, String.valueOf(selectedAvatarId)); - dialog.setVisible(false); + try { + SessionHandler.updatePreferencesForServer(getUserData()); + + prefs.flush(); + } catch (BackingStoreException ex) { + logger.error("Error: couldn't save preferences", ex); + UserRequestMessage message = new UserRequestMessage("Error", "Error: couldn't save preferences. Please try once again."); + message.setButton1("OK", null); + MageFrame.getInstance().showUserRequestDialog(message); + } + + dialog.setVisible(false); }//GEN-LAST:event_saveButtonActionPerformed private void exitButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exitButtonActionPerformed - dialog.setVisible(false); + dialog.setVisible(false); }//GEN-LAST:event_exitButtonActionPerformed - private void useDefaultPath() { - txtImageFolderPath.setText("./plugins/images/"); - txtImageFolderPath.setEnabled(false); - btnBrowseImageLocation.setEnabled(false); - } + private void useDefaultPath() { + txtImageFolderPath.setText("./plugins/images/"); + txtImageFolderPath.setEnabled(false); + btnBrowseImageLocation.setEnabled(false); + } - private void useConfigurablePath() { - String path = CACHE.get(KEY_CARD_IMAGES_PATH); - dialog.txtImageFolderPath.setText(path); - txtImageFolderPath.setEnabled(true); - btnBrowseImageLocation.setEnabled(true); - } + private void useConfigurablePath() { + String path = CACHE.get(KEY_CARD_IMAGES_PATH); + dialog.txtImageFolderPath.setText(path); + txtImageFolderPath.setEnabled(true); + btnBrowseImageLocation.setEnabled(true); + } private void cbProxyTypeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbProxyTypeActionPerformed - this.showProxySettings(); + this.showProxySettings(); }//GEN-LAST:event_cbProxyTypeActionPerformed private void txtPasswordFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtPasswordFieldActionPerformed @@ -2680,128 +2804,128 @@ public class PreferencesDialog extends javax.swing.JDialog { }//GEN-LAST:event_rememberPswdActionPerformed private void cbEnableGameSoundsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbEnableGameSoundsActionPerformed - // TODO add your handling code here: + // TODO add your handling code here: }//GEN-LAST:event_cbEnableGameSoundsActionPerformed private void cbEnableBattlefieldBGMActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbEnableBattlefieldBGMActionPerformed - if (cbEnableBattlefieldBGM.isSelected()) { - txtBattlefieldIBGMPath.setEnabled(true); - btnBattlefieldBGMBrowse.setEnabled(true); - } else { - txtBattlefieldIBGMPath.setEnabled(false); - btnBattlefieldBGMBrowse.setEnabled(false); - } + if (cbEnableBattlefieldBGM.isSelected()) { + txtBattlefieldIBGMPath.setEnabled(true); + btnBattlefieldBGMBrowse.setEnabled(true); + } else { + txtBattlefieldIBGMPath.setEnabled(false); + btnBattlefieldBGMBrowse.setEnabled(false); + } }//GEN-LAST:event_cbEnableBattlefieldBGMActionPerformed - private void cbUseDefaultBackgroundActionPerformed(java.awt.event.ActionEvent evt) { - if (cbUseDefaultBackground.isSelected()) { - useDefaultBackgroundImage(); - } else { - useSelectBackgroundImage(); - } - } + private void cbUseDefaultBackgroundActionPerformed(java.awt.event.ActionEvent evt) { + if (cbUseDefaultBackground.isSelected()) { + useDefaultBackgroundImage(); + } else { + useSelectBackgroundImage(); + } + } - private void useDefaultBackgroundImage() { - txtBackgroundImagePath.setEnabled(false); - btnBrowseBackgroundImage.setEnabled(false); - txtBackgroundImagePath.setText(""); - } + private void useDefaultBackgroundImage() { + txtBackgroundImagePath.setEnabled(false); + btnBrowseBackgroundImage.setEnabled(false); + txtBackgroundImagePath.setText(""); + } - private void useSelectBackgroundImage() { - String path = CACHE.get(KEY_BACKGROUND_IMAGE); - dialog.txtBackgroundImagePath.setText(path); - txtBackgroundImagePath.setEnabled(true); - btnBrowseBackgroundImage.setEnabled(true); - } + private void useSelectBackgroundImage() { + String path = CACHE.get(KEY_BACKGROUND_IMAGE); + dialog.txtBackgroundImagePath.setText(path); + txtBackgroundImagePath.setEnabled(true); + btnBrowseBackgroundImage.setEnabled(true); + } - private void cbUseDefaultBattleImageActionPerformed(java.awt.event.ActionEvent evt) { - if (cbUseDefaultBattleImage.isSelected()) { - useDefaultBattlefield(); - } else { - useSelectedOrRandom(); - } - } + private void cbUseDefaultBattleImageActionPerformed(java.awt.event.ActionEvent evt) { + if (cbUseDefaultBattleImage.isSelected()) { + useDefaultBattlefield(); + } else { + useSelectedOrRandom(); + } + } - private void useDefaultBattlefield() { - cbUseRandomBattleImage.setEnabled(false); - txtBattlefieldImagePath.setEnabled(false); - btnBrowseBattlefieldImage.setEnabled(false); - } + private void useDefaultBattlefield() { + cbUseRandomBattleImage.setEnabled(false); + txtBattlefieldImagePath.setEnabled(false); + btnBrowseBattlefieldImage.setEnabled(false); + } - private void useSelectedOrRandom() { - cbUseRandomBattleImage.setEnabled(true); - String temp = CACHE.get(KEY_BATTLEFIELD_IMAGE_RANDOM); - if (temp != null) { - if (temp.equals("true")) { - useRandomBattleField(); - cbUseRandomBattleImage.setSelected(true); - } else { - useSelectedBattleField(); - cbUseRandomBattleImage.setSelected(false); - } - } else { - useSelectedBattleField(); - cbUseRandomBattleImage.setSelected(false); - } - } + private void useSelectedOrRandom() { + cbUseRandomBattleImage.setEnabled(true); + String temp = CACHE.get(KEY_BATTLEFIELD_IMAGE_RANDOM); + if (temp != null) { + if (temp.equals("true")) { + useRandomBattleField(); + cbUseRandomBattleImage.setSelected(true); + } else { + useSelectedBattleField(); + cbUseRandomBattleImage.setSelected(false); + } + } else { + useSelectedBattleField(); + cbUseRandomBattleImage.setSelected(false); + } + } - private void cbUseRandomBattleImageActionPerformed(java.awt.event.ActionEvent evt) { - if (cbUseRandomBattleImage.isSelected()) { - useRandomBattleField(); - } else { - useSelectedBattleField(); - } - } + private void cbUseRandomBattleImageActionPerformed(java.awt.event.ActionEvent evt) { + if (cbUseRandomBattleImage.isSelected()) { + useRandomBattleField(); + } else { + useSelectedBattleField(); + } + } - private void useRandomBattleField() { - txtBattlefieldImagePath.setEnabled(false); - btnBrowseBattlefieldImage.setEnabled(false); - } + private void useRandomBattleField() { + txtBattlefieldImagePath.setEnabled(false); + btnBrowseBattlefieldImage.setEnabled(false); + } - private void useSelectedBattleField() { - txtBattlefieldImagePath.setEnabled(true); - btnBrowseBattlefieldImage.setEnabled(true); - } + private void useSelectedBattleField() { + txtBattlefieldImagePath.setEnabled(true); + btnBrowseBattlefieldImage.setEnabled(true); + } - private void btnBrowseBackgroundImageActionPerformed(java.awt.event.ActionEvent evt) { - int returnVal = fc_i.showOpenDialog(PreferencesDialog.this); - if (returnVal == JFileChooser.APPROVE_OPTION) { - File file = fc_i.getSelectedFile(); - txtBackgroundImagePath.setText(file.getAbsolutePath()); - } - } + private void btnBrowseBackgroundImageActionPerformed(java.awt.event.ActionEvent evt) { + int returnVal = fc_i.showOpenDialog(PreferencesDialog.this); + if (returnVal == JFileChooser.APPROVE_OPTION) { + File file = fc_i.getSelectedFile(); + txtBackgroundImagePath.setText(file.getAbsolutePath()); + } + } - private void btnBrowseBattlefieldImageActionPerformed(java.awt.event.ActionEvent evt) { - int returnVal = fc_i.showOpenDialog(PreferencesDialog.this); - if (returnVal == JFileChooser.APPROVE_OPTION) { - File file = fc_i.getSelectedFile(); - txtBattlefieldImagePath.setText(file.getAbsolutePath()); - } - } + private void btnBrowseBattlefieldImageActionPerformed(java.awt.event.ActionEvent evt) { + int returnVal = fc_i.showOpenDialog(PreferencesDialog.this); + if (returnVal == JFileChooser.APPROVE_OPTION) { + File file = fc_i.getSelectedFile(); + txtBattlefieldImagePath.setText(file.getAbsolutePath()); + } + } private void txtBackgroundImagePathActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtBackgroundImagePathActionPerformed - // TODO add your handling code here: + // TODO add your handling code here: }//GEN-LAST:event_txtBackgroundImagePathActionPerformed private void txtBattlefieldImagePathActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtBattlefieldImagePathActionPerformed - // TODO add your handling code here: + // TODO add your handling code here: }//GEN-LAST:event_txtBattlefieldImagePathActionPerformed private void txtBattlefieldIBGMPathActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtBattlefieldIBGMPathActionPerformed - // TODO add your handling code here: + // TODO add your handling code here: }//GEN-LAST:event_txtBattlefieldIBGMPathActionPerformed private void btnBattlefieldBGMBrowseActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnBattlefieldBGMBrowseActionPerformed - // TODO add your handling code here: - int returnVal = fc.showOpenDialog(PreferencesDialog.this); - if (returnVal == JFileChooser.APPROVE_OPTION) { - File file = fc.getSelectedFile(); - txtBattlefieldIBGMPath.setText(file.getAbsolutePath()); - } + // TODO add your handling code here: + int returnVal = fc.showOpenDialog(PreferencesDialog.this); + if (returnVal == JFileChooser.APPROVE_OPTION) { + File file = fc.getSelectedFile(); + txtBattlefieldIBGMPath.setText(file.getAbsolutePath()); + } }//GEN-LAST:event_btnBattlefieldBGMBrowseActionPerformed private void cbGameLogAutoSaveActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbGameLogAutoSaveActionPerformed - // TODO add your handling code here: + // TODO add your handling code here: }//GEN-LAST:event_cbGameLogAutoSaveActionPerformed private void nonLandPermanentsInOnePileActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nonLandPermanentsInOnePileActionPerformed @@ -2809,7 +2933,7 @@ public class PreferencesDialog extends javax.swing.JDialog { }//GEN-LAST:event_nonLandPermanentsInOnePileActionPerformed private void showPlayerNamesPermanentlyActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showPlayerNamesPermanentlyActionPerformed - // TODO add your handling code here: + // TODO add your handling code here: }//GEN-LAST:event_showPlayerNamesPermanentlyActionPerformed private void showCardNameActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showCardNameActionPerformed @@ -2817,653 +2941,677 @@ public class PreferencesDialog extends javax.swing.JDialog { }//GEN-LAST:event_showCardNameActionPerformed private void showAbilityPickerForcedActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showAbilityPickerForcedActionPerformed - // TODO add your handling code here: + // TODO add your handling code here: }//GEN-LAST:event_showAbilityPickerForcedActionPerformed private void cbEnableOtherSoundsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbEnableOtherSoundsActionPerformed - // TODO add your handling code here: + // TODO add your handling code here: }//GEN-LAST:event_cbEnableOtherSoundsActionPerformed private void cbStopAttackActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbStopAttackActionPerformed - // TODO add your handling code here: + // TODO add your handling code here: }//GEN-LAST:event_cbStopAttackActionPerformed private void cbStopBlockActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbStopBlockActionPerformed - // TODO add your handling code here: + // TODO add your handling code here: }//GEN-LAST:event_cbStopBlockActionPerformed private void cbStopOnAllMainActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbStopOnAllMainActionPerformed - // TODO add your handling code here: + // TODO add your handling code here: }//GEN-LAST:event_cbStopOnAllMainActionPerformed private void cbStopOnAllEndActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbStopOnAllEndActionPerformed - // TODO add your handling code here: + // TODO add your handling code here: }//GEN-LAST:event_cbStopOnAllEndActionPerformed private void cbEnableDraftSoundsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbEnableDraftSoundsActionPerformed - // TODO add your handling code here: + // TODO add your handling code here: }//GEN-LAST:event_cbEnableDraftSoundsActionPerformed private void cbEnableSkipButtonsSoundsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbEnableSkipButtonsSoundsActionPerformed - // TODO add your handling code here: + // TODO add your handling code here: }//GEN-LAST:event_cbEnableSkipButtonsSoundsActionPerformed private void cbAllowRequestToShowHandCardsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbAllowRequestToShowHandCardsActionPerformed - // TODO add your handling code here: + // TODO add your handling code here: }//GEN-LAST:event_cbAllowRequestToShowHandCardsActionPerformed private void cbShowStormCounterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbShowStormCounterActionPerformed - // TODO add your handling code here: + // TODO add your handling code here: }//GEN-LAST:event_cbShowStormCounterActionPerformed private void cbConfirmEmptyManaPoolActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbConfirmEmptyManaPoolActionPerformed - // TODO add your handling code here: + // TODO add your handling code here: }//GEN-LAST:event_cbConfirmEmptyManaPoolActionPerformed private void cbAskMoveToGraveOrderActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbAskMoveToGraveOrderActionPerformed - // TODO add your handling code here: + // TODO add your handling code here: }//GEN-LAST:event_cbAskMoveToGraveOrderActionPerformed private void cbDraftLogAutoSaveActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbDraftLogAutoSaveActionPerformed - // TODO add your handling code here: + // TODO add your handling code here: }//GEN-LAST:event_cbDraftLogAutoSaveActionPerformed private void cbPassPriorityCastActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbPassPriorityCastActionPerformed - // TODO add your handling code here: + // TODO add your handling code here: }//GEN-LAST:event_cbPassPriorityCastActionPerformed private void cbPassPriorityActivationActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbPassPriorityActivationActionPerformed - // TODO add your handling code here: + // TODO add your handling code here: }//GEN-LAST:event_cbPassPriorityActivationActionPerformed private void cbAutoOrderTriggerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbAutoOrderTriggerActionPerformed - // TODO add your handling code here: + // TODO add your handling code here: }//GEN-LAST:event_cbAutoOrderTriggerActionPerformed private void cbCardRenderImageFallbackActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbCardRenderImageFallbackActionPerformed - // TODO add your handling code here: + // TODO add your handling code here: }//GEN-LAST:event_cbCardRenderImageFallbackActionPerformed private void cbCardRenderShowReminderTextActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbCardRenderShowReminderTextActionPerformed - // TODO add your handling code here: + // TODO add your handling code here: }//GEN-LAST:event_cbCardRenderShowReminderTextActionPerformed private void cbSaveToZipFilesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbSaveToZipFilesActionPerformed - // TODO add your handling code here: + // TODO add your handling code here: }//GEN-LAST:event_cbSaveToZipFilesActionPerformed private void cbCheckForNewImagesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbCheckForNewImagesActionPerformed - // TODO add your handling code here: + // TODO add your handling code here: }//GEN-LAST:event_cbCheckForNewImagesActionPerformed private void btnBrowseImageLocationActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnBrowseImageLocationActionPerformed - int returnVal = fc.showOpenDialog(PreferencesDialog.this); + int returnVal = fc.showOpenDialog(PreferencesDialog.this); - if (returnVal == JFileChooser.APPROVE_OPTION) { - File file = fc.getSelectedFile(); - txtImageFolderPath.setText(file.getAbsolutePath()); - } + if (returnVal == JFileChooser.APPROVE_OPTION) { + File file = fc.getSelectedFile(); + txtImageFolderPath.setText(file.getAbsolutePath()); + } }//GEN-LAST:event_btnBrowseImageLocationActionPerformed private void cbUseDefaultImageFolderActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbUseDefaultImageFolderActionPerformed - if (cbUseDefaultImageFolder.isSelected()) { - useDefaultPath(); - } else { - useConfigurablePath(); - } + if (cbUseDefaultImageFolder.isSelected()) { + useDefaultPath(); + } else { + useConfigurablePath(); + } }//GEN-LAST:event_cbUseDefaultImageFolderActionPerformed private void cbCardRenderHideSetSymbolActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbCardRenderHideSetSymbolActionPerformed - // TODO add your handling code here: + // TODO add your handling code here: }//GEN-LAST:event_cbCardRenderHideSetSymbolActionPerformed - private void showProxySettings() { - Connection.ProxyType proxyType = (Connection.ProxyType) cbProxyType.getSelectedItem(); - switch (proxyType) { - case SOCKS: - this.pnlProxy.setVisible(true); - this.pnlProxySettings.setVisible(true); - break; - case HTTP: - this.pnlProxy.setVisible(true); - this.pnlProxySettings.setVisible(true); - break; - case NONE: - this.pnlProxy.setVisible(false); - this.pnlProxySettings.setVisible(false); - break; - default: - break; - } - this.pack(); - this.repaint(); - } + private void showProxySettings() { + Connection.ProxyType proxyType = (Connection.ProxyType) cbProxyType.getSelectedItem(); + switch (proxyType) { + case SOCKS: + this.pnlProxy.setVisible(true); + this.pnlProxySettings.setVisible(true); + break; + case HTTP: + this.pnlProxy.setVisible(true); + this.pnlProxySettings.setVisible(true); + break; + case NONE: + this.pnlProxy.setVisible(false); + this.pnlProxySettings.setVisible(false); + break; + default: + break; + } + this.pack(); + this.repaint(); + } - public static void setProxyInformation(Connection connection) { - ProxyType configProxyType = Connection.ProxyType.valueByText(getCachedValue(KEY_PROXY_TYPE, "None")); - if (configProxyType == null) { - return; - } + public static void setProxyInformation(Connection connection) { + ProxyType configProxyType = Connection.ProxyType.valueByText(getCachedValue(KEY_PROXY_TYPE, "None")); + if (configProxyType == null) { + return; + } - connection.setProxyType(configProxyType); - if (!configProxyType.equals(ProxyType.NONE)) { - String host = getCachedValue(KEY_PROXY_ADDRESS, ""); - String port = getCachedValue(KEY_PROXY_PORT, ""); - if (!host.isEmpty() && !port.isEmpty()) { - connection.setProxyHost(host); - connection.setProxyPort(Integer.valueOf(port)); - String username = getCachedValue(KEY_PROXY_USERNAME, ""); - connection.setProxyUsername(username); - if (getCachedValue(KEY_PROXY_REMEMBER, "false").equals("true")) { - String password = getCachedValue(KEY_PROXY_PSWD, ""); - connection.setProxyPassword(password); - } - } else { - logger.warn("host or\\and port are empty: host=" + host + ", port=" + port); - } - } - } + connection.setProxyType(configProxyType); + if (!configProxyType.equals(ProxyType.NONE)) { + String host = getCachedValue(KEY_PROXY_ADDRESS, ""); + String port = getCachedValue(KEY_PROXY_PORT, ""); + if (!host.isEmpty() && !port.isEmpty()) { + connection.setProxyHost(host); + connection.setProxyPort(Integer.valueOf(port)); + String username = getCachedValue(KEY_PROXY_USERNAME, ""); + connection.setProxyUsername(username); + if (getCachedValue(KEY_PROXY_REMEMBER, "false").equals("true")) { + String password = getCachedValue(KEY_PROXY_PSWD, ""); + connection.setProxyPassword(password); + } + } else { + logger.warn("host or\\and port are empty: host=" + host + ", port=" + port); + } + } + } - /** - * @param args the command line arguments - */ - public static void main(String args[]) { - int param = 0; - if (args.length > 0) { - String param1 = args[0]; - if (param1.equals(OPEN_CONNECTION_TAB)) { - param = 4; - } - if (param1.equals(OPEN_PHASES_TAB)) { - param = 1; - } - } - final int openedTab = param; - java.awt.EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - if (!dialog.isVisible()) { - Preferences prefs = MageFrame.getPreferences(); + /** + * @param args the command line arguments + */ + public static void main(String args[]) { + int param = 0; + if (args.length > 0) { + String param1 = args[0]; + if (param1.equals(OPEN_CONNECTION_TAB)) { + param = 4; + } + if (param1.equals(OPEN_PHASES_TAB)) { + param = 1; + } + } + final int openedTab = param; + java.awt.EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + if (!dialog.isVisible()) { + Preferences prefs = MageFrame.getPreferences(); - // Main & Phases - loadPhases(prefs); + // Main & Phases + loadPhases(prefs); - // Gui Size - loadGuiSize(prefs); + // Gui Size + loadGuiSize(prefs); - // Images - loadImagesSettings(prefs); + // Images + loadImagesSettings(prefs); - // Sounds - loadSoundSettings(prefs); + // Sounds + loadSoundSettings(prefs); - // Connection - loadProxySettings(prefs); + // Connection + loadProxySettings(prefs); - // Selected avatar - loadSelectedAvatar(prefs); + // Controls + loadControlSettings(prefs); - dialog.reset(); - // open specified tab before displaying - openTab(openedTab); + // Selected avatar + loadSelectedAvatar(prefs); - dialog.setLocation(300, 200); + dialog.reset(); + // open specified tab before displaying + openTab(openedTab); - dialog.setVisible(true); - } else { - dialog.requestFocus(); - } - } - }); - } + dialog.setLocation(300, 200); - private static void loadPhases(Preferences prefs) { - load(prefs, dialog.tooltipDelay, KEY_SHOW_TOOLTIPS_DELAY, "300"); - load(prefs, dialog.showCardName, KEY_SHOW_CARD_NAMES, "true"); - load(prefs, dialog.nonLandPermanentsInOnePile, KEY_PERMANENTS_IN_ONE_PILE, "true"); - load(prefs, dialog.showPlayerNamesPermanently, KEY_SHOW_PLAYER_NAMES_PERMANENTLY, "true"); - load(prefs, dialog.showAbilityPickerForced, KEY_SHOW_ABILITY_PICKER_FORCED, "true"); - load(prefs, dialog.cbAllowRequestToShowHandCards, KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS, "true"); - load(prefs, dialog.cbShowStormCounter, KEY_GAME_SHOW_STORM_COUNTER, "true"); - load(prefs, dialog.cbConfirmEmptyManaPool, KEY_GAME_CONFIRM_EMPTY_MANA_POOL, "true"); - load(prefs, dialog.cbAskMoveToGraveOrder, KEY_GAME_ASK_MOVE_TO_GRAVE_ORDER, "true"); + dialog.setVisible(true); + } else { + dialog.requestFocus(); + } + } + }); + } - load(prefs, dialog.cbGameLogAutoSave, KEY_GAME_LOG_AUTO_SAVE, "true"); - load(prefs, dialog.cbDraftLogAutoSave, KEY_DRAFT_LOG_AUTO_SAVE, "true"); + private static void loadPhases(Preferences prefs) { + load(prefs, dialog.tooltipDelay, KEY_SHOW_TOOLTIPS_DELAY, "300"); + load(prefs, dialog.showCardName, KEY_SHOW_CARD_NAMES, "true"); + load(prefs, dialog.nonLandPermanentsInOnePile, KEY_PERMANENTS_IN_ONE_PILE, "true"); + load(prefs, dialog.showPlayerNamesPermanently, KEY_SHOW_PLAYER_NAMES_PERMANENTLY, "true"); + load(prefs, dialog.showAbilityPickerForced, KEY_SHOW_ABILITY_PICKER_FORCED, "true"); + load(prefs, dialog.cbAllowRequestToShowHandCards, KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS, "true"); + load(prefs, dialog.cbShowStormCounter, KEY_GAME_SHOW_STORM_COUNTER, "true"); + load(prefs, dialog.cbConfirmEmptyManaPool, KEY_GAME_CONFIRM_EMPTY_MANA_POOL, "true"); + load(prefs, dialog.cbAskMoveToGraveOrder, KEY_GAME_ASK_MOVE_TO_GRAVE_ORDER, "true"); - load(prefs, dialog.checkBoxUpkeepYou, UPKEEP_YOU, "on", "on"); - load(prefs, dialog.checkBoxDrawYou, DRAW_YOU, "on", "on"); - load(prefs, dialog.checkBoxMainYou, MAIN_YOU, "on", "on"); - load(prefs, dialog.checkBoxBeforeCYou, BEFORE_COMBAT_YOU, "on", "on"); - load(prefs, dialog.checkBoxEndOfCYou, END_OF_COMBAT_YOU, "on", "on"); - load(prefs, dialog.checkBoxMain2You, MAIN_TWO_YOU, "on", "on"); - load(prefs, dialog.checkBoxEndTurnYou, END_OF_TURN_YOU, "on", "on"); + load(prefs, dialog.cbGameLogAutoSave, KEY_GAME_LOG_AUTO_SAVE, "true"); + load(prefs, dialog.cbDraftLogAutoSave, KEY_DRAFT_LOG_AUTO_SAVE, "true"); - load(prefs, dialog.checkBoxUpkeepOthers, UPKEEP_OTHERS, "on", "on"); - load(prefs, dialog.checkBoxDrawOthers, DRAW_OTHERS, "on", "on"); - load(prefs, dialog.checkBoxMainOthers, MAIN_OTHERS, "on", "on"); - load(prefs, dialog.checkBoxBeforeCOthers, BEFORE_COMBAT_OTHERS, "on", "on"); - load(prefs, dialog.checkBoxEndOfCOthers, END_OF_COMBAT_OTHERS, "on", "on"); - load(prefs, dialog.checkBoxMain2Others, MAIN_TWO_OTHERS, "on", "on"); - load(prefs, dialog.checkBoxEndTurnOthers, END_OF_TURN_OTHERS, "on", "on"); + load(prefs, dialog.checkBoxUpkeepYou, UPKEEP_YOU, "on", "on"); + load(prefs, dialog.checkBoxDrawYou, DRAW_YOU, "on", "on"); + load(prefs, dialog.checkBoxMainYou, MAIN_YOU, "on", "on"); + load(prefs, dialog.checkBoxBeforeCYou, BEFORE_COMBAT_YOU, "on", "on"); + load(prefs, dialog.checkBoxEndOfCYou, END_OF_COMBAT_YOU, "on", "on"); + load(prefs, dialog.checkBoxMain2You, MAIN_TWO_YOU, "on", "on"); + load(prefs, dialog.checkBoxEndTurnYou, END_OF_TURN_YOU, "on", "on"); - load(prefs, dialog.cbStopAttack, KEY_STOP_ATTACK, "true", "true"); - load(prefs, dialog.cbStopBlock, KEY_STOP_BLOCK, "true", "true"); - load(prefs, dialog.cbStopOnAllMain, KEY_STOP_ALL_MAIN_PHASES, "true", "false"); - load(prefs, dialog.cbStopOnAllEnd, KEY_STOP_ALL_END_PHASES, "true", "false"); - load(prefs, dialog.cbPassPriorityCast, KEY_PASS_PRIORITY_CAST, "true", "false"); - load(prefs, dialog.cbPassPriorityActivation, KEY_PASS_PRIORITY_ACTIVATION, "true", "false"); - load(prefs, dialog.cbAutoOrderTrigger, KEY_AUTO_ORDER_TRIGGER, "true", "true"); + load(prefs, dialog.checkBoxUpkeepOthers, UPKEEP_OTHERS, "on", "on"); + load(prefs, dialog.checkBoxDrawOthers, DRAW_OTHERS, "on", "on"); + load(prefs, dialog.checkBoxMainOthers, MAIN_OTHERS, "on", "on"); + load(prefs, dialog.checkBoxBeforeCOthers, BEFORE_COMBAT_OTHERS, "on", "on"); + load(prefs, dialog.checkBoxEndOfCOthers, END_OF_COMBAT_OTHERS, "on", "on"); + load(prefs, dialog.checkBoxMain2Others, MAIN_TWO_OTHERS, "on", "on"); + load(prefs, dialog.checkBoxEndTurnOthers, END_OF_TURN_OTHERS, "on", "on"); - } + load(prefs, dialog.cbStopAttack, KEY_STOP_ATTACK, "true", "true"); + load(prefs, dialog.cbStopBlock, KEY_STOP_BLOCK, "true", "true"); + load(prefs, dialog.cbStopOnAllMain, KEY_STOP_ALL_MAIN_PHASES, "true", "false"); + load(prefs, dialog.cbStopOnAllEnd, KEY_STOP_ALL_END_PHASES, "true", "false"); + load(prefs, dialog.cbPassPriorityCast, KEY_PASS_PRIORITY_CAST, "true", "false"); + load(prefs, dialog.cbPassPriorityActivation, KEY_PASS_PRIORITY_ACTIVATION, "true", "false"); + load(prefs, dialog.cbAutoOrderTrigger, KEY_AUTO_ORDER_TRIGGER, "true", "true"); - private static void loadGuiSize(Preferences prefs) { - load(prefs, dialog.sliderFontSize, KEY_GUI_TABLE_FONT_SIZE, "14"); - load(prefs, dialog.sliderChatFontSize, KEY_GUI_CHAT_FONT_SIZE, "14"); - load(prefs, dialog.sliderCardSizeHand, KEY_GUI_CARD_HAND_SIZE, "14"); - load(prefs, dialog.sliderEditorCardSize, KEY_GUI_CARD_EDITOR_SIZE, "14"); - load(prefs, dialog.sliderEditorCardOffset, KEY_GUI_CARD_OFFSET_SIZE, "14"); - load(prefs, dialog.sliderEnlargedImageSize, KEY_GUI_ENLARGED_IMAGE_SIZE, "20"); - load(prefs, dialog.sliderStackWidth, KEY_GUI_STACK_WIDTH, "14"); - load(prefs, dialog.sliderDialogFont, KEY_GUI_DIALOG_FONT_SIZE, "14"); - load(prefs, dialog.sliderTooltipSize, KEY_GUI_TOOLTIP_SIZE, "14"); - load(prefs, dialog.sliderGameFeedbackArea, KEY_GUI_FEEDBACK_AREA_SIZE, "14"); - load(prefs, dialog.sliderCardSizeOtherZones, KEY_GUI_CARD_OTHER_ZONES_SIZE, "14"); - load(prefs, dialog.sliderCardSizeMinBattlefield, KEY_GUI_CARD_BATTLEFIELD_MIN_SIZE, "10"); - load(prefs, dialog.sliderCardSizeMaxBattlefield, KEY_GUI_CARD_BATTLEFIELD_MAX_SIZE, "14"); - } + } - private static void loadImagesSettings(Preferences prefs) { - String prop = prefs.get(KEY_CARD_IMAGES_USE_DEFAULT, "true"); - if (prop.equals("true")) { - dialog.cbUseDefaultImageFolder.setSelected(true); - dialog.useDefaultPath(); - } else { - dialog.cbUseDefaultImageFolder.setSelected(false); - dialog.useConfigurablePath(); - String path = prefs.get(KEY_CARD_IMAGES_PATH, ""); - dialog.txtImageFolderPath.setText(path); - updateCache(KEY_CARD_IMAGES_PATH, path); - } - load(prefs, dialog.cbCheckForNewImages, KEY_CARD_IMAGES_CHECK, "true"); - load(prefs, dialog.cbSaveToZipFiles, KEY_CARD_IMAGES_SAVE_TO_ZIP, "true"); - dialog.cbNumberOfDownloadThreads.setSelectedItem(MageFrame.getPreferences().get(KEY_CARD_IMAGES_THREADS, "10")); - dialog.cbPreferedImageLanguage.setSelectedItem(MageFrame.getPreferences().get(KEY_CARD_IMAGES_PREF_LANGUAGE, "en")); + private static void loadGuiSize(Preferences prefs) { + load(prefs, dialog.sliderFontSize, KEY_GUI_TABLE_FONT_SIZE, "14"); + load(prefs, dialog.sliderChatFontSize, KEY_GUI_CHAT_FONT_SIZE, "14"); + load(prefs, dialog.sliderCardSizeHand, KEY_GUI_CARD_HAND_SIZE, "14"); + load(prefs, dialog.sliderEditorCardSize, KEY_GUI_CARD_EDITOR_SIZE, "14"); + load(prefs, dialog.sliderEditorCardOffset, KEY_GUI_CARD_OFFSET_SIZE, "14"); + load(prefs, dialog.sliderEnlargedImageSize, KEY_GUI_ENLARGED_IMAGE_SIZE, "20"); + load(prefs, dialog.sliderStackWidth, KEY_GUI_STACK_WIDTH, "14"); + load(prefs, dialog.sliderDialogFont, KEY_GUI_DIALOG_FONT_SIZE, "14"); + load(prefs, dialog.sliderTooltipSize, KEY_GUI_TOOLTIP_SIZE, "14"); + load(prefs, dialog.sliderGameFeedbackArea, KEY_GUI_FEEDBACK_AREA_SIZE, "14"); + load(prefs, dialog.sliderCardSizeOtherZones, KEY_GUI_CARD_OTHER_ZONES_SIZE, "14"); + load(prefs, dialog.sliderCardSizeMinBattlefield, KEY_GUI_CARD_BATTLEFIELD_MIN_SIZE, "10"); + load(prefs, dialog.sliderCardSizeMaxBattlefield, KEY_GUI_CARD_BATTLEFIELD_MAX_SIZE, "14"); + } - // rendering settings - load(prefs, dialog.cbCardRenderImageFallback, KEY_CARD_RENDERING_FALLBACK, "true"); - load(prefs, dialog.cbCardRenderHideSetSymbol, KEY_CARD_RENDERING_SET_SYMBOL, "true"); - load(prefs, dialog.cbCardRenderShowReminderText, KEY_CARD_RENDERING_REMINDER_TEXT, "true"); - - //add background load precedure - prop = prefs.get(KEY_BACKGROUND_IMAGE_DEFAULT, "true"); - if (prop.equals("true")) { - dialog.cbUseDefaultBackground.setSelected(true); - dialog.useDefaultBackgroundImage(); - } else { - dialog.cbUseDefaultBackground.setSelected(false); - dialog.useSelectBackgroundImage(); - String path = prefs.get(KEY_BACKGROUND_IMAGE, ""); - dialog.txtBackgroundImagePath.setText(path); - updateCache(KEY_BACKGROUND_IMAGE, path); - } - prop = prefs.get(KEY_BATTLEFIELD_IMAGE_DEFAULT, "true"); - if (prop.equals("true")) { - dialog.cbUseDefaultBattleImage.setSelected(true); - dialog.useDefaultBattlefield(); - } else { - dialog.cbUseDefaultBattleImage.setSelected(false); - dialog.useSelectedOrRandom(); - } - prop = prefs.get(KEY_BATTLEFIELD_IMAGE_RANDOM, "true"); + private static void loadImagesSettings(Preferences prefs) { + String prop = prefs.get(KEY_CARD_IMAGES_USE_DEFAULT, "true"); + if (prop.equals("true")) { + dialog.cbUseDefaultImageFolder.setSelected(true); + dialog.useDefaultPath(); + } else { + dialog.cbUseDefaultImageFolder.setSelected(false); + dialog.useConfigurablePath(); + String path = prefs.get(KEY_CARD_IMAGES_PATH, ""); + dialog.txtImageFolderPath.setText(path); + updateCache(KEY_CARD_IMAGES_PATH, path); + } + load(prefs, dialog.cbCheckForNewImages, KEY_CARD_IMAGES_CHECK, "true"); + load(prefs, dialog.cbSaveToZipFiles, KEY_CARD_IMAGES_SAVE_TO_ZIP, "true"); + dialog.cbNumberOfDownloadThreads.setSelectedItem(MageFrame.getPreferences().get(KEY_CARD_IMAGES_THREADS, "10")); + dialog.cbPreferedImageLanguage.setSelectedItem(MageFrame.getPreferences().get(KEY_CARD_IMAGES_PREF_LANGUAGE, "en")); - if (dialog.cbUseRandomBattleImage.isEnabled()) { - if (prop.equals("true")) { - dialog.cbUseRandomBattleImage.setSelected(true); - dialog.useRandomBattleField(); - } else { - dialog.cbUseRandomBattleImage.setSelected(false); - dialog.useSelectedBattleField(); - String path = prefs.get(KEY_BATTLEFIELD_IMAGE, ""); - dialog.txtBattlefieldImagePath.setText(path); - updateCache(KEY_BATTLEFIELD_IMAGE, path); - } - } - } + // rendering settings + load(prefs, dialog.cbCardRenderImageFallback, KEY_CARD_RENDERING_FALLBACK, "true"); + load(prefs, dialog.cbCardRenderHideSetSymbol, KEY_CARD_RENDERING_SET_SYMBOL, "true"); + load(prefs, dialog.cbCardRenderShowReminderText, KEY_CARD_RENDERING_REMINDER_TEXT, "true"); - private static void loadSoundSettings(Preferences prefs) { - dialog.cbEnableGameSounds.setSelected(prefs.get(KEY_SOUNDS_GAME_ON, "true").equals("true")); - dialog.cbEnableDraftSounds.setSelected(prefs.get(KEY_SOUNDS_DRAFT_ON, "true").equals("true")); - dialog.cbEnableSkipButtonsSounds.setSelected(prefs.get(KEY_SOUNDS_SKIP_BUTTONS_ON, "true").equals("true")); - dialog.cbEnableOtherSounds.setSelected(prefs.get(KEY_SOUNDS_OTHER_ON, "true").equals("true")); + //add background load precedure + prop = prefs.get(KEY_BACKGROUND_IMAGE_DEFAULT, "true"); + if (prop.equals("true")) { + dialog.cbUseDefaultBackground.setSelected(true); + dialog.useDefaultBackgroundImage(); + } else { + dialog.cbUseDefaultBackground.setSelected(false); + dialog.useSelectBackgroundImage(); + String path = prefs.get(KEY_BACKGROUND_IMAGE, ""); + dialog.txtBackgroundImagePath.setText(path); + updateCache(KEY_BACKGROUND_IMAGE, path); + } + prop = prefs.get(KEY_BATTLEFIELD_IMAGE_DEFAULT, "true"); + if (prop.equals("true")) { + dialog.cbUseDefaultBattleImage.setSelected(true); + dialog.useDefaultBattlefield(); + } else { + dialog.cbUseDefaultBattleImage.setSelected(false); + dialog.useSelectedOrRandom(); + } + prop = prefs.get(KEY_BATTLEFIELD_IMAGE_RANDOM, "true"); - // Match music - dialog.cbEnableBattlefieldBGM.setSelected(prefs.get(KEY_SOUNDS_MATCH_MUSIC_ON, "true").equals("true")); - dialog.txtBattlefieldIBGMPath.setEnabled(dialog.cbEnableBattlefieldBGM.isSelected()); - dialog.btnBattlefieldBGMBrowse.setEnabled(dialog.cbEnableBattlefieldBGM.isSelected()); - // load and save the path always, so you can reactivate music without selecting path again - String path = prefs.get(KEY_SOUNDS_MATCH_MUSIC_PATH, ""); - dialog.txtBattlefieldIBGMPath.setText(path); + if (dialog.cbUseRandomBattleImage.isEnabled()) { + if (prop.equals("true")) { + dialog.cbUseRandomBattleImage.setSelected(true); + dialog.useRandomBattleField(); + } else { + dialog.cbUseRandomBattleImage.setSelected(false); + dialog.useSelectedBattleField(); + String path = prefs.get(KEY_BATTLEFIELD_IMAGE, ""); + dialog.txtBattlefieldImagePath.setText(path); + updateCache(KEY_BATTLEFIELD_IMAGE, path); + } + } + } - updateCache(KEY_SOUNDS_MATCH_MUSIC_PATH, path); - } + private static void loadSoundSettings(Preferences prefs) { + dialog.cbEnableGameSounds.setSelected(prefs.get(KEY_SOUNDS_GAME_ON, "true").equals("true")); + dialog.cbEnableDraftSounds.setSelected(prefs.get(KEY_SOUNDS_DRAFT_ON, "true").equals("true")); + dialog.cbEnableSkipButtonsSounds.setSelected(prefs.get(KEY_SOUNDS_SKIP_BUTTONS_ON, "true").equals("true")); + dialog.cbEnableOtherSounds.setSelected(prefs.get(KEY_SOUNDS_OTHER_ON, "true").equals("true")); - private static void loadProxySettings(Preferences prefs) { - dialog.cbProxyType.setSelectedItem(Connection.ProxyType.valueOf(MageFrame.getPreferences().get(KEY_PROXY_TYPE, "NONE").toUpperCase())); + // Match music + dialog.cbEnableBattlefieldBGM.setSelected(prefs.get(KEY_SOUNDS_MATCH_MUSIC_ON, "true").equals("true")); + dialog.txtBattlefieldIBGMPath.setEnabled(dialog.cbEnableBattlefieldBGM.isSelected()); + dialog.btnBattlefieldBGMBrowse.setEnabled(dialog.cbEnableBattlefieldBGM.isSelected()); + // load and save the path always, so you can reactivate music without selecting path again + String path = prefs.get(KEY_SOUNDS_MATCH_MUSIC_PATH, ""); + dialog.txtBattlefieldIBGMPath.setText(path); - load(prefs, dialog.txtProxyServer, KEY_PROXY_ADDRESS, Config.serverName); - load(prefs, dialog.txtProxyPort, KEY_PROXY_PORT, Integer.toString(Config.port)); - load(prefs, dialog.txtProxyUserName, KEY_PROXY_USERNAME, ""); - load(prefs, dialog.rememberPswd, KEY_PROXY_REMEMBER, "true", "false"); - if (dialog.rememberPswd.isSelected()) { - load(prefs, dialog.txtPasswordField, KEY_PROXY_PSWD, ""); - } - load(prefs, dialog.txtURLServerList, KEY_CONNECTION_URL_SERVER_LIST, "http://XMage.de/files/server-list.txt"); - } + updateCache(KEY_SOUNDS_MATCH_MUSIC_PATH, path); + } - private static void loadSelectedAvatar(Preferences prefs) { - getSelectedAvatar(); - dialog.setSelectedId(selectedAvatarId); - } + private static void loadProxySettings(Preferences prefs) { + dialog.cbProxyType.setSelectedItem(Connection.ProxyType.valueOf(MageFrame.getPreferences().get(KEY_PROXY_TYPE, "NONE").toUpperCase())); - public static int getSelectedAvatar() { - try { - selectedAvatarId = Integer.valueOf(MageFrame.getPreferences().get(KEY_AVATAR, String.valueOf(DEFAULT_AVATAR_ID))); - } catch (NumberFormatException n) { - selectedAvatarId = DEFAULT_AVATAR_ID; - } finally { - if (selectedAvatarId < MIN_AVATAR_ID || selectedAvatarId > MAX_AVATAR_ID) { - selectedAvatarId = DEFAULT_AVATAR_ID; - } - } - return selectedAvatarId; - } + load(prefs, dialog.txtProxyServer, KEY_PROXY_ADDRESS, Config.serverName); + load(prefs, dialog.txtProxyPort, KEY_PROXY_PORT, Integer.toString(Config.port)); + load(prefs, dialog.txtProxyUserName, KEY_PROXY_USERNAME, ""); + load(prefs, dialog.rememberPswd, KEY_PROXY_REMEMBER, "true", "false"); + if (dialog.rememberPswd.isSelected()) { + load(prefs, dialog.txtPasswordField, KEY_PROXY_PSWD, ""); + } + load(prefs, dialog.txtURLServerList, KEY_CONNECTION_URL_SERVER_LIST, "http://XMage.de/files/server-list.txt"); + } - public static UserSkipPrioritySteps getUserSkipPrioritySteps() { - if (!dialog.isVisible()) { - loadPhases(MageFrame.getPreferences()); - } - UserSkipPrioritySteps userSkipPrioritySteps = new UserSkipPrioritySteps(); + private static void loadControlSettings(Preferences prefs) { + load(prefs, dialog.keyCancelSkip, KEY_CONTROL_CANCEL_SKIP, KeyEvent.VK_F3); + load(prefs, dialog.keyNextTurn, KEY_CONTROL_NEXT_TURN, KeyEvent.VK_F4); + load(prefs, dialog.keyEndStep, KEY_CONTROL_END_STEP, KeyEvent.VK_F5); + load(prefs, dialog.keyMainStep, KEY_CONTROL_MAIN_STEP, KeyEvent.VK_F7); + load(prefs, dialog.keyYourTurn, KEY_CONTROL_YOUR_TURN, KeyEvent.VK_F9); + load(prefs, dialog.keySkipStack, KEY_CONTROL_SKIP_STACK, KeyEvent.VK_F10); + load(prefs, dialog.keyPriorEnd, KEY_CONTROL_PRIOR_END, KeyEvent.VK_F11); + } - userSkipPrioritySteps.getYourTurn().setUpkeep(dialog.checkBoxUpkeepYou.isSelected()); - userSkipPrioritySteps.getYourTurn().setDraw(dialog.checkBoxDrawYou.isSelected()); - userSkipPrioritySteps.getYourTurn().setMain1(dialog.checkBoxMainYou.isSelected()); - userSkipPrioritySteps.getYourTurn().setBeforeCombat(dialog.checkBoxBeforeCYou.isSelected()); - userSkipPrioritySteps.getYourTurn().setEndOfCombat(dialog.checkBoxEndOfCYou.isSelected()); - userSkipPrioritySteps.getYourTurn().setMain2(dialog.checkBoxMain2You.isSelected()); - userSkipPrioritySteps.getYourTurn().setEndOfTurn(dialog.checkBoxEndTurnYou.isSelected()); + private static void loadSelectedAvatar(Preferences prefs) { + getSelectedAvatar(); + dialog.setSelectedId(selectedAvatarId); + } - userSkipPrioritySteps.getOpponentTurn().setUpkeep(dialog.checkBoxUpkeepOthers.isSelected()); - userSkipPrioritySteps.getOpponentTurn().setDraw(dialog.checkBoxDrawOthers.isSelected()); - userSkipPrioritySteps.getOpponentTurn().setMain1(dialog.checkBoxMainOthers.isSelected()); - userSkipPrioritySteps.getOpponentTurn().setBeforeCombat(dialog.checkBoxBeforeCOthers.isSelected()); - userSkipPrioritySteps.getOpponentTurn().setEndOfCombat(dialog.checkBoxEndOfCOthers.isSelected()); - userSkipPrioritySteps.getOpponentTurn().setMain2(dialog.checkBoxMain2Others.isSelected()); - userSkipPrioritySteps.getOpponentTurn().setEndOfTurn(dialog.checkBoxEndTurnOthers.isSelected()); + public static int getSelectedAvatar() { + try { + selectedAvatarId = Integer.valueOf(MageFrame.getPreferences().get(KEY_AVATAR, String.valueOf(DEFAULT_AVATAR_ID))); + } catch (NumberFormatException n) { + selectedAvatarId = DEFAULT_AVATAR_ID; + } finally { + if (selectedAvatarId < MIN_AVATAR_ID || selectedAvatarId > MAX_AVATAR_ID) { + selectedAvatarId = DEFAULT_AVATAR_ID; + } + } + return selectedAvatarId; + } - userSkipPrioritySteps.setStopOnDeclareAttackersDuringSkipActions(dialog.cbStopAttack.isSelected()); - userSkipPrioritySteps.setStopOnDeclareBlockerIfNoneAvailable(dialog.cbStopBlock.isSelected()); - userSkipPrioritySteps.setStopOnAllEndPhases(dialog.cbStopOnAllEnd.isSelected()); - userSkipPrioritySteps.setStopOnAllMainPhases(dialog.cbStopOnAllMain.isSelected()); + public static UserSkipPrioritySteps getUserSkipPrioritySteps() { + if (!dialog.isVisible()) { + loadPhases(MageFrame.getPreferences()); + } + UserSkipPrioritySteps userSkipPrioritySteps = new UserSkipPrioritySteps(); - return userSkipPrioritySteps; - } + userSkipPrioritySteps.getYourTurn().setUpkeep(dialog.checkBoxUpkeepYou.isSelected()); + userSkipPrioritySteps.getYourTurn().setDraw(dialog.checkBoxDrawYou.isSelected()); + userSkipPrioritySteps.getYourTurn().setMain1(dialog.checkBoxMainYou.isSelected()); + userSkipPrioritySteps.getYourTurn().setBeforeCombat(dialog.checkBoxBeforeCYou.isSelected()); + userSkipPrioritySteps.getYourTurn().setEndOfCombat(dialog.checkBoxEndOfCYou.isSelected()); + userSkipPrioritySteps.getYourTurn().setMain2(dialog.checkBoxMain2You.isSelected()); + userSkipPrioritySteps.getYourTurn().setEndOfTurn(dialog.checkBoxEndTurnYou.isSelected()); - private static void openTab(int index) { - try { - if (index > 0) { - dialog.tabsPanel.setSelectedIndex(index); - } - } catch (Exception e) { - logger.error("Error during open tab", e); - } - } + userSkipPrioritySteps.getOpponentTurn().setUpkeep(dialog.checkBoxUpkeepOthers.isSelected()); + userSkipPrioritySteps.getOpponentTurn().setDraw(dialog.checkBoxDrawOthers.isSelected()); + userSkipPrioritySteps.getOpponentTurn().setMain1(dialog.checkBoxMainOthers.isSelected()); + userSkipPrioritySteps.getOpponentTurn().setBeforeCombat(dialog.checkBoxBeforeCOthers.isSelected()); + userSkipPrioritySteps.getOpponentTurn().setEndOfCombat(dialog.checkBoxEndOfCOthers.isSelected()); + userSkipPrioritySteps.getOpponentTurn().setMain2(dialog.checkBoxMain2Others.isSelected()); + userSkipPrioritySteps.getOpponentTurn().setEndOfTurn(dialog.checkBoxEndTurnOthers.isSelected()); - private static void saveImagesPath(Preferences prefs) { - if (!dialog.cbUseDefaultImageFolder.isSelected()) { - String path = dialog.txtImageFolderPath.getText(); - prefs.put(KEY_CARD_IMAGES_PATH, path); - updateCache(KEY_CARD_IMAGES_PATH, path); - } - // background path save precedure - if (!dialog.cbUseDefaultBackground.isSelected()) { - String path = dialog.txtBackgroundImagePath.getText(); - prefs.put(KEY_BACKGROUND_IMAGE, path); - updateCache(KEY_BACKGROUND_IMAGE, path); - } - if (!dialog.cbUseDefaultBattleImage.isSelected() && !dialog.cbUseRandomBattleImage.isSelected()) { - String path = dialog.txtBattlefieldImagePath.getText(); - prefs.put(KEY_BATTLEFIELD_IMAGE, path); - updateCache(KEY_BATTLEFIELD_IMAGE, path); - } - } + userSkipPrioritySteps.setStopOnDeclareAttackersDuringSkipActions(dialog.cbStopAttack.isSelected()); + userSkipPrioritySteps.setStopOnDeclareBlockerIfNoneAvailable(dialog.cbStopBlock.isSelected()); + userSkipPrioritySteps.setStopOnAllEndPhases(dialog.cbStopOnAllEnd.isSelected()); + userSkipPrioritySteps.setStopOnAllMainPhases(dialog.cbStopOnAllMain.isSelected()); - private static void saveSoundPath(Preferences prefs) { - String path = dialog.txtBattlefieldIBGMPath.getText(); - prefs.put(KEY_SOUNDS_MATCH_MUSIC_PATH, path); - updateCache(KEY_SOUNDS_MATCH_MUSIC_PATH, path); - } + return userSkipPrioritySteps; + } - public static boolean isSaveImagesToZip() { - return PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_SAVE_TO_ZIP, "true").equals("true"); - } + private static void openTab(int index) { + try { + if (index > 0) { + dialog.tabsPanel.setSelectedIndex(index); + } + } catch (Exception e) { + logger.error("Error during open tab", e); + } + } - private static void load(Preferences prefs, JCheckBox checkBox, String propName, String yesValue) { - String prop = prefs.get(propName, yesValue); - checkBox.setSelected(prop.equals(yesValue)); - } + private static void saveImagesPath(Preferences prefs) { + if (!dialog.cbUseDefaultImageFolder.isSelected()) { + String path = dialog.txtImageFolderPath.getText(); + prefs.put(KEY_CARD_IMAGES_PATH, path); + updateCache(KEY_CARD_IMAGES_PATH, path); + } + // background path save precedure + if (!dialog.cbUseDefaultBackground.isSelected()) { + String path = dialog.txtBackgroundImagePath.getText(); + prefs.put(KEY_BACKGROUND_IMAGE, path); + updateCache(KEY_BACKGROUND_IMAGE, path); + } + if (!dialog.cbUseDefaultBattleImage.isSelected() && !dialog.cbUseRandomBattleImage.isSelected()) { + String path = dialog.txtBattlefieldImagePath.getText(); + prefs.put(KEY_BATTLEFIELD_IMAGE, path); + updateCache(KEY_BATTLEFIELD_IMAGE, path); + } + } - private static void load(Preferences prefs, JCheckBox checkBox, String propName, String yesValue, String defaultValue) { - String prop = prefs.get(propName, defaultValue); - checkBox.setSelected(prop.equals(yesValue)); - updateCache(propName, prop); - } + private static void saveSoundPath(Preferences prefs) { + String path = dialog.txtBattlefieldIBGMPath.getText(); + prefs.put(KEY_SOUNDS_MATCH_MUSIC_PATH, path); + updateCache(KEY_SOUNDS_MATCH_MUSIC_PATH, path); + } - private static void load(Preferences prefs, JTextField field, String propName, String defaultValue) { - String prop = prefs.get(propName, defaultValue); - field.setText(prop); - } + public static boolean isSaveImagesToZip() { + return PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_SAVE_TO_ZIP, "true").equals("true"); + } - private static void load(Preferences prefs, JSlider field, String propName, String defaultValue) { - String prop = prefs.get(propName, defaultValue); - int value; - try { - value = Integer.parseInt(prop); - } catch (NumberFormatException e) { - // It's OK to ignore "e" here because returning a default value is the documented behaviour on invalid input. - value = Integer.parseInt(defaultValue); - } - field.setValue(value); - } + private static void load(Preferences prefs, JCheckBox checkBox, String propName, String yesValue) { + String prop = prefs.get(propName, yesValue); + checkBox.setSelected(prop.equals(yesValue)); + } - private static void load(Preferences prefs, JComboBox field, String propName, String defaultValue) { - String prop = prefs.get(propName, defaultValue); - field.setSelectedItem(prop); - } + private static void load(Preferences prefs, JCheckBox checkBox, String propName, String yesValue, String defaultValue) { + String prop = prefs.get(propName, defaultValue); + checkBox.setSelected(prop.equals(yesValue)); + updateCache(propName, prop); + } - private static void load(Preferences prefs, JCheckBox checkBox, String propName) { - load(prefs, checkBox, propName, PHASE_ON); - } + private static void load(Preferences prefs, JTextField field, String propName, String defaultValue) { + String prop = prefs.get(propName, defaultValue); + field.setText(prop); + } - private static void save(Preferences prefs, JCheckBox checkBox, String propName) { - save(prefs, checkBox, propName, PHASE_ON, PHASE_OFF, false); - } + private static void load(Preferences prefs, JSlider field, String propName, String defaultValue) { + String prop = prefs.get(propName, defaultValue); + int value; + try { + value = Integer.parseInt(prop); + } catch (NumberFormatException e) { + // It's OK to ignore "e" here because returning a default value is the documented behaviour on invalid input. + value = Integer.parseInt(defaultValue); + } + field.setValue(value); + } - public static void setPrefValue(String key, boolean value) { - switch (key) { - case KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS: - dialog.cbAllowRequestToShowHandCards.setSelected(value); - save(MageFrame.getPreferences(), dialog.cbAllowRequestToShowHandCards, KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS, "true", "false", UPDATE_CACHE_POLICY); - break; - } - } + private static void load(Preferences prefs, JComboBox field, String propName, String defaultValue) { + String prop = prefs.get(propName, defaultValue); + field.setSelectedItem(prop); + } - private static void save(Preferences prefs, JCheckBox checkBox, String propName, String yesValue, String noValue, boolean updateCache) { - prefs.put(propName, checkBox.isSelected() ? yesValue : noValue); - if (updateCache) { - updateCache(propName, checkBox.isSelected() ? yesValue : noValue); - } - } + private static void load(Preferences prefs, JCheckBox checkBox, String propName) { + load(prefs, checkBox, propName, PHASE_ON); + } - private static void save(Preferences prefs, JSlider slider, String propName, String yesValue, String noValue, boolean updateCache) { - prefs.put(propName, Integer.toString(slider.getValue())); - if (updateCache) { - updateCache(propName, Integer.toString(slider.getValue())); - } - } + private static void load(Preferences prefs, KeyBindButton button, String propName, int defaultValue) { + int prop = prefs.getInt(propName, defaultValue); + button.setKeyCode(prop); + } - private static void save(Preferences prefs, JTextField textField, String propName) { - prefs.put(propName, textField.getText().trim()); - updateCache(propName, textField.getText().trim()); - } + private static void save(Preferences prefs, JCheckBox checkBox, String propName) { + save(prefs, checkBox, propName, PHASE_ON, PHASE_OFF, false); + } - private static void save(Preferences prefs, JComboBox comboBox, String propName) { - prefs.put(propName, comboBox.getSelectedItem().toString().trim()); - updateCache(propName, comboBox.getSelectedItem().toString().trim()); - } + public static void setPrefValue(String key, boolean value) { + switch (key) { + case KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS: + dialog.cbAllowRequestToShowHandCards.setSelected(value); + save(MageFrame.getPreferences(), dialog.cbAllowRequestToShowHandCards, KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS, "true", "false", UPDATE_CACHE_POLICY); + break; + } + } - public void reset() { - tabsPanel.setSelectedIndex(0); - } + private static void save(Preferences prefs, JCheckBox checkBox, String propName, String yesValue, String noValue, boolean updateCache) { + prefs.put(propName, checkBox.isSelected() ? yesValue : noValue); + if (updateCache) { + updateCache(propName, checkBox.isSelected() ? yesValue : noValue); + } + } - public static int getCachedValue(String key, int def) { - String stringValue = getCachedValue(key, String.valueOf(def)); - int value; - try { - value = Integer.parseInt(stringValue); - } catch (NumberFormatException e) { - // It's OK to ignore "e" here because returning a default value is the documented behaviour on invalid input. - value = def; - } - return value; - } + private static void save(Preferences prefs, JSlider slider, String propName, String yesValue, String noValue, boolean updateCache) { + prefs.put(propName, Integer.toString(slider.getValue())); + if (updateCache) { + updateCache(propName, Integer.toString(slider.getValue())); + } + } - public static String getCachedValue(String key, String def) { - if (CACHE.containsKey(key)) { - return CACHE.get(key); - } else { - Preferences prefs = MageFrame.getPreferences(); - String value = prefs.get(key, def); - if (value == null) { - return null; - } - CACHE.put(key, value); - return value; - } - } + private static void save(Preferences prefs, JTextField textField, String propName) { + prefs.put(propName, textField.getText().trim()); + updateCache(propName, textField.getText().trim()); + } - private static void updateCache(String key, String value) { - CACHE.put(key, value); - } + private static void save(Preferences prefs, JComboBox comboBox, String propName) { + prefs.put(propName, comboBox.getSelectedItem().toString().trim()); + updateCache(propName, comboBox.getSelectedItem().toString().trim()); + } - public static void saveValue(String key, String value) { - Preferences prefs = MageFrame.getPreferences(); - prefs.put(key, value); - try { - prefs.flush(); - } catch (BackingStoreException ex) { - ex.printStackTrace(); - JOptionPane.showMessageDialog(null, "Error: couldn't save preferences. Please try once again."); - } - updateCache(key, value); - } + private static void save(Preferences prefs, KeyBindButton button, String propName) { + int code = button.getKeyCode(); + prefs.putInt(propName, code); + updateCache(propName, Integer.toString(code)); + } - private void addAvatars() { - try { - addAvatar(jPanel10, 10, true, false); - addAvatar(jPanel11, 11, false, false); - addAvatar(jPanel12, 12, false, false); - addAvatar(jPanel13, 13, false, false); - addAvatar(jPanel14, 14, false, false); - addAvatar(jPanel15, 15, false, false); - addAvatar(jPanel16, 16, false, false); - addAvatar(jPanel17, 17, false, false); - addAvatar(jPanel18, 18, false, false); - addAvatar(jPanel19, 19, false, false); - addAvatar(jPanel20, 20, false, false); - addAvatar(jPanel21, 21, false, false); - addAvatar(jPanel22, 22, false, false); - addAvatar(jPanel23, 23, false, false); - addAvatar(jPanel24, 24, false, false); - addAvatar(jPanel25, 25, false, false); - addAvatar(jPanel26, 26, false, false); - addAvatar(jPanel27, 27, false, false); - addAvatar(jPanel28, 28, false, false); - addAvatar(jPanel29, 29, false, false); - addAvatar(jPanel30, 30, false, false); - addAvatar(jPanel31, 31, false, false); - addAvatar(jPanel32, 32, false, false); + public void reset() { + tabsPanel.setSelectedIndex(0); + } - } catch (Exception e) { - logger.error(e, e); - } - } + public static int getCachedValue(String key, int def) { + String stringValue = getCachedValue(key, String.valueOf(def)); + int value; + try { + value = Integer.parseInt(stringValue); + } catch (NumberFormatException e) { + // It's OK to ignore "e" here because returning a default value is the documented behaviour on invalid input. + value = def; + } + return value; + } - public void setSelectedId(int id) { - if (id >= MIN_AVATAR_ID && id <= MAX_AVATAR_ID) { - for (JPanel panel : PANELS.values()) { - panel.setBorder(BLACK_BORDER); - } - PreferencesDialog.selectedAvatarId = id; - PANELS.get(PreferencesDialog.selectedAvatarId).setBorder(GREEN_BORDER); - } - } + public static String getCachedValue(String key, String def) { + if (CACHE.containsKey(key)) { + return CACHE.get(key); + } else { + Preferences prefs = MageFrame.getPreferences(); + String value = prefs.get(key, def); + if (value == null) { + return null; + } + CACHE.put(key, value); + return value; + } + } - private void addAvatar(JPanel jPanel, final int id, boolean selected, boolean locked) { - String path = "/avatars/" + String.valueOf(id) + ".jpg"; - PANELS.put(id, jPanel); - Image image = ImageHelper.getImageFromResources(path); + private static void updateCache(String key, String value) { + CACHE.put(key, value); + } - Rectangle r = new Rectangle(jPanel.getWidth() - 5, jPanel.getHeight() - 5); - BufferedImage bufferedImage; - if (!locked) { - bufferedImage = BufferedImageBuilder.bufferImage(image, BufferedImage.TYPE_INT_ARGB); - } else { - bufferedImage = BufferedImageBuilder.bufferImage(image, BufferedImage.TYPE_INT_ARGB, new Color(150, 150, 150, 170)); - } - BufferedImage resized = ImageHelper.getResizedImage(bufferedImage, r); - final JLabel jLabel = new JLabel(); - jLabel.setIcon(new ImageIcon(resized)); - if (selected) { - jPanel.setBorder(GREEN_BORDER); - } else { - jPanel.setBorder(BLACK_BORDER); - } - jPanel.setLayout(new BorderLayout()); - jPanel.add(jLabel); - if (!locked) { - jLabel.addMouseListener(new MouseAdapter() { - @Override - public void mousePressed(MouseEvent e) { - if (selectedAvatarId != id) { - setSelectedId(id); - SessionHandler.updatePreferencesForServer(getUserData()); - } - } - }); - } - } + public static void saveValue(String key, String value) { + Preferences prefs = MageFrame.getPreferences(); + prefs.put(key, value); + try { + prefs.flush(); + } catch (BackingStoreException ex) { + ex.printStackTrace(); + JOptionPane.showMessageDialog(null, "Error: couldn't save preferences. Please try once again."); + } + updateCache(key, value); + } - public static UserData getUserData() { - if (selectedAvatarId == 0) { - getSelectedAvatar(); - } - return new UserData(UserGroup.PLAYER, - PreferencesDialog.selectedAvatarId, - PreferencesDialog.getCachedValue(PreferencesDialog.KEY_SHOW_ABILITY_PICKER_FORCED, "true").equals("true"), - PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS, "true").equals("true"), - PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAME_CONFIRM_EMPTY_MANA_POOL, "true").equals("true"), - getUserSkipPrioritySteps(), - MageFrame.getPreferences().get(KEY_CONNECT_FLAG, "world"), - PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAME_ASK_MOVE_TO_GRAVE_ORDER, "false").equals("true"), - PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAME_MANA_AUTOPAYMENT, "true").equals("true"), - PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAME_MANA_AUTOPAYMENT_ONLY_ONE, "true").equals("true"), - PreferencesDialog.getCachedValue(PreferencesDialog.KEY_PASS_PRIORITY_CAST, "true").equals("true"), - PreferencesDialog.getCachedValue(PreferencesDialog.KEY_PASS_PRIORITY_ACTIVATION, "true").equals("true"), - PreferencesDialog.getCachedValue(PreferencesDialog.KEY_AUTO_ORDER_TRIGGER, "true").equals("true"), - PreferencesDialog.getCachedValue(PreferencesDialog.KEY_USE_FIRST_MANA_ABILITY, "false").equals("true") - ); - } + private void addAvatars() { + try { + addAvatar(jPanel10, 10, true, false); + addAvatar(jPanel11, 11, false, false); + addAvatar(jPanel12, 12, false, false); + addAvatar(jPanel13, 13, false, false); + addAvatar(jPanel14, 14, false, false); + addAvatar(jPanel15, 15, false, false); + addAvatar(jPanel16, 16, false, false); + addAvatar(jPanel17, 17, false, false); + addAvatar(jPanel18, 18, false, false); + addAvatar(jPanel19, 19, false, false); + addAvatar(jPanel20, 20, false, false); + addAvatar(jPanel21, 21, false, false); + addAvatar(jPanel22, 22, false, false); + addAvatar(jPanel23, 23, false, false); + addAvatar(jPanel24, 24, false, false); + addAvatar(jPanel25, 25, false, false); + addAvatar(jPanel26, 26, false, false); + addAvatar(jPanel27, 27, false, false); + addAvatar(jPanel28, 28, false, false); + addAvatar(jPanel29, 29, false, false); + addAvatar(jPanel30, 30, false, false); + addAvatar(jPanel31, 31, false, false); + addAvatar(jPanel32, 32, false, false); + + } catch (Exception e) { + logger.error(e, e); + } + } + + public void setSelectedId(int id) { + if (id >= MIN_AVATAR_ID && id <= MAX_AVATAR_ID) { + for (JPanel panel : PANELS.values()) { + panel.setBorder(BLACK_BORDER); + } + PreferencesDialog.selectedAvatarId = id; + PANELS.get(PreferencesDialog.selectedAvatarId).setBorder(GREEN_BORDER); + } + } + + private void addAvatar(JPanel jPanel, final int id, boolean selected, boolean locked) { + String path = "/avatars/" + String.valueOf(id) + ".jpg"; + PANELS.put(id, jPanel); + Image image = ImageHelper.getImageFromResources(path); + + Rectangle r = new Rectangle(jPanel.getWidth() - 5, jPanel.getHeight() - 5); + BufferedImage bufferedImage; + if (!locked) { + bufferedImage = BufferedImageBuilder.bufferImage(image, BufferedImage.TYPE_INT_ARGB); + } else { + bufferedImage = BufferedImageBuilder.bufferImage(image, BufferedImage.TYPE_INT_ARGB, new Color(150, 150, 150, 170)); + } + BufferedImage resized = ImageHelper.getResizedImage(bufferedImage, r); + final JLabel jLabel = new JLabel(); + jLabel.setIcon(new ImageIcon(resized)); + if (selected) { + jPanel.setBorder(GREEN_BORDER); + } else { + jPanel.setBorder(BLACK_BORDER); + } + jPanel.setLayout(new BorderLayout()); + jPanel.add(jLabel); + if (!locked) { + jLabel.addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + if (selectedAvatarId != id) { + setSelectedId(id); + SessionHandler.updatePreferencesForServer(getUserData()); + } + } + }); + } + } + + public static UserData getUserData() { + if (selectedAvatarId == 0) { + getSelectedAvatar(); + } + return new UserData(UserGroup.PLAYER, + PreferencesDialog.selectedAvatarId, + PreferencesDialog.getCachedValue(PreferencesDialog.KEY_SHOW_ABILITY_PICKER_FORCED, "true").equals("true"), + PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS, "true").equals("true"), + PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAME_CONFIRM_EMPTY_MANA_POOL, "true").equals("true"), + getUserSkipPrioritySteps(), + MageFrame.getPreferences().get(KEY_CONNECT_FLAG, "world"), + PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAME_ASK_MOVE_TO_GRAVE_ORDER, "false").equals("true"), + PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAME_MANA_AUTOPAYMENT, "true").equals("true"), + PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAME_MANA_AUTOPAYMENT_ONLY_ONE, "true").equals("true"), + PreferencesDialog.getCachedValue(PreferencesDialog.KEY_PASS_PRIORITY_CAST, "true").equals("true"), + PreferencesDialog.getCachedValue(PreferencesDialog.KEY_PASS_PRIORITY_ACTIVATION, "true").equals("true"), + PreferencesDialog.getCachedValue(PreferencesDialog.KEY_AUTO_ORDER_TRIGGER, "true").equals("true"), + PreferencesDialog.getCachedValue(PreferencesDialog.KEY_USE_FIRST_MANA_ABILITY, "false").equals("true") + ); + } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JScrollPane avatarPane; @@ -3562,6 +3710,14 @@ public class PreferencesDialog extends javax.swing.JDialog { private javax.swing.JPanel jPanel31; private javax.swing.JPanel jPanel32; private javax.swing.JPanel jPanel33; + private mage.client.components.KeyBindButton keyCancelSkip; + private mage.client.components.KeyBindButton keyEndStep; + private mage.client.components.KeyBindButton keyMainStep; + private mage.client.components.KeyBindButton keyNextTurn; + private mage.client.components.KeyBindButton keyPriorEnd; + private mage.client.components.KeyBindButton keySkipStack; + private mage.client.components.KeyBindButton keyYourTurn; + private javax.swing.JLabel labelCancel; private javax.swing.JLabel labelCardSizeHand; private javax.swing.JLabel labelCardSizeMaxBattlefield; private javax.swing.JLabel labelCardSizeMinBattlefield; @@ -3569,18 +3725,24 @@ public class PreferencesDialog extends javax.swing.JDialog { private javax.swing.JLabel labelDialogFont; private javax.swing.JLabel labelEditorCardOffset; private javax.swing.JLabel labelEditorCardSize; + private javax.swing.JLabel labelEndStep; private javax.swing.JLabel labelEnlargedImageSize; private javax.swing.JLabel labelGameFeedback; + private javax.swing.JLabel labelMainStep; + private javax.swing.JLabel labelNextTurn; private javax.swing.JLabel labelNumberOfDownloadThreads; private javax.swing.JLabel labelPreferedImageLanguage; + private javax.swing.JLabel labelPriorEnd; private javax.swing.JLabel labelStackWidth; private javax.swing.JLabel labelTooltipSize; + private javax.swing.JLabel labelYourTurn; private javax.swing.JLabel lblProxyPassword; private javax.swing.JLabel lblProxyPort; private javax.swing.JLabel lblProxyServer; private javax.swing.JLabel lblProxyType; private javax.swing.JLabel lblProxyUserName; private javax.swing.JLabel lblURLServerList; + private javax.swing.JLabel lebelSkip; private javax.swing.JPanel main_card; private javax.swing.JPanel main_game; private javax.swing.JPanel main_gamelog; @@ -3612,6 +3774,7 @@ public class PreferencesDialog extends javax.swing.JDialog { private javax.swing.JPanel sounds_clips; private javax.swing.JPanel tabAvatars; private javax.swing.JPanel tabConnection; + private javax.swing.JPanel tabControls; private javax.swing.JPanel tabGuiSize; private javax.swing.JPanel tabImages; private javax.swing.JPanel tabMain; @@ -3631,9 +3794,9 @@ public class PreferencesDialog extends javax.swing.JDialog { private javax.swing.JTextField txtURLServerList; // End of variables declaration//GEN-END:variables - private static final PreferencesDialog dialog = new PreferencesDialog(new javax.swing.JFrame(), true); + private static final PreferencesDialog dialog = new PreferencesDialog(new javax.swing.JFrame(), true); - static { - dialog.setResizable(false); - } + static { + dialog.setResizable(false); + } } From e910778e545f6bffdc1716beb0521e95103b7dfa Mon Sep 17 00:00:00 2001 From: Campbell Suter Date: Fri, 14 Oct 2016 10:41:26 +1300 Subject: [PATCH 16/35] Add F2/F6, use bindings in game --- .../mage/client/dialog/PreferencesDialog.form | 36 +- .../mage/client/dialog/PreferencesDialog.java | 44 +- .../main/java/mage/client/game/GamePanel.java | 4590 +++++++++-------- 3 files changed, 2378 insertions(+), 2292 deletions(-) diff --git a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form index 02e5d4b84bb..eb5be90e6e1 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form +++ b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form @@ -5896,9 +5896,13 @@ + + + + @@ -5915,6 +5919,11 @@ + + + + + @@ -5930,6 +5939,11 @@ + + + + + @@ -5949,7 +5963,7 @@ - + @@ -6025,6 +6039,26 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java index d43ec0b5557..87f4b8c19eb 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java @@ -57,6 +57,7 @@ import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JSlider; import javax.swing.JTextField; +import javax.swing.KeyStroke; import javax.swing.border.Border; import javax.swing.filechooser.FileFilter; import mage.client.MageFrame; @@ -295,9 +296,11 @@ public class PreferencesDialog extends javax.swing.JDialog { public static final String KEY_CONNECTION_URL_SERVER_LIST = "connectionURLServerList"; // controls + public static final String KEY_CONTROL_CONFIRM = "controlConfirm"; public static final String KEY_CONTROL_CANCEL_SKIP = "controlCancelSkip"; public static final String KEY_CONTROL_NEXT_TURN = "controlNextTurn"; public static final String KEY_CONTROL_END_STEP = "controlEndStep"; + public static final String KEY_CONTROL_SKIP_STEP = "controlSkipTurn"; public static final String KEY_CONTROL_MAIN_STEP = "controlMainStep"; public static final String KEY_CONTROL_YOUR_TURN = "controlYourTurn"; public static final String KEY_CONTROL_SKIP_STACK = "controlSkipStack"; @@ -564,6 +567,10 @@ public class PreferencesDialog extends javax.swing.JDialog { keyYourTurn = new mage.client.components.KeyBindButton(); keySkipStack = new mage.client.components.KeyBindButton(); keyPriorEnd = new mage.client.components.KeyBindButton(); + keySkipStep = new mage.client.components.KeyBindButton(); + labelSkipStep = new javax.swing.JLabel(); + keyConfirm = new mage.client.components.KeyBindButton(); + labelConfirm = new javax.swing.JLabel(); saveButton = new javax.swing.JButton(); exitButton = new javax.swing.JButton(); @@ -2494,6 +2501,14 @@ public class PreferencesDialog extends javax.swing.JDialog { keyPriorEnd.setText("keyBindButton1"); + keySkipStep.setText("keyBindButton1"); + + labelSkipStep.setText("Skip Step"); + + keyConfirm.setText("keyBindButton1"); + + labelConfirm.setText("Confirm"); + org.jdesktop.layout.GroupLayout tabControlsLayout = new org.jdesktop.layout.GroupLayout(tabControls); tabControls.setLayout(tabControlsLayout); tabControlsLayout.setHorizontalGroup( @@ -2507,9 +2522,13 @@ public class PreferencesDialog extends javax.swing.JDialog { .add(labelMainStep) .add(labelYourTurn) .add(lebelSkip) - .add(labelPriorEnd)) + .add(labelPriorEnd) + .add(labelSkipStep) + .add(labelConfirm)) .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(keyConfirm, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(keySkipStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .add(keySkipStack, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .add(keyYourTurn, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .add(keyNextTurn, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) @@ -2523,6 +2542,10 @@ public class PreferencesDialog extends javax.swing.JDialog { tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(tabControlsLayout.createSequentialGroup() .addContainerGap() + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(labelConfirm) + .add(keyConfirm, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(labelCancel) .add(keyCancelSkip, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) @@ -2535,6 +2558,10 @@ public class PreferencesDialog extends javax.swing.JDialog { .add(labelEndStep) .add(keyEndStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(labelSkipStep) + .add(keySkipStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(labelMainStep) .add(keyMainStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) @@ -2550,7 +2577,7 @@ public class PreferencesDialog extends javax.swing.JDialog { .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(labelPriorEnd) .add(keyPriorEnd, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) - .addContainerGap(301, Short.MAX_VALUE)) + .addContainerGap(263, Short.MAX_VALUE)) ); tabsPanel.addTab("Controls", tabControls); @@ -2744,9 +2771,11 @@ public class PreferencesDialog extends javax.swing.JDialog { save(prefs, dialog.txtURLServerList, KEY_CONNECTION_URL_SERVER_LIST); // controls + save(prefs, dialog.keyConfirm, KEY_CONTROL_CONFIRM); save(prefs, dialog.keyCancelSkip, KEY_CONTROL_CANCEL_SKIP); save(prefs, dialog.keyNextTurn, KEY_CONTROL_NEXT_TURN); save(prefs, dialog.keyEndStep, KEY_CONTROL_END_STEP); + save(prefs, dialog.keySkipStep, KEY_CONTROL_SKIP_STEP); save(prefs, dialog.keyMainStep, KEY_CONTROL_MAIN_STEP); save(prefs, dialog.keyYourTurn, KEY_CONTROL_YOUR_TURN); save(prefs, dialog.keySkipStack, KEY_CONTROL_SKIP_STACK); @@ -3289,9 +3318,11 @@ public class PreferencesDialog extends javax.swing.JDialog { } private static void loadControlSettings(Preferences prefs) { + load(prefs, dialog.keyConfirm, KEY_CONTROL_CONFIRM, KeyEvent.VK_F2); load(prefs, dialog.keyCancelSkip, KEY_CONTROL_CANCEL_SKIP, KeyEvent.VK_F3); load(prefs, dialog.keyNextTurn, KEY_CONTROL_NEXT_TURN, KeyEvent.VK_F4); load(prefs, dialog.keyEndStep, KEY_CONTROL_END_STEP, KeyEvent.VK_F5); + load(prefs, dialog.keySkipStep, KEY_CONTROL_SKIP_STEP, KeyEvent.VK_F6); load(prefs, dialog.keyMainStep, KEY_CONTROL_MAIN_STEP, KeyEvent.VK_F7); load(prefs, dialog.keyYourTurn, KEY_CONTROL_YOUR_TURN, KeyEvent.VK_F9); load(prefs, dialog.keySkipStack, KEY_CONTROL_SKIP_STACK, KeyEvent.VK_F10); @@ -3500,6 +3531,11 @@ public class PreferencesDialog extends javax.swing.JDialog { } } + public static KeyStroke getCachedKeystroke(String key, int def) { + int code = getCachedValue(key, def); + return KeyStroke.getKeyStroke(code, 0); + } + private static void updateCache(String key, String value) { CACHE.put(key, value); } @@ -3711,17 +3747,20 @@ public class PreferencesDialog extends javax.swing.JDialog { private javax.swing.JPanel jPanel32; private javax.swing.JPanel jPanel33; private mage.client.components.KeyBindButton keyCancelSkip; + private mage.client.components.KeyBindButton keyConfirm; private mage.client.components.KeyBindButton keyEndStep; private mage.client.components.KeyBindButton keyMainStep; private mage.client.components.KeyBindButton keyNextTurn; private mage.client.components.KeyBindButton keyPriorEnd; private mage.client.components.KeyBindButton keySkipStack; + private mage.client.components.KeyBindButton keySkipStep; private mage.client.components.KeyBindButton keyYourTurn; private javax.swing.JLabel labelCancel; private javax.swing.JLabel labelCardSizeHand; private javax.swing.JLabel labelCardSizeMaxBattlefield; private javax.swing.JLabel labelCardSizeMinBattlefield; private javax.swing.JLabel labelCardSizeOtherZones; + private javax.swing.JLabel labelConfirm; private javax.swing.JLabel labelDialogFont; private javax.swing.JLabel labelEditorCardOffset; private javax.swing.JLabel labelEditorCardSize; @@ -3733,6 +3772,7 @@ public class PreferencesDialog extends javax.swing.JDialog { private javax.swing.JLabel labelNumberOfDownloadThreads; private javax.swing.JLabel labelPreferedImageLanguage; private javax.swing.JLabel labelPriorEnd; + private javax.swing.JLabel labelSkipStep; private javax.swing.JLabel labelStackWidth; private javax.swing.JLabel labelTooltipSize; private javax.swing.JLabel labelYourTurn; diff --git a/Mage.Client/src/main/java/mage/client/game/GamePanel.java b/Mage.Client/src/main/java/mage/client/game/GamePanel.java index 4508045ac9f..2c149d864b3 100644 --- a/Mage.Client/src/main/java/mage/client/game/GamePanel.java +++ b/Mage.Client/src/main/java/mage/client/game/GamePanel.java @@ -99,6 +99,9 @@ import mage.client.dialog.PickChoiceDialog; import mage.client.dialog.PickNumberDialog; import mage.client.dialog.PickPileDialog; import mage.client.dialog.PreferencesDialog; +import static mage.client.dialog.PreferencesDialog.KEY_CONTROL_NEXT_TURN; +import static mage.client.dialog.PreferencesDialog.KEY_CONTROL_PRIOR_END; +import static mage.client.dialog.PreferencesDialog.KEY_CONTROL_YOUR_TURN; import static mage.client.dialog.PreferencesDialog.KEY_GAME_MANA_AUTOPAYMENT; import static mage.client.dialog.PreferencesDialog.KEY_GAME_MANA_AUTOPAYMENT_ONLY_ONE; import static mage.client.dialog.PreferencesDialog.KEY_USE_FIRST_MANA_ABILITY; @@ -146,2353 +149,2362 @@ import org.mage.plugins.card.utils.impl.ImageManagerImpl; */ public final class GamePanel extends javax.swing.JPanel { - private static final Logger logger = Logger.getLogger(GamePanel.class); - private static final String YOUR_HAND = "Your hand"; - private static final int X_PHASE_WIDTH = 55; - private static final int STACK_MIN_CARDS_OFFSET_Y = 7; // TODO: Size bui GUISize value - - private static final String CMD_AUTO_ORDER_FIRST = "cmdAutoOrderFirst"; - private static final String CMD_AUTO_ORDER_LAST = "cmdAutoOrderLast"; - private static final String CMD_AUTO_ORDER_NAME_FIRST = "cmdAutoOrderNameFirst"; - private static final String CMD_AUTO_ORDER_NAME_LAST = "cmdAutoOrderNameLast"; - private static final String CMD_AUTO_ORDER_RESET_ALL = "cmdAutoOrderResetAll"; - - private final Map players = new HashMap<>(); - private final Map playersWhoLeft = new HashMap<>(); - - // non modal frames - private final Map exiles = new HashMap<>(); - private final Map revealed = new HashMap<>(); - private final Map lookedAt = new HashMap<>(); - private final Map graveyardWindows = new HashMap<>(); - private final Map graveyards = new HashMap<>(); - - private final ArrayList pickTarget = new ArrayList<>(); - private UUID gameId; - private UUID playerId; // playerId of the player - GamePane gamePane; - private ReplayTask replayTask; - private final PickNumberDialog pickNumber; - private JLayeredPane jLayeredPane; - private String chosenHandKey = "You"; - private boolean smallMode = false; - private boolean initialized = false; - - private boolean menuNameSet = false; - private boolean handCardsOfOpponentAvailable = false; - - private Map loadedCards = new HashMap<>(); - - private int storedHeight; - private Map hoverButtons; - - private MageDialogState choiceWindowState; - - private boolean initComponents; - - private Timer resizeTimer; - - private enum PopUpMenuType { - - TRIGGER_ORDER - } - // CardView popupMenu was invoked last - private CardView cardViewPopupMenu; - - // popup menu for triggered abilities order - private JPopupMenu popupMenuTriggerOrder; - - public GamePanel() { - initComponents = true; - initComponents(); - - pickNumber = new PickNumberDialog(); - MageFrame.getDesktop().add(pickNumber, JLayeredPane.MODAL_LAYER); - - this.feedbackPanel.setConnectedChatPanel(this.userChatPanel); - - this.stackObjects.setMinOffsetY(STACK_MIN_CARDS_OFFSET_Y); - - // Override layout (I can't edit generated code) - this.setLayout(new BorderLayout()); - final JLayeredPane jLayeredBackgroundPane = new JLayeredPane(); - jLayeredBackgroundPane.setSize(1024, 768); - this.add(jLayeredBackgroundPane); - jLayeredBackgroundPane.add(jSplitPane0, JLayeredPane.DEFAULT_LAYER); - - Map myUi = getUIComponents(jLayeredBackgroundPane); - Plugins.getInstance().updateGamePanel(myUi); - - // Enlarge jlayeredpane on resize of game panel - addComponentListener(new ComponentAdapter() { - @Override - public void componentResized(ComponentEvent e) { - int width = ((JComponent) e.getSource()).getWidth(); - int height = ((JComponent) e.getSource()).getHeight(); - jLayeredBackgroundPane.setSize(width, height); - jSplitPane0.setSize(width, height); - - if (height < storedHeight) { - pnlBattlefield.setSize(0, 200); - } - storedHeight = height; - - sizeToScreen(); - - if (!initialized) { - String state = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_BIG_CARD_TOGGLED, null); - if (state != null && state.equals("down")) { - jSplitPane0.setDividerLocation(1.0); - } - initialized = true; - } - - } - }); - // Resize the width of the stack area if the size of the play area is changed - ComponentAdapter componentAdapterPlayField = new ComponentAdapter() { - @Override - public void componentResized(ComponentEvent e) { - if (!initComponents) { - if (resizeTimer.isRunning()) { - resizeTimer.restart(); - } else { - resizeTimer.start(); - } - } - } - }; - - resizeTimer = new Timer(1000, new ActionListener() { - @Override - public void actionPerformed(ActionEvent evt) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - resizeTimer.stop(); - setGUISize(); - feedbackPanel.changeGUISize(); - - } - }); - } - }); - - pnlHelperHandButtonsStackArea.addComponentListener(componentAdapterPlayField); - initComponents = false; - } - - private Map getUIComponents(JLayeredPane jLayeredPane) { - Map components = new HashMap<>(); - - components.put("jSplitPane1", jSplitPane1); - components.put("pnlBattlefield", pnlBattlefield); - components.put("pnlHelperHandButtonsStackArea", pnlHelperHandButtonsStackArea); - components.put("hand", handContainer); - components.put("gameChatPanel", gameChatPanel); - components.put("userChatPanel", userChatPanel); - components.put("jLayeredPane", jLayeredPane); - components.put("gamePanel", this); - - return components; - } - - public void cleanUp() { - MageFrame.removeGame(gameId); - saveDividerLocations(); - this.gameChatPanel.disconnect(); - this.userChatPanel.disconnect(); - - this.removeListener(); - - this.handContainer.cleanUp(); - this.stackObjects.cleanUp(); - for (Map.Entry playAreaPanelEntry : players.entrySet()) { - playAreaPanelEntry.getValue().CleanUp(); - } - this.players.clear(); - this.playersWhoLeft.clear(); - - jLayeredPane.remove(abilityPicker); - this.abilityPicker.cleanUp(); - - jLayeredPane.remove(DialogManager.getManager(gameId)); - DialogManager.removeGame(gameId); - - if (pickNumber != null) { - pickNumber.removeDialog(); - } - for (CardInfoWindowDialog exileDialog : exiles.values()) { - exileDialog.cleanUp(); - exileDialog.removeDialog(); - } - for (CardInfoWindowDialog graveyardDialog : graveyardWindows.values()) { - graveyardDialog.cleanUp(); - graveyardDialog.removeDialog(); - } - for (CardInfoWindowDialog revealDialog : revealed.values()) { - revealDialog.cleanUp(); - revealDialog.removeDialog(); - } - for (CardInfoWindowDialog lookedAtDialog : lookedAt.values()) { - lookedAtDialog.cleanUp(); - lookedAtDialog.removeDialog(); - } - for (ShowCardsDialog pickTargetDialog : pickTarget) { - pickTargetDialog.cleanUp(); - pickTargetDialog.removeDialog(); - } - Plugins.getInstance().getActionCallback().hideTooltipPopup(); - try { - Component popupContainer = MageFrame.getUI().getComponent(MageComponents.POPUP_CONTAINER); - popupContainer.setVisible(false); - } catch (InterruptedException ex) { - logger.fatal("popupContainer error:", ex); - } - jPanel2.remove(bigCard); - this.bigCard = null; - } - - public void changeGUISize() { - initComponents = true; - setGUISize(); - stackObjects.changeGUISize(); - feedbackPanel.changeGUISize(); - handContainer.changeGUISize(); - for (PlayAreaPanel playAreaPanel : players.values()) { - playAreaPanel.changeGUISize(); - } - - for (CardInfoWindowDialog cardInfoWindowDialog : exiles.values()) { - cardInfoWindowDialog.changeGUISize(); - } - for (CardInfoWindowDialog cardInfoWindowDialog : revealed.values()) { - cardInfoWindowDialog.changeGUISize(); - } - for (CardInfoWindowDialog cardInfoWindowDialog : lookedAt.values()) { - cardInfoWindowDialog.changeGUISize(); - } - for (CardInfoWindowDialog cardInfoWindowDialog : graveyardWindows.values()) { - cardInfoWindowDialog.changeGUISize(); - } - for (ShowCardsDialog showCardsDialog : pickTarget) { - showCardsDialog.changeGUISize(); - } - - this.revalidate(); - this.repaint(); - initComponents = false; - } - - private void setGUISize() { - jSplitPane0.setDividerSize(GUISizeHelper.dividerBarSize); - jSplitPane1.setDividerSize(GUISizeHelper.dividerBarSize); - jSplitPane2.setDividerSize(GUISizeHelper.dividerBarSize); - stackObjects.setCardDimension(GUISizeHelper.handCardDimension); - - txtSpellsCast.setFont(new Font(GUISizeHelper.gameDialogAreaFont.getFontName(), Font.BOLD, GUISizeHelper.gameDialogAreaFont.getSize())); - txtHoldPriority.setFont(new Font(GUISizeHelper.gameDialogAreaFont.getFontName(), Font.BOLD, GUISizeHelper.gameDialogAreaFont.getSize())); - GUISizeHelper.changePopupMenuFont(popupMenuTriggerOrder); - - int newStackWidth = pnlHelperHandButtonsStackArea.getWidth() * GUISizeHelper.stackWidth / 100; - if (newStackWidth < 410) { - newStackWidth = 410; - } - Dimension newDimension = new Dimension(pnlHelperHandButtonsStackArea.getWidth() - newStackWidth, GUISizeHelper.handCardDimension.height + GUISizeHelper.scrollBarSize); - handContainer.setPreferredSize(newDimension); - handContainer.setMaximumSize(newDimension); - - newDimension = new Dimension(newStackWidth, STACK_MIN_CARDS_OFFSET_Y + GUISizeHelper.handCardDimension.height + GUISizeHelper.scrollBarSize); - stackObjects.setPreferredSize(newDimension); - stackObjects.setMinimumSize(newDimension); - stackObjects.setMaximumSize(newDimension); - - newDimension = new Dimension(newStackWidth, (int) pnlShortCuts.getPreferredSize().getHeight()); - pnlShortCuts.setPreferredSize(newDimension); - pnlShortCuts.setMinimumSize(newDimension); - pnlShortCuts.setMaximumSize(newDimension); - } - - private void saveDividerLocations() { - // save panel sizes and divider locations. - Rectangle rec = MageFrame.getDesktop().getBounds(); - String sb = Double.toString(rec.getWidth()) + "x" + Double.toString(rec.getHeight()); - PreferencesDialog.saveValue(PreferencesDialog.KEY_MAGE_PANEL_LAST_SIZE, sb); - PreferencesDialog.saveValue(PreferencesDialog.KEY_GAMEPANEL_DIVIDER_LOCATION_0, Integer.toString(this.jSplitPane0.getDividerLocation())); - PreferencesDialog.saveValue(PreferencesDialog.KEY_GAMEPANEL_DIVIDER_LOCATION_1, Integer.toString(this.jSplitPane1.getDividerLocation())); - PreferencesDialog.saveValue(PreferencesDialog.KEY_GAMEPANEL_DIVIDER_LOCATION_2, Integer.toString(this.jSplitPane2.getDividerLocation())); - } - - private void restoreDividerLocations() { - Rectangle rec = MageFrame.getDesktop().getBounds(); - if (rec != null) { - String size = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_MAGE_PANEL_LAST_SIZE, null); - String sb = Double.toString(rec.getWidth()) + "x" + Double.toString(rec.getHeight()); - // use divider positions only if screen size is the same as it was the time the settings were saved - if (size != null && size.equals(sb)) { - - String location = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAMEPANEL_DIVIDER_LOCATION_0, null); - if (location != null && jSplitPane0 != null) { - jSplitPane0.setDividerLocation(Integer.parseInt(location)); - } - location = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAMEPANEL_DIVIDER_LOCATION_1, null); - if (location != null && jSplitPane1 != null) { - jSplitPane1.setDividerLocation(Integer.parseInt(location)); - } - location = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAMEPANEL_DIVIDER_LOCATION_2, null); - if (location != null && jSplitPane2 != null) { - jSplitPane2.setDividerLocation(Integer.parseInt(location)); - } - } - } - } - - private void sizeToScreen() { - Rectangle rect = this.getBounds(); - - if (rect.height < 720) { - if (!smallMode) { - smallMode = true; - Dimension bbDimension = new Dimension(128, 184); - bigCard.setMaximumSize(bbDimension); - bigCard.setMinimumSize(bbDimension); - bigCard.setPreferredSize(bbDimension); - pnlShortCuts.revalidate(); - pnlShortCuts.repaint(); - for (PlayAreaPanel p : players.values()) { - p.sizePlayer(smallMode); - } - } - } else if (smallMode) { - smallMode = false; - Dimension bbDimension = new Dimension(256, 367); - bigCard.setMaximumSize(bbDimension); - bigCard.setMinimumSize(bbDimension); - bigCard.setPreferredSize(bbDimension); - pnlShortCuts.revalidate(); - pnlShortCuts.repaint(); - for (PlayAreaPanel p : players.values()) { - p.sizePlayer(smallMode); - } - } - - ArrowBuilder.getBuilder().setSize(rect.width, rect.height); - - DialogManager.getManager(gameId).setScreenWidth(rect.width); - DialogManager.getManager(gameId).setScreenHeight(rect.height); - DialogManager.getManager(gameId).setBounds(0, 0, rect.width, rect.height); - } - - public synchronized void showGame(UUID gameId, UUID playerId, GamePane gamePane) { - this.gameId = gameId; - this.gamePane = gamePane; - this.playerId = playerId; - MageFrame.addGame(gameId, this); - this.feedbackPanel.init(gameId); - this.feedbackPanel.clear(); - this.abilityPicker.init(gameId); - - this.btnConcede.setVisible(true); - this.btnStopWatching.setVisible(false); - this.btnSwitchHands.setVisible(false); - this.btnCancelSkip.setVisible(true); - - this.btnSkipToNextTurn.setVisible(true); - this.btnSkipToEndTurn.setVisible(true); - this.btnSkipToNextMain.setVisible(true); - this.btnSkipStack.setVisible(true); - this.btnSkipToYourTurn.setVisible(true); - this.btnSkipToEndStepBeforeYourTurn.setVisible(true); - - this.pnlReplay.setVisible(false); - - this.gameChatPanel.clear(); - this.gameChatPanel.connect(SessionHandler.getGameChatId(gameId)); - if (!SessionHandler.joinGame(gameId)) { - removeGame(); - } else { - // play start sound - AudioManager.playYourGameStarted(); - } - } - - public synchronized void watchGame(UUID gameId, GamePane gamePane) { - this.gameId = gameId; - this.gamePane = gamePane; - this.playerId = null; - MageFrame.addGame(gameId, this); - this.feedbackPanel.init(gameId); - this.feedbackPanel.clear(); - - this.btnConcede.setVisible(false); - this.btnStopWatching.setVisible(true); - this.btnSwitchHands.setVisible(false); - this.chosenHandKey = ""; - this.btnCancelSkip.setVisible(false); - - this.btnSkipToNextTurn.setVisible(false); - this.btnSkipToEndTurn.setVisible(false); - this.btnSkipToNextMain.setVisible(false); - this.btnSkipStack.setVisible(false); - this.btnSkipToYourTurn.setVisible(false); - this.btnSkipToEndStepBeforeYourTurn.setVisible(false); - - this.pnlReplay.setVisible(false); - this.gameChatPanel.clear(); - this.gameChatPanel.connect(SessionHandler.getGameChatId(gameId)); - if (!SessionHandler.watchGame(gameId)) { - removeGame(); - } - for (PlayAreaPanel panel : getPlayers().values()) { - panel.setPlayingMode(false); - } - } - - public synchronized void replayGame(UUID gameId) { - this.gameId = gameId; - this.playerId = null; - MageFrame.addGame(gameId, this); - this.feedbackPanel.init(gameId); - this.feedbackPanel.clear(); - this.btnConcede.setVisible(false); - this.btnSkipToNextTurn.setVisible(false); - this.btnSwitchHands.setVisible(false); - this.btnStopWatching.setVisible(false); - this.pnlReplay.setVisible(true); - this.gameChatPanel.clear(); - if (!SessionHandler.startReplay(gameId)) { - removeGame(); - } - for (PlayAreaPanel panel : getPlayers().values()) { - panel.setPlayingMode(false); - } - } - - /** - * Closes the game and it's resources - */ - public void removeGame() { - Component c = this.getParent(); - while (c != null && !(c instanceof GamePane)) { - c = c.getParent(); - } - if (c != null) { - ((GamePane) c).removeGame(); - } - } - - public synchronized void init(GameView game) { - addPlayers(game); - // default menu states - setMenuStates( - PreferencesDialog.getCachedValue(KEY_GAME_MANA_AUTOPAYMENT, "true").equals("true"), - PreferencesDialog.getCachedValue(KEY_GAME_MANA_AUTOPAYMENT_ONLY_ONE, "true").equals("true"), - PreferencesDialog.getCachedValue(KEY_USE_FIRST_MANA_ABILITY, "false").equals("true"), - holdingPriority - ); - - updateGame(game); - } - - private void addPlayers(GameView game) { - this.players.clear(); - this.playersWhoLeft.clear(); - this.pnlBattlefield.removeAll(); - //arrange players in a circle with the session player at the bottom left - int numSeats = game.getPlayers().size(); - int numColumns = (numSeats + 1) / 2; - boolean oddNumber = (numColumns > 1 && numSeats % 2 == 1); - int col = 0; - int row = 1; - int playerSeat = 0; - if (playerId != null) { - for (PlayerView player : game.getPlayers()) { - if (playerId.equals(player.getPlayerId())) { - break; - } - playerSeat++; - } - } - PlayerView player = game.getPlayers().get(playerSeat); - PlayAreaPanel playAreaPanel = new PlayAreaPanel(player, bigCard, gameId, game.getPriorityTime(), this, - new PlayAreaPanelOptions(game.isPlayer(), game.isPlayer(), game.isRollbackTurnsAllowed(), row == 0)); - players.put(player.getPlayerId(), playAreaPanel); - playersWhoLeft.put(player.getPlayerId(), false); - GridBagConstraints c = new GridBagConstraints(); - c.fill = GridBagConstraints.BOTH; - c.weightx = 0.5; - c.weighty = 0.5; - if (oddNumber) { - c.gridwidth = 2; - } - c.gridx = col; - c.gridy = 0; - - // Top panel (row=0) - JPanel topPanel = new JPanel(); - topPanel.setOpaque(false); - - // Bottom panel (row=1) - JPanel bottomPanel = new JPanel(); - bottomPanel.setOpaque(false); - topPanel.setLayout(new GridBagLayout()); - bottomPanel.setLayout(new GridBagLayout()); - - bottomPanel.add(playAreaPanel, c); - playAreaPanel.setVisible(true); - if (oddNumber) { - col++; - } - int playerNum = playerSeat + 1; - if (playerNum >= numSeats) { - playerNum = 0; - } - while (true) { - if (row == 1) { - col++; - } else { - col--; - } - if (col >= numColumns) { - row = 0; - col = numColumns - 1; - } - player = game.getPlayers().get(playerNum); - PlayAreaPanel playerPanel = new PlayAreaPanel(player, bigCard, gameId, game.getPriorityTime(), this, - new PlayAreaPanelOptions(game.isPlayer(), false, game.isRollbackTurnsAllowed(), row == 0)); - players.put(player.getPlayerId(), playerPanel); - playersWhoLeft.put(player.getPlayerId(), false); - c = new GridBagConstraints(); - c.fill = GridBagConstraints.BOTH; - c.weightx = 0.5; - c.weighty = 0.5; - c.gridx = col; - c.gridy = 0; - - if (row == 0) { - topPanel.add(playerPanel, c); - } else { - bottomPanel.add(playerPanel, c); - } - - playerPanel.setVisible(true); - playerNum++; - if (playerNum >= numSeats) { - playerNum = 0; - } - if (playerNum == playerSeat) { - break; - } - } - for (PlayAreaPanel p : players.values()) { - p.sizePlayer(smallMode); - } - - GridBagConstraints panelC = new GridBagConstraints(); - panelC.fill = GridBagConstraints.BOTH; - panelC.weightx = 0.5; - panelC.weighty = 0.5; - panelC.gridwidth = 1; - panelC.gridy = 0; - this.pnlBattlefield.add(topPanel, panelC); - panelC.gridy = 1; - this.pnlBattlefield.add(bottomPanel, panelC); - } - - public synchronized void updateGame(GameView game) { - updateGame(game, null); - } - - public synchronized void updateGame(GameView game, Map options) { - if (playerId == null && game.getWatchedHands() == null) { - this.handContainer.setVisible(false); - } else { - this.handContainer.setVisible(true); - handCards.clear(); - if (game.getWatchedHands() != null) { - for (Map.Entry hand : game.getWatchedHands().entrySet()) { - handCards.put(hand.getKey(), CardsViewUtil.convertSimple(hand.getValue(), loadedCards)); - } - } - if (playerId != null) { - handCards.put(YOUR_HAND, game.getHand()); - // Mark playable - if (game.getCanPlayInHand() != null) { - for (CardView card : handCards.get(YOUR_HAND).values()) { - if (game.getCanPlayInHand().contains(card.getId())) { - card.setPlayable(true); - } - } - } - // Get opponents hand cards if available (only possible for players) - if (game.getOpponentHands() != null) { - for (Map.Entry hand : game.getOpponentHands().entrySet()) { - handCards.put(hand.getKey(), CardsViewUtil.convertSimple(hand.getValue(), loadedCards)); - } - } - if (!handCards.containsKey(chosenHandKey)) { - chosenHandKey = YOUR_HAND; - } - } else if (chosenHandKey.isEmpty() && handCards.size() > 0) { - chosenHandKey = handCards.keySet().iterator().next(); - } - if (chosenHandKey != null && handCards.containsKey(chosenHandKey)) { - handContainer.loadCards(handCards.get(chosenHandKey), bigCard, gameId); - } - - hideAll(); - - if (playerId != null) { - // set visible only if we have any other hand visible than ours - btnSwitchHands.setVisible(handCards.size() > 1); - boolean change = (handCardsOfOpponentAvailable != (game.getOpponentHands() != null)); - if (change) { - handCardsOfOpponentAvailable = !handCardsOfOpponentAvailable; - if (handCardsOfOpponentAvailable) { - JOptionPane.showMessageDialog(null, "You control other player's turn. \nUse \"Switch Hand\" button to switch between cards in different hands."); - } else { - JOptionPane.showMessageDialog(null, "You lost control on other player's turn."); - } - } - } else { - btnSwitchHands.setVisible(!handCards.isEmpty()); - } - } - - if (game.getPhase() != null) { - this.txtPhase.setText(game.getPhase().toString()); - } else { - this.txtPhase.setText(""); - } - - if (game.getStep() != null) { - updatePhases(game.getStep()); - this.txtStep.setText(game.getStep().toString()); - } else { - logger.debug("Step is empty"); - this.txtStep.setText(""); - } - if (game.getSpellsCastCurrentTurn() > 0 && PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAME_SHOW_STORM_COUNTER, "true").equals("true")) { - this.txtSpellsCast.setVisible(true); - this.txtSpellsCast.setText(" " + Integer.toString(game.getSpellsCastCurrentTurn()) + " "); - } else { - this.txtSpellsCast.setVisible(false); - } - - this.txtActivePlayer.setText(game.getActivePlayerName()); - this.txtPriority.setText(game.getPriorityPlayerName()); - this.txtTurn.setText(Integer.toString(game.getTurn())); - - List possibleAttackers = new ArrayList<>(); - if (options != null && options.containsKey(Constants.Option.POSSIBLE_ATTACKERS)) { - if (options.get(Constants.Option.POSSIBLE_ATTACKERS) instanceof List) { - possibleAttackers.addAll((List) options.get(Constants.Option.POSSIBLE_ATTACKERS)); - } - } - - for (PlayerView player : game.getPlayers()) { - if (players.containsKey(player.getPlayerId())) { - if (!possibleAttackers.isEmpty()) { - for (UUID permanentId : possibleAttackers) { - if (player.getBattlefield().containsKey(permanentId)) { - player.getBattlefield().get(permanentId).setCanAttack(true); - } - } - } - players.get(player.getPlayerId()).update(player); - if (player.getPlayerId().equals(playerId)) { - updateSkipButtons(player.isPassedTurn(), player.isPassedUntilEndOfTurn(), player.isPassedUntilNextMain(), player.isPassedAllTurns(), player.isPassedUntilStackResolved(), - player.isPassedUntilEndStepBeforeMyTurn()); - } - // update open or remove closed graveyard windows - graveyards.put(player.getName(), player.getGraveyard()); - if (graveyardWindows.containsKey(player.getName())) { - CardInfoWindowDialog cardInfoWindowDialog = graveyardWindows.get(player.getName()); - if (cardInfoWindowDialog.isClosed()) { - graveyardWindows.remove(player.getName()); - } else { - cardInfoWindowDialog.loadCards(player.getGraveyard(), bigCard, gameId, false); - } - } - // show top card window - if (player.getTopCard() != null) { - CardsView cardsView = new CardsView(); - cardsView.put(player.getTopCard().getId(), player.getTopCard()); - handleGameInfoWindow(revealed, ShowType.REVEAL_TOP_LIBRARY, player.getName() + "'s top library card", cardsView); - } - } else { - logger.warn("Couldn't find player."); - logger.warn(" uuid:" + player.getPlayerId()); - logger.warn(" players:"); - for (PlayAreaPanel p : players.values()) { - logger.warn("" + p); - } - } - } - if (!menuNameSet) { - StringBuilder sb = new StringBuilder(); - if (playerId == null) { - sb.append("Watching: "); - } else { - sb.append("Playing: "); - } - boolean first = true; - for (PlayerView player : game.getPlayers()) { - if (first) { - first = false; - } else { - sb.append(" - "); - } - sb.append(player.getName()); - } - menuNameSet = true; - gamePane.setTitle(sb.toString()); - } - - GameManager.getInstance().setStackSize(game.getStack().size()); - displayStack(game, bigCard, feedbackPanel, gameId); - - for (ExileView exile : game.getExile()) { - if (!exiles.containsKey(exile.getId())) { - CardInfoWindowDialog newExile = new CardInfoWindowDialog(ShowType.EXILE, exile.getName()); - exiles.put(exile.getId(), newExile); - MageFrame.getDesktop().add(newExile, JLayeredPane.MODAL_LAYER); - newExile.show(); - } - exiles.get(exile.getId()).loadCards(exile, bigCard, gameId); - } - - showRevealed(game); - showLookedAt(game); - if (game.getCombat().size() > 0) { - CombatManager.getInstance().showCombat(game.getCombat(), gameId); - } else { - CombatManager.getInstance().hideCombat(gameId); - } - - for (PlayerView player : game.getPlayers()) { - if (player.hasLeft() && !playersWhoLeft.get(player.getPlayerId())) { - PlayAreaPanel playerLeftPanel = players.get(player.getPlayerId()); - playersWhoLeft.put(player.getPlayerId(), true); - - Container parent = playerLeftPanel.getParent(); - GridBagLayout layout = (GridBagLayout) parent.getLayout(); - - for (Component otherPanel : parent.getComponents()) { - - if (otherPanel instanceof PlayAreaPanel) { - GridBagConstraints gbc = layout.getConstraints(otherPanel); - if (gbc.weightx > 0.1) { - gbc.weightx = 0.99; - } - gbc.fill = GridBagConstraints.BOTH; - gbc.anchor = GridBagConstraints.WEST; - if (gbc.gridx > 0) { - gbc.anchor = GridBagConstraints.EAST; - } - if (otherPanel == playerLeftPanel) { - gbc.weightx = 0.01; - Dimension d = playerLeftPanel.getPreferredSize(); - d.width = 95; - otherPanel.setPreferredSize(d); - } - parent.remove(otherPanel); - parent.add(otherPanel, gbc); - } - } - - parent.validate(); - parent.repaint(); - } - } - - feedbackPanel.disableUndo(); - - this.revalidate(); - this.repaint(); - } - - static final int BORDER_SIZE = 2; - - private void updateSkipButtons(boolean turn, boolean endOfTurn, boolean nextMain, boolean allTurns, boolean stack, boolean endStepBeforeYourStep) { - if (turn) { //F4 - btnSkipToNextTurn.setBorder(new LineBorder(Color.orange, BORDER_SIZE)); - } else { - btnSkipToNextTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); - } - if (endOfTurn) { // F5 - btnSkipToEndTurn.setBorder(new LineBorder(Color.orange, BORDER_SIZE)); - } else { - btnSkipToEndTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); - } - if (nextMain) { // F7 - btnSkipToNextMain.setBorder(new LineBorder(Color.orange, BORDER_SIZE)); - } else { - btnSkipToNextMain.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); - } - if (stack) { // F8 - btnSkipStack.setBorder(new LineBorder(Color.orange, BORDER_SIZE)); - } else { - btnSkipStack.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); - } - if (allTurns) { // F9 - btnSkipToYourTurn.setBorder(new LineBorder(Color.orange, BORDER_SIZE)); - } else { - btnSkipToYourTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); - } - - if (endStepBeforeYourStep) { // F11 - btnSkipToEndStepBeforeYourTurn.setBorder(new LineBorder(Color.orange, BORDER_SIZE)); - } else { - btnSkipToEndStepBeforeYourTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); - } - - } - - /** - * Set the same state for menu selections to all player areas. - * - * @param manaPoolAutomatic - * @param manaPoolAutomaticRestricted - * @param useFirstManaAbility - */ - public void setMenuStates(boolean manaPoolAutomatic, boolean manaPoolAutomaticRestricted, boolean useFirstManaAbility, boolean holdPriority) { - for (PlayAreaPanel playAreaPanel : players.values()) { - playAreaPanel.setMenuStates(manaPoolAutomatic, manaPoolAutomaticRestricted, useFirstManaAbility, holdPriority); - } - } - - private void displayStack(GameView game, BigCard bigCard, FeedbackPanel feedbackPanel, UUID gameId) { - this.stackObjects.loadCards(game.getStack(), bigCard, gameId, true); - } - - /** - * Update phase buttons\labels. - */ - private void updatePhases(PhaseStep step) { - if (step == null) { - logger.warn("step is null"); - return; - } - if (currentStep != null) { - currentStep.setLocation(prevPoint); - } - switch (step) { - case UNTAP: - updateButton("Untap"); - break; - case UPKEEP: - updateButton("Upkeep"); - break; - case DRAW: - updateButton("Draw"); - break; - case PRECOMBAT_MAIN: - updateButton("Main1"); - break; - case BEGIN_COMBAT: - updateButton("Combat_Start"); - break; - case DECLARE_ATTACKERS: - updateButton("Combat_Attack"); - break; - case DECLARE_BLOCKERS: - updateButton("Combat_Block"); - break; - case FIRST_COMBAT_DAMAGE: - case COMBAT_DAMAGE: - updateButton("Combat_Damage"); - break; - case END_COMBAT: - updateButton("Combat_End"); - break; - case POSTCOMBAT_MAIN: - updateButton("Main2"); - break; - case END_TURN: - updateButton("Cleanup"); - break; - } - } - - private void updateButton(String name) { - if (hoverButtons.containsKey(name)) { - currentStep = hoverButtons.get(name); - prevPoint = currentStep.getLocation(); - currentStep.setLocation(prevPoint.x - 15, prevPoint.y); - } - } - - // Called if the game frame is deactivated because the tabled the deck editor or other frames go to foreground - public void deactivated() { - // hide the non modal windows (because otherwise they are shown on top of the new active pane) - for (CardInfoWindowDialog exileDialog : exiles.values()) { - exileDialog.hideDialog(); - } - for (CardInfoWindowDialog graveyardDialog : graveyardWindows.values()) { - graveyardDialog.hideDialog(); - } - for (CardInfoWindowDialog revealDialog : revealed.values()) { - revealDialog.hideDialog(); - } - for (CardInfoWindowDialog lookedAtDialog : lookedAt.values()) { - lookedAtDialog.hideDialog(); - } - } - - // Called if the game frame comes to front again - public void activated() { - // hide the non modal windows (because otherwise they are shown on top of the new active pane) - for (CardInfoWindowDialog exileDialog : exiles.values()) { - exileDialog.show(); - } - for (CardInfoWindowDialog graveyardDialog : graveyardWindows.values()) { - graveyardDialog.show(); - } - for (CardInfoWindowDialog revealDialog : revealed.values()) { - revealDialog.show(); - } - for (CardInfoWindowDialog lookedAtDialog : lookedAt.values()) { - lookedAtDialog.show(); - } - } - - public void openGraveyardWindow(String playerName) { - if (graveyardWindows.containsKey(playerName)) { - CardInfoWindowDialog cardInfoWindowDialog = graveyardWindows.get(playerName); - if (cardInfoWindowDialog.isVisible()) { - cardInfoWindowDialog.hideDialog(); - } else { - cardInfoWindowDialog.show(); - } - return; - } - CardInfoWindowDialog newGraveyard = new CardInfoWindowDialog(ShowType.GRAVEYARD, playerName); - graveyardWindows.put(playerName, newGraveyard); - MageFrame.getDesktop().add(newGraveyard, JLayeredPane.MODAL_LAYER); - newGraveyard.loadCards(graveyards.get(playerName), bigCard, gameId, false); - } - - public void openTopLibraryWindow(String playerName) { - String title = playerName + "'s top library card"; - if (revealed.containsKey(title)) { - CardInfoWindowDialog cardInfoWindowDialog = revealed.get(title); - if (cardInfoWindowDialog.isVisible()) { - cardInfoWindowDialog.hideDialog(); - } else { - cardInfoWindowDialog.show(); - } - } - } - - private void showRevealed(GameView game) { - for (RevealedView revealView : game.getRevealed()) { - handleGameInfoWindow(revealed, ShowType.REVEAL, revealView.getName(), revealView.getCards()); - } - removeClosedCardInfoWindows(revealed); - } - - private void showLookedAt(GameView game) { - for (LookedAtView lookedAtView : game.getLookedAt()) { - handleGameInfoWindow(lookedAt, ShowType.LOOKED_AT, lookedAtView.getName(), lookedAtView.getCards()); - } - removeClosedCardInfoWindows(lookedAt); - } - - private void handleGameInfoWindow(Map windowMap, ShowType showType, String name, LinkedHashMap cardsView) { - CardInfoWindowDialog cardInfoWindowDialog; - if (!windowMap.containsKey(name)) { - cardInfoWindowDialog = new CardInfoWindowDialog(showType, name); - windowMap.put(name, cardInfoWindowDialog); - MageFrame.getDesktop().add(cardInfoWindowDialog, JLayeredPane.MODAL_LAYER); - } else { - cardInfoWindowDialog = windowMap.get(name); - } - - if (cardInfoWindowDialog != null && !cardInfoWindowDialog.isClosed()) { - switch (showType) { - case REVEAL: - case REVEAL_TOP_LIBRARY: - cardInfoWindowDialog.loadCards((CardsView) cardsView, bigCard, gameId); - break; - case LOOKED_AT: - cardInfoWindowDialog.loadCards((SimpleCardsView) cardsView, bigCard, gameId); - break; - } - } - } - - private void removeClosedCardInfoWindows(Map windowMap) { - // Remove closed window objects from the maps - for (Iterator> iterator = windowMap.entrySet().iterator(); iterator.hasNext();) { - Map.Entry entry = iterator.next(); - if (entry.getValue().isClosed()) { - iterator.remove(); - } - } - } - - public void ask(String question, GameView gameView, int messageId, Map options) { - updateGame(gameView); - this.feedbackPanel.getFeedback(FeedbackMode.QUESTION, question, false, options, messageId); - } - - /** - * Shows a pick target dialog and allows the player to pick a target (e.g. - * the pick triggered ability) - * - * @param message - * @param cardView - * @param gameView - * @param targets - * @param required - * @param options - * @param messageId - */ - public void pickTarget(String message, CardsView cardView, GameView gameView, Set targets, boolean required, Map options, int messageId) { - PopUpMenuType popupMenuType = null; - if (options != null) { - if (options.containsKey("targetZone")) { - if (Zone.HAND.equals(options.get("targetZone"))) { // mark selectable target cards in hand - List choosen = null; - if (options.containsKey("chosen")) { - choosen = (List) options.get("chosen"); - } - for (CardView card : gameView.getHand().values()) { - if (targets == null || targets.isEmpty()) { - card.setPlayable(false); - card.setChoosable(true); - } else if (targets.contains(card.getId())) { - card.setPlayable(false); - card.setChoosable(true); - } - if (choosen != null && choosen.contains(card.getId())) { - card.setSelected(true); - } - } - } - } - if (options.containsKey("queryType") && PlayerQueryEvent.QueryType.PICK_ABILITY.equals(options.get("queryType"))) { - popupMenuType = PopUpMenuType.TRIGGER_ORDER; - } - } - updateGame(gameView); - Map options0 = options == null ? new HashMap<>() : options; - ShowCardsDialog dialog = null; - if (cardView != null && cardView.size() > 0) { - dialog = showCards(message, cardView, required, options0, popupMenuType); - options0.put("dialog", dialog); - } - this.feedbackPanel.getFeedback(required ? FeedbackMode.INFORM : FeedbackMode.CANCEL, message, gameView.getSpecial(), options0, messageId); - if (dialog != null) { - this.pickTarget.add(dialog); - } - } - - public void inform(String information, GameView gameView, int messageId) { - updateGame(gameView); - this.feedbackPanel.getFeedback(FeedbackMode.INFORM, information, gameView.getSpecial(), null, messageId); - } - - public void endMessage(String message, int messageId) { - this.feedbackPanel.getFeedback(FeedbackMode.END, message, false, null, messageId); - ArrowBuilder.getBuilder().removeAllArrows(gameId); - } - - public void select(String message, GameView gameView, int messageId, Map options) { - holdingPriority = false; - txtHoldPriority.setVisible(false); - setMenuStates( - PreferencesDialog.getCachedValue(KEY_GAME_MANA_AUTOPAYMENT, "true").equals("true"), - PreferencesDialog.getCachedValue(KEY_GAME_MANA_AUTOPAYMENT_ONLY_ONE, "true").equals("true"), - PreferencesDialog.getCachedValue(KEY_USE_FIRST_MANA_ABILITY, "false").equals("true"), - false); - - updateGame(gameView, options); - boolean controllingPlayer = false; - for (PlayerView playerView : gameView.getPlayers()) { - if (playerView.getPlayerId().equals(playerId)) { - // magenoxx: because of uncaught bug with saving state, rolling back and stack - // undo is allowed only for empty stack - controllingPlayer = !gameView.getPriorityPlayerName().equals(playerView.getName()); - if (playerView.getStatesSavedSize() > 0 && gameView.getStack().isEmpty()) { - feedbackPanel.allowUndo(playerView.getStatesSavedSize()); - } - break; - } - - } - Map panelOptions = new HashMap<>(); - if (options != null) { - panelOptions.putAll(options); - } - panelOptions.put("your_turn", true); - String activePlayerText; - if (gameView.getActivePlayerId().equals(playerId)) { - activePlayerText = "Your turn"; - } else { - activePlayerText = gameView.getActivePlayerName() + "'s turn"; - } - String priorityPlayerText = ""; - if (controllingPlayer) { - priorityPlayerText = " / priority " + gameView.getPriorityPlayerName(); - } - String messageToDisplay = message + FeedbackPanel.getSmallText(activePlayerText + " / " + gameView.getStep().toString() + priorityPlayerText); - this.feedbackPanel.getFeedback(FeedbackMode.SELECT, messageToDisplay, gameView.getSpecial(), panelOptions, messageId); - } - - public void playMana(String message, GameView gameView, Map options, int messageId) { - updateGame(gameView); - DialogManager.getManager(gameId).fadeOut(); - this.feedbackPanel.getFeedback(FeedbackMode.CANCEL, message, gameView.getSpecial(), options, messageId); - } - - public void playXMana(String message, GameView gameView, int messageId) { - updateGame(gameView); - DialogManager.getManager(gameId).fadeOut(); - this.feedbackPanel.getFeedback(FeedbackMode.CONFIRM, message, gameView.getSpecial(), null, messageId); - } - - public void replayMessage(String message) { - //TODO: implement this - } - - public void pickAbility(AbilityPickerView choices) { - hideAll(); - DialogManager.getManager(gameId).fadeOut(); - this.abilityPicker.show(choices, MageFrame.getDesktop().getMousePosition()); - } - - private void hideAll() { - ActionCallback callback = Plugins.getInstance().getActionCallback(); - ((MageActionCallback) callback).hideGameUpdate(gameId); - } - - private ShowCardsDialog showCards(String title, CardsView cards, boolean required, Map options, PopUpMenuType popupMenuType) { - hideAll(); - ShowCardsDialog showCards = new ShowCardsDialog(); - JPopupMenu popupMenu = null; - if (PopUpMenuType.TRIGGER_ORDER.equals(popupMenuType)) { - popupMenu = popupMenuTriggerOrder; - } - showCards.loadCards(title, cards, bigCard, gameId, required, options, popupMenu, getShowCardsEventListener(showCards)); - return showCards; - } - - public void getAmount(int min, int max, String message) { - pickNumber.showDialog(min, max, message); - if (pickNumber.isCancel()) { - SessionHandler.sendPlayerBoolean(gameId, false); - } else { - SessionHandler.sendPlayerInteger(gameId, pickNumber.getAmount()); - } - } - - public void getChoice(Choice choice, UUID objectId) { - hideAll(); - PickChoiceDialog pickChoice = new PickChoiceDialog(); - pickChoice.showDialog(choice, objectId, choiceWindowState); - if (choice.isKeyChoice()) { - if (pickChoice.isAutoSelect()) { - SessionHandler.sendPlayerString(gameId, "#" + choice.getChoiceKey()); - } else { - SessionHandler.sendPlayerString(gameId, choice.getChoiceKey()); - } - } else { - SessionHandler.sendPlayerString(gameId, choice.getChoice()); - } - choiceWindowState = new MageDialogState(pickChoice); - pickChoice.removeDialog(); - } - - public void pickPile(String message, CardsView pile1, CardsView pile2) { - hideAll(); - PickPileDialog pickPileDialog = new PickPileDialog(); - pickPileDialog.loadCards(message, pile1, pile2, bigCard, gameId); - SessionHandler.sendPlayerBoolean(gameId, pickPileDialog.isPickedPile1()); - pickPileDialog.cleanUp(); - pickPileDialog.removeDialog(); - } - - public Map getPlayers() { - return players; - } - - @SuppressWarnings("unchecked") - private void initComponents() { - - abilityPicker = new mage.client.components.ability.AbilityPicker(); - jSplitPane1 = new javax.swing.JSplitPane(); - jSplitPane0 = new javax.swing.JSplitPane(); - jPanel2 = new javax.swing.JPanel(); - pnlHelperHandButtonsStackArea = new javax.swing.JPanel(); - pnlShortCuts = new javax.swing.JPanel(); - lblPhase = new javax.swing.JLabel(); - txtPhase = new javax.swing.JLabel(); - lblStep = new javax.swing.JLabel(); - txtStep = new javax.swing.JLabel(); - lblTurn = new javax.swing.JLabel(); - txtTurn = new javax.swing.JLabel(); - txtActivePlayer = new javax.swing.JLabel(); - lblActivePlayer = new javax.swing.JLabel(); - txtPriority = new javax.swing.JLabel(); - lblPriority = new javax.swing.JLabel(); - feedbackPanel = new mage.client.game.FeedbackPanel(); - - txtSpellsCast = new javax.swing.JLabel(); - Border paddingBorder = BorderFactory.createEmptyBorder(4, 4, 4, 4); - Border border = BorderFactory.createLineBorder(Color.DARK_GRAY, 2); - txtSpellsCast.setBorder(BorderFactory.createCompoundBorder(border, paddingBorder)); - txtSpellsCast.setBackground(Color.LIGHT_GRAY); - txtSpellsCast.setOpaque(true); - txtSpellsCast.setToolTipText("spells cast during the current turn"); - - txtHoldPriority = new javax.swing.JLabel(); - txtHoldPriority.setText("Hold"); - txtHoldPriority.setBorder(BorderFactory.createCompoundBorder(border, paddingBorder)); - txtHoldPriority.setBackground(Color.LIGHT_GRAY); - txtHoldPriority.setOpaque(true); - txtHoldPriority.setToolTipText("Holding priority after the next spell cast or ability activation"); - txtHoldPriority.setVisible(false); - - btnCancelSkip = new javax.swing.JButton(); // F3 - btnSkipToNextTurn = new javax.swing.JButton(); // F4 - btnSkipToEndTurn = new javax.swing.JButton(); // F5 - btnSkipToNextMain = new javax.swing.JButton(); // F7 - btnSkipStack = new javax.swing.JButton(); // F8 - btnSkipToYourTurn = new javax.swing.JButton(); // F9 - btnSkipToEndStepBeforeYourTurn = new javax.swing.JButton(); // F11 - - btnConcede = new javax.swing.JButton(); - btnSwitchHands = new javax.swing.JButton(); - btnStopWatching = new javax.swing.JButton(); - - bigCard = new mage.client.cards.BigCard(); - pnlReplay = new javax.swing.JPanel(); - btnStopReplay = new javax.swing.JButton(); - btnNextPlay = new javax.swing.JButton(); - btnPlay = new javax.swing.JButton(); - btnSkipForward = new javax.swing.JButton(); - btnPreviousPlay = new javax.swing.JButton(); - pnlBattlefield = new javax.swing.JPanel(); - gameChatPanel = new mage.client.chat.ChatPanelBasic(); - gameChatPanel.useExtendedView(ChatPanelBasic.VIEW_MODE.GAME); - userChatPanel = new mage.client.chat.ChatPanelBasic(); - userChatPanel.setParentChat(gameChatPanel); - userChatPanel.useExtendedView(ChatPanelBasic.VIEW_MODE.CHAT); - userChatPanel.setChatType(ChatPanelBasic.ChatType.GAME); - gameChatPanel.setConnectedChat(userChatPanel); - gameChatPanel.disableInput(); - gameChatPanel.setMinimumSize(new java.awt.Dimension(100, 48)); - gameChatPanel.enableHyperlinks(); - jSplitPane2 = new javax.swing.JSplitPane(); - handContainer = new HandPanel(); - handCards = new HashMap<>(); - - pnlShortCuts.setOpaque(false); - pnlShortCuts.setPreferredSize(new Dimension(410, 72)); - - stackObjects = new mage.client.cards.Cards(); - - jSplitPane1.setBorder(null); - jSplitPane1.setDividerSize(7); - jSplitPane1.setResizeWeight(1.0); - jSplitPane1.setOneTouchExpandable(true); - jSplitPane1.setMinimumSize(new java.awt.Dimension(26, 48)); - - jSplitPane0.setBorder(null); - jSplitPane0.setDividerSize(7); - jSplitPane0.setResizeWeight(1.0); - jSplitPane0.setOneTouchExpandable(true); - - restoreDividerLocations(); - - lblPhase.setLabelFor(txtPhase); - lblPhase.setText("Phase:"); - - txtPhase.setText("Phase"); - txtPhase.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(153, 153, 153), 1, true)); - txtPhase.setMinimumSize(new java.awt.Dimension(0, 16)); - - lblStep.setLabelFor(txtStep); - lblStep.setText("Step:"); - - txtStep.setText("Step"); - txtStep.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(153, 153, 153), 1, true)); - txtStep.setMinimumSize(new java.awt.Dimension(0, 16)); - - lblTurn.setLabelFor(txtTurn); - lblTurn.setText("Turn:"); - - txtTurn.setText("Turn"); - txtTurn.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(153, 153, 153), 1, true)); - txtTurn.setMinimumSize(new java.awt.Dimension(0, 16)); - - txtActivePlayer.setText("Active Player"); - txtActivePlayer.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(153, 153, 153), 1, true)); - txtActivePlayer.setMinimumSize(new java.awt.Dimension(0, 16)); - - lblActivePlayer.setLabelFor(txtActivePlayer); - lblActivePlayer.setText("Active Player:"); - - txtPriority.setText("Priority Player"); - txtPriority.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(153, 153, 153), 1, true)); - txtPriority.setMinimumSize(new java.awt.Dimension(0, 16)); - - lblPriority.setLabelFor(txtPriority); - lblPriority.setText("Priority Player:"); - - bigCard.setBorder(new LineBorder(Color.black, 1, true)); - - int c = JComponent.WHEN_IN_FOCUSED_WINDOW; - - KeyStroke ks3 = KeyStroke.getKeyStroke(KeyEvent.VK_F3, 0); - this.getInputMap(c).put(ks3, "F3_PRESS"); - this.getActionMap().put("F3_PRESS", new AbstractAction() { - @Override - public void actionPerformed(ActionEvent actionEvent) { - restorePriorityActionPerformed(actionEvent); - } - }); - - btnCancelSkip.setContentAreaFilled(false); - btnCancelSkip.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); - btnCancelSkip.setIcon(new ImageIcon(ImageManagerImpl.getInstance().getCancelSkipButtonImage())); - btnCancelSkip.setToolTipText("Cancel all skip actions (F3)."); - btnCancelSkip.setFocusable(false); - btnCancelSkip.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent evt) { - if (evt.getButton() == MouseEvent.BUTTON1) { - restorePriorityActionPerformed(null); - } - } - }); - - btnSkipToNextTurn.setContentAreaFilled(false); - btnSkipToNextTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); - btnSkipToNextTurn.setIcon(new ImageIcon(ImageManagerImpl.getInstance().getSkipNextTurnButtonImage())); - btnSkipToNextTurn.setToolTipText("Skip to next turn (F4)."); - btnSkipToNextTurn.setFocusable(false); - btnSkipToNextTurn.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent evt) { - if (evt.getButton() == MouseEvent.BUTTON1) { - btnEndTurnActionPerformed(null); - } - } - }); - - KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_F4, 0); - this.getInputMap(c).put(ks, "F4_PRESS"); - this.getActionMap().put("F4_PRESS", new AbstractAction() { - @Override - public void actionPerformed(ActionEvent actionEvent) { - btnEndTurnActionPerformed(actionEvent); - } - }); - - btnSkipToEndTurn.setContentAreaFilled(false); - btnSkipToEndTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); - btnSkipToEndTurn.setIcon(new ImageIcon(ImageManagerImpl.getInstance().getSkipEndTurnButtonImage())); - btnSkipToEndTurn.setToolTipText("Skip to (opponents/next) end of turn step (F5) - adjust using preferences."); - btnSkipToEndTurn.setFocusable(false); - btnSkipToEndTurn.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent evt) { - if (evt.getButton() == MouseEvent.BUTTON1) { - btnUntilEndOfTurnActionPerformed(null); - } - } - }); - - ks = KeyStroke.getKeyStroke(KeyEvent.VK_F5, 0); - this.getInputMap(c).put(ks, "F5_PRESS"); - this.getActionMap().put("F5_PRESS", new AbstractAction() { - @Override - public void actionPerformed(ActionEvent actionEvent) { - btnUntilEndOfTurnActionPerformed(actionEvent); - } - }); - - ks = KeyStroke.getKeyStroke(KeyEvent.VK_F6, 0); - this.getInputMap(c).put(ks, "F6_PRESS"); - this.getActionMap().put("F6_PRESS", new AbstractAction() { - @Override - public void actionPerformed(ActionEvent actionEvent) { - btnEndTurnSkipStackActionPerformed(actionEvent); - } - }); - - btnSkipToNextMain.setContentAreaFilled(false); - btnSkipToNextMain.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); - btnSkipToNextMain.setIcon(new ImageIcon(ImageManagerImpl.getInstance().getSkipMainButtonImage())); - btnSkipToNextMain.setToolTipText("Skip to (your) next main phase (F7) - adjust using preferences."); - btnSkipToNextMain.setFocusable(false); - btnSkipToNextMain.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent evt) { - if (evt.getButton() == MouseEvent.BUTTON1) { - btnUntilNextMainPhaseActionPerformed(null); - } - } - }); - - ks = KeyStroke.getKeyStroke(KeyEvent.VK_F7, 0); - this.getInputMap(c).put(ks, "F7_PRESS"); - this.getActionMap().put("F7_PRESS", new AbstractAction() { - @Override - public void actionPerformed(ActionEvent actionEvent) { - btnUntilNextMainPhaseActionPerformed(actionEvent); - } - }); - - btnSkipToYourTurn.setContentAreaFilled(false); - btnSkipToYourTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); - btnSkipToYourTurn.setIcon(new ImageIcon(ImageManagerImpl.getInstance().getSkipYourNextTurnButtonImage())); - btnSkipToYourTurn.setToolTipText("Skip to your next turn (F9)."); - btnSkipToYourTurn.setFocusable(false); - btnSkipToYourTurn.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent evt) { - if (evt.getButton() == MouseEvent.BUTTON1) { - btnPassPriorityUntilNextYourTurnActionPerformed(null); - } - } - }); - - KeyStroke ks9 = KeyStroke.getKeyStroke(KeyEvent.VK_F9, 0); - this.getInputMap(c).put(ks9, "F9_PRESS"); - this.getActionMap().put("F9_PRESS", new AbstractAction() { - @Override - public void actionPerformed(ActionEvent actionEvent) { - btnPassPriorityUntilNextYourTurnActionPerformed(actionEvent); - } - }); - - btnSkipToEndStepBeforeYourTurn.setContentAreaFilled(false); - btnSkipToEndStepBeforeYourTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); - btnSkipToEndStepBeforeYourTurn.setIcon(new ImageIcon(ImageManagerImpl.getInstance().getSkipEndStepBeforeYourTurnButtonImage())); - btnSkipToEndStepBeforeYourTurn.setToolTipText("Skip to the end step before your turn (F11) - adjust using preferences."); - btnSkipToEndStepBeforeYourTurn.setFocusable(false); - btnSkipToEndStepBeforeYourTurn.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent evt) { - if (evt.getButton() == MouseEvent.BUTTON1) { - btnSkipToEndStepBeforeYourTurnActionPerformed(null); - } - } - }); - - KeyStroke ks11 = KeyStroke.getKeyStroke(KeyEvent.VK_F11, 0); - this.getInputMap(c).put(ks11, "F11_PRESS"); - this.getActionMap().put("F11_PRESS", new AbstractAction() { - @Override - public void actionPerformed(ActionEvent actionEvent) { - btnSkipToEndStepBeforeYourTurnActionPerformed(actionEvent); - } - }); - - btnSkipStack.setContentAreaFilled(false); - btnSkipStack.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); - btnSkipStack.setIcon(new ImageIcon(ImageManagerImpl.getInstance().getSkipStackButtonImage())); - btnSkipStack.setToolTipText("Skip until stack is resolved (F10)."); - btnSkipStack.setFocusable(false); - btnSkipStack.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent evt) { - if (evt.getButton() == MouseEvent.BUTTON1) { - btnPassPriorityUntilStackResolvedActionPerformed(null); - } - } - }); - - ks = KeyStroke.getKeyStroke(KeyEvent.VK_F10, 0); - this.getInputMap(c).put(ks, "F10_PRESS"); - this.getActionMap().put("F10_PRESS", new AbstractAction() { - @Override - public void actionPerformed(ActionEvent actionEvent) { - btnPassPriorityUntilStackResolvedActionPerformed(actionEvent); - } - }); - - btnConcede.setContentAreaFilled(false); - btnConcede.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); - btnConcede.setIcon(new ImageIcon(ImageManagerImpl.getInstance().getConcedeButtonImage())); - btnConcede.setToolTipText("Concede the current game."); - btnConcede.setFocusable(false); - btnConcede.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent evt) { - if (evt.getButton() == MouseEvent.BUTTON1) { - btnConcedeActionPerformed(null); - } - } - }); - - KeyStroke ks2 = KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0); - this.getInputMap(c).put(ks2, "F2_PRESS"); - this.getActionMap().put("F2_PRESS", new AbstractAction() { - @Override - public void actionPerformed(ActionEvent actionEvent) { - if (feedbackPanel != null) { - feedbackPanel.pressOKYesOrDone(); - } - } - }); - - KeyStroke ksAltE = KeyStroke.getKeyStroke(KeyEvent.VK_E, InputEvent.ALT_MASK); - this.getInputMap(c).put(ksAltE, "ENLARGE"); - this.getActionMap().put("ENLARGE", new AbstractAction() { - @Override - public void actionPerformed(ActionEvent actionEvent) { - ActionCallback callback = Plugins.getInstance().getActionCallback(); - ((MageActionCallback) callback).enlargeCard(EnlargeMode.NORMAL); - } - }); - - KeyStroke ksAltS = KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.ALT_MASK); - this.getInputMap(c).put(ksAltS, "ENLARGE_SOURCE"); - this.getActionMap().put("ENLARGE_SOURCE", new AbstractAction() { - @Override - public void actionPerformed(ActionEvent actionEvent) { - ActionCallback callback = Plugins.getInstance().getActionCallback(); - ((MageActionCallback) callback).enlargeCard(EnlargeMode.ALTERNATE); - } - }); - - KeyStroke ksAltD = KeyStroke.getKeyStroke(KeyEvent.VK_D, InputEvent.ALT_MASK); - this.getInputMap(c).put(ksAltD, "BIG_IMAGE"); - this.getActionMap().put("BIG_IMAGE", new AbstractAction() { - @Override - public void actionPerformed(ActionEvent actionEvent) { - imagePanelState = !imagePanelState; - if (!imagePanelState) { - jSplitPane0.resetToPreferredSizes(); - jSplitPane0.setDividerLocation(jSplitPane0.getSize().width - jSplitPane0.getInsets().right - jSplitPane0.getDividerSize() - 260); - } else { - jSplitPane0.setDividerLocation(1.0); - } - } - }); - - KeyStroke ksAlt1 = KeyStroke.getKeyStroke(KeyEvent.VK_1, InputEvent.ALT_MASK); - this.getInputMap(c).put(ksAlt1, "USEFIRSTMANAABILITY"); - this.getActionMap().put("USEFIRSTMANAABILITY", new AbstractAction() { - @Override - public void actionPerformed(ActionEvent actionEvent) { - SessionHandler.sendPlayerAction(PlayerAction.USE_FIRST_MANA_ABILITY_ON, gameId, null); - setMenuStates( - PreferencesDialog.getCachedValue(KEY_GAME_MANA_AUTOPAYMENT, "true").equals("true"), - PreferencesDialog.getCachedValue(KEY_GAME_MANA_AUTOPAYMENT_ONLY_ONE, "true").equals("true"), - PreferencesDialog.getCachedValue(KEY_USE_FIRST_MANA_ABILITY, "false").equals("true"), - holdingPriority); - } - }); - - final BasicSplitPaneUI myUi = (BasicSplitPaneUI) jSplitPane0.getUI(); - final BasicSplitPaneDivider divider = myUi.getDivider(); - final JButton upArrowButton = (JButton) divider.getComponent(0); - upArrowButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent actionEvent) { - PreferencesDialog.saveValue(PreferencesDialog.KEY_BIG_CARD_TOGGLED, "up"); - } - }); - - final JButton downArrowButton = (JButton) divider.getComponent(1); - downArrowButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent actionEvent) { - PreferencesDialog.saveValue(PreferencesDialog.KEY_BIG_CARD_TOGGLED, "down"); - } - }); - - KeyStroke ksAltEReleased = KeyStroke.getKeyStroke(KeyEvent.VK_E, InputEvent.ALT_MASK, true); - this.getInputMap(c).put(ksAltEReleased, "ENLARGE_RELEASE"); - KeyStroke ksAltSReleased = KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.ALT_MASK, true); - this.getInputMap(c).put(ksAltSReleased, "ENLARGE_RELEASE"); - this.getActionMap().put("ENLARGE_RELEASE", new AbstractAction() { - @Override - public void actionPerformed(ActionEvent actionEvent) { - ActionCallback callback = Plugins.getInstance().getActionCallback(); - ((MageActionCallback) callback).hideEnlargedCard(); - } - }); - - KeyStroke ksAlt1Released = KeyStroke.getKeyStroke(KeyEvent.VK_1, InputEvent.ALT_MASK, true); - this.getInputMap(c).put(ksAlt1Released, "USEFIRSTMANAABILITY_RELEASE"); - this.getActionMap().put("USEFIRSTMANAABILITY_RELEASE", new AbstractAction() { - @Override - public void actionPerformed(ActionEvent actionEvent) { - SessionHandler.sendPlayerAction(PlayerAction.USE_FIRST_MANA_ABILITY_OFF, gameId, null); - setMenuStates( - PreferencesDialog.getCachedValue(KEY_GAME_MANA_AUTOPAYMENT, "true").equals("true"), - PreferencesDialog.getCachedValue(KEY_GAME_MANA_AUTOPAYMENT_ONLY_ONE, "true").equals("true"), - PreferencesDialog.getCachedValue(KEY_USE_FIRST_MANA_ABILITY, "false").equals("true"), - holdingPriority); - } - }); - - btnSwitchHands.setContentAreaFilled(false); - btnSwitchHands.setBorder(new EmptyBorder(0, 0, 0, 0)); - btnSwitchHands.setIcon(new ImageIcon(ImageManagerImpl.getInstance().getSwitchHandsButtonImage())); - btnSwitchHands.setFocusable(false); - btnSwitchHands.setToolTipText("Switch between your hand cards and hand cards of controlled players."); - btnSwitchHands.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent evt) { - if (evt.getButton() == MouseEvent.BUTTON1) { - btnSwitchHandActionPerformed(null); - } - } - }); - - btnStopWatching.setContentAreaFilled(false); - btnStopWatching.setBorder(new EmptyBorder(0, 0, 0, 0)); - btnStopWatching.setIcon(new ImageIcon(ImageManagerImpl.getInstance().getStopWatchButtonImage())); - btnStopWatching.setFocusable(false); - btnStopWatching.setToolTipText("Stop watching this game."); - btnStopWatching.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent evt) { - if (evt.getButton() == MouseEvent.BUTTON1) { - btnStopWatchingActionPerformed(null); - } - } - }); - - stackObjects.setBackgroundColor(new Color(0, 0, 0, 40)); - - btnStopReplay.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/control_stop.png"))); - btnStopReplay.addActionListener(new java.awt.event.ActionListener() { - @Override - public void actionPerformed(java.awt.event.ActionEvent evt) { - btnStopReplayActionPerformed(evt); - } - }); - - btnNextPlay.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/control_stop_right.png"))); - btnNextPlay.addActionListener(new java.awt.event.ActionListener() { - @Override - public void actionPerformed(java.awt.event.ActionEvent evt) { - btnNextPlayActionPerformed(evt); - } - }); - - btnPlay.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/control_right.png"))); - btnPlay.addActionListener(new java.awt.event.ActionListener() { - @Override - public void actionPerformed(java.awt.event.ActionEvent evt) { - btnPlayActionPerformed(evt); - } - }); - - btnSkipForward.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/control_double_stop_right.png"))); - btnSkipForward.addActionListener(new java.awt.event.ActionListener() { - @Override - public void actionPerformed(java.awt.event.ActionEvent evt) { - btnSkipForwardActionPerformed(evt); - } - }); - - btnPreviousPlay.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/control_stop_left.png"))); - btnPreviousPlay.addActionListener(new java.awt.event.ActionListener() { - @Override - public void actionPerformed(java.awt.event.ActionEvent evt) { - btnPreviousPlayActionPerformed(evt); - } - }); - - initPopupMenuTriggerOrder(); - - setGUISize(); - - // Replay panel to control replay of games - javax.swing.GroupLayout gl_pnlReplay = new javax.swing.GroupLayout(pnlReplay); - pnlReplay.setLayout(gl_pnlReplay); - gl_pnlReplay.setHorizontalGroup( - gl_pnlReplay.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(gl_pnlReplay.createSequentialGroup() - .addComponent(btnPreviousPlay, javax.swing.GroupLayout.PREFERRED_SIZE, 41, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnPlay, javax.swing.GroupLayout.PREFERRED_SIZE, 35, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(btnStopReplay, javax.swing.GroupLayout.PREFERRED_SIZE, 38, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnNextPlay, javax.swing.GroupLayout.PREFERRED_SIZE, 36, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnSkipForward, javax.swing.GroupLayout.PREFERRED_SIZE, 39, javax.swing.GroupLayout.PREFERRED_SIZE)) - ); - gl_pnlReplay.setVerticalGroup( - gl_pnlReplay.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(btnSkipForward, 0, 0, Short.MAX_VALUE) - .addComponent(btnNextPlay, 0, 0, Short.MAX_VALUE) - .addComponent(btnStopReplay, 0, 0, Short.MAX_VALUE) - .addComponent(btnPlay, 0, 0, Short.MAX_VALUE) - .addComponent(btnPreviousPlay, javax.swing.GroupLayout.PREFERRED_SIZE, 31, Short.MAX_VALUE) - ); - - // Game info panel (buttons on the right panel) - javax.swing.GroupLayout gl_pnlShortCuts = new javax.swing.GroupLayout(pnlShortCuts); - pnlShortCuts.setLayout(gl_pnlShortCuts); - gl_pnlShortCuts.setHorizontalGroup(gl_pnlShortCuts.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(gl_pnlShortCuts.createSequentialGroup() - .addComponent(btnSkipToNextTurn) - .addComponent(btnSkipToEndTurn) - .addComponent(btnSkipToNextMain) - .addComponent(btnSkipToYourTurn) - .addComponent(btnSkipStack) - .addComponent(btnSkipToEndStepBeforeYourTurn) - ) - .addGroup(gl_pnlShortCuts.createSequentialGroup() - .addComponent(txtHoldPriority) - .addComponent(txtSpellsCast) - .addComponent(btnSwitchHands) - .addComponent(btnCancelSkip) - .addComponent(btnConcede) - .addComponent(btnStopWatching) - ) - //.addComponent(bigCard, javax.swing.GroupLayout.DEFAULT_SIZE, 256, Short.MAX_VALUE) - //.addComponent(feedbackPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 256, Short.MAX_VALUE) - //.addComponent(stack, javax.swing.GroupLayout.DEFAULT_SIZE, 256, Short.MAX_VALUE) - - .addGroup(gl_pnlShortCuts.createSequentialGroup() - .addContainerGap() - .addComponent(pnlReplay, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(51, Short.MAX_VALUE)) - ); - gl_pnlShortCuts.setVerticalGroup(gl_pnlShortCuts.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(gl_pnlShortCuts.createSequentialGroup() - //.addComponent(bigCard, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - //.addGap(1, 1, 1) - //.addComponent(feedbackPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 109, javax.swing.GroupLayout.PREFERRED_SIZE) - //.addComponent(stack, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 164, Short.MAX_VALUE) - .addComponent(pnlReplay, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(gl_pnlShortCuts.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(btnSkipToNextTurn) - .addComponent(btnSkipToEndTurn) - .addComponent(btnSkipToNextMain) - .addComponent(btnSkipToYourTurn) - .addComponent(btnSkipStack) - .addComponent(btnSkipToEndStepBeforeYourTurn) - ) - .addGroup(gl_pnlShortCuts.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(txtHoldPriority) - .addComponent(txtSpellsCast) - .addComponent(btnSwitchHands) - .addComponent(btnCancelSkip) - .addComponent(btnConcede) - .addComponent(btnStopWatching) - ) - ) - ); - - pnlBattlefield.setLayout(new java.awt.GridBagLayout()); - - jPhases = new JPanel(); - jPhases.setBackground(new Color(0, 0, 0, 0)); - jPhases.setLayout(null); - jPhases.setPreferredSize(new Dimension(X_PHASE_WIDTH, 435)); - - MouseAdapter phasesMouseAdapter = new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent evt) { - mouseClickPhaseBar(evt); - } - }; - String[] phases = {"Untap", "Upkeep", "Draw", "Main1", - "Combat_Start", "Combat_Attack", "Combat_Block", "Combat_Damage", "Combat_End", - "Main2", "Cleanup", "Next_Turn"}; - for (String name : phases) { - createPhaseButton(name, phasesMouseAdapter); - } - - int i = 0; - for (String name : hoverButtons.keySet()) { - HoverButton hoverButton = hoverButtons.get(name); - hoverButton.setAlignmentX(LEFT_ALIGNMENT); - hoverButton.setBounds(X_PHASE_WIDTH - 36, i * 36, 36, 36); - jPhases.add(hoverButton); - i++; - } - jPhases.addMouseListener(phasesMouseAdapter); - - pnlReplay.setOpaque(false); - - helper = new HelperPanel(); - feedbackPanel.setHelperPanel(helper); - - jSplitPane2.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT); - jSplitPane2.setResizeWeight(0.5); - jSplitPane2.setLeftComponent(userChatPanel); - jSplitPane2.setBottomComponent(gameChatPanel); - - phasesContainer = new JPanel(); - phasesContainer.setLayout(new RelativeLayout(RelativeLayout.Y_AXIS)); - phasesContainer.setBackground(new Color(0, 0, 0, 0)); - Float ratio = (float) 1; - JPanel empty1 = new JPanel(); - empty1.setBackground(new Color(0, 0, 0, 0)); - phasesContainer.add(empty1, ratio); - phasesContainer.add(jPhases); - - javax.swing.GroupLayout gl_helperHandButtonsStackArea = new javax.swing.GroupLayout(pnlHelperHandButtonsStackArea); - gl_helperHandButtonsStackArea.setHorizontalGroup( - gl_helperHandButtonsStackArea.createParallelGroup(Alignment.LEADING) - .addGroup(gl_helperHandButtonsStackArea.createSequentialGroup() - // .addGap(0) - .addGroup(gl_helperHandButtonsStackArea.createParallelGroup(Alignment.LEADING) - .addGroup(gl_helperHandButtonsStackArea.createSequentialGroup() - .addGroup(gl_helperHandButtonsStackArea.createParallelGroup(Alignment.LEADING) - .addComponent(helper, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(handContainer, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - ) - .addGroup(gl_helperHandButtonsStackArea.createParallelGroup(Alignment.LEADING) - .addComponent(pnlShortCuts, 410, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE) - .addComponent(stackObjects, 410, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE) - ) - ) - .addGap(0) - //.addComponent(jPhases, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(gl_helperHandButtonsStackArea.createSequentialGroup() - .addComponent(pnlBattlefield, GroupLayout.DEFAULT_SIZE, 200, Short.MAX_VALUE) - .addComponent(phasesContainer, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) - ))) - ); - gl_helperHandButtonsStackArea.setVerticalGroup( - gl_helperHandButtonsStackArea.createParallelGroup(Alignment.TRAILING) - .addGroup(gl_helperHandButtonsStackArea.createSequentialGroup() - .addGroup(gl_helperHandButtonsStackArea.createParallelGroup(Alignment.LEADING) - .addComponent(pnlBattlefield, GroupLayout.DEFAULT_SIZE, 200, Short.MAX_VALUE) - .addComponent(phasesContainer, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) - ) - //.addPreferredGap(ComponentPlacement.RELATED) - .addGroup(gl_helperHandButtonsStackArea.createParallelGroup(Alignment.LEADING) - .addGroup(gl_helperHandButtonsStackArea.createSequentialGroup() - .addGap(2) - .addComponent(pnlShortCuts, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) - .addComponent(stackObjects, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) - ) - .addGroup(gl_helperHandButtonsStackArea.createSequentialGroup() - .addComponent(helper, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) - .addComponent(handContainer, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) - ) - ) - ) - ); - pnlHelperHandButtonsStackArea.setLayout(gl_helperHandButtonsStackArea); - - jSplitPane1.setLeftComponent(pnlHelperHandButtonsStackArea); - jSplitPane1.setRightComponent(jSplitPane2); - - // Set individual area sizes of big card pane - GridBagLayout gbl = new GridBagLayout(); - jPanel2.setLayout(gbl); - - GridBagConstraints gbc = new GridBagConstraints(); - gbc.fill = GridBagConstraints.BOTH; - gbc.gridx = 0; - gbc.gridy = 0; - gbc.gridwidth = 1; - gbc.gridheight = 4; // size 4/5 - gbc.weightx = 1.0; - gbc.weighty = 1.0; - gbl.setConstraints(bigCard, gbc); - jPanel2.add(bigCard); - - jPanel2.setOpaque(false); - - // game pane and chat/log pane - jSplitPane0.setLeftComponent(jSplitPane1); - // big card and buttons - jSplitPane0.setRightComponent(jPanel2); - - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); - this.setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jSplitPane0, javax.swing.GroupLayout.DEFAULT_SIZE, 1078, Short.MAX_VALUE) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jSplitPane0, javax.swing.GroupLayout.DEFAULT_SIZE, 798, Short.MAX_VALUE) - ); - } - - private void removeListener() { - for (MouseListener ml : this.getMouseListeners()) { - this.removeMouseListener(ml); - } - for (MouseListener ml : this.btnCancelSkip.getMouseListeners()) { - this.btnCancelSkip.removeMouseListener(ml); - } - for (MouseListener ml : this.btnConcede.getMouseListeners()) { - this.btnConcede.removeMouseListener(ml); - } - for (MouseListener ml : this.btnSkipToYourTurn.getMouseListeners()) { - this.btnSkipToYourTurn.removeMouseListener(ml); - } - for (MouseListener ml : this.btnSkipStack.getMouseListeners()) { - this.btnSkipStack.removeMouseListener(ml); - } - for (MouseListener ml : this.btnSkipToEndStepBeforeYourTurn.getMouseListeners()) { - this.btnSkipToEndStepBeforeYourTurn.removeMouseListener(ml); - } - for (MouseListener ml : this.btnSkipToEndTurn.getMouseListeners()) { - this.btnSkipToEndTurn.removeMouseListener(ml); - } - for (MouseListener ml : this.btnSkipToNextMain.getMouseListeners()) { - this.btnSkipToNextMain.removeMouseListener(ml); - } - for (MouseListener ml : this.btnSkipToNextTurn.getMouseListeners()) { - this.btnSkipToNextTurn.removeMouseListener(ml); - } - for (MouseListener ml : this.btnSwitchHands.getMouseListeners()) { - this.btnSwitchHands.removeMouseListener(ml); - } - for (MouseListener ml : this.btnStopWatching.getMouseListeners()) { - this.btnStopWatching.removeMouseListener(ml); - } - for (MouseListener ml : this.jPhases.getMouseListeners()) { - this.jPhases.removeMouseListener(ml); - } - for (String name : hoverButtons.keySet()) { - HoverButton hoverButton = hoverButtons.get(name); - for (MouseListener ml : hoverButton.getMouseListeners()) { - hoverButton.removeMouseListener(ml); - } - } - for (ActionListener al : this.btnPlay.getActionListeners()) { - this.btnPlay.removeActionListener(al); - } - for (ActionListener al : this.btnStopReplay.getActionListeners()) { - this.btnStopReplay.removeActionListener(al); - } - for (ActionListener al : this.btnNextPlay.getActionListeners()) { - this.btnNextPlay.removeActionListener(al); - } - for (ActionListener al : this.btnNextPlay.getActionListeners()) { - this.btnNextPlay.removeActionListener(al); - } - for (ActionListener al : this.btnPreviousPlay.getActionListeners()) { - this.btnPreviousPlay.removeActionListener(al); - } - for (ActionListener al : this.btnSkipForward.getActionListeners()) { - this.btnSkipForward.removeActionListener(al); - } - - final BasicSplitPaneUI myUi = (BasicSplitPaneUI) jSplitPane0.getUI(); - final BasicSplitPaneDivider divider = myUi.getDivider(); - final JButton upArrowButton = (JButton) divider.getComponent(0); - for (ActionListener al : upArrowButton.getActionListeners()) { - upArrowButton.removeActionListener(al); - } - final JButton downArrowButton = (JButton) divider.getComponent(1); - for (ActionListener al : downArrowButton.getActionListeners()) { - downArrowButton.removeActionListener(al); - } - - for (ComponentListener cl : this.getComponentListeners()) { - this.removeComponentListener(cl); - } - } - - private void btnConcedeActionPerformed(java.awt.event.ActionEvent evt) { - UserRequestMessage message = new UserRequestMessage("Confirm concede", "Are you sure you want to concede?"); - message.setButton1("No", null); - message.setButton2("Yes", PlayerAction.CLIENT_CONCEDE_GAME); - message.setGameId(gameId); - MageFrame.getInstance().showUserRequestDialog(message); - } - - private void btnEndTurnActionPerformed(java.awt.event.ActionEvent evt) { - SessionHandler.sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_NEXT_TURN, gameId, null); - AudioManager.playOnSkipButton(); - updateSkipButtons(true, false, false, false, false, false); - } - - private void btnUntilEndOfTurnActionPerformed(java.awt.event.ActionEvent evt) { - SessionHandler.sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_TURN_END_STEP, gameId, null); - AudioManager.playOnSkipButton(); - updateSkipButtons(false, true, false, false, false, false); - } - - private void btnEndTurnSkipStackActionPerformed(java.awt.event.ActionEvent evt) { - SessionHandler.sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_NEXT_TURN_SKIP_STACK, gameId, null); - AudioManager.playOnSkipButton(); - updateSkipButtons(true, false, false, false, true, false); - } - - private void btnUntilNextMainPhaseActionPerformed(java.awt.event.ActionEvent evt) { - SessionHandler.sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_NEXT_MAIN_PHASE, gameId, null); - AudioManager.playOnSkipButton(); - updateSkipButtons(false, false, true, false, false, false); - } - - private void btnPassPriorityUntilNextYourTurnActionPerformed(java.awt.event.ActionEvent evt) { - SessionHandler.sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_MY_NEXT_TURN, gameId, null); - AudioManager.playOnSkipButton(); - updateSkipButtons(false, false, false, true, false, false); - } - - private void btnPassPriorityUntilStackResolvedActionPerformed(java.awt.event.ActionEvent evt) { - SessionHandler.sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_STACK_RESOLVED, gameId, null); - AudioManager.playOnSkipButton(); - updateSkipButtons(false, false, false, false, true, false); - } - - private void btnSkipToEndStepBeforeYourTurnActionPerformed(java.awt.event.ActionEvent evt) { - SessionHandler.sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_END_STEP_BEFORE_MY_NEXT_TURN, gameId, null); - AudioManager.playOnSkipButton(); - updateSkipButtons(false, false, false, false, false, true); - } - - private void restorePriorityActionPerformed(java.awt.event.ActionEvent evt) { - SessionHandler.sendPlayerAction(PlayerAction.PASS_PRIORITY_CANCEL_ALL_ACTIONS, gameId, null); - AudioManager.playOnSkipButtonCancel(); - updateSkipButtons(false, false, false, false, false, false); - } - - private void mouseClickPhaseBar(MouseEvent evt) { - if (evt.getButton() == MouseEvent.BUTTON1) { // Left button - PreferencesDialog.main(new String[]{PreferencesDialog.OPEN_PHASES_TAB}); - } - } - - private void btnSwitchHandActionPerformed(java.awt.event.ActionEvent evt) { - String[] choices = handCards.keySet().toArray(new String[0]); - - String newChosenHandKey = (String) JOptionPane.showInputDialog( - this, - "Choose hand to display:", "Switch between hands", - JOptionPane.PLAIN_MESSAGE, - null, - choices, - this.chosenHandKey); - - if (newChosenHandKey != null && newChosenHandKey.length() > 0) { - this.chosenHandKey = newChosenHandKey; - CardsView cards = handCards.get(chosenHandKey); - handContainer.loadCards(cards, bigCard, gameId); - } - } + private static final Logger logger = Logger.getLogger(GamePanel.class); + private static final String YOUR_HAND = "Your hand"; + private static final int X_PHASE_WIDTH = 55; + private static final int STACK_MIN_CARDS_OFFSET_Y = 7; // TODO: Size bui GUISize value + + private static final String CMD_AUTO_ORDER_FIRST = "cmdAutoOrderFirst"; + private static final String CMD_AUTO_ORDER_LAST = "cmdAutoOrderLast"; + private static final String CMD_AUTO_ORDER_NAME_FIRST = "cmdAutoOrderNameFirst"; + private static final String CMD_AUTO_ORDER_NAME_LAST = "cmdAutoOrderNameLast"; + private static final String CMD_AUTO_ORDER_RESET_ALL = "cmdAutoOrderResetAll"; + + private final Map players = new HashMap<>(); + private final Map playersWhoLeft = new HashMap<>(); + + // non modal frames + private final Map exiles = new HashMap<>(); + private final Map revealed = new HashMap<>(); + private final Map lookedAt = new HashMap<>(); + private final Map graveyardWindows = new HashMap<>(); + private final Map graveyards = new HashMap<>(); + + private final ArrayList pickTarget = new ArrayList<>(); + private UUID gameId; + private UUID playerId; // playerId of the player + GamePane gamePane; + private ReplayTask replayTask; + private final PickNumberDialog pickNumber; + private JLayeredPane jLayeredPane; + private String chosenHandKey = "You"; + private boolean smallMode = false; + private boolean initialized = false; + + private boolean menuNameSet = false; + private boolean handCardsOfOpponentAvailable = false; + + private Map loadedCards = new HashMap<>(); + + private int storedHeight; + private Map hoverButtons; + + private MageDialogState choiceWindowState; + + private boolean initComponents; + + private Timer resizeTimer; + + private enum PopUpMenuType { + + TRIGGER_ORDER + } + // CardView popupMenu was invoked last + private CardView cardViewPopupMenu; + + // popup menu for triggered abilities order + private JPopupMenu popupMenuTriggerOrder; + + public GamePanel() { + initComponents = true; + initComponents(); + + pickNumber = new PickNumberDialog(); + MageFrame.getDesktop().add(pickNumber, JLayeredPane.MODAL_LAYER); + + this.feedbackPanel.setConnectedChatPanel(this.userChatPanel); + + this.stackObjects.setMinOffsetY(STACK_MIN_CARDS_OFFSET_Y); + + // Override layout (I can't edit generated code) + this.setLayout(new BorderLayout()); + final JLayeredPane jLayeredBackgroundPane = new JLayeredPane(); + jLayeredBackgroundPane.setSize(1024, 768); + this.add(jLayeredBackgroundPane); + jLayeredBackgroundPane.add(jSplitPane0, JLayeredPane.DEFAULT_LAYER); + + Map myUi = getUIComponents(jLayeredBackgroundPane); + Plugins.getInstance().updateGamePanel(myUi); + + // Enlarge jlayeredpane on resize of game panel + addComponentListener(new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent e) { + int width = ((JComponent) e.getSource()).getWidth(); + int height = ((JComponent) e.getSource()).getHeight(); + jLayeredBackgroundPane.setSize(width, height); + jSplitPane0.setSize(width, height); + + if (height < storedHeight) { + pnlBattlefield.setSize(0, 200); + } + storedHeight = height; + + sizeToScreen(); + + if (!initialized) { + String state = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_BIG_CARD_TOGGLED, null); + if (state != null && state.equals("down")) { + jSplitPane0.setDividerLocation(1.0); + } + initialized = true; + } + + } + }); + // Resize the width of the stack area if the size of the play area is changed + ComponentAdapter componentAdapterPlayField = new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent e) { + if (!initComponents) { + if (resizeTimer.isRunning()) { + resizeTimer.restart(); + } else { + resizeTimer.start(); + } + } + } + }; + + resizeTimer = new Timer(1000, new ActionListener() { + @Override + public void actionPerformed(ActionEvent evt) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + resizeTimer.stop(); + setGUISize(); + feedbackPanel.changeGUISize(); + + } + }); + } + }); + + pnlHelperHandButtonsStackArea.addComponentListener(componentAdapterPlayField); + initComponents = false; + } + + private Map getUIComponents(JLayeredPane jLayeredPane) { + Map components = new HashMap<>(); + + components.put("jSplitPane1", jSplitPane1); + components.put("pnlBattlefield", pnlBattlefield); + components.put("pnlHelperHandButtonsStackArea", pnlHelperHandButtonsStackArea); + components.put("hand", handContainer); + components.put("gameChatPanel", gameChatPanel); + components.put("userChatPanel", userChatPanel); + components.put("jLayeredPane", jLayeredPane); + components.put("gamePanel", this); + + return components; + } + + public void cleanUp() { + MageFrame.removeGame(gameId); + saveDividerLocations(); + this.gameChatPanel.disconnect(); + this.userChatPanel.disconnect(); + + this.removeListener(); + + this.handContainer.cleanUp(); + this.stackObjects.cleanUp(); + for (Map.Entry playAreaPanelEntry : players.entrySet()) { + playAreaPanelEntry.getValue().CleanUp(); + } + this.players.clear(); + this.playersWhoLeft.clear(); + + jLayeredPane.remove(abilityPicker); + this.abilityPicker.cleanUp(); + + jLayeredPane.remove(DialogManager.getManager(gameId)); + DialogManager.removeGame(gameId); + + if (pickNumber != null) { + pickNumber.removeDialog(); + } + for (CardInfoWindowDialog exileDialog : exiles.values()) { + exileDialog.cleanUp(); + exileDialog.removeDialog(); + } + for (CardInfoWindowDialog graveyardDialog : graveyardWindows.values()) { + graveyardDialog.cleanUp(); + graveyardDialog.removeDialog(); + } + for (CardInfoWindowDialog revealDialog : revealed.values()) { + revealDialog.cleanUp(); + revealDialog.removeDialog(); + } + for (CardInfoWindowDialog lookedAtDialog : lookedAt.values()) { + lookedAtDialog.cleanUp(); + lookedAtDialog.removeDialog(); + } + for (ShowCardsDialog pickTargetDialog : pickTarget) { + pickTargetDialog.cleanUp(); + pickTargetDialog.removeDialog(); + } + Plugins.getInstance().getActionCallback().hideTooltipPopup(); + try { + Component popupContainer = MageFrame.getUI().getComponent(MageComponents.POPUP_CONTAINER); + popupContainer.setVisible(false); + } catch (InterruptedException ex) { + logger.fatal("popupContainer error:", ex); + } + jPanel2.remove(bigCard); + this.bigCard = null; + } + + public void changeGUISize() { + initComponents = true; + setGUISize(); + stackObjects.changeGUISize(); + feedbackPanel.changeGUISize(); + handContainer.changeGUISize(); + for (PlayAreaPanel playAreaPanel : players.values()) { + playAreaPanel.changeGUISize(); + } + + for (CardInfoWindowDialog cardInfoWindowDialog : exiles.values()) { + cardInfoWindowDialog.changeGUISize(); + } + for (CardInfoWindowDialog cardInfoWindowDialog : revealed.values()) { + cardInfoWindowDialog.changeGUISize(); + } + for (CardInfoWindowDialog cardInfoWindowDialog : lookedAt.values()) { + cardInfoWindowDialog.changeGUISize(); + } + for (CardInfoWindowDialog cardInfoWindowDialog : graveyardWindows.values()) { + cardInfoWindowDialog.changeGUISize(); + } + for (ShowCardsDialog showCardsDialog : pickTarget) { + showCardsDialog.changeGUISize(); + } + + this.revalidate(); + this.repaint(); + initComponents = false; + } + + private void setGUISize() { + jSplitPane0.setDividerSize(GUISizeHelper.dividerBarSize); + jSplitPane1.setDividerSize(GUISizeHelper.dividerBarSize); + jSplitPane2.setDividerSize(GUISizeHelper.dividerBarSize); + stackObjects.setCardDimension(GUISizeHelper.handCardDimension); + + txtSpellsCast.setFont(new Font(GUISizeHelper.gameDialogAreaFont.getFontName(), Font.BOLD, GUISizeHelper.gameDialogAreaFont.getSize())); + txtHoldPriority.setFont(new Font(GUISizeHelper.gameDialogAreaFont.getFontName(), Font.BOLD, GUISizeHelper.gameDialogAreaFont.getSize())); + GUISizeHelper.changePopupMenuFont(popupMenuTriggerOrder); + + int newStackWidth = pnlHelperHandButtonsStackArea.getWidth() * GUISizeHelper.stackWidth / 100; + if (newStackWidth < 410) { + newStackWidth = 410; + } + Dimension newDimension = new Dimension(pnlHelperHandButtonsStackArea.getWidth() - newStackWidth, GUISizeHelper.handCardDimension.height + GUISizeHelper.scrollBarSize); + handContainer.setPreferredSize(newDimension); + handContainer.setMaximumSize(newDimension); + + newDimension = new Dimension(newStackWidth, STACK_MIN_CARDS_OFFSET_Y + GUISizeHelper.handCardDimension.height + GUISizeHelper.scrollBarSize); + stackObjects.setPreferredSize(newDimension); + stackObjects.setMinimumSize(newDimension); + stackObjects.setMaximumSize(newDimension); + + newDimension = new Dimension(newStackWidth, (int) pnlShortCuts.getPreferredSize().getHeight()); + pnlShortCuts.setPreferredSize(newDimension); + pnlShortCuts.setMinimumSize(newDimension); + pnlShortCuts.setMaximumSize(newDimension); + } + + private void saveDividerLocations() { + // save panel sizes and divider locations. + Rectangle rec = MageFrame.getDesktop().getBounds(); + String sb = Double.toString(rec.getWidth()) + "x" + Double.toString(rec.getHeight()); + PreferencesDialog.saveValue(PreferencesDialog.KEY_MAGE_PANEL_LAST_SIZE, sb); + PreferencesDialog.saveValue(PreferencesDialog.KEY_GAMEPANEL_DIVIDER_LOCATION_0, Integer.toString(this.jSplitPane0.getDividerLocation())); + PreferencesDialog.saveValue(PreferencesDialog.KEY_GAMEPANEL_DIVIDER_LOCATION_1, Integer.toString(this.jSplitPane1.getDividerLocation())); + PreferencesDialog.saveValue(PreferencesDialog.KEY_GAMEPANEL_DIVIDER_LOCATION_2, Integer.toString(this.jSplitPane2.getDividerLocation())); + } + + private void restoreDividerLocations() { + Rectangle rec = MageFrame.getDesktop().getBounds(); + if (rec != null) { + String size = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_MAGE_PANEL_LAST_SIZE, null); + String sb = Double.toString(rec.getWidth()) + "x" + Double.toString(rec.getHeight()); + // use divider positions only if screen size is the same as it was the time the settings were saved + if (size != null && size.equals(sb)) { + + String location = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAMEPANEL_DIVIDER_LOCATION_0, null); + if (location != null && jSplitPane0 != null) { + jSplitPane0.setDividerLocation(Integer.parseInt(location)); + } + location = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAMEPANEL_DIVIDER_LOCATION_1, null); + if (location != null && jSplitPane1 != null) { + jSplitPane1.setDividerLocation(Integer.parseInt(location)); + } + location = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAMEPANEL_DIVIDER_LOCATION_2, null); + if (location != null && jSplitPane2 != null) { + jSplitPane2.setDividerLocation(Integer.parseInt(location)); + } + } + } + } + + private void sizeToScreen() { + Rectangle rect = this.getBounds(); + + if (rect.height < 720) { + if (!smallMode) { + smallMode = true; + Dimension bbDimension = new Dimension(128, 184); + bigCard.setMaximumSize(bbDimension); + bigCard.setMinimumSize(bbDimension); + bigCard.setPreferredSize(bbDimension); + pnlShortCuts.revalidate(); + pnlShortCuts.repaint(); + for (PlayAreaPanel p : players.values()) { + p.sizePlayer(smallMode); + } + } + } else if (smallMode) { + smallMode = false; + Dimension bbDimension = new Dimension(256, 367); + bigCard.setMaximumSize(bbDimension); + bigCard.setMinimumSize(bbDimension); + bigCard.setPreferredSize(bbDimension); + pnlShortCuts.revalidate(); + pnlShortCuts.repaint(); + for (PlayAreaPanel p : players.values()) { + p.sizePlayer(smallMode); + } + } + + ArrowBuilder.getBuilder().setSize(rect.width, rect.height); + + DialogManager.getManager(gameId).setScreenWidth(rect.width); + DialogManager.getManager(gameId).setScreenHeight(rect.height); + DialogManager.getManager(gameId).setBounds(0, 0, rect.width, rect.height); + } + + public synchronized void showGame(UUID gameId, UUID playerId, GamePane gamePane) { + this.gameId = gameId; + this.gamePane = gamePane; + this.playerId = playerId; + MageFrame.addGame(gameId, this); + this.feedbackPanel.init(gameId); + this.feedbackPanel.clear(); + this.abilityPicker.init(gameId); + + this.btnConcede.setVisible(true); + this.btnStopWatching.setVisible(false); + this.btnSwitchHands.setVisible(false); + this.btnCancelSkip.setVisible(true); + + this.btnSkipToNextTurn.setVisible(true); + this.btnSkipToEndTurn.setVisible(true); + this.btnSkipToNextMain.setVisible(true); + this.btnSkipStack.setVisible(true); + this.btnSkipToYourTurn.setVisible(true); + this.btnSkipToEndStepBeforeYourTurn.setVisible(true); + + this.pnlReplay.setVisible(false); + + this.gameChatPanel.clear(); + this.gameChatPanel.connect(SessionHandler.getGameChatId(gameId)); + if (!SessionHandler.joinGame(gameId)) { + removeGame(); + } else { + // play start sound + AudioManager.playYourGameStarted(); + } + } + + public synchronized void watchGame(UUID gameId, GamePane gamePane) { + this.gameId = gameId; + this.gamePane = gamePane; + this.playerId = null; + MageFrame.addGame(gameId, this); + this.feedbackPanel.init(gameId); + this.feedbackPanel.clear(); + + this.btnConcede.setVisible(false); + this.btnStopWatching.setVisible(true); + this.btnSwitchHands.setVisible(false); + this.chosenHandKey = ""; + this.btnCancelSkip.setVisible(false); + + this.btnSkipToNextTurn.setVisible(false); + this.btnSkipToEndTurn.setVisible(false); + this.btnSkipToNextMain.setVisible(false); + this.btnSkipStack.setVisible(false); + this.btnSkipToYourTurn.setVisible(false); + this.btnSkipToEndStepBeforeYourTurn.setVisible(false); + + this.pnlReplay.setVisible(false); + this.gameChatPanel.clear(); + this.gameChatPanel.connect(SessionHandler.getGameChatId(gameId)); + if (!SessionHandler.watchGame(gameId)) { + removeGame(); + } + for (PlayAreaPanel panel : getPlayers().values()) { + panel.setPlayingMode(false); + } + } + + public synchronized void replayGame(UUID gameId) { + this.gameId = gameId; + this.playerId = null; + MageFrame.addGame(gameId, this); + this.feedbackPanel.init(gameId); + this.feedbackPanel.clear(); + this.btnConcede.setVisible(false); + this.btnSkipToNextTurn.setVisible(false); + this.btnSwitchHands.setVisible(false); + this.btnStopWatching.setVisible(false); + this.pnlReplay.setVisible(true); + this.gameChatPanel.clear(); + if (!SessionHandler.startReplay(gameId)) { + removeGame(); + } + for (PlayAreaPanel panel : getPlayers().values()) { + panel.setPlayingMode(false); + } + } + + /** + * Closes the game and it's resources + */ + public void removeGame() { + Component c = this.getParent(); + while (c != null && !(c instanceof GamePane)) { + c = c.getParent(); + } + if (c != null) { + ((GamePane) c).removeGame(); + } + } + + public synchronized void init(GameView game) { + addPlayers(game); + // default menu states + setMenuStates( + PreferencesDialog.getCachedValue(KEY_GAME_MANA_AUTOPAYMENT, "true").equals("true"), + PreferencesDialog.getCachedValue(KEY_GAME_MANA_AUTOPAYMENT_ONLY_ONE, "true").equals("true"), + PreferencesDialog.getCachedValue(KEY_USE_FIRST_MANA_ABILITY, "false").equals("true"), + holdingPriority + ); + + updateGame(game); + } + + private void addPlayers(GameView game) { + this.players.clear(); + this.playersWhoLeft.clear(); + this.pnlBattlefield.removeAll(); + //arrange players in a circle with the session player at the bottom left + int numSeats = game.getPlayers().size(); + int numColumns = (numSeats + 1) / 2; + boolean oddNumber = (numColumns > 1 && numSeats % 2 == 1); + int col = 0; + int row = 1; + int playerSeat = 0; + if (playerId != null) { + for (PlayerView player : game.getPlayers()) { + if (playerId.equals(player.getPlayerId())) { + break; + } + playerSeat++; + } + } + PlayerView player = game.getPlayers().get(playerSeat); + PlayAreaPanel playAreaPanel = new PlayAreaPanel(player, bigCard, gameId, game.getPriorityTime(), this, + new PlayAreaPanelOptions(game.isPlayer(), game.isPlayer(), game.isRollbackTurnsAllowed(), row == 0)); + players.put(player.getPlayerId(), playAreaPanel); + playersWhoLeft.put(player.getPlayerId(), false); + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.BOTH; + c.weightx = 0.5; + c.weighty = 0.5; + if (oddNumber) { + c.gridwidth = 2; + } + c.gridx = col; + c.gridy = 0; + + // Top panel (row=0) + JPanel topPanel = new JPanel(); + topPanel.setOpaque(false); + + // Bottom panel (row=1) + JPanel bottomPanel = new JPanel(); + bottomPanel.setOpaque(false); + topPanel.setLayout(new GridBagLayout()); + bottomPanel.setLayout(new GridBagLayout()); + + bottomPanel.add(playAreaPanel, c); + playAreaPanel.setVisible(true); + if (oddNumber) { + col++; + } + int playerNum = playerSeat + 1; + if (playerNum >= numSeats) { + playerNum = 0; + } + while (true) { + if (row == 1) { + col++; + } else { + col--; + } + if (col >= numColumns) { + row = 0; + col = numColumns - 1; + } + player = game.getPlayers().get(playerNum); + PlayAreaPanel playerPanel = new PlayAreaPanel(player, bigCard, gameId, game.getPriorityTime(), this, + new PlayAreaPanelOptions(game.isPlayer(), false, game.isRollbackTurnsAllowed(), row == 0)); + players.put(player.getPlayerId(), playerPanel); + playersWhoLeft.put(player.getPlayerId(), false); + c = new GridBagConstraints(); + c.fill = GridBagConstraints.BOTH; + c.weightx = 0.5; + c.weighty = 0.5; + c.gridx = col; + c.gridy = 0; + + if (row == 0) { + topPanel.add(playerPanel, c); + } else { + bottomPanel.add(playerPanel, c); + } + + playerPanel.setVisible(true); + playerNum++; + if (playerNum >= numSeats) { + playerNum = 0; + } + if (playerNum == playerSeat) { + break; + } + } + for (PlayAreaPanel p : players.values()) { + p.sizePlayer(smallMode); + } + + GridBagConstraints panelC = new GridBagConstraints(); + panelC.fill = GridBagConstraints.BOTH; + panelC.weightx = 0.5; + panelC.weighty = 0.5; + panelC.gridwidth = 1; + panelC.gridy = 0; + this.pnlBattlefield.add(topPanel, panelC); + panelC.gridy = 1; + this.pnlBattlefield.add(bottomPanel, panelC); + } + + public synchronized void updateGame(GameView game) { + updateGame(game, null); + } + + public synchronized void updateGame(GameView game, Map options) { + if (playerId == null && game.getWatchedHands() == null) { + this.handContainer.setVisible(false); + } else { + this.handContainer.setVisible(true); + handCards.clear(); + if (game.getWatchedHands() != null) { + for (Map.Entry hand : game.getWatchedHands().entrySet()) { + handCards.put(hand.getKey(), CardsViewUtil.convertSimple(hand.getValue(), loadedCards)); + } + } + if (playerId != null) { + handCards.put(YOUR_HAND, game.getHand()); + // Mark playable + if (game.getCanPlayInHand() != null) { + for (CardView card : handCards.get(YOUR_HAND).values()) { + if (game.getCanPlayInHand().contains(card.getId())) { + card.setPlayable(true); + } + } + } + // Get opponents hand cards if available (only possible for players) + if (game.getOpponentHands() != null) { + for (Map.Entry hand : game.getOpponentHands().entrySet()) { + handCards.put(hand.getKey(), CardsViewUtil.convertSimple(hand.getValue(), loadedCards)); + } + } + if (!handCards.containsKey(chosenHandKey)) { + chosenHandKey = YOUR_HAND; + } + } else if (chosenHandKey.isEmpty() && handCards.size() > 0) { + chosenHandKey = handCards.keySet().iterator().next(); + } + if (chosenHandKey != null && handCards.containsKey(chosenHandKey)) { + handContainer.loadCards(handCards.get(chosenHandKey), bigCard, gameId); + } + + hideAll(); + + if (playerId != null) { + // set visible only if we have any other hand visible than ours + btnSwitchHands.setVisible(handCards.size() > 1); + boolean change = (handCardsOfOpponentAvailable != (game.getOpponentHands() != null)); + if (change) { + handCardsOfOpponentAvailable = !handCardsOfOpponentAvailable; + if (handCardsOfOpponentAvailable) { + JOptionPane.showMessageDialog(null, "You control other player's turn. \nUse \"Switch Hand\" button to switch between cards in different hands."); + } else { + JOptionPane.showMessageDialog(null, "You lost control on other player's turn."); + } + } + } else { + btnSwitchHands.setVisible(!handCards.isEmpty()); + } + } + + if (game.getPhase() != null) { + this.txtPhase.setText(game.getPhase().toString()); + } else { + this.txtPhase.setText(""); + } + + if (game.getStep() != null) { + updatePhases(game.getStep()); + this.txtStep.setText(game.getStep().toString()); + } else { + logger.debug("Step is empty"); + this.txtStep.setText(""); + } + if (game.getSpellsCastCurrentTurn() > 0 && PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAME_SHOW_STORM_COUNTER, "true").equals("true")) { + this.txtSpellsCast.setVisible(true); + this.txtSpellsCast.setText(" " + Integer.toString(game.getSpellsCastCurrentTurn()) + " "); + } else { + this.txtSpellsCast.setVisible(false); + } + + this.txtActivePlayer.setText(game.getActivePlayerName()); + this.txtPriority.setText(game.getPriorityPlayerName()); + this.txtTurn.setText(Integer.toString(game.getTurn())); + + List possibleAttackers = new ArrayList<>(); + if (options != null && options.containsKey(Constants.Option.POSSIBLE_ATTACKERS)) { + if (options.get(Constants.Option.POSSIBLE_ATTACKERS) instanceof List) { + possibleAttackers.addAll((List) options.get(Constants.Option.POSSIBLE_ATTACKERS)); + } + } + + for (PlayerView player : game.getPlayers()) { + if (players.containsKey(player.getPlayerId())) { + if (!possibleAttackers.isEmpty()) { + for (UUID permanentId : possibleAttackers) { + if (player.getBattlefield().containsKey(permanentId)) { + player.getBattlefield().get(permanentId).setCanAttack(true); + } + } + } + players.get(player.getPlayerId()).update(player); + if (player.getPlayerId().equals(playerId)) { + updateSkipButtons(player.isPassedTurn(), player.isPassedUntilEndOfTurn(), player.isPassedUntilNextMain(), player.isPassedAllTurns(), player.isPassedUntilStackResolved(), + player.isPassedUntilEndStepBeforeMyTurn()); + } + // update open or remove closed graveyard windows + graveyards.put(player.getName(), player.getGraveyard()); + if (graveyardWindows.containsKey(player.getName())) { + CardInfoWindowDialog cardInfoWindowDialog = graveyardWindows.get(player.getName()); + if (cardInfoWindowDialog.isClosed()) { + graveyardWindows.remove(player.getName()); + } else { + cardInfoWindowDialog.loadCards(player.getGraveyard(), bigCard, gameId, false); + } + } + // show top card window + if (player.getTopCard() != null) { + CardsView cardsView = new CardsView(); + cardsView.put(player.getTopCard().getId(), player.getTopCard()); + handleGameInfoWindow(revealed, ShowType.REVEAL_TOP_LIBRARY, player.getName() + "'s top library card", cardsView); + } + } else { + logger.warn("Couldn't find player."); + logger.warn(" uuid:" + player.getPlayerId()); + logger.warn(" players:"); + for (PlayAreaPanel p : players.values()) { + logger.warn("" + p); + } + } + } + if (!menuNameSet) { + StringBuilder sb = new StringBuilder(); + if (playerId == null) { + sb.append("Watching: "); + } else { + sb.append("Playing: "); + } + boolean first = true; + for (PlayerView player : game.getPlayers()) { + if (first) { + first = false; + } else { + sb.append(" - "); + } + sb.append(player.getName()); + } + menuNameSet = true; + gamePane.setTitle(sb.toString()); + } + + GameManager.getInstance().setStackSize(game.getStack().size()); + displayStack(game, bigCard, feedbackPanel, gameId); + + for (ExileView exile : game.getExile()) { + if (!exiles.containsKey(exile.getId())) { + CardInfoWindowDialog newExile = new CardInfoWindowDialog(ShowType.EXILE, exile.getName()); + exiles.put(exile.getId(), newExile); + MageFrame.getDesktop().add(newExile, JLayeredPane.MODAL_LAYER); + newExile.show(); + } + exiles.get(exile.getId()).loadCards(exile, bigCard, gameId); + } + + showRevealed(game); + showLookedAt(game); + if (game.getCombat().size() > 0) { + CombatManager.getInstance().showCombat(game.getCombat(), gameId); + } else { + CombatManager.getInstance().hideCombat(gameId); + } + + for (PlayerView player : game.getPlayers()) { + if (player.hasLeft() && !playersWhoLeft.get(player.getPlayerId())) { + PlayAreaPanel playerLeftPanel = players.get(player.getPlayerId()); + playersWhoLeft.put(player.getPlayerId(), true); + + Container parent = playerLeftPanel.getParent(); + GridBagLayout layout = (GridBagLayout) parent.getLayout(); + + for (Component otherPanel : parent.getComponents()) { + + if (otherPanel instanceof PlayAreaPanel) { + GridBagConstraints gbc = layout.getConstraints(otherPanel); + if (gbc.weightx > 0.1) { + gbc.weightx = 0.99; + } + gbc.fill = GridBagConstraints.BOTH; + gbc.anchor = GridBagConstraints.WEST; + if (gbc.gridx > 0) { + gbc.anchor = GridBagConstraints.EAST; + } + if (otherPanel == playerLeftPanel) { + gbc.weightx = 0.01; + Dimension d = playerLeftPanel.getPreferredSize(); + d.width = 95; + otherPanel.setPreferredSize(d); + } + parent.remove(otherPanel); + parent.add(otherPanel, gbc); + } + } + + parent.validate(); + parent.repaint(); + } + } + + feedbackPanel.disableUndo(); + + this.revalidate(); + this.repaint(); + } + + static final int BORDER_SIZE = 2; + + private void updateSkipButtons(boolean turn, boolean endOfTurn, boolean nextMain, boolean allTurns, boolean stack, boolean endStepBeforeYourStep) { + if (turn) { //F4 + btnSkipToNextTurn.setBorder(new LineBorder(Color.orange, BORDER_SIZE)); + } else { + btnSkipToNextTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); + } + if (endOfTurn) { // F5 + btnSkipToEndTurn.setBorder(new LineBorder(Color.orange, BORDER_SIZE)); + } else { + btnSkipToEndTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); + } + if (nextMain) { // F7 + btnSkipToNextMain.setBorder(new LineBorder(Color.orange, BORDER_SIZE)); + } else { + btnSkipToNextMain.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); + } + if (stack) { // F8 + btnSkipStack.setBorder(new LineBorder(Color.orange, BORDER_SIZE)); + } else { + btnSkipStack.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); + } + if (allTurns) { // F9 + btnSkipToYourTurn.setBorder(new LineBorder(Color.orange, BORDER_SIZE)); + } else { + btnSkipToYourTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); + } + + if (endStepBeforeYourStep) { // F11 + btnSkipToEndStepBeforeYourTurn.setBorder(new LineBorder(Color.orange, BORDER_SIZE)); + } else { + btnSkipToEndStepBeforeYourTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); + } + + } + + /** + * Set the same state for menu selections to all player areas. + * + * @param manaPoolAutomatic + * @param manaPoolAutomaticRestricted + * @param useFirstManaAbility + */ + public void setMenuStates(boolean manaPoolAutomatic, boolean manaPoolAutomaticRestricted, boolean useFirstManaAbility, boolean holdPriority) { + for (PlayAreaPanel playAreaPanel : players.values()) { + playAreaPanel.setMenuStates(manaPoolAutomatic, manaPoolAutomaticRestricted, useFirstManaAbility, holdPriority); + } + } + + private void displayStack(GameView game, BigCard bigCard, FeedbackPanel feedbackPanel, UUID gameId) { + this.stackObjects.loadCards(game.getStack(), bigCard, gameId, true); + } + + /** + * Update phase buttons\labels. + */ + private void updatePhases(PhaseStep step) { + if (step == null) { + logger.warn("step is null"); + return; + } + if (currentStep != null) { + currentStep.setLocation(prevPoint); + } + switch (step) { + case UNTAP: + updateButton("Untap"); + break; + case UPKEEP: + updateButton("Upkeep"); + break; + case DRAW: + updateButton("Draw"); + break; + case PRECOMBAT_MAIN: + updateButton("Main1"); + break; + case BEGIN_COMBAT: + updateButton("Combat_Start"); + break; + case DECLARE_ATTACKERS: + updateButton("Combat_Attack"); + break; + case DECLARE_BLOCKERS: + updateButton("Combat_Block"); + break; + case FIRST_COMBAT_DAMAGE: + case COMBAT_DAMAGE: + updateButton("Combat_Damage"); + break; + case END_COMBAT: + updateButton("Combat_End"); + break; + case POSTCOMBAT_MAIN: + updateButton("Main2"); + break; + case END_TURN: + updateButton("Cleanup"); + break; + } + } + + private void updateButton(String name) { + if (hoverButtons.containsKey(name)) { + currentStep = hoverButtons.get(name); + prevPoint = currentStep.getLocation(); + currentStep.setLocation(prevPoint.x - 15, prevPoint.y); + } + } + + // Called if the game frame is deactivated because the tabled the deck editor or other frames go to foreground + public void deactivated() { + // hide the non modal windows (because otherwise they are shown on top of the new active pane) + for (CardInfoWindowDialog exileDialog : exiles.values()) { + exileDialog.hideDialog(); + } + for (CardInfoWindowDialog graveyardDialog : graveyardWindows.values()) { + graveyardDialog.hideDialog(); + } + for (CardInfoWindowDialog revealDialog : revealed.values()) { + revealDialog.hideDialog(); + } + for (CardInfoWindowDialog lookedAtDialog : lookedAt.values()) { + lookedAtDialog.hideDialog(); + } + } + + // Called if the game frame comes to front again + public void activated() { + // hide the non modal windows (because otherwise they are shown on top of the new active pane) + for (CardInfoWindowDialog exileDialog : exiles.values()) { + exileDialog.show(); + } + for (CardInfoWindowDialog graveyardDialog : graveyardWindows.values()) { + graveyardDialog.show(); + } + for (CardInfoWindowDialog revealDialog : revealed.values()) { + revealDialog.show(); + } + for (CardInfoWindowDialog lookedAtDialog : lookedAt.values()) { + lookedAtDialog.show(); + } + } + + public void openGraveyardWindow(String playerName) { + if (graveyardWindows.containsKey(playerName)) { + CardInfoWindowDialog cardInfoWindowDialog = graveyardWindows.get(playerName); + if (cardInfoWindowDialog.isVisible()) { + cardInfoWindowDialog.hideDialog(); + } else { + cardInfoWindowDialog.show(); + } + return; + } + CardInfoWindowDialog newGraveyard = new CardInfoWindowDialog(ShowType.GRAVEYARD, playerName); + graveyardWindows.put(playerName, newGraveyard); + MageFrame.getDesktop().add(newGraveyard, JLayeredPane.MODAL_LAYER); + newGraveyard.loadCards(graveyards.get(playerName), bigCard, gameId, false); + } + + public void openTopLibraryWindow(String playerName) { + String title = playerName + "'s top library card"; + if (revealed.containsKey(title)) { + CardInfoWindowDialog cardInfoWindowDialog = revealed.get(title); + if (cardInfoWindowDialog.isVisible()) { + cardInfoWindowDialog.hideDialog(); + } else { + cardInfoWindowDialog.show(); + } + } + } + + private void showRevealed(GameView game) { + for (RevealedView revealView : game.getRevealed()) { + handleGameInfoWindow(revealed, ShowType.REVEAL, revealView.getName(), revealView.getCards()); + } + removeClosedCardInfoWindows(revealed); + } + + private void showLookedAt(GameView game) { + for (LookedAtView lookedAtView : game.getLookedAt()) { + handleGameInfoWindow(lookedAt, ShowType.LOOKED_AT, lookedAtView.getName(), lookedAtView.getCards()); + } + removeClosedCardInfoWindows(lookedAt); + } + + private void handleGameInfoWindow(Map windowMap, ShowType showType, String name, LinkedHashMap cardsView) { + CardInfoWindowDialog cardInfoWindowDialog; + if (!windowMap.containsKey(name)) { + cardInfoWindowDialog = new CardInfoWindowDialog(showType, name); + windowMap.put(name, cardInfoWindowDialog); + MageFrame.getDesktop().add(cardInfoWindowDialog, JLayeredPane.MODAL_LAYER); + } else { + cardInfoWindowDialog = windowMap.get(name); + } + + if (cardInfoWindowDialog != null && !cardInfoWindowDialog.isClosed()) { + switch (showType) { + case REVEAL: + case REVEAL_TOP_LIBRARY: + cardInfoWindowDialog.loadCards((CardsView) cardsView, bigCard, gameId); + break; + case LOOKED_AT: + cardInfoWindowDialog.loadCards((SimpleCardsView) cardsView, bigCard, gameId); + break; + } + } + } + + private void removeClosedCardInfoWindows(Map windowMap) { + // Remove closed window objects from the maps + for (Iterator> iterator = windowMap.entrySet().iterator(); iterator.hasNext();) { + Map.Entry entry = iterator.next(); + if (entry.getValue().isClosed()) { + iterator.remove(); + } + } + } + + public void ask(String question, GameView gameView, int messageId, Map options) { + updateGame(gameView); + this.feedbackPanel.getFeedback(FeedbackMode.QUESTION, question, false, options, messageId); + } + + /** + * Shows a pick target dialog and allows the player to pick a target (e.g. + * the pick triggered ability) + * + * @param message + * @param cardView + * @param gameView + * @param targets + * @param required + * @param options + * @param messageId + */ + public void pickTarget(String message, CardsView cardView, GameView gameView, Set targets, boolean required, Map options, int messageId) { + PopUpMenuType popupMenuType = null; + if (options != null) { + if (options.containsKey("targetZone")) { + if (Zone.HAND.equals(options.get("targetZone"))) { // mark selectable target cards in hand + List choosen = null; + if (options.containsKey("chosen")) { + choosen = (List) options.get("chosen"); + } + for (CardView card : gameView.getHand().values()) { + if (targets == null || targets.isEmpty()) { + card.setPlayable(false); + card.setChoosable(true); + } else if (targets.contains(card.getId())) { + card.setPlayable(false); + card.setChoosable(true); + } + if (choosen != null && choosen.contains(card.getId())) { + card.setSelected(true); + } + } + } + } + if (options.containsKey("queryType") && PlayerQueryEvent.QueryType.PICK_ABILITY.equals(options.get("queryType"))) { + popupMenuType = PopUpMenuType.TRIGGER_ORDER; + } + } + updateGame(gameView); + Map options0 = options == null ? new HashMap<>() : options; + ShowCardsDialog dialog = null; + if (cardView != null && cardView.size() > 0) { + dialog = showCards(message, cardView, required, options0, popupMenuType); + options0.put("dialog", dialog); + } + this.feedbackPanel.getFeedback(required ? FeedbackMode.INFORM : FeedbackMode.CANCEL, message, gameView.getSpecial(), options0, messageId); + if (dialog != null) { + this.pickTarget.add(dialog); + } + } + + public void inform(String information, GameView gameView, int messageId) { + updateGame(gameView); + this.feedbackPanel.getFeedback(FeedbackMode.INFORM, information, gameView.getSpecial(), null, messageId); + } + + public void endMessage(String message, int messageId) { + this.feedbackPanel.getFeedback(FeedbackMode.END, message, false, null, messageId); + ArrowBuilder.getBuilder().removeAllArrows(gameId); + } + + public void select(String message, GameView gameView, int messageId, Map options) { + holdingPriority = false; + txtHoldPriority.setVisible(false); + setMenuStates( + PreferencesDialog.getCachedValue(KEY_GAME_MANA_AUTOPAYMENT, "true").equals("true"), + PreferencesDialog.getCachedValue(KEY_GAME_MANA_AUTOPAYMENT_ONLY_ONE, "true").equals("true"), + PreferencesDialog.getCachedValue(KEY_USE_FIRST_MANA_ABILITY, "false").equals("true"), + false); + + updateGame(gameView, options); + boolean controllingPlayer = false; + for (PlayerView playerView : gameView.getPlayers()) { + if (playerView.getPlayerId().equals(playerId)) { + // magenoxx: because of uncaught bug with saving state, rolling back and stack + // undo is allowed only for empty stack + controllingPlayer = !gameView.getPriorityPlayerName().equals(playerView.getName()); + if (playerView.getStatesSavedSize() > 0 && gameView.getStack().isEmpty()) { + feedbackPanel.allowUndo(playerView.getStatesSavedSize()); + } + break; + } + + } + Map panelOptions = new HashMap<>(); + if (options != null) { + panelOptions.putAll(options); + } + panelOptions.put("your_turn", true); + String activePlayerText; + if (gameView.getActivePlayerId().equals(playerId)) { + activePlayerText = "Your turn"; + } else { + activePlayerText = gameView.getActivePlayerName() + "'s turn"; + } + String priorityPlayerText = ""; + if (controllingPlayer) { + priorityPlayerText = " / priority " + gameView.getPriorityPlayerName(); + } + String messageToDisplay = message + FeedbackPanel.getSmallText(activePlayerText + " / " + gameView.getStep().toString() + priorityPlayerText); + this.feedbackPanel.getFeedback(FeedbackMode.SELECT, messageToDisplay, gameView.getSpecial(), panelOptions, messageId); + } + + public void playMana(String message, GameView gameView, Map options, int messageId) { + updateGame(gameView); + DialogManager.getManager(gameId).fadeOut(); + this.feedbackPanel.getFeedback(FeedbackMode.CANCEL, message, gameView.getSpecial(), options, messageId); + } + + public void playXMana(String message, GameView gameView, int messageId) { + updateGame(gameView); + DialogManager.getManager(gameId).fadeOut(); + this.feedbackPanel.getFeedback(FeedbackMode.CONFIRM, message, gameView.getSpecial(), null, messageId); + } + + public void replayMessage(String message) { + //TODO: implement this + } + + public void pickAbility(AbilityPickerView choices) { + hideAll(); + DialogManager.getManager(gameId).fadeOut(); + this.abilityPicker.show(choices, MageFrame.getDesktop().getMousePosition()); + } + + private void hideAll() { + ActionCallback callback = Plugins.getInstance().getActionCallback(); + ((MageActionCallback) callback).hideGameUpdate(gameId); + } + + private ShowCardsDialog showCards(String title, CardsView cards, boolean required, Map options, PopUpMenuType popupMenuType) { + hideAll(); + ShowCardsDialog showCards = new ShowCardsDialog(); + JPopupMenu popupMenu = null; + if (PopUpMenuType.TRIGGER_ORDER.equals(popupMenuType)) { + popupMenu = popupMenuTriggerOrder; + } + showCards.loadCards(title, cards, bigCard, gameId, required, options, popupMenu, getShowCardsEventListener(showCards)); + return showCards; + } + + public void getAmount(int min, int max, String message) { + pickNumber.showDialog(min, max, message); + if (pickNumber.isCancel()) { + SessionHandler.sendPlayerBoolean(gameId, false); + } else { + SessionHandler.sendPlayerInteger(gameId, pickNumber.getAmount()); + } + } + + public void getChoice(Choice choice, UUID objectId) { + hideAll(); + PickChoiceDialog pickChoice = new PickChoiceDialog(); + pickChoice.showDialog(choice, objectId, choiceWindowState); + if (choice.isKeyChoice()) { + if (pickChoice.isAutoSelect()) { + SessionHandler.sendPlayerString(gameId, "#" + choice.getChoiceKey()); + } else { + SessionHandler.sendPlayerString(gameId, choice.getChoiceKey()); + } + } else { + SessionHandler.sendPlayerString(gameId, choice.getChoice()); + } + choiceWindowState = new MageDialogState(pickChoice); + pickChoice.removeDialog(); + } + + public void pickPile(String message, CardsView pile1, CardsView pile2) { + hideAll(); + PickPileDialog pickPileDialog = new PickPileDialog(); + pickPileDialog.loadCards(message, pile1, pile2, bigCard, gameId); + SessionHandler.sendPlayerBoolean(gameId, pickPileDialog.isPickedPile1()); + pickPileDialog.cleanUp(); + pickPileDialog.removeDialog(); + } + + public Map getPlayers() { + return players; + } + + @SuppressWarnings("unchecked") + private void initComponents() { + + abilityPicker = new mage.client.components.ability.AbilityPicker(); + jSplitPane1 = new javax.swing.JSplitPane(); + jSplitPane0 = new javax.swing.JSplitPane(); + jPanel2 = new javax.swing.JPanel(); + pnlHelperHandButtonsStackArea = new javax.swing.JPanel(); + pnlShortCuts = new javax.swing.JPanel(); + lblPhase = new javax.swing.JLabel(); + txtPhase = new javax.swing.JLabel(); + lblStep = new javax.swing.JLabel(); + txtStep = new javax.swing.JLabel(); + lblTurn = new javax.swing.JLabel(); + txtTurn = new javax.swing.JLabel(); + txtActivePlayer = new javax.swing.JLabel(); + lblActivePlayer = new javax.swing.JLabel(); + txtPriority = new javax.swing.JLabel(); + lblPriority = new javax.swing.JLabel(); + feedbackPanel = new mage.client.game.FeedbackPanel(); + + txtSpellsCast = new javax.swing.JLabel(); + Border paddingBorder = BorderFactory.createEmptyBorder(4, 4, 4, 4); + Border border = BorderFactory.createLineBorder(Color.DARK_GRAY, 2); + txtSpellsCast.setBorder(BorderFactory.createCompoundBorder(border, paddingBorder)); + txtSpellsCast.setBackground(Color.LIGHT_GRAY); + txtSpellsCast.setOpaque(true); + txtSpellsCast.setToolTipText("spells cast during the current turn"); + + txtHoldPriority = new javax.swing.JLabel(); + txtHoldPriority.setText("Hold"); + txtHoldPriority.setBorder(BorderFactory.createCompoundBorder(border, paddingBorder)); + txtHoldPriority.setBackground(Color.LIGHT_GRAY); + txtHoldPriority.setOpaque(true); + txtHoldPriority.setToolTipText("Holding priority after the next spell cast or ability activation"); + txtHoldPriority.setVisible(false); + + btnCancelSkip = new javax.swing.JButton(); // F3 + btnSkipToNextTurn = new javax.swing.JButton(); // F4 + btnSkipToEndTurn = new javax.swing.JButton(); // F5 + btnSkipToNextMain = new javax.swing.JButton(); // F7 + btnSkipStack = new javax.swing.JButton(); // F8 + btnSkipToYourTurn = new javax.swing.JButton(); // F9 + btnSkipToEndStepBeforeYourTurn = new javax.swing.JButton(); // F11 + + btnConcede = new javax.swing.JButton(); + btnSwitchHands = new javax.swing.JButton(); + btnStopWatching = new javax.swing.JButton(); + + bigCard = new mage.client.cards.BigCard(); + pnlReplay = new javax.swing.JPanel(); + btnStopReplay = new javax.swing.JButton(); + btnNextPlay = new javax.swing.JButton(); + btnPlay = new javax.swing.JButton(); + btnSkipForward = new javax.swing.JButton(); + btnPreviousPlay = new javax.swing.JButton(); + pnlBattlefield = new javax.swing.JPanel(); + gameChatPanel = new mage.client.chat.ChatPanelBasic(); + gameChatPanel.useExtendedView(ChatPanelBasic.VIEW_MODE.GAME); + userChatPanel = new mage.client.chat.ChatPanelBasic(); + userChatPanel.setParentChat(gameChatPanel); + userChatPanel.useExtendedView(ChatPanelBasic.VIEW_MODE.CHAT); + userChatPanel.setChatType(ChatPanelBasic.ChatType.GAME); + gameChatPanel.setConnectedChat(userChatPanel); + gameChatPanel.disableInput(); + gameChatPanel.setMinimumSize(new java.awt.Dimension(100, 48)); + gameChatPanel.enableHyperlinks(); + jSplitPane2 = new javax.swing.JSplitPane(); + handContainer = new HandPanel(); + handCards = new HashMap<>(); + + pnlShortCuts.setOpaque(false); + pnlShortCuts.setPreferredSize(new Dimension(410, 72)); + + stackObjects = new mage.client.cards.Cards(); + + jSplitPane1.setBorder(null); + jSplitPane1.setDividerSize(7); + jSplitPane1.setResizeWeight(1.0); + jSplitPane1.setOneTouchExpandable(true); + jSplitPane1.setMinimumSize(new java.awt.Dimension(26, 48)); + + jSplitPane0.setBorder(null); + jSplitPane0.setDividerSize(7); + jSplitPane0.setResizeWeight(1.0); + jSplitPane0.setOneTouchExpandable(true); + + restoreDividerLocations(); + + lblPhase.setLabelFor(txtPhase); + lblPhase.setText("Phase:"); + + txtPhase.setText("Phase"); + txtPhase.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(153, 153, 153), 1, true)); + txtPhase.setMinimumSize(new java.awt.Dimension(0, 16)); + + lblStep.setLabelFor(txtStep); + lblStep.setText("Step:"); + + txtStep.setText("Step"); + txtStep.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(153, 153, 153), 1, true)); + txtStep.setMinimumSize(new java.awt.Dimension(0, 16)); + + lblTurn.setLabelFor(txtTurn); + lblTurn.setText("Turn:"); + + txtTurn.setText("Turn"); + txtTurn.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(153, 153, 153), 1, true)); + txtTurn.setMinimumSize(new java.awt.Dimension(0, 16)); + + txtActivePlayer.setText("Active Player"); + txtActivePlayer.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(153, 153, 153), 1, true)); + txtActivePlayer.setMinimumSize(new java.awt.Dimension(0, 16)); + + lblActivePlayer.setLabelFor(txtActivePlayer); + lblActivePlayer.setText("Active Player:"); + + txtPriority.setText("Priority Player"); + txtPriority.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(153, 153, 153), 1, true)); + txtPriority.setMinimumSize(new java.awt.Dimension(0, 16)); + + lblPriority.setLabelFor(txtPriority); + lblPriority.setText("Priority Player:"); + + bigCard.setBorder(new LineBorder(Color.black, 1, true)); + + int c = JComponent.WHEN_IN_FOCUSED_WINDOW; + + KeyStroke ks3 = PreferencesDialog.getCachedKeystroke( + PreferencesDialog.KEY_CONTROL_CANCEL_SKIP, KeyEvent.VK_F3); + this.getInputMap(c).put(ks3, "F3_PRESS"); + this.getActionMap().put("F3_PRESS", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + restorePriorityActionPerformed(actionEvent); + } + }); + + btnCancelSkip.setContentAreaFilled(false); + btnCancelSkip.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); + btnCancelSkip.setIcon(new ImageIcon(ImageManagerImpl.getInstance().getCancelSkipButtonImage())); + btnCancelSkip.setToolTipText("Cancel all skip actions (F3)."); + btnCancelSkip.setFocusable(false); + btnCancelSkip.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent evt) { + if (evt.getButton() == MouseEvent.BUTTON1) { + restorePriorityActionPerformed(null); + } + } + }); + + btnSkipToNextTurn.setContentAreaFilled(false); + btnSkipToNextTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); + btnSkipToNextTurn.setIcon(new ImageIcon(ImageManagerImpl.getInstance().getSkipNextTurnButtonImage())); + btnSkipToNextTurn.setToolTipText("Skip to next turn (F4)."); + btnSkipToNextTurn.setFocusable(false); + btnSkipToNextTurn.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent evt) { + if (evt.getButton() == MouseEvent.BUTTON1) { + btnEndTurnActionPerformed(null); + } + } + }); + + KeyStroke ks = PreferencesDialog.getCachedKeystroke( + PreferencesDialog.KEY_CONTROL_NEXT_TURN, KeyEvent.VK_F4); + this.getInputMap(c).put(ks, "F4_PRESS"); + this.getActionMap().put("F4_PRESS", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + btnEndTurnActionPerformed(actionEvent); + } + }); + + btnSkipToEndTurn.setContentAreaFilled(false); + btnSkipToEndTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); + btnSkipToEndTurn.setIcon(new ImageIcon(ImageManagerImpl.getInstance().getSkipEndTurnButtonImage())); + btnSkipToEndTurn.setToolTipText("Skip to (opponents/next) end of turn step (F5) - adjust using preferences."); + btnSkipToEndTurn.setFocusable(false); + btnSkipToEndTurn.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent evt) { + if (evt.getButton() == MouseEvent.BUTTON1) { + btnUntilEndOfTurnActionPerformed(null); + } + } + }); + + ks = PreferencesDialog.getCachedKeystroke( + PreferencesDialog.KEY_CONTROL_END_STEP, KeyEvent.VK_F5); + this.getInputMap(c).put(ks, "F5_PRESS"); + this.getActionMap().put("F5_PRESS", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + btnUntilEndOfTurnActionPerformed(actionEvent); + } + }); + + ks = PreferencesDialog.getCachedKeystroke( + PreferencesDialog.KEY_CONTROL_SKIP_STEP, KeyEvent.VK_F6); + this.getInputMap(c).put(ks, "F6_PRESS"); + this.getActionMap().put("F6_PRESS", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + btnEndTurnSkipStackActionPerformed(actionEvent); + } + }); + + btnSkipToNextMain.setContentAreaFilled(false); + btnSkipToNextMain.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); + btnSkipToNextMain.setIcon(new ImageIcon(ImageManagerImpl.getInstance().getSkipMainButtonImage())); + btnSkipToNextMain.setToolTipText("Skip to (your) next main phase (F7) - adjust using preferences."); + btnSkipToNextMain.setFocusable(false); + btnSkipToNextMain.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent evt) { + if (evt.getButton() == MouseEvent.BUTTON1) { + btnUntilNextMainPhaseActionPerformed(null); + } + } + }); + + ks = PreferencesDialog.getCachedKeystroke( + PreferencesDialog.KEY_CONTROL_MAIN_STEP, KeyEvent.VK_F7); + this.getInputMap(c).put(ks, "F7_PRESS"); + this.getActionMap().put("F7_PRESS", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + btnUntilNextMainPhaseActionPerformed(actionEvent); + } + }); + + btnSkipToYourTurn.setContentAreaFilled(false); + btnSkipToYourTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); + btnSkipToYourTurn.setIcon(new ImageIcon(ImageManagerImpl.getInstance().getSkipYourNextTurnButtonImage())); + btnSkipToYourTurn.setToolTipText("Skip to your next turn (F9)."); + btnSkipToYourTurn.setFocusable(false); + btnSkipToYourTurn.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent evt) { + if (evt.getButton() == MouseEvent.BUTTON1) { + btnPassPriorityUntilNextYourTurnActionPerformed(null); + } + } + }); + + KeyStroke ks9 = PreferencesDialog.getCachedKeystroke( + PreferencesDialog.KEY_CONTROL_YOUR_TURN, KeyEvent.VK_F9); + this.getInputMap(c).put(ks9, "F9_PRESS"); + this.getActionMap().put("F9_PRESS", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + btnPassPriorityUntilNextYourTurnActionPerformed(actionEvent); + } + }); + + btnSkipToEndStepBeforeYourTurn.setContentAreaFilled(false); + btnSkipToEndStepBeforeYourTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); + btnSkipToEndStepBeforeYourTurn.setIcon(new ImageIcon(ImageManagerImpl.getInstance().getSkipEndStepBeforeYourTurnButtonImage())); + btnSkipToEndStepBeforeYourTurn.setToolTipText("Skip to the end step before your turn (F11) - adjust using preferences."); + btnSkipToEndStepBeforeYourTurn.setFocusable(false); + btnSkipToEndStepBeforeYourTurn.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent evt) { + if (evt.getButton() == MouseEvent.BUTTON1) { + btnSkipToEndStepBeforeYourTurnActionPerformed(null); + } + } + }); + + KeyStroke ks11 = PreferencesDialog.getCachedKeystroke( + PreferencesDialog.KEY_CONTROL_PRIOR_END, KeyEvent.VK_F11); + this.getInputMap(c).put(ks11, "F11_PRESS"); + this.getActionMap().put("F11_PRESS", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + btnSkipToEndStepBeforeYourTurnActionPerformed(actionEvent); + } + }); + + btnSkipStack.setContentAreaFilled(false); + btnSkipStack.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); + btnSkipStack.setIcon(new ImageIcon(ImageManagerImpl.getInstance().getSkipStackButtonImage())); + btnSkipStack.setToolTipText("Skip until stack is resolved (F10)."); + btnSkipStack.setFocusable(false); + btnSkipStack.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent evt) { + if (evt.getButton() == MouseEvent.BUTTON1) { + btnPassPriorityUntilStackResolvedActionPerformed(null); + } + } + }); + + ks = PreferencesDialog.getCachedKeystroke( + PreferencesDialog.KEY_CONTROL_SKIP_STACK, KeyEvent.VK_F10); + this.getInputMap(c).put(ks, "F10_PRESS"); + this.getActionMap().put("F10_PRESS", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + btnPassPriorityUntilStackResolvedActionPerformed(actionEvent); + } + }); + + btnConcede.setContentAreaFilled(false); + btnConcede.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); + btnConcede.setIcon(new ImageIcon(ImageManagerImpl.getInstance().getConcedeButtonImage())); + btnConcede.setToolTipText("Concede the current game."); + btnConcede.setFocusable(false); + btnConcede.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent evt) { + if (evt.getButton() == MouseEvent.BUTTON1) { + btnConcedeActionPerformed(null); + } + } + }); + + KeyStroke ks2 = PreferencesDialog.getCachedKeystroke( + PreferencesDialog.KEY_CONTROL_CONFIRM, KeyEvent.VK_F2); + this.getInputMap(c).put(ks2, "F2_PRESS"); + this.getActionMap().put("F2_PRESS", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + if (feedbackPanel != null) { + feedbackPanel.pressOKYesOrDone(); + } + } + }); + + KeyStroke ksAltE = KeyStroke.getKeyStroke(KeyEvent.VK_E, InputEvent.ALT_MASK); + this.getInputMap(c).put(ksAltE, "ENLARGE"); + this.getActionMap().put("ENLARGE", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + ActionCallback callback = Plugins.getInstance().getActionCallback(); + ((MageActionCallback) callback).enlargeCard(EnlargeMode.NORMAL); + } + }); + + KeyStroke ksAltS = KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.ALT_MASK); + this.getInputMap(c).put(ksAltS, "ENLARGE_SOURCE"); + this.getActionMap().put("ENLARGE_SOURCE", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + ActionCallback callback = Plugins.getInstance().getActionCallback(); + ((MageActionCallback) callback).enlargeCard(EnlargeMode.ALTERNATE); + } + }); + + KeyStroke ksAltD = KeyStroke.getKeyStroke(KeyEvent.VK_D, InputEvent.ALT_MASK); + this.getInputMap(c).put(ksAltD, "BIG_IMAGE"); + this.getActionMap().put("BIG_IMAGE", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + imagePanelState = !imagePanelState; + if (!imagePanelState) { + jSplitPane0.resetToPreferredSizes(); + jSplitPane0.setDividerLocation(jSplitPane0.getSize().width - jSplitPane0.getInsets().right - jSplitPane0.getDividerSize() - 260); + } else { + jSplitPane0.setDividerLocation(1.0); + } + } + }); + + KeyStroke ksAlt1 = KeyStroke.getKeyStroke(KeyEvent.VK_1, InputEvent.ALT_MASK); + this.getInputMap(c).put(ksAlt1, "USEFIRSTMANAABILITY"); + this.getActionMap().put("USEFIRSTMANAABILITY", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + SessionHandler.sendPlayerAction(PlayerAction.USE_FIRST_MANA_ABILITY_ON, gameId, null); + setMenuStates( + PreferencesDialog.getCachedValue(KEY_GAME_MANA_AUTOPAYMENT, "true").equals("true"), + PreferencesDialog.getCachedValue(KEY_GAME_MANA_AUTOPAYMENT_ONLY_ONE, "true").equals("true"), + PreferencesDialog.getCachedValue(KEY_USE_FIRST_MANA_ABILITY, "false").equals("true"), + holdingPriority); + } + }); + + final BasicSplitPaneUI myUi = (BasicSplitPaneUI) jSplitPane0.getUI(); + final BasicSplitPaneDivider divider = myUi.getDivider(); + final JButton upArrowButton = (JButton) divider.getComponent(0); + upArrowButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + PreferencesDialog.saveValue(PreferencesDialog.KEY_BIG_CARD_TOGGLED, "up"); + } + }); + + final JButton downArrowButton = (JButton) divider.getComponent(1); + downArrowButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + PreferencesDialog.saveValue(PreferencesDialog.KEY_BIG_CARD_TOGGLED, "down"); + } + }); + + KeyStroke ksAltEReleased = KeyStroke.getKeyStroke(KeyEvent.VK_E, InputEvent.ALT_MASK, true); + this.getInputMap(c).put(ksAltEReleased, "ENLARGE_RELEASE"); + KeyStroke ksAltSReleased = KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.ALT_MASK, true); + this.getInputMap(c).put(ksAltSReleased, "ENLARGE_RELEASE"); + this.getActionMap().put("ENLARGE_RELEASE", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + ActionCallback callback = Plugins.getInstance().getActionCallback(); + ((MageActionCallback) callback).hideEnlargedCard(); + } + }); + + KeyStroke ksAlt1Released = KeyStroke.getKeyStroke(KeyEvent.VK_1, InputEvent.ALT_MASK, true); + this.getInputMap(c).put(ksAlt1Released, "USEFIRSTMANAABILITY_RELEASE"); + this.getActionMap().put("USEFIRSTMANAABILITY_RELEASE", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + SessionHandler.sendPlayerAction(PlayerAction.USE_FIRST_MANA_ABILITY_OFF, gameId, null); + setMenuStates( + PreferencesDialog.getCachedValue(KEY_GAME_MANA_AUTOPAYMENT, "true").equals("true"), + PreferencesDialog.getCachedValue(KEY_GAME_MANA_AUTOPAYMENT_ONLY_ONE, "true").equals("true"), + PreferencesDialog.getCachedValue(KEY_USE_FIRST_MANA_ABILITY, "false").equals("true"), + holdingPriority); + } + }); + + btnSwitchHands.setContentAreaFilled(false); + btnSwitchHands.setBorder(new EmptyBorder(0, 0, 0, 0)); + btnSwitchHands.setIcon(new ImageIcon(ImageManagerImpl.getInstance().getSwitchHandsButtonImage())); + btnSwitchHands.setFocusable(false); + btnSwitchHands.setToolTipText("Switch between your hand cards and hand cards of controlled players."); + btnSwitchHands.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent evt) { + if (evt.getButton() == MouseEvent.BUTTON1) { + btnSwitchHandActionPerformed(null); + } + } + }); + + btnStopWatching.setContentAreaFilled(false); + btnStopWatching.setBorder(new EmptyBorder(0, 0, 0, 0)); + btnStopWatching.setIcon(new ImageIcon(ImageManagerImpl.getInstance().getStopWatchButtonImage())); + btnStopWatching.setFocusable(false); + btnStopWatching.setToolTipText("Stop watching this game."); + btnStopWatching.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent evt) { + if (evt.getButton() == MouseEvent.BUTTON1) { + btnStopWatchingActionPerformed(null); + } + } + }); + + stackObjects.setBackgroundColor(new Color(0, 0, 0, 40)); + + btnStopReplay.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/control_stop.png"))); + btnStopReplay.addActionListener(new java.awt.event.ActionListener() { + @Override + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnStopReplayActionPerformed(evt); + } + }); + + btnNextPlay.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/control_stop_right.png"))); + btnNextPlay.addActionListener(new java.awt.event.ActionListener() { + @Override + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnNextPlayActionPerformed(evt); + } + }); + + btnPlay.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/control_right.png"))); + btnPlay.addActionListener(new java.awt.event.ActionListener() { + @Override + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnPlayActionPerformed(evt); + } + }); + + btnSkipForward.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/control_double_stop_right.png"))); + btnSkipForward.addActionListener(new java.awt.event.ActionListener() { + @Override + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnSkipForwardActionPerformed(evt); + } + }); + + btnPreviousPlay.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/control_stop_left.png"))); + btnPreviousPlay.addActionListener(new java.awt.event.ActionListener() { + @Override + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnPreviousPlayActionPerformed(evt); + } + }); + + initPopupMenuTriggerOrder(); + + setGUISize(); + + // Replay panel to control replay of games + javax.swing.GroupLayout gl_pnlReplay = new javax.swing.GroupLayout(pnlReplay); + pnlReplay.setLayout(gl_pnlReplay); + gl_pnlReplay.setHorizontalGroup( + gl_pnlReplay.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(gl_pnlReplay.createSequentialGroup() + .addComponent(btnPreviousPlay, javax.swing.GroupLayout.PREFERRED_SIZE, 41, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnPlay, javax.swing.GroupLayout.PREFERRED_SIZE, 35, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(btnStopReplay, javax.swing.GroupLayout.PREFERRED_SIZE, 38, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnNextPlay, javax.swing.GroupLayout.PREFERRED_SIZE, 36, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnSkipForward, javax.swing.GroupLayout.PREFERRED_SIZE, 39, javax.swing.GroupLayout.PREFERRED_SIZE)) + ); + gl_pnlReplay.setVerticalGroup( + gl_pnlReplay.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(btnSkipForward, 0, 0, Short.MAX_VALUE) + .addComponent(btnNextPlay, 0, 0, Short.MAX_VALUE) + .addComponent(btnStopReplay, 0, 0, Short.MAX_VALUE) + .addComponent(btnPlay, 0, 0, Short.MAX_VALUE) + .addComponent(btnPreviousPlay, javax.swing.GroupLayout.PREFERRED_SIZE, 31, Short.MAX_VALUE) + ); + + // Game info panel (buttons on the right panel) + javax.swing.GroupLayout gl_pnlShortCuts = new javax.swing.GroupLayout(pnlShortCuts); + pnlShortCuts.setLayout(gl_pnlShortCuts); + gl_pnlShortCuts.setHorizontalGroup(gl_pnlShortCuts.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(gl_pnlShortCuts.createSequentialGroup() + .addComponent(btnSkipToNextTurn) + .addComponent(btnSkipToEndTurn) + .addComponent(btnSkipToNextMain) + .addComponent(btnSkipToYourTurn) + .addComponent(btnSkipStack) + .addComponent(btnSkipToEndStepBeforeYourTurn) + ) + .addGroup(gl_pnlShortCuts.createSequentialGroup() + .addComponent(txtHoldPriority) + .addComponent(txtSpellsCast) + .addComponent(btnSwitchHands) + .addComponent(btnCancelSkip) + .addComponent(btnConcede) + .addComponent(btnStopWatching) + ) + //.addComponent(bigCard, javax.swing.GroupLayout.DEFAULT_SIZE, 256, Short.MAX_VALUE) + //.addComponent(feedbackPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 256, Short.MAX_VALUE) + //.addComponent(stack, javax.swing.GroupLayout.DEFAULT_SIZE, 256, Short.MAX_VALUE) + + .addGroup(gl_pnlShortCuts.createSequentialGroup() + .addContainerGap() + .addComponent(pnlReplay, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(51, Short.MAX_VALUE)) + ); + gl_pnlShortCuts.setVerticalGroup(gl_pnlShortCuts.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(gl_pnlShortCuts.createSequentialGroup() + //.addComponent(bigCard, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + //.addGap(1, 1, 1) + //.addComponent(feedbackPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 109, javax.swing.GroupLayout.PREFERRED_SIZE) + //.addComponent(stack, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 164, Short.MAX_VALUE) + .addComponent(pnlReplay, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(gl_pnlShortCuts.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(btnSkipToNextTurn) + .addComponent(btnSkipToEndTurn) + .addComponent(btnSkipToNextMain) + .addComponent(btnSkipToYourTurn) + .addComponent(btnSkipStack) + .addComponent(btnSkipToEndStepBeforeYourTurn) + ) + .addGroup(gl_pnlShortCuts.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(txtHoldPriority) + .addComponent(txtSpellsCast) + .addComponent(btnSwitchHands) + .addComponent(btnCancelSkip) + .addComponent(btnConcede) + .addComponent(btnStopWatching) + ) + ) + ); + + pnlBattlefield.setLayout(new java.awt.GridBagLayout()); + + jPhases = new JPanel(); + jPhases.setBackground(new Color(0, 0, 0, 0)); + jPhases.setLayout(null); + jPhases.setPreferredSize(new Dimension(X_PHASE_WIDTH, 435)); + + MouseAdapter phasesMouseAdapter = new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent evt) { + mouseClickPhaseBar(evt); + } + }; + String[] phases = {"Untap", "Upkeep", "Draw", "Main1", + "Combat_Start", "Combat_Attack", "Combat_Block", "Combat_Damage", "Combat_End", + "Main2", "Cleanup", "Next_Turn"}; + for (String name : phases) { + createPhaseButton(name, phasesMouseAdapter); + } + + int i = 0; + for (String name : hoverButtons.keySet()) { + HoverButton hoverButton = hoverButtons.get(name); + hoverButton.setAlignmentX(LEFT_ALIGNMENT); + hoverButton.setBounds(X_PHASE_WIDTH - 36, i * 36, 36, 36); + jPhases.add(hoverButton); + i++; + } + jPhases.addMouseListener(phasesMouseAdapter); + + pnlReplay.setOpaque(false); + + helper = new HelperPanel(); + feedbackPanel.setHelperPanel(helper); + + jSplitPane2.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT); + jSplitPane2.setResizeWeight(0.5); + jSplitPane2.setLeftComponent(userChatPanel); + jSplitPane2.setBottomComponent(gameChatPanel); + + phasesContainer = new JPanel(); + phasesContainer.setLayout(new RelativeLayout(RelativeLayout.Y_AXIS)); + phasesContainer.setBackground(new Color(0, 0, 0, 0)); + Float ratio = (float) 1; + JPanel empty1 = new JPanel(); + empty1.setBackground(new Color(0, 0, 0, 0)); + phasesContainer.add(empty1, ratio); + phasesContainer.add(jPhases); + + javax.swing.GroupLayout gl_helperHandButtonsStackArea = new javax.swing.GroupLayout(pnlHelperHandButtonsStackArea); + gl_helperHandButtonsStackArea.setHorizontalGroup( + gl_helperHandButtonsStackArea.createParallelGroup(Alignment.LEADING) + .addGroup(gl_helperHandButtonsStackArea.createSequentialGroup() + // .addGap(0) + .addGroup(gl_helperHandButtonsStackArea.createParallelGroup(Alignment.LEADING) + .addGroup(gl_helperHandButtonsStackArea.createSequentialGroup() + .addGroup(gl_helperHandButtonsStackArea.createParallelGroup(Alignment.LEADING) + .addComponent(helper, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(handContainer, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + ) + .addGroup(gl_helperHandButtonsStackArea.createParallelGroup(Alignment.LEADING) + .addComponent(pnlShortCuts, 410, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE) + .addComponent(stackObjects, 410, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE) + ) + ) + .addGap(0) + //.addComponent(jPhases, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(gl_helperHandButtonsStackArea.createSequentialGroup() + .addComponent(pnlBattlefield, GroupLayout.DEFAULT_SIZE, 200, Short.MAX_VALUE) + .addComponent(phasesContainer, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + ))) + ); + gl_helperHandButtonsStackArea.setVerticalGroup( + gl_helperHandButtonsStackArea.createParallelGroup(Alignment.TRAILING) + .addGroup(gl_helperHandButtonsStackArea.createSequentialGroup() + .addGroup(gl_helperHandButtonsStackArea.createParallelGroup(Alignment.LEADING) + .addComponent(pnlBattlefield, GroupLayout.DEFAULT_SIZE, 200, Short.MAX_VALUE) + .addComponent(phasesContainer, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + ) + //.addPreferredGap(ComponentPlacement.RELATED) + .addGroup(gl_helperHandButtonsStackArea.createParallelGroup(Alignment.LEADING) + .addGroup(gl_helperHandButtonsStackArea.createSequentialGroup() + .addGap(2) + .addComponent(pnlShortCuts, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addComponent(stackObjects, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + ) + .addGroup(gl_helperHandButtonsStackArea.createSequentialGroup() + .addComponent(helper, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + .addComponent(handContainer, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) + ) + ) + ) + ); + pnlHelperHandButtonsStackArea.setLayout(gl_helperHandButtonsStackArea); + + jSplitPane1.setLeftComponent(pnlHelperHandButtonsStackArea); + jSplitPane1.setRightComponent(jSplitPane2); + + // Set individual area sizes of big card pane + GridBagLayout gbl = new GridBagLayout(); + jPanel2.setLayout(gbl); + + GridBagConstraints gbc = new GridBagConstraints(); + gbc.fill = GridBagConstraints.BOTH; + gbc.gridx = 0; + gbc.gridy = 0; + gbc.gridwidth = 1; + gbc.gridheight = 4; // size 4/5 + gbc.weightx = 1.0; + gbc.weighty = 1.0; + gbl.setConstraints(bigCard, gbc); + jPanel2.add(bigCard); + + jPanel2.setOpaque(false); + + // game pane and chat/log pane + jSplitPane0.setLeftComponent(jSplitPane1); + // big card and buttons + jSplitPane0.setRightComponent(jPanel2); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jSplitPane0, javax.swing.GroupLayout.DEFAULT_SIZE, 1078, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jSplitPane0, javax.swing.GroupLayout.DEFAULT_SIZE, 798, Short.MAX_VALUE) + ); + } + + private void removeListener() { + for (MouseListener ml : this.getMouseListeners()) { + this.removeMouseListener(ml); + } + for (MouseListener ml : this.btnCancelSkip.getMouseListeners()) { + this.btnCancelSkip.removeMouseListener(ml); + } + for (MouseListener ml : this.btnConcede.getMouseListeners()) { + this.btnConcede.removeMouseListener(ml); + } + for (MouseListener ml : this.btnSkipToYourTurn.getMouseListeners()) { + this.btnSkipToYourTurn.removeMouseListener(ml); + } + for (MouseListener ml : this.btnSkipStack.getMouseListeners()) { + this.btnSkipStack.removeMouseListener(ml); + } + for (MouseListener ml : this.btnSkipToEndStepBeforeYourTurn.getMouseListeners()) { + this.btnSkipToEndStepBeforeYourTurn.removeMouseListener(ml); + } + for (MouseListener ml : this.btnSkipToEndTurn.getMouseListeners()) { + this.btnSkipToEndTurn.removeMouseListener(ml); + } + for (MouseListener ml : this.btnSkipToNextMain.getMouseListeners()) { + this.btnSkipToNextMain.removeMouseListener(ml); + } + for (MouseListener ml : this.btnSkipToNextTurn.getMouseListeners()) { + this.btnSkipToNextTurn.removeMouseListener(ml); + } + for (MouseListener ml : this.btnSwitchHands.getMouseListeners()) { + this.btnSwitchHands.removeMouseListener(ml); + } + for (MouseListener ml : this.btnStopWatching.getMouseListeners()) { + this.btnStopWatching.removeMouseListener(ml); + } + for (MouseListener ml : this.jPhases.getMouseListeners()) { + this.jPhases.removeMouseListener(ml); + } + for (String name : hoverButtons.keySet()) { + HoverButton hoverButton = hoverButtons.get(name); + for (MouseListener ml : hoverButton.getMouseListeners()) { + hoverButton.removeMouseListener(ml); + } + } + for (ActionListener al : this.btnPlay.getActionListeners()) { + this.btnPlay.removeActionListener(al); + } + for (ActionListener al : this.btnStopReplay.getActionListeners()) { + this.btnStopReplay.removeActionListener(al); + } + for (ActionListener al : this.btnNextPlay.getActionListeners()) { + this.btnNextPlay.removeActionListener(al); + } + for (ActionListener al : this.btnNextPlay.getActionListeners()) { + this.btnNextPlay.removeActionListener(al); + } + for (ActionListener al : this.btnPreviousPlay.getActionListeners()) { + this.btnPreviousPlay.removeActionListener(al); + } + for (ActionListener al : this.btnSkipForward.getActionListeners()) { + this.btnSkipForward.removeActionListener(al); + } + + final BasicSplitPaneUI myUi = (BasicSplitPaneUI) jSplitPane0.getUI(); + final BasicSplitPaneDivider divider = myUi.getDivider(); + final JButton upArrowButton = (JButton) divider.getComponent(0); + for (ActionListener al : upArrowButton.getActionListeners()) { + upArrowButton.removeActionListener(al); + } + final JButton downArrowButton = (JButton) divider.getComponent(1); + for (ActionListener al : downArrowButton.getActionListeners()) { + downArrowButton.removeActionListener(al); + } + + for (ComponentListener cl : this.getComponentListeners()) { + this.removeComponentListener(cl); + } + } + + private void btnConcedeActionPerformed(java.awt.event.ActionEvent evt) { + UserRequestMessage message = new UserRequestMessage("Confirm concede", "Are you sure you want to concede?"); + message.setButton1("No", null); + message.setButton2("Yes", PlayerAction.CLIENT_CONCEDE_GAME); + message.setGameId(gameId); + MageFrame.getInstance().showUserRequestDialog(message); + } + + private void btnEndTurnActionPerformed(java.awt.event.ActionEvent evt) { + SessionHandler.sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_NEXT_TURN, gameId, null); + AudioManager.playOnSkipButton(); + updateSkipButtons(true, false, false, false, false, false); + } + + private void btnUntilEndOfTurnActionPerformed(java.awt.event.ActionEvent evt) { + SessionHandler.sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_TURN_END_STEP, gameId, null); + AudioManager.playOnSkipButton(); + updateSkipButtons(false, true, false, false, false, false); + } + + private void btnEndTurnSkipStackActionPerformed(java.awt.event.ActionEvent evt) { + SessionHandler.sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_NEXT_TURN_SKIP_STACK, gameId, null); + AudioManager.playOnSkipButton(); + updateSkipButtons(true, false, false, false, true, false); + } + + private void btnUntilNextMainPhaseActionPerformed(java.awt.event.ActionEvent evt) { + SessionHandler.sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_NEXT_MAIN_PHASE, gameId, null); + AudioManager.playOnSkipButton(); + updateSkipButtons(false, false, true, false, false, false); + } + + private void btnPassPriorityUntilNextYourTurnActionPerformed(java.awt.event.ActionEvent evt) { + SessionHandler.sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_MY_NEXT_TURN, gameId, null); + AudioManager.playOnSkipButton(); + updateSkipButtons(false, false, false, true, false, false); + } + + private void btnPassPriorityUntilStackResolvedActionPerformed(java.awt.event.ActionEvent evt) { + SessionHandler.sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_STACK_RESOLVED, gameId, null); + AudioManager.playOnSkipButton(); + updateSkipButtons(false, false, false, false, true, false); + } + + private void btnSkipToEndStepBeforeYourTurnActionPerformed(java.awt.event.ActionEvent evt) { + SessionHandler.sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_END_STEP_BEFORE_MY_NEXT_TURN, gameId, null); + AudioManager.playOnSkipButton(); + updateSkipButtons(false, false, false, false, false, true); + } + + private void restorePriorityActionPerformed(java.awt.event.ActionEvent evt) { + SessionHandler.sendPlayerAction(PlayerAction.PASS_PRIORITY_CANCEL_ALL_ACTIONS, gameId, null); + AudioManager.playOnSkipButtonCancel(); + updateSkipButtons(false, false, false, false, false, false); + } + + private void mouseClickPhaseBar(MouseEvent evt) { + if (evt.getButton() == MouseEvent.BUTTON1) { // Left button + PreferencesDialog.main(new String[]{PreferencesDialog.OPEN_PHASES_TAB}); + } + } + + private void btnSwitchHandActionPerformed(java.awt.event.ActionEvent evt) { + String[] choices = handCards.keySet().toArray(new String[0]); + + String newChosenHandKey = (String) JOptionPane.showInputDialog( + this, + "Choose hand to display:", "Switch between hands", + JOptionPane.PLAIN_MESSAGE, + null, + choices, + this.chosenHandKey); + + if (newChosenHandKey != null && newChosenHandKey.length() > 0) { + this.chosenHandKey = newChosenHandKey; + CardsView cards = handCards.get(chosenHandKey); + handContainer.loadCards(cards, bigCard, gameId); + } + } private void btnStopWatchingActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnStopWatchingActionPerformed - UserRequestMessage message = new UserRequestMessage("Stop watching", "Are you sure you want to stop watching?"); - message.setButton1("No", null); - message.setButton2("Yes", PlayerAction.CLIENT_STOP_WATCHING); - message.setGameId(gameId); - MageFrame.getInstance().showUserRequestDialog(message); + UserRequestMessage message = new UserRequestMessage("Stop watching", "Are you sure you want to stop watching?"); + message.setButton1("No", null); + message.setButton2("Yes", PlayerAction.CLIENT_STOP_WATCHING); + message.setGameId(gameId); + MageFrame.getInstance().showUserRequestDialog(message); }//GEN-LAST:event_btnStopWatchingActionPerformed private void btnStopReplayActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnStopReplayActionPerformed - if (replayTask != null && !replayTask.isDone()) { - replayTask.cancel(true); - } else { - UserRequestMessage message = new UserRequestMessage("Stop replay", "Are you sure you want to stop replay?"); - message.setButton1("No", null); - message.setButton2("Yes", PlayerAction.CLIENT_REPLAY_ACTION); - message.setGameId(gameId); - MageFrame.getInstance().showUserRequestDialog(message); - } + if (replayTask != null && !replayTask.isDone()) { + replayTask.cancel(true); + } else { + UserRequestMessage message = new UserRequestMessage("Stop replay", "Are you sure you want to stop replay?"); + message.setButton1("No", null); + message.setButton2("Yes", PlayerAction.CLIENT_REPLAY_ACTION); + message.setGameId(gameId); + MageFrame.getInstance().showUserRequestDialog(message); + } }//GEN-LAST:event_btnStopReplayActionPerformed private void btnNextPlayActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnNextPlayActionPerformed - SessionHandler.nextPlay(gameId); + SessionHandler.nextPlay(gameId); }//GEN-LAST:event_btnNextPlayActionPerformed private void btnPreviousPlayActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnPreviousPlayActionPerformed - SessionHandler.previousPlay(gameId); + SessionHandler.previousPlay(gameId); }//GEN-LAST:event_btnPreviousPlayActionPerformed private void btnPlayActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnPlayActionPerformed - if (replayTask == null || replayTask.isDone()) { - replayTask = new ReplayTask(gameId); - replayTask.execute(); - } + if (replayTask == null || replayTask.isDone()) { + replayTask = new ReplayTask(gameId); + replayTask.execute(); + } }//GEN-LAST:event_btnPlayActionPerformed private void btnSkipForwardActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnSkipForwardActionPerformed - SessionHandler.skipForward(gameId, 10); + SessionHandler.skipForward(gameId, 10); }//GEN-LAST:event_btnSkipForwardActionPerformed - public void setJLayeredPane(JLayeredPane jLayeredPane) { - this.jLayeredPane = jLayeredPane; - } + public void setJLayeredPane(JLayeredPane jLayeredPane) { + this.jLayeredPane = jLayeredPane; + } - public void installComponents() { - jLayeredPane.setOpaque(false); - jLayeredPane.add(abilityPicker); - jLayeredPane.add(DialogManager.getManager(gameId), JLayeredPane.MODAL_LAYER, 0); - abilityPicker.setVisible(false); - } + public void installComponents() { + jLayeredPane.setOpaque(false); + jLayeredPane.add(abilityPicker); + jLayeredPane.add(DialogManager.getManager(gameId), JLayeredPane.MODAL_LAYER, 0); + abilityPicker.setVisible(false); + } - private void createPhaseButton(String name, MouseAdapter mouseAdapter) { - if (hoverButtons == null) { - hoverButtons = new LinkedHashMap<>(); - } - Rectangle rect = new Rectangle(36, 36); - HoverButton button = new HoverButton("", ImageManagerImpl.getInstance().getPhaseImage(name), rect); - button.setToolTipText(name.replaceAll("_", " ")); - button.setPreferredSize(new Dimension(36, 36)); - button.addMouseListener(mouseAdapter); - hoverButtons.put(name, button); - } + private void createPhaseButton(String name, MouseAdapter mouseAdapter) { + if (hoverButtons == null) { + hoverButtons = new LinkedHashMap<>(); + } + Rectangle rect = new Rectangle(36, 36); + HoverButton button = new HoverButton("", ImageManagerImpl.getInstance().getPhaseImage(name), rect); + button.setToolTipText(name.replaceAll("_", " ")); + button.setPreferredSize(new Dimension(36, 36)); + button.addMouseListener(mouseAdapter); + hoverButtons.put(name, button); + } - // Event listener for the ShowCardsDialog - private Listener getShowCardsEventListener(final ShowCardsDialog dialog) { - return new Listener() { - @Override - public void event(Event event) { - if (event.getEventName().equals("show-popup-menu")) { - if (event.getComponent() != null && event.getComponent() instanceof CardPanel) { - JPopupMenu menu = ((CardPanel) event.getComponent()).getPopupMenu(); - if (menu != null) { - cardViewPopupMenu = ((CardView) event.getSource()); - menu.show(event.getComponent(), event.getxPos(), event.getyPos()); - } - } - } - if (event.getEventName().equals("action-consumed")) { - dialog.removeDialog(); - } - } - }; - } + // Event listener for the ShowCardsDialog + private Listener getShowCardsEventListener(final ShowCardsDialog dialog) { + return new Listener() { + @Override + public void event(Event event) { + if (event.getEventName().equals("show-popup-menu")) { + if (event.getComponent() != null && event.getComponent() instanceof CardPanel) { + JPopupMenu menu = ((CardPanel) event.getComponent()).getPopupMenu(); + if (menu != null) { + cardViewPopupMenu = ((CardView) event.getSource()); + menu.show(event.getComponent(), event.getxPos(), event.getyPos()); + } + } + } + if (event.getEventName().equals("action-consumed")) { + dialog.removeDialog(); + } + } + }; + } - public void handleTriggerOrderPopupMenuEvent(ActionEvent e) { - UUID abilityId = null; - String abilityRuleText = null; - if (cardViewPopupMenu instanceof CardView && cardViewPopupMenu.getAbility() != null) { - abilityId = cardViewPopupMenu.getAbility().getId(); - if (!cardViewPopupMenu.getAbility().getRules().isEmpty() - && !cardViewPopupMenu.getAbility().getRules().get(0).isEmpty()) { - abilityRuleText = cardViewPopupMenu.getAbility().getRules().get(0); - } - } - switch (e.getActionCommand()) { - case CMD_AUTO_ORDER_FIRST: - SessionHandler.sendPlayerAction(TRIGGER_AUTO_ORDER_ABILITY_FIRST, gameId, abilityId); - SessionHandler.sendPlayerUUID(gameId, abilityId); - break; - case CMD_AUTO_ORDER_LAST: - SessionHandler.sendPlayerAction(TRIGGER_AUTO_ORDER_ABILITY_LAST, gameId, abilityId); - SessionHandler.sendPlayerUUID(gameId, null); // Don't use this but refresh the displayed abilities - break; - case CMD_AUTO_ORDER_NAME_FIRST: - if (abilityRuleText != null) { - SessionHandler.sendPlayerAction(TRIGGER_AUTO_ORDER_NAME_FIRST, gameId, abilityRuleText); - SessionHandler.sendPlayerUUID(gameId, abilityId); - } - break; - case CMD_AUTO_ORDER_NAME_LAST: - if (abilityRuleText != null) { - SessionHandler.sendPlayerAction(TRIGGER_AUTO_ORDER_NAME_LAST, gameId, abilityRuleText); - SessionHandler.sendPlayerUUID(gameId, null); // Don't use this but refresh the displayed abilities - } - break; - case CMD_AUTO_ORDER_RESET_ALL: - SessionHandler.sendPlayerAction(TRIGGER_AUTO_ORDER_RESET_ALL, gameId, null); - break; - } - for (ShowCardsDialog dialog : pickTarget) { - dialog.removeDialog(); - } - } + public void handleTriggerOrderPopupMenuEvent(ActionEvent e) { + UUID abilityId = null; + String abilityRuleText = null; + if (cardViewPopupMenu instanceof CardView && cardViewPopupMenu.getAbility() != null) { + abilityId = cardViewPopupMenu.getAbility().getId(); + if (!cardViewPopupMenu.getAbility().getRules().isEmpty() + && !cardViewPopupMenu.getAbility().getRules().get(0).isEmpty()) { + abilityRuleText = cardViewPopupMenu.getAbility().getRules().get(0); + } + } + switch (e.getActionCommand()) { + case CMD_AUTO_ORDER_FIRST: + SessionHandler.sendPlayerAction(TRIGGER_AUTO_ORDER_ABILITY_FIRST, gameId, abilityId); + SessionHandler.sendPlayerUUID(gameId, abilityId); + break; + case CMD_AUTO_ORDER_LAST: + SessionHandler.sendPlayerAction(TRIGGER_AUTO_ORDER_ABILITY_LAST, gameId, abilityId); + SessionHandler.sendPlayerUUID(gameId, null); // Don't use this but refresh the displayed abilities + break; + case CMD_AUTO_ORDER_NAME_FIRST: + if (abilityRuleText != null) { + SessionHandler.sendPlayerAction(TRIGGER_AUTO_ORDER_NAME_FIRST, gameId, abilityRuleText); + SessionHandler.sendPlayerUUID(gameId, abilityId); + } + break; + case CMD_AUTO_ORDER_NAME_LAST: + if (abilityRuleText != null) { + SessionHandler.sendPlayerAction(TRIGGER_AUTO_ORDER_NAME_LAST, gameId, abilityRuleText); + SessionHandler.sendPlayerUUID(gameId, null); // Don't use this but refresh the displayed abilities + } + break; + case CMD_AUTO_ORDER_RESET_ALL: + SessionHandler.sendPlayerAction(TRIGGER_AUTO_ORDER_RESET_ALL, gameId, null); + break; + } + for (ShowCardsDialog dialog : pickTarget) { + dialog.removeDialog(); + } + } - private void initPopupMenuTriggerOrder() { + private void initPopupMenuTriggerOrder() { - ActionListener actionListener = new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - handleTriggerOrderPopupMenuEvent(e); - } - }; + ActionListener actionListener = new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + handleTriggerOrderPopupMenuEvent(e); + } + }; - popupMenuTriggerOrder = new JPopupMenu(); + popupMenuTriggerOrder = new JPopupMenu(); - // String tooltipText = ""; - JMenuItem menuItem; - menuItem = new JMenuItem("Put this ability always first on the stack"); - menuItem.setActionCommand(CMD_AUTO_ORDER_FIRST); - menuItem.addActionListener(actionListener); - popupMenuTriggerOrder.add(menuItem); + // String tooltipText = ""; + JMenuItem menuItem; + menuItem = new JMenuItem("Put this ability always first on the stack"); + menuItem.setActionCommand(CMD_AUTO_ORDER_FIRST); + menuItem.addActionListener(actionListener); + popupMenuTriggerOrder.add(menuItem); - menuItem = new JMenuItem("Put this ability always last on the stack"); - menuItem.setActionCommand(CMD_AUTO_ORDER_LAST); - menuItem.addActionListener(actionListener); - popupMenuTriggerOrder.add(menuItem); + menuItem = new JMenuItem("Put this ability always last on the stack"); + menuItem.setActionCommand(CMD_AUTO_ORDER_LAST); + menuItem.addActionListener(actionListener); + popupMenuTriggerOrder.add(menuItem); - menuItem = new JMenuItem("Put all abilities with that rule text always first on the stack"); - menuItem.setActionCommand(CMD_AUTO_ORDER_NAME_FIRST); - menuItem.addActionListener(actionListener); - popupMenuTriggerOrder.add(menuItem); + menuItem = new JMenuItem("Put all abilities with that rule text always first on the stack"); + menuItem.setActionCommand(CMD_AUTO_ORDER_NAME_FIRST); + menuItem.addActionListener(actionListener); + popupMenuTriggerOrder.add(menuItem); - menuItem = new JMenuItem("Put all abilities with that rule text always last on the stack"); - menuItem.setActionCommand(CMD_AUTO_ORDER_NAME_LAST); - menuItem.addActionListener(actionListener); - popupMenuTriggerOrder.add(menuItem); + menuItem = new JMenuItem("Put all abilities with that rule text always last on the stack"); + menuItem.setActionCommand(CMD_AUTO_ORDER_NAME_LAST); + menuItem.addActionListener(actionListener); + popupMenuTriggerOrder.add(menuItem); - menuItem = new JMenuItem("Reset all order settings for triggered abilities"); - menuItem.setActionCommand(CMD_AUTO_ORDER_RESET_ALL); - menuItem.addActionListener(actionListener); - popupMenuTriggerOrder.add(menuItem); - } + menuItem = new JMenuItem("Reset all order settings for triggered abilities"); + menuItem.setActionCommand(CMD_AUTO_ORDER_RESET_ALL); + menuItem.addActionListener(actionListener); + popupMenuTriggerOrder.add(menuItem); + } - public String getGameLog() { - return gameChatPanel.getText(); - } + public String getGameLog() { + return gameChatPanel.getText(); + } - public Map getLoadedCards() { - return loadedCards; - } + public Map getLoadedCards() { + return loadedCards; + } - public void setLoadedCards(Map loadedCards) { - this.loadedCards = loadedCards; - } + public void setLoadedCards(Map loadedCards) { + this.loadedCards = loadedCards; + } - public FeedbackPanel getFeedbackPanel() { - return feedbackPanel; - } + public FeedbackPanel getFeedbackPanel() { + return feedbackPanel; + } - // Use Cmd on OSX since Ctrl+click is already used to simulate right click - private static int holdPriorityMask = System.getProperty("os.name").contains("Mac OS X") ? InputEvent.META_DOWN_MASK : InputEvent.CTRL_DOWN_MASK; + // Use Cmd on OSX since Ctrl+click is already used to simulate right click + private static int holdPriorityMask = System.getProperty("os.name").contains("Mac OS X") ? InputEvent.META_DOWN_MASK : InputEvent.CTRL_DOWN_MASK; - public void handleEvent(AWTEvent event) { - if (event instanceof InputEvent) { - int id = event.getID(); - boolean isActionEvent = false; - if (id == MouseEvent.MOUSE_PRESSED) { - isActionEvent = true; - } else if (id == KeyEvent.KEY_PRESSED) { - KeyEvent key = (KeyEvent) event; - int keyCode = key.getKeyCode(); - if (keyCode == KeyEvent.VK_ENTER || keyCode == KeyEvent.VK_SPACE) { - isActionEvent = true; - } - } - if (isActionEvent) { - InputEvent input = (InputEvent) event; - if ((input.getModifiersEx() & holdPriorityMask) != 0) { - setMenuStates( - PreferencesDialog.getCachedValue(KEY_GAME_MANA_AUTOPAYMENT, "true").equals("true"), - PreferencesDialog.getCachedValue(KEY_GAME_MANA_AUTOPAYMENT_ONLY_ONE, "true").equals("true"), - PreferencesDialog.getCachedValue(KEY_USE_FIRST_MANA_ABILITY, "false").equals("true"), - true); - holdPriority(true); - } - } - } - } + public void handleEvent(AWTEvent event) { + if (event instanceof InputEvent) { + int id = event.getID(); + boolean isActionEvent = false; + if (id == MouseEvent.MOUSE_PRESSED) { + isActionEvent = true; + } else if (id == KeyEvent.KEY_PRESSED) { + KeyEvent key = (KeyEvent) event; + int keyCode = key.getKeyCode(); + if (keyCode == KeyEvent.VK_ENTER || keyCode == KeyEvent.VK_SPACE) { + isActionEvent = true; + } + } + if (isActionEvent) { + InputEvent input = (InputEvent) event; + if ((input.getModifiersEx() & holdPriorityMask) != 0) { + setMenuStates( + PreferencesDialog.getCachedValue(KEY_GAME_MANA_AUTOPAYMENT, "true").equals("true"), + PreferencesDialog.getCachedValue(KEY_GAME_MANA_AUTOPAYMENT_ONLY_ONE, "true").equals("true"), + PreferencesDialog.getCachedValue(KEY_USE_FIRST_MANA_ABILITY, "false").equals("true"), + true); + holdPriority(true); + } + } + } + } - public void holdPriority(boolean holdPriority) { - if (holdingPriority != holdPriority) { - holdingPriority = holdPriority; - txtHoldPriority.setVisible(holdPriority); - if (holdPriority) { - SessionHandler.sendPlayerAction(PlayerAction.HOLD_PRIORITY, gameId, null); - } else { - SessionHandler.sendPlayerAction(PlayerAction.UNHOLD_PRIORITY, gameId, null); - } - } - } + public void holdPriority(boolean holdPriority) { + if (holdingPriority != holdPriority) { + holdingPriority = holdPriority; + txtHoldPriority.setVisible(holdPriority); + if (holdPriority) { + SessionHandler.sendPlayerAction(PlayerAction.HOLD_PRIORITY, gameId, null); + } else { + SessionHandler.sendPlayerAction(PlayerAction.UNHOLD_PRIORITY, gameId, null); + } + } + } - private boolean holdingPriority; - private mage.client.components.ability.AbilityPicker abilityPicker; - private mage.client.cards.BigCard bigCard; + private boolean holdingPriority; + private mage.client.components.ability.AbilityPicker abilityPicker; + private mage.client.cards.BigCard bigCard; // private JPanel cancelSkipPanel; - private javax.swing.JButton btnCancelSkip; - private javax.swing.JButton btnSkipToNextTurn; // F4 - private javax.swing.JButton btnSkipToEndTurn; // F5 - private javax.swing.JButton btnSkipToNextMain; // F7 - private javax.swing.JButton btnSkipStack; // F8 - private javax.swing.JButton btnSkipToYourTurn; // F9 - private javax.swing.JButton btnSkipToEndStepBeforeYourTurn; // F11 + private javax.swing.JButton btnCancelSkip; + private javax.swing.JButton btnSkipToNextTurn; // F4 + private javax.swing.JButton btnSkipToEndTurn; // F5 + private javax.swing.JButton btnSkipToNextMain; // F7 + private javax.swing.JButton btnSkipStack; // F8 + private javax.swing.JButton btnSkipToYourTurn; // F9 + private javax.swing.JButton btnSkipToEndStepBeforeYourTurn; // F11 - private javax.swing.JButton btnConcede; - private javax.swing.JButton btnSwitchHands; + private javax.swing.JButton btnConcede; + private javax.swing.JButton btnSwitchHands; - private javax.swing.JButton btnNextPlay; - private javax.swing.JButton btnPlay; - private javax.swing.JButton btnPreviousPlay; - private javax.swing.JButton btnSkipForward; - private javax.swing.JButton btnStopReplay; + private javax.swing.JButton btnNextPlay; + private javax.swing.JButton btnPlay; + private javax.swing.JButton btnPreviousPlay; + private javax.swing.JButton btnSkipForward; + private javax.swing.JButton btnStopReplay; - private javax.swing.JButton btnStopWatching; + private javax.swing.JButton btnStopWatching; - private mage.client.chat.ChatPanelBasic gameChatPanel; - private mage.client.game.FeedbackPanel feedbackPanel; - private HelperPanel helper; - private mage.client.chat.ChatPanelBasic userChatPanel; - private javax.swing.JPanel jPanel2; - private javax.swing.JPanel pnlHelperHandButtonsStackArea; - private javax.swing.JSplitPane jSplitPane0; - private javax.swing.JSplitPane jSplitPane1; - private javax.swing.JLabel lblActivePlayer; - private javax.swing.JLabel lblPhase; - private javax.swing.JLabel lblPriority; - private javax.swing.JLabel lblStep; - private javax.swing.JLabel lblTurn; - private javax.swing.JPanel pnlBattlefield; - private javax.swing.JPanel pnlShortCuts; - private javax.swing.JPanel pnlReplay; - private javax.swing.JLabel txtActivePlayer; - private javax.swing.JLabel txtPhase; - private javax.swing.JLabel txtPriority; - private javax.swing.JLabel txtStep; - private javax.swing.JLabel txtTurn; + private mage.client.chat.ChatPanelBasic gameChatPanel; + private mage.client.game.FeedbackPanel feedbackPanel; + private HelperPanel helper; + private mage.client.chat.ChatPanelBasic userChatPanel; + private javax.swing.JPanel jPanel2; + private javax.swing.JPanel pnlHelperHandButtonsStackArea; + private javax.swing.JSplitPane jSplitPane0; + private javax.swing.JSplitPane jSplitPane1; + private javax.swing.JLabel lblActivePlayer; + private javax.swing.JLabel lblPhase; + private javax.swing.JLabel lblPriority; + private javax.swing.JLabel lblStep; + private javax.swing.JLabel lblTurn; + private javax.swing.JPanel pnlBattlefield; + private javax.swing.JPanel pnlShortCuts; + private javax.swing.JPanel pnlReplay; + private javax.swing.JLabel txtActivePlayer; + private javax.swing.JLabel txtPhase; + private javax.swing.JLabel txtPriority; + private javax.swing.JLabel txtStep; + private javax.swing.JLabel txtTurn; - private Map handCards; + private Map handCards; - private mage.client.cards.Cards stackObjects; - private HandPanel handContainer; + private mage.client.cards.Cards stackObjects; + private HandPanel handContainer; - private javax.swing.JSplitPane jSplitPane2; - private JPanel jPhases; - private JPanel phasesContainer; - private javax.swing.JLabel txtSpellsCast; - private javax.swing.JLabel txtHoldPriority; + private javax.swing.JSplitPane jSplitPane2; + private JPanel jPhases; + private JPanel phasesContainer; + private javax.swing.JLabel txtSpellsCast; + private javax.swing.JLabel txtHoldPriority; - private HoverButton currentStep; - private Point prevPoint; + private HoverButton currentStep; + private Point prevPoint; - private boolean imagePanelState; + private boolean imagePanelState; } class ReplayTask extends SwingWorker> { - private final UUID gameId; + private final UUID gameId; - private static final Logger logger = Logger.getLogger(ReplayTask.class); + private static final Logger logger = Logger.getLogger(ReplayTask.class); - ReplayTask(UUID gameId) { - this.gameId = gameId; - } + ReplayTask(UUID gameId) { + this.gameId = gameId; + } - @Override - protected Void doInBackground() throws Exception { - while (!isCancelled()) { - SessionHandler.nextPlay(gameId); - Thread.sleep(1000); - } - return null; - } + @Override + protected Void doInBackground() throws Exception { + while (!isCancelled()) { + SessionHandler.nextPlay(gameId); + Thread.sleep(1000); + } + return null; + } - @Override - protected void done() { - try { - get(); - } catch (InterruptedException ex) { - logger.fatal("Replay Match Task error", ex); - } catch (ExecutionException ex) { - logger.fatal("Replay Match Task error", ex); - } catch (CancellationException ex) { - } - } + @Override + protected void done() { + try { + get(); + } catch (InterruptedException ex) { + logger.fatal("Replay Match Task error", ex); + } catch (ExecutionException ex) { + logger.fatal("Replay Match Task error", ex); + } catch (CancellationException ex) { + } + } } From d9ebceec207378856df14b963b80ef95ac06dbc0 Mon Sep 17 00:00:00 2001 From: Campbell Suter Date: Wed, 19 Oct 2016 09:15:37 +1300 Subject: [PATCH 17/35] Make tooltips work properly --- .../mage/client/dialog/PreferencesDialog.java | 56 ++++++++++++++----- .../main/java/mage/client/game/GamePanel.java | 55 ++++++++---------- 2 files changed, 67 insertions(+), 44 deletions(-) diff --git a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java index 87f4b8c19eb..a7be9ed7c83 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java @@ -3318,15 +3318,15 @@ public class PreferencesDialog extends javax.swing.JDialog { } private static void loadControlSettings(Preferences prefs) { - load(prefs, dialog.keyConfirm, KEY_CONTROL_CONFIRM, KeyEvent.VK_F2); - load(prefs, dialog.keyCancelSkip, KEY_CONTROL_CANCEL_SKIP, KeyEvent.VK_F3); - load(prefs, dialog.keyNextTurn, KEY_CONTROL_NEXT_TURN, KeyEvent.VK_F4); - load(prefs, dialog.keyEndStep, KEY_CONTROL_END_STEP, KeyEvent.VK_F5); - load(prefs, dialog.keySkipStep, KEY_CONTROL_SKIP_STEP, KeyEvent.VK_F6); - load(prefs, dialog.keyMainStep, KEY_CONTROL_MAIN_STEP, KeyEvent.VK_F7); - load(prefs, dialog.keyYourTurn, KEY_CONTROL_YOUR_TURN, KeyEvent.VK_F9); - load(prefs, dialog.keySkipStack, KEY_CONTROL_SKIP_STACK, KeyEvent.VK_F10); - load(prefs, dialog.keyPriorEnd, KEY_CONTROL_PRIOR_END, KeyEvent.VK_F11); + load(prefs, dialog.keyConfirm, KEY_CONTROL_CONFIRM); + load(prefs, dialog.keyCancelSkip, KEY_CONTROL_CANCEL_SKIP); + load(prefs, dialog.keyNextTurn, KEY_CONTROL_NEXT_TURN); + load(prefs, dialog.keyEndStep, KEY_CONTROL_END_STEP); + load(prefs, dialog.keySkipStep, KEY_CONTROL_SKIP_STEP); + load(prefs, dialog.keyMainStep, KEY_CONTROL_MAIN_STEP); + load(prefs, dialog.keyYourTurn, KEY_CONTROL_YOUR_TURN); + load(prefs, dialog.keySkipStack, KEY_CONTROL_SKIP_STACK); + load(prefs, dialog.keyPriorEnd, KEY_CONTROL_PRIOR_END); } private static void loadSelectedAvatar(Preferences prefs) { @@ -3453,8 +3453,8 @@ public class PreferencesDialog extends javax.swing.JDialog { load(prefs, checkBox, propName, PHASE_ON); } - private static void load(Preferences prefs, KeyBindButton button, String propName, int defaultValue) { - int prop = prefs.getInt(propName, defaultValue); + private static void load(Preferences prefs, KeyBindButton button, String propName) { + int prop = prefs.getInt(propName, getDefaultControlKey(propName)); button.setKeyCode(prop); } @@ -3531,11 +3531,41 @@ public class PreferencesDialog extends javax.swing.JDialog { } } - public static KeyStroke getCachedKeystroke(String key, int def) { - int code = getCachedValue(key, def); + private static int getDefaultControlKey(String key) { + switch (key) { + case KEY_CONTROL_CONFIRM: + return KeyEvent.VK_F2; + case KEY_CONTROL_CANCEL_SKIP: + return KeyEvent.VK_F3; + case KEY_CONTROL_NEXT_TURN: + return KeyEvent.VK_F4; + case KEY_CONTROL_END_STEP: + return KeyEvent.VK_F5; + case KEY_CONTROL_SKIP_STEP: + return KeyEvent.VK_F6; + case KEY_CONTROL_MAIN_STEP: + return KeyEvent.VK_F7; + case KEY_CONTROL_YOUR_TURN: + return KeyEvent.VK_F9; + case KEY_CONTROL_SKIP_STACK: + return KeyEvent.VK_F10; + case KEY_CONTROL_PRIOR_END: + return KeyEvent.VK_F11; + default: + return 0; + } + } + + public static KeyStroke getCachedKeystroke(String key) { + int code = getCachedValue(key, getDefaultControlKey(key)); return KeyStroke.getKeyStroke(code, 0); } + public static String getCachedKeyText(String key) { + int code = getCachedValue(key, getDefaultControlKey(key)); + return KeyEvent.getKeyText(code); + } + private static void updateCache(String key, String value) { CACHE.put(key, value); } diff --git a/Mage.Client/src/main/java/mage/client/game/GamePanel.java b/Mage.Client/src/main/java/mage/client/game/GamePanel.java index 2c149d864b3..6f745e3aaa8 100644 --- a/Mage.Client/src/main/java/mage/client/game/GamePanel.java +++ b/Mage.Client/src/main/java/mage/client/game/GamePanel.java @@ -99,12 +99,7 @@ import mage.client.dialog.PickChoiceDialog; import mage.client.dialog.PickNumberDialog; import mage.client.dialog.PickPileDialog; import mage.client.dialog.PreferencesDialog; -import static mage.client.dialog.PreferencesDialog.KEY_CONTROL_NEXT_TURN; -import static mage.client.dialog.PreferencesDialog.KEY_CONTROL_PRIOR_END; -import static mage.client.dialog.PreferencesDialog.KEY_CONTROL_YOUR_TURN; -import static mage.client.dialog.PreferencesDialog.KEY_GAME_MANA_AUTOPAYMENT; -import static mage.client.dialog.PreferencesDialog.KEY_GAME_MANA_AUTOPAYMENT_ONLY_ONE; -import static mage.client.dialog.PreferencesDialog.KEY_USE_FIRST_MANA_ABILITY; +import static mage.client.dialog.PreferencesDialog.*; import mage.client.dialog.ShowCardsDialog; import mage.client.game.FeedbackPanel.FeedbackMode; import mage.client.plugins.adapters.MageActionCallback; @@ -1449,8 +1444,7 @@ public final class GamePanel extends javax.swing.JPanel { int c = JComponent.WHEN_IN_FOCUSED_WINDOW; - KeyStroke ks3 = PreferencesDialog.getCachedKeystroke( - PreferencesDialog.KEY_CONTROL_CANCEL_SKIP, KeyEvent.VK_F3); + KeyStroke ks3 = getCachedKeystroke(KEY_CONTROL_CANCEL_SKIP); this.getInputMap(c).put(ks3, "F3_PRESS"); this.getActionMap().put("F3_PRESS", new AbstractAction() { @Override @@ -1462,7 +1456,8 @@ public final class GamePanel extends javax.swing.JPanel { btnCancelSkip.setContentAreaFilled(false); btnCancelSkip.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); btnCancelSkip.setIcon(new ImageIcon(ImageManagerImpl.getInstance().getCancelSkipButtonImage())); - btnCancelSkip.setToolTipText("Cancel all skip actions (F3)."); + btnCancelSkip.setToolTipText("Cancel all skip actions (" + + getCachedKeyText(KEY_CONTROL_CANCEL_SKIP) + ")."); btnCancelSkip.setFocusable(false); btnCancelSkip.addMouseListener(new MouseAdapter() { @Override @@ -1476,7 +1471,8 @@ public final class GamePanel extends javax.swing.JPanel { btnSkipToNextTurn.setContentAreaFilled(false); btnSkipToNextTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); btnSkipToNextTurn.setIcon(new ImageIcon(ImageManagerImpl.getInstance().getSkipNextTurnButtonImage())); - btnSkipToNextTurn.setToolTipText("Skip to next turn (F4)."); + btnSkipToNextTurn.setToolTipText("Skip to next turn (" + + getCachedKeyText(KEY_CONTROL_NEXT_TURN) + ")."); btnSkipToNextTurn.setFocusable(false); btnSkipToNextTurn.addMouseListener(new MouseAdapter() { @Override @@ -1487,8 +1483,7 @@ public final class GamePanel extends javax.swing.JPanel { } }); - KeyStroke ks = PreferencesDialog.getCachedKeystroke( - PreferencesDialog.KEY_CONTROL_NEXT_TURN, KeyEvent.VK_F4); + KeyStroke ks = getCachedKeystroke(KEY_CONTROL_NEXT_TURN); this.getInputMap(c).put(ks, "F4_PRESS"); this.getActionMap().put("F4_PRESS", new AbstractAction() { @Override @@ -1500,7 +1495,8 @@ public final class GamePanel extends javax.swing.JPanel { btnSkipToEndTurn.setContentAreaFilled(false); btnSkipToEndTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); btnSkipToEndTurn.setIcon(new ImageIcon(ImageManagerImpl.getInstance().getSkipEndTurnButtonImage())); - btnSkipToEndTurn.setToolTipText("Skip to (opponents/next) end of turn step (F5) - adjust using preferences."); + btnSkipToEndTurn.setToolTipText("Skip to (opponents/next) end of turn step (" + + getCachedKeyText(KEY_CONTROL_END_STEP) + ") - adjust using preferences."); btnSkipToEndTurn.setFocusable(false); btnSkipToEndTurn.addMouseListener(new MouseAdapter() { @Override @@ -1511,8 +1507,7 @@ public final class GamePanel extends javax.swing.JPanel { } }); - ks = PreferencesDialog.getCachedKeystroke( - PreferencesDialog.KEY_CONTROL_END_STEP, KeyEvent.VK_F5); + ks = getCachedKeystroke(KEY_CONTROL_END_STEP); this.getInputMap(c).put(ks, "F5_PRESS"); this.getActionMap().put("F5_PRESS", new AbstractAction() { @Override @@ -1521,8 +1516,7 @@ public final class GamePanel extends javax.swing.JPanel { } }); - ks = PreferencesDialog.getCachedKeystroke( - PreferencesDialog.KEY_CONTROL_SKIP_STEP, KeyEvent.VK_F6); + ks = getCachedKeystroke(KEY_CONTROL_SKIP_STEP); this.getInputMap(c).put(ks, "F6_PRESS"); this.getActionMap().put("F6_PRESS", new AbstractAction() { @Override @@ -1534,7 +1528,8 @@ public final class GamePanel extends javax.swing.JPanel { btnSkipToNextMain.setContentAreaFilled(false); btnSkipToNextMain.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); btnSkipToNextMain.setIcon(new ImageIcon(ImageManagerImpl.getInstance().getSkipMainButtonImage())); - btnSkipToNextMain.setToolTipText("Skip to (your) next main phase (F7) - adjust using preferences."); + btnSkipToNextMain.setToolTipText("Skip to (your) next main phase (" + + getCachedKeyText(KEY_CONTROL_MAIN_STEP) + ") - adjust using preferences."); btnSkipToNextMain.setFocusable(false); btnSkipToNextMain.addMouseListener(new MouseAdapter() { @Override @@ -1545,8 +1540,7 @@ public final class GamePanel extends javax.swing.JPanel { } }); - ks = PreferencesDialog.getCachedKeystroke( - PreferencesDialog.KEY_CONTROL_MAIN_STEP, KeyEvent.VK_F7); + ks = getCachedKeystroke(KEY_CONTROL_MAIN_STEP); this.getInputMap(c).put(ks, "F7_PRESS"); this.getActionMap().put("F7_PRESS", new AbstractAction() { @Override @@ -1558,7 +1552,8 @@ public final class GamePanel extends javax.swing.JPanel { btnSkipToYourTurn.setContentAreaFilled(false); btnSkipToYourTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); btnSkipToYourTurn.setIcon(new ImageIcon(ImageManagerImpl.getInstance().getSkipYourNextTurnButtonImage())); - btnSkipToYourTurn.setToolTipText("Skip to your next turn (F9)."); + btnSkipToYourTurn.setToolTipText("Skip to your next turn (" + + getCachedKeyText(KEY_CONTROL_YOUR_TURN) + ")."); btnSkipToYourTurn.setFocusable(false); btnSkipToYourTurn.addMouseListener(new MouseAdapter() { @Override @@ -1569,8 +1564,7 @@ public final class GamePanel extends javax.swing.JPanel { } }); - KeyStroke ks9 = PreferencesDialog.getCachedKeystroke( - PreferencesDialog.KEY_CONTROL_YOUR_TURN, KeyEvent.VK_F9); + KeyStroke ks9 = getCachedKeystroke(KEY_CONTROL_YOUR_TURN); this.getInputMap(c).put(ks9, "F9_PRESS"); this.getActionMap().put("F9_PRESS", new AbstractAction() { @Override @@ -1582,7 +1576,8 @@ public final class GamePanel extends javax.swing.JPanel { btnSkipToEndStepBeforeYourTurn.setContentAreaFilled(false); btnSkipToEndStepBeforeYourTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); btnSkipToEndStepBeforeYourTurn.setIcon(new ImageIcon(ImageManagerImpl.getInstance().getSkipEndStepBeforeYourTurnButtonImage())); - btnSkipToEndStepBeforeYourTurn.setToolTipText("Skip to the end step before your turn (F11) - adjust using preferences."); + btnSkipToEndStepBeforeYourTurn.setToolTipText("Skip to the end step before your turn (" + + getCachedKeyText(KEY_CONTROL_PRIOR_END) + ") - adjust using preferences."); btnSkipToEndStepBeforeYourTurn.setFocusable(false); btnSkipToEndStepBeforeYourTurn.addMouseListener(new MouseAdapter() { @Override @@ -1593,8 +1588,7 @@ public final class GamePanel extends javax.swing.JPanel { } }); - KeyStroke ks11 = PreferencesDialog.getCachedKeystroke( - PreferencesDialog.KEY_CONTROL_PRIOR_END, KeyEvent.VK_F11); + KeyStroke ks11 = getCachedKeystroke(KEY_CONTROL_PRIOR_END); this.getInputMap(c).put(ks11, "F11_PRESS"); this.getActionMap().put("F11_PRESS", new AbstractAction() { @Override @@ -1606,7 +1600,8 @@ public final class GamePanel extends javax.swing.JPanel { btnSkipStack.setContentAreaFilled(false); btnSkipStack.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); btnSkipStack.setIcon(new ImageIcon(ImageManagerImpl.getInstance().getSkipStackButtonImage())); - btnSkipStack.setToolTipText("Skip until stack is resolved (F10)."); + btnSkipStack.setToolTipText("Skip until stack is resolved (" + + getCachedKeyText(KEY_CONTROL_SKIP_STACK) + ")."); btnSkipStack.setFocusable(false); btnSkipStack.addMouseListener(new MouseAdapter() { @Override @@ -1617,8 +1612,7 @@ public final class GamePanel extends javax.swing.JPanel { } }); - ks = PreferencesDialog.getCachedKeystroke( - PreferencesDialog.KEY_CONTROL_SKIP_STACK, KeyEvent.VK_F10); + ks = getCachedKeystroke(KEY_CONTROL_SKIP_STACK); this.getInputMap(c).put(ks, "F10_PRESS"); this.getActionMap().put("F10_PRESS", new AbstractAction() { @Override @@ -1641,8 +1635,7 @@ public final class GamePanel extends javax.swing.JPanel { } }); - KeyStroke ks2 = PreferencesDialog.getCachedKeystroke( - PreferencesDialog.KEY_CONTROL_CONFIRM, KeyEvent.VK_F2); + KeyStroke ks2 = getCachedKeystroke(KEY_CONTROL_CONFIRM); this.getInputMap(c).put(ks2, "F2_PRESS"); this.getActionMap().put("F2_PRESS", new AbstractAction() { @Override From 5ea636126fa38c5a7f591f8c408afe66b4ff2fd5 Mon Sep 17 00:00:00 2001 From: Campbell Suter Date: Wed, 19 Oct 2016 09:44:20 +1300 Subject: [PATCH 18/35] Make the text on the playing buttons update with the current keybinds --- .../client/components/KeyboundButton.java | 46 ++++++++++++++++++ .../main/java/mage/client/game/GamePanel.java | 29 +++++------ .../main/resources/buttons/cancel_skip.png | Bin 22467 -> 2478 bytes .../src/main/resources/buttons/skip_all.png | Bin 22318 -> 2276 bytes .../src/main/resources/buttons/skip_stack.png | Bin 22558 -> 2374 bytes .../main/resources/buttons/skip_to_end.png | Bin 22382 -> 2379 bytes .../main/resources/buttons/skip_to_main.png | Bin 22369 -> 2443 bytes .../buttons/skip_to_previous_end.png | Bin 22494 -> 2432 bytes .../src/main/resources/buttons/skip_turn.png | Bin 22331 -> 2368 bytes 9 files changed, 61 insertions(+), 14 deletions(-) create mode 100644 Mage.Client/src/main/java/mage/client/components/KeyboundButton.java diff --git a/Mage.Client/src/main/java/mage/client/components/KeyboundButton.java b/Mage.Client/src/main/java/mage/client/components/KeyboundButton.java new file mode 100644 index 00000000000..dd4b8bd896c --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/components/KeyboundButton.java @@ -0,0 +1,46 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.client.components; + +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics; +import javax.swing.JButton; +import mage.client.dialog.PreferencesDialog; + +/** + * + * @author Campbell Suter + */ +public class KeyboundButton extends JButton { + + private final String key; + private static final Font keyFont = new Font(Font.SANS_SERIF, Font.BOLD, 13); + + public KeyboundButton(String key) { + this.key = key; + } + + @Override + protected void paintComponent(Graphics g) { + if (ui != null && g != null) { + Graphics sg = g.create(); + try { + ui.update(sg, this); + sg.setColor(Color.white); + sg.setFont(keyFont); + + String text = PreferencesDialog.getCachedKeyText(key); + int textWidth = sg.getFontMetrics(keyFont).stringWidth(text); + int centerX = (getWidth() - textWidth) / 2; + + sg.drawString(text, centerX, 28); + } finally { + sg.dispose(); + } + } + } +} diff --git a/Mage.Client/src/main/java/mage/client/game/GamePanel.java b/Mage.Client/src/main/java/mage/client/game/GamePanel.java index 6f745e3aaa8..729ab26b029 100644 --- a/Mage.Client/src/main/java/mage/client/game/GamePanel.java +++ b/Mage.Client/src/main/java/mage/client/game/GamePanel.java @@ -90,6 +90,7 @@ import mage.client.cards.BigCard; import mage.client.chat.ChatPanelBasic; import mage.client.combat.CombatManager; import mage.client.components.HoverButton; +import mage.client.components.KeyboundButton; import mage.client.components.MageComponents; import mage.client.components.ext.dlg.DialogManager; import mage.client.components.layout.RelativeLayout; @@ -1353,13 +1354,13 @@ public final class GamePanel extends javax.swing.JPanel { txtHoldPriority.setToolTipText("Holding priority after the next spell cast or ability activation"); txtHoldPriority.setVisible(false); - btnCancelSkip = new javax.swing.JButton(); // F3 - btnSkipToNextTurn = new javax.swing.JButton(); // F4 - btnSkipToEndTurn = new javax.swing.JButton(); // F5 - btnSkipToNextMain = new javax.swing.JButton(); // F7 - btnSkipStack = new javax.swing.JButton(); // F8 - btnSkipToYourTurn = new javax.swing.JButton(); // F9 - btnSkipToEndStepBeforeYourTurn = new javax.swing.JButton(); // F11 + btnCancelSkip = new KeyboundButton(KEY_CONTROL_CANCEL_SKIP); // F3 + btnSkipToNextTurn = new KeyboundButton(KEY_CONTROL_NEXT_TURN); // F4 + btnSkipToEndTurn = new KeyboundButton(KEY_CONTROL_END_STEP); // F5 + btnSkipToNextMain = new KeyboundButton(KEY_CONTROL_MAIN_STEP); // F7 + btnSkipStack = new KeyboundButton(KEY_CONTROL_SKIP_STACK); // F10 + btnSkipToYourTurn = new KeyboundButton(KEY_CONTROL_YOUR_TURN); // F9 + btnSkipToEndStepBeforeYourTurn = new KeyboundButton(KEY_CONTROL_PRIOR_END); // F11 btnConcede = new javax.swing.JButton(); btnSwitchHands = new javax.swing.JButton(); @@ -2410,13 +2411,13 @@ public final class GamePanel extends javax.swing.JPanel { private mage.client.cards.BigCard bigCard; // private JPanel cancelSkipPanel; - private javax.swing.JButton btnCancelSkip; - private javax.swing.JButton btnSkipToNextTurn; // F4 - private javax.swing.JButton btnSkipToEndTurn; // F5 - private javax.swing.JButton btnSkipToNextMain; // F7 - private javax.swing.JButton btnSkipStack; // F8 - private javax.swing.JButton btnSkipToYourTurn; // F9 - private javax.swing.JButton btnSkipToEndStepBeforeYourTurn; // F11 + private KeyboundButton btnCancelSkip; + private KeyboundButton btnSkipToNextTurn; // F4 + private KeyboundButton btnSkipToEndTurn; // F5 + private KeyboundButton btnSkipToNextMain; // F7 + private KeyboundButton btnSkipStack; // F8 + private KeyboundButton btnSkipToYourTurn; // F9 + private KeyboundButton btnSkipToEndStepBeforeYourTurn; // F11 private javax.swing.JButton btnConcede; private javax.swing.JButton btnSwitchHands; diff --git a/Mage.Client/src/main/resources/buttons/cancel_skip.png b/Mage.Client/src/main/resources/buttons/cancel_skip.png index 30755df931764df502f287510e723a313ddd97e2..4df1d6db2f701e0efec278877acb89ee2df41106 100644 GIT binary patch delta 2449 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 UC+x-YPXGV_07*qoM6N<$g0FW>fB*mh literal 22318 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 diff --git a/Mage.Client/src/main/resources/buttons/skip_stack.png b/Mage.Client/src/main/resources/buttons/skip_stack.png index 06816b1f3935511e136778c565c6b4140c031715..2ddce1c39b30af2a7716fddc6c10b1f5953969cb 100644 GIT binary patch delta 2345 zcmV+^3D)+WumQ#rkR%NRb3#c}2nYxWdSEC zC>W86z^;qCuv~V5h24EG&vS15@w~f1;2+Q^vEMV#Jnx+6Ip_KQe&=^P=M@}<+rIhL z`hit{mEZ7by1;rrB`p>S!4U#y9HJ1!5b@5DqzT_2pv!$X9RtR99A@wI&2dYAof};C&>227j7GIW>e3u-=mtG&W7?uIk}%w?;^@ zWa3%1p}BS6-TKQnE|^xO^Ji*7iCQYhaq03bGmbDINi&$5Q)P|1zd)d?4%8~9aZ0gQf3qXJn3Z*1cDiZI1 zIg&5pyhBQfEhgXAg<^hjzK|o=rO~>KgB|TO?P#Qs6u^Ux0h?N^_ZY1Z2)uK+2wH$t z>bMvol>!05d2EOX0cBcKZZuLzLJTC%;jKdmfmRX^Sm%i)Lo-TZj6q6~%?U^$0Z4RbQKNh*ag8Z9I!P)brPCI|$7h=BM0MqSJoYx4OVT}GmGIeYiCkt^hhKHwu% zS5@-$TW_VZvYN&nTiLOFJJ&B*)F$juBoBnh6aWV9md{$ZEW1|77K4^IF3_m%T6ABdjEO*|sjBSn0 zbad?FcaJ^6TN~fTdB-1~d7e#wTmD6JQxhv!KFPYZuP|ZaBqmRoK$1E}kE&tX)al&! zz%O|E=|3{HzMj_IE!=s}GQ6{_Tl)&DUi=He1rU<+&zs4Gvo9b?QgZo}h8q{Ndsi#p zyJHER2M@AmfBOkJJ^J_xgvhdij{yk8-WDUoh)lhwm^u=hQYaQkt;73&Sc?9jbQ!}( zjAY{YIv#xZQOdL-60y!vGi)f=Uw19PerP$tJBV4ol!8$shBNu>dV-I*5OCh(Ld3_w zfB_X)@0tI(Ic#}v8>?RaD{I!Sr`#y4^SBWB+lEc-Y}w7ci!LO_z>FEQ$fYUulO|AZ z%6R*ozf)Z`fahLV#jZVndr!q=J{OY&Md1cKSCQq5d ztm)J6J^+z*>t3a9!gyv)KNnZhHW4B*n-5sG?p5x+|9)P3?G4JyGyqCUHve-gOMmtN zX_B&V!9r~Cgcyi_AzLNuEHkG~B~4PEd0{mG^X6VmdwT~lMk*@GaV}tt!IYa)@I01N z7F3T_KyT{{*g}95r5^%>5Pes0k;^W3O$aeyT|fvyRdpr#qGjGC zmojwd5N^5oCXO8LV#?$xYY?@FnTuSG|r}U96E@U0+D@}Tw=Lk=1dyCun?&P&%d;a zTz8Hi{qP4EZ5T6pEL9bX`ueGC*|M4Ck3B&}x#H}z&tc;D(fsMp&oX!JJg&d`Dy(;O z9B4lwr?I1Icz;JDTFH_Epsl?#OPeu^OX9MN&yQn&Mh$29u)z!*Sk3O1U47<}y%b1O zj~Ad-roG?-o`@C_VuybcKuW#6hRrdW~KS}h}05Yo!v=joPBwA+&B3kxy1sr7oLV(sg>wZNvX)?@(3X@M)g%p z{Q)6H^2LOv*7j0QBm_?kw5gFJ2G<53=N6Nc&aONMkMs~jz-WamZ6nWAgcwOu%Yn{r z-fe2@vw#pI&U>tL4~kj!bz{)wZN?~nybFED()|~a)H#yGQgDTFYTv=G?y3O;TtYKu(m~55I%4C@_GqRV&?NTXA?!8hf+f^aA zO$(`8RKzVM?NX>z>Z&B$?;T6tq^5iO{r^3`=b3q)F~>RI@AsVV=bZC>zwddU=Z$xE zv{hD`sRV&Ql*xA1RN&Vf_`(#%1Aq7JS{DoaDDv$*gb>I?HSt#llAbXG0+GRSt*o4# zeR(3D(3i)Dk*%y?d;yQc^=CsMp|=YXi|zk(RyVKRysybwPcDcbnzCrov1i^D+3+RM zgEurU)o1Uu=c;;n-B=f!wPM2bkTd0%mhqi?Wc$s7o;5->H*Qqe{q*ji&4RPPHw5R= zQ|VB@8-c`YZzBoa=O?*9{!%=AJ@BXsq)9vR{n=JM*~YNCLSyB=ipXCVD?3EL2uzKG zEjI7B%$s?B26E%N{T6p+a*5oV<|dFFua^jO-HW}-i*#>xSVTfNwQnPlEfCDbD0yVC zC|_m`nMn01b%7s9W0OzqluI(1%O=ib3CvW~b}ZPRm1VHKe?mEJH>&>sRr_N}> zxGYmGH$w`N!nb1ka_zzeY?p9H8Z+FFNnmN2k(5kAiGYCswulZ34e$>X5<^Y32J8}n zvbY+d1sf0%`I%~2h&zP2Q=DN|JOLYKXn=z=Q79D5h+u#+#ADEg`Y<#SWr#o$5GW)Z zi6WwqL^KjM^wA>Z!uf+nhV59hg-ijLFXHk7VPd;<1}|7-s--3F=;LR|uK@nXjsk^4 z>;Q_0P&yxhGC(56QerVb>hOaF{sTi}F%fKkb^tq2Bn0$OW9k7&DU^?@V|Eu1Fs7zZ zv}7&d!4Q!#HHEY=J{v)03wgl;CVRYm+MHp0m6-VdBPUC zaRXVr5TULKVzkQ0!Wpr~wx)~NBtR1fM-t#D91VpfBJo6wkscC5L?S^(1|>(?pa7eQ zMHkUOwSuRi42fto5rYF;`9yZK9UhCz3Hv51Ba$E+EGCh|69mvjByIrRhmGI|`j{X_ zDnXJ1tCvU)6pHA9Og7n?1XLJsxhx`!#bFb$NCw;p$L7EZI4m1ZC*T-xBo>Wk)0r$Z zlE4|jL7{-vKQnF3V+M;i5MX*R*06X?!2HLBM8q?VaA-8z2yVn8(BUW)8waPeSxh(s zgJ*Ft977HpgCFh)WbCt!oCI7T6w>`cGGbp?Kxal+EW;3QNPsg~cmf=Q$I{^pBnyaI zcml?dj%6}f?2o>TVdk^0?6^W;-GzbHBd{t5f}IOH=+oNa27m5A(BjhtLbiBMn`#Yj z>W@+GV-OST48#T^ohc4?B&K+wvsosHPijYo^-*(3jr;j@ej9>8`yll%_YvaD4*c3i z88kH@^<^VM9!C^H7qBgSfEDsBdw9_5r)s0kn;^uO2Y>GW!9)n@Yrk(A@GL_^G!t0o zXhRMPjy1&M;dDG61vg?4=tvA5!(483M76~!z z*>J`G(##Qnc!V>equ^)`)(DPcVL5OHii3yaPz)v>!$BEwkc46X{>99FevOdM+)(i2 z1+HZa{z>=)f-D_KXW0TFi6h_z!03FwKbJ`thf>7aK-N$``0)w^6Y*f6%j6(;kd6Px zRmx%uxc?-=fJVt2#svEx^ZC1D>bGSogVQSAnS;5);5G8oY-Kpf`aHW4=f^;rXFa$& zZNz&@e2JBu%mDcaaHBy4Q6Ek(zcrkWQvYNx4p|2h%CBdb1P+eFLSZp*Bj65pFvBE> zQ&|QJOJLwoSSA_^q<@1$1sNNwFW&binS;HIVP>Sa;dubz2Bk74ALAC$is#Q0PKzQ-|ga8jr}+uDHdeMp=mVw zZXdsD><9VivXtx$IA~$D6lQ}04n)RU&7=2^c=wNz8yLL=TR+G{VE;H%$xhUP9chCC z?#D)rePG9atB(?`{Wvc@oR(9E_9JlX@|{k8)z}a6(aHk2QaHc{mYK~b*T{cy!T7qZ zALOA6&B+<&W{2ev$~O>GAQpZJ|y%H9ykOvLL-3>@UR8=45@;fN2_{# zT@~CsT6IKoc_3FrLJ##esv4vvKB6DYMqPl%Qfv~=&=3P8F{7(TYdCX5+5Yaz5J=A@l~X-F(faY;l37Leis(~ww};*y96EFi@NrXjH`#U&9DSU`#kOhaN> zic2CQuz(a7n1;l%6qiIqU;!yEFb#=iDK3eKzyeZSU>Xw3Qd|-dfd!T7patP+nIvH6_lgCN46mxH~yJFX8+^0 zIn;ut(hCtar>4ci-bWu!!^dmPHR#MRF?{2$TRgdCbJn|zb&mR{ngkWcj$W>sR^8Wq zHK4$6i+aO$#-mj2t*`6VYHXDu2BFukCu^e?I_`e_g0)>lH3#S=6+i{)6QoQ>1)mC$*q~Q8k6cDmRgaONsSqmVVjQk zsa1Ndk4mXeSW$PKQMWiBu61;8f5WoGH}3>%e79qZTMOi2<_d9CRo$t@!i>dk#Wh+v z*`5V=a}V6O{7jHz&2`QSKL5Ip^zOxry{c~I7Bfw_$;re`SCuxDdu&$TBX5^eb50>& zUEx)I(uZg$luN1c&EEdLF}~nJ&NNLqPx9>Tp0>Yhq%TutPNF9GQ_PhV&70u3;NKj0 zp*MM#wRZqsOjA`~q?7N;l#`9EBy`HG(sd(NHLGs4*(XZOvQ=@}pQ>2%NET}}wX5n5 zFVEdS*Qed!-OF2l2Hz~&&s$rCaXQrW%#ZN?**eGqN=9|<+SBKYy1PBrH7g}t;6TE? z?qA5|txL&3(duHC-|RPgh_SQPF&EH<$6!jaZ#~a^THqdy?Hmc>2_yfV|?E6 z?U?b?P1K0SPs{f1yc)p7fA~Q63h$G5z5iEKnnUS?$**2z?S$HFn4mMYCaxL_ecx!z zK1$t7Ep#r>PF<`se*A<(^-VE(s+Fhvqi!Br|A5rjQgh1L{_xwb7ykEqlrtz@?@Rr{ zPWYJh_7-*Au*Lm-ZYhGXtJ$oq8-FLHFS)n-U2#~4QNxG3haGmUlfmRV>Nx7F5sAMU zN6gLi>L--FE#P4y>h;4X&w2c)v+%;L)Ph>msuZW5>G#8-$zAO$FXsHR(qZ<()XR$Z z=DA!>{IlbB^FJubSeh@WSw_(hN_Wn8wWDqp z?)|B6kLY|u&Xo$Op)b;h(rrd>bw;A(q|%97&h68^ON z@&`NJTMv;MV-{v2wi7E8I`uiNMP4nJ^46E9wH`~tBwQyR?Ck06xI^H-f-XgzN`;zC zoTk4oRlEA6_hN$D>!#YiO)a@5+oJl(UdDnqchPaxhEDC3C(HvL#6lIKt1nu{99Ho& z#T~unt)QSdxwqTqaN-}>1vd!Ed3nDHPnL}mjlShxOG_03)E zn$sbF_;nhjd!}oc74CZds50et>Rzg%u3XUU`BPfc6rV*9qST^Ks+#` zRYHq_Q0+e?X0ld0O?E3NNx(ZosakS&I?ISFthki3k1sVl%(;-~FuOK$ZPEEn=Ii@W z*R(4pIIS_YR7g+XoO(caX_33liaWl6C!X3kDo;WSD;(Coe5r}A)tNXQwKD(jvIB0& zu%6J<9X^+6lse*-q6bIy+9upE%ohgu2{$nInrmkI@L#E0vNp=hxN*Ds*~=UHt0Faw zLtetj4A+8ZHue`z^*vFY+wclH9g$I+syN4__bzUMD3RXZw=wl6J@qXWxr)6D6X)lc zv)Xgi^H!ebYu;P`hibmuHnX?dIeS$@)<5T=ZX<)vX{ReCcpT;&7PhM3O#Vo+bPReJ zHyu^#C)?k(tG$?YiCTE7r8K+dT7O%a@G>?(E9G89#9#LH>X1#{jvP9MRid4?nq=ni zd`49RD$AG4ZTai$%^K%Rjm0%7+A0gp4>&~J51%aq*RHTzoc}0oR{xf96W(<^YF%xq z=dm+0E~EM!D{9p&lb|)l2Hx4)XjQ28(S}6mle)ZY`6SoSRMwQ*%4PR*waxm z^VeOJ%d*R|krn*g@~ij_*B|=BE_07iedC@y z+3~{YHOYH+q}u6TwO8Y&pbk7ZtfB4|)>2)veMR7z4oYUkbK{-2js;J&;rJg~Ssd9i zudMvZvVh3urTypoq9T$klgB$nbjt(%$Hi7v=VU8Hl>o_%Z2)ve8QYUrXg zCrHoR0;8mg9VdMpgw>uMS1k5FJntLf2_y+NO{;0Kv#hi<_vFxg3*xur@7m-4*D+Yaq+E{7>b_?cQ~o>^(i=13+apZXL?Vo2Y-zC;Ioe z>eE_TXEZ0eD5vc`dJXpW=^C2p4jaV{$b@kbA(+lp?eufm2BNZy$rqMR zxq#y<){@@JJ+d)0a@AI*$I3%xiScvtDaG+RiI4g_&|cZ-9fEg+a|?jaP17{$u_U4t_|rF z^w1O)Xeqx6bO;A0RNW}5Qfn%-H!R33FS$xNauhdZ$(aWeg-Pp{F7DY$S-Ql}qBLL6 zT7HS};pF#7RatVfKyc{%?)%J)nFp_T`>~6+GWrg3)podU+PVzi*2aE%oHtRsUbRw} z%vgA!rKQPvb{>vgr}w}PYJU0!?xhthI8mDt|LDzb$hJ1J%Srs9{vE;R_QkZ4@@8Ac z_#)?HU_dTBw8*(-s76Km&9mW+(@k&O@mRZ)>yRu(WHr1 zXk+bwPG#m<w22{1zc)8|`Q3AV=X-wVx83^$N8pC< zeq-8y*qZ9^xHMg6oSTxCN_cPap5qQd2!andYe~|C!J*-uef@*a4chdPx8B;m{qQ&e zuxiyRS?&5(k3VtTO_3DXV6cfHH3{B&!trPUzy*&nmNZT1>FuSnvxogXef0Gg?s{kE zhqnM;1DN5CJI2)3-ZZAV3avHXThhpoGZD^z1%h|Scq{)Ky!ROANQxShrVQ2$(Ko0O zQrvXfzMsr9c+7d8~ww>gz}-sTA{TjIEyRGlmHb) zXdwac!IM}^YAhi@q$E;GyvvLywZdD64FN3#LQ0HtgaBGVq!m#VAwQUu>gl}o_EwaVI1dL8^>FrotXZsi@FDv94$|A(Pq8pW^W

gu@XfrmJE?pfUS z^IuRZ7HO!j=kEJ{iAjf9yy#-K@7TfM@G#B?Ce_xm^pd5lzUMwV+x9W#jMLcHwr>Ql zs+?y1rZ<=|^$dCr9psL?@1?nM5^w%vD-*_#rDgA4o_&5D3+K-VJbU(kw9wJr3xM+; zYb`Q$j#6q#OiHm-Bm~DxuWlp|u->DzxE~%$Pov+S)pzNU(n68x)g-*|TP1 ztiuOSK3|1#j*Ayw#MbwJKH!CyHt^!h8%FSYX59I`SbsmY}#aA`}FlWxW#8o+* z^JPvB7d#jX+5ClRAthJ1Ptr>%{7J*>BSYY8HZ;1vi6z#2nCQzJkA!42f|F#)jF($qMaZ(sW@+S}Ur(<^^Q zO9=s}7y)Dm0UyXpUD+}Sk==mv0U@Bhvjal5SZWPb`8+l;6iUTx4rLv{Bac1KORsLg z22YS##69uU)8wLmm|PTtC=>7j=N-;C2vAH)fFOi`l9Da|e4kZ!-bI?EEMK-9W8DZ| z04@X&u&Y z6UGw)?AW;*9cva`a6UpPCZBo=9i46Dbc86Af^5DJl5yjI#xeDCr(&(8y1JU4-X1n? zd@bW2%4tXlN{MCZk_D(p@y@&NqIFgUnj7o++KT1)5a{mSk4Z~d>qhXh#FBBe5JXfEQx1KPjit4H=s`7dI`}=5WsOO3+u0%=2 z^yxEbZP`tKM^`sKEwNzHVwNmiNN-Oszkc#5@^OTenZkwh=F!l2GUuK%mkZ82kG*?$ zbJ?XUsI9HzgsL3tH*KPB!gzM>*~5kB%%!%jp2Z91)7aR^Yp-qKy=^+4||3@J}2xuv@H@!HDh_tTM;n9jp4AAwX*_ zkxHVJKx>5@?H(|~00J!lrLyd=r9#QkodXVct-@ysQ41-`eK`mbP-66!K_9|VNl>PL ziNjcfO)W{19Ak=~EsQZo$+U4Pg+h_R!J$fx9F6cH&^u5#O0JWl+t)iV+$^PHc({NN zk|m6+M`I}tgn0uAH4{q){-QKqAi}Rx(*Et z*5vaxwPrDV)F71qHXKC=_z=q9It-=6{G_e@;JU-R6q6h4ewvG;+q9Ah338P61Lc^< zI!}_CTU$F0+zx~h$K2G^bh5@=Cj`rd5N94EuAd1)2p@#NA1u+D_V)I+!}5O>0R#4w UPvgNTZU6uP07*qoM6N<$f`=Z8lK=n! literal 22382 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 P_qo!*mw)6ttcw00^S|ll diff --git a/Mage.Client/src/main/resources/buttons/skip_to_main.png b/Mage.Client/src/main/resources/buttons/skip_to_main.png index 0d1b2bf1155add4984b911375baee3ef472eab76..d1bbef6b864a7b1380193048e69474573744addd 100644 GIT binary patch delta 2414 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 V_aHIpU2p&Z002ovPDHLkV1jaZifI4< literal 22494 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 JPDHLkV1f?pe*pjh literal 22331 zcmeI42{@GN`^N_rIY=dYr!lFBF*`GJjCJgZP+3kg%ZsthjG2*9igrpVOKDN3fon$GF>|9AbaYv#J}c%S?JKF|Gmp67n=dFQ$&&ULPx zqP(U&3c^zZ^?lRV->Y?tkoRFeZ#EOw!ZKd*)Yu0BNI~ zbxY^c?F0K9S(AKyZ>?C9?jx%fajy8%Jg(~}>0XPlXAhNiR5%ZJ^k9(mQgVOnm1ACCK&GG^0DY} zL8erY1KBO0&>eYX8{m+?Ys^;DUjecvlV`3pIc4VI^mL;wy|TshqB=I2mmTD_to0Kv zr}^@|`UK?|&!vXmmPC){2eaeT9yC8L7iuVRXiMEr-ZwaXCuVKy{_F+&3dVLdpo+^~ zx?8+m=rEY$HkOB{z|(mSnZXG)qA@viz(^R%1$o0@rshH}jS&n8;B+8>#ik(I^3NgQ zEG7l9kl>7V=2`=REc>NAzUE$Uo9snm886z1O3sjzwb#C^QL$K_k%^ zG6qe?qTvHCgqb|pGUYM-$!=8Jf#JaaD2PCTfJ;W9A|fJ;B5+0=UH}S1B9TyNEDDQ7 zf)+@ABwIieBH8@u{UU=pRDjRmvA6;jhYc6$(&(IU0R@2&4K(x`h%1ykG!UCVzz(E{ z64JORj1d|&niG>Tuz0oW`7XEJ@X$@2wnz%bnJkOIv|72*z_*wN=T)csYA0+#<* zCL-$jsv96=eZ@`G)9==|r}~%L6r@hJ<^ePThv&iJgqZbj*Wr8vrW?`rgzGJ2v6-9* zzP>4Hq|5Ne8CCRVV_?e>xA#t@}DGlpoR158uYXIF=(HRL(q#`~9^EeyKjIuZ!?G z{(=Y^53mdXcgXjg;eOT6-A2lrqC~fc5Z3>}Lhxxzery?tOacMR0QWhT;EzG#33wus zMkHd8CUg=FjicchOaf+bng8uFfXN1j9n3U8ZyAPnF(Z)14gi>DsKLkvFZ?g9oC%YF z_NQY^kTg2e80k;P14tqbz#~nJ=?s4ciEctf8xO|!FIMi$dxT`=29h6#y#(O>lk^8B zSsGZ*0zAH%KaUd%r*XLNML%z=7v=ne!IaNv;JWIuO^#{c6kWdc0bKglqV zSuzGO!T-l%{^6YZeU(c8vPw>7f347ekNmt^8LWW5tZqd0F<9nN`*)|U=uC-jvEqvv zupR;5XpkY)2g}RvO{XK=KRb&9>R>_n?Fy6RZ|u*+;K2$LdBry3=~{$c2;mb@J%=oe2+A$*{CuefKV`p7AZ=y!~LRrzG!Dy(E>idI@s|~ z%i!Vp^o=za%>E_1DIs5a2a4tIVwmw~-LLPRw4uZr|_juiRtR+J;A(-)J63*2Td z74Gg~;|jMW{8(sWw0>TMb8S35;2!hc=E809KOEvW#eQCl&Xx{y2bR&~hhzMv*iVYl z-O0ff4A9cr32uu4ABc>$n@64>(di#y*Ef4HT0bd5@cg*CIk>p>ok&{@_WSgzUVQhF<2G! z`Hbus)zNF%5eH6j*b&k(;Ml)nkPndhiqrn9;Kx(oCu69gkH)^JTltK@B9hpftp`CAh>Qf*MG0L1~C>OK^!r1T~Q0g3=J%mf#YL2x=g~ z1*IXjEx{!g5!66}3ra(5TY^h0BB+4`7nFwBwgi`0L{I|>E+`GLZ3!;1h@b`%Tu>Tf z+Y(%25kU-sf zBXY~svgH-#=U(oKtoZfsTW1no7tA6T@{SqGBwDB%Uj#NfYTtF3e~h2Pm}PV~x=dO7 zF#NAgjD=EblMpGqL}{r>ayk~q*kqlx7RqduyMO$0Ec``Kc-GscZPjz8y=UxMke@}L z+>vY4|>*l3y)zrAMBHnx5CqAj~MX}zI~NFMLi`iN;A8g>5=E_aW$8KBPg2NvLk1O?;msWa!>iH>6ffi*u^~H zwd&L!u2~R_TapB9!#fji)!IdL>2FRWS3h0(?9|5U?8T^*%k{BxPO3|K7V(|lpKaoe zXDHPBT-QtAVnbAut54f5|EfNTWama;vMT*)EHXJ4m_9S$A4m z(=RHQO`NAaSr7i_y2Gr3%dd1|CNwWre>m^iNK+P`WhJ-)}TL zQI}=we_3yG*e6dDy9vJ@h~~x^<~C=`!r}X`dGAY}8Me8{QL)v~Q9mg6+2Wnv*&i|; z!&4tgt;S#qDU|1TPHZnJvBYk#SP_EvE*|^p%D(B=Oa)sNGvRT=(z7Qb&#!B*rzaoY zHRF%?nQJT#CH$qs^|uefm#eQjaWktS&E3XZ2f;LIn@oGM!+v~aU_tmAWmoTpv{EUX z^m&elZcQ2^)lO_)QR887iFE1 ztbM~2L(h|I0wP{KxjujUrmf+xBiOXkiX6Yj^$Rw+GePy>{Kb#1I~i%cUu0yGaF26O zXtKBaIU)ISwQ0{grJRBe2JHER-f_Fy?ylnNL@17#_6dKVw7g@JbB6TRI9J=S&K3+g zpxUpYu#11Ga>}QczosfIT<2B9)Gy<0-M(13(kk=f;akCVXI^{7uiE?aH;dZiWmTzW zN!dQ9Fah=2Max=W#Gb0!K}k5e;)Qop^`0_Z{vO7i>oZQ`3GL5b-k-Av8`n^gz^`eN zwPns(pR_LZ$}yW9N)4if64JTTc=jN*j;uz+vg1T znicuaIZc^qzn$ThNIPa=^OwBP&0KJX|5`?6dg-J3q5>;nLau5G*$$bj>*bicplp47 z#onk5MJvs+YVLRL`IvW&6ktTTZ+EAsZnAdk%YEuKpyRkFV zo$4reg^^~XoJZ-w@8Cf-K&5_cB0j^z&@ZiG?QZV#s1K~aXXW8&R$AL)a`)(F zw^#3C``xZmI_dVwuOdm;q4Lt?SuK=Xc3E%Ky`=TFhN)A>sA=E!wvrR7@eIgLJAvPq zzZsX68`Ych(Y3hsXm4^)iH_0P78&N7-O5%muy{Qw4>_r67oF~FRIjm+E6U0EUB|dO zl^BM|@m)amJMBhs4{O(X_33i{Q_2#BPywZ6ELA0XdFg|WxBJp{jTtX?rYI;WVS<;; z`lY#g#t8MX}G$u~K=2QS=S7OxLSs5s4tk}K#bcX^k6CoL9RaP-K=pzO+hFJGE&^jSZN_IGkz zNPUO0+uobC`gyaC(YozYP4bg+8rzzieAu&yHS?zxCI)41xZNI`m376WK2GO!%ylbw zcidX5m3iYsJGIRnxM$*nGAiTheRDkXw^e!1%sch^1Vxs3EZW?A%=E}N#Mha>5zg|P zPHOq=a!PiZ;aG-{k?Ho-I{oNu@I1$BcSu^B8h14N`bE}a&5Bk~^r~fi^5~)RmhaB* z?H+&QU=1^}mggJQIAe~Sf|9~<|LP!bpIO{nQ(6PrJBlCMY-EM9fwp=R<#xm0Ps?$F zKRun+-5zV$uD?Ei*(%IAO1F z)r6dP@XPsU14Bdi@oi=AMwpftkkX#t?VVY!x4HA}%9shiwrY1gayolHJ~Js5A0~}N zR%`c^>11{3#+8jru#IJ;)%vzxDyV>~$ZMwKjfII-^hL$72<$31E4h_bl^3scqMAX~7!A^`_m_Ia=!vY>Sw5sj4Z= zGnNphf|;!wc4e!l6W3KQaA*4C)E+)f{l3yvvkPfjZPd8^XFRoClz^M_$E2rN>94)E zu8vCeHi?h(k88|}erHyGq4{}l&3)8~_QkzhJuAX(Tl7^cqZ-Q39rR$+KU#Oa?sPZ5 zlHF}|_vm>PV*0`v^69$D8qO*#MEW&v&C?nyFJ8FNeui>DS?y}#<<6KR-bL?Hj$XTM ztRtH_W)of|>9B!?!CE=>3>9yK_}lNzXyI+G=fDu;F6he9AaCozFZsPpQZ za+1o3k2yYs$mdYXYf_^K_&UQpoF`5$>AF zC4p;IHE`$LS7FB8j6O%qczxrL?ZXb8c$ZbI#}`A^IU^ksKb`yajz)&Cvt(H$_eR?E zion&@gr3mLN>?#1X2;{~ru|LjpQ%%)Zvz@IOrs39Oe~Rzcbl$tYrlQMUk3_SU)7tq zVQnh?k)gY`^UlY0u7>5)pEO1XcNeX!6r#FYGTO|E;k?UP4x!ojDF~{{yaQT@n@jCx zTza)5-7_|}p=IHfkG|yvyUG>@jXzo#wk4^%)Z&kAGd&JJok#)PeAY+M<|7@RY8~Pp zkB)sv*?R5Jhw;ys9ZcI`#ne-!$6sp;%IU&3ZAY3q;O2HJb|lHz*_sxwj|tywc%oN# z(J#$aS8b=oAvT@Z!|f^TeK)Pm)h*Z|F&>|**3#6};g`rXu09@~K3@7F=id3{a?C4R z{WTmCyPadE?c8yK9QiTZ2auFAF}s zKo{TT6vkN@S)AW)^CW1ZYPanj^JBBtyppplY97D7xhhSzI9d?~pXgk_=)eba(U-G2 MfZybiW97H%KShM$ZU6uP From b4dc47fbc9e27a39092d6a4e5b8fff2f6d715bb9 Mon Sep 17 00:00:00 2001 From: Campbell Suter Date: Thu, 20 Oct 2016 12:30:42 +1300 Subject: [PATCH 19/35] Improve keybinding buttons, add information --- .../mage/client/components/KeyBindButton.java | 70 +++++++--- .../client/components/KeyboundButton.java | 5 - .../mage/client/dialog/PreferencesDialog.form | 131 ++++++++++-------- .../mage/client/dialog/PreferencesDialog.java | 104 +++++++------- 4 files changed, 177 insertions(+), 133 deletions(-) diff --git a/Mage.Client/src/main/java/mage/client/components/KeyBindButton.java b/Mage.Client/src/main/java/mage/client/components/KeyBindButton.java index 12f332859b2..ff842f4a3b5 100644 --- a/Mage.Client/src/main/java/mage/client/components/KeyBindButton.java +++ b/Mage.Client/src/main/java/mage/client/components/KeyBindButton.java @@ -1,44 +1,42 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ package mage.client.components; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; -import javax.swing.JToggleButton; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPopupMenu; /** * * @author Campbell Suter */ -public class KeyBindButton extends JToggleButton implements KeyListener { +public class KeyBindButton extends JButton implements ActionListener { + private final JPopupMenu menu; + private final PopupItem item; private int keyCode; private String text; public KeyBindButton() { + menu = new JPopupMenu(); + menu.add(item = new PopupItem()); + addActionListener(this); + fixText(); - addKeyListener(this); } - @Override - public void keyTyped(KeyEvent e) { - } - - @Override - public void keyPressed(KeyEvent e) { - } - - @Override - public void keyReleased(KeyEvent e) { - if (!isSelected()) { - return; + private void applyNewKeycode(int code) { + keyCode = code; + switch (keyCode) { + case KeyEvent.VK_ESCAPE: + case KeyEvent.VK_SPACE: + keyCode = 0; } - keyCode = e.getKeyCode(); fixText(); - setSelected(false); + menu.setVisible(false); + setSize(getPreferredSize()); System.out.println("text: " + text); } @@ -65,4 +63,32 @@ public class KeyBindButton extends JToggleButton implements KeyListener { return text; } + @Override + public void actionPerformed(ActionEvent e) { + menu.show(this, 0, 0); + item.requestFocusInWindow(); + } + + private class PopupItem extends JLabel implements KeyListener { + + public PopupItem() { + super("Press a key"); + addKeyListener(this); + setFocusable(true); + } + + @Override + public void keyTyped(KeyEvent e) { + } + + @Override + public void keyPressed(KeyEvent e) { + applyNewKeycode(e.getKeyCode()); + } + + @Override + public void keyReleased(KeyEvent e) { + } + + } } diff --git a/Mage.Client/src/main/java/mage/client/components/KeyboundButton.java b/Mage.Client/src/main/java/mage/client/components/KeyboundButton.java index dd4b8bd896c..3e0516f726e 100644 --- a/Mage.Client/src/main/java/mage/client/components/KeyboundButton.java +++ b/Mage.Client/src/main/java/mage/client/components/KeyboundButton.java @@ -1,8 +1,3 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ package mage.client.components; import java.awt.Color; diff --git a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form index eb5be90e6e1..7a3e9afd3ee 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form +++ b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form @@ -3949,7 +3949,7 @@ - + @@ -4171,7 +4171,7 @@ - + @@ -4230,7 +4230,7 @@ - + @@ -4744,7 +4744,7 @@ - + @@ -5655,7 +5655,7 @@ - + @@ -5901,17 +5901,19 @@ - - - - - - - - - + + + + + + + + + - + + + @@ -5919,51 +5921,56 @@ - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -6059,6 +6066,12 @@ + + + + + + diff --git a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java index a7be9ed7c83..f8a02a5cd03 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java @@ -571,6 +571,7 @@ public class PreferencesDialog extends javax.swing.JDialog { labelSkipStep = new javax.swing.JLabel(); keyConfirm = new mage.client.components.KeyBindButton(); labelConfirm = new javax.swing.JLabel(); + controlsDescriptionLabel = new javax.swing.JLabel(); saveButton = new javax.swing.JButton(); exitButton = new javax.swing.JButton(); @@ -1435,7 +1436,7 @@ public class PreferencesDialog extends javax.swing.JDialog { .add(jLabelEndOfTurn) .add(checkBoxEndTurnOthers)) .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) - .add(phases_stopSettings, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 266, Short.MAX_VALUE) + .add(phases_stopSettings, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 356, Short.MAX_VALUE) .addContainerGap()) ); @@ -1514,7 +1515,7 @@ public class PreferencesDialog extends javax.swing.JDialog { .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(cbNumberOfDownloadThreads, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 153, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))) .add(cbUseDefaultImageFolder)) - .add(0, 231, Short.MAX_VALUE))) + .add(0, 270, Short.MAX_VALUE))) .addContainerGap()) ); panelCardImagesLayout.setVerticalGroup( @@ -1709,7 +1710,7 @@ public class PreferencesDialog extends javax.swing.JDialog { .add(panelCardImages, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(panelBackgroundImages, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .addContainerGap(53, Short.MAX_VALUE)) + .addContainerGap(125, Short.MAX_VALUE)) ); tabsPanel.addTab("Images", tabImages); @@ -2284,7 +2285,7 @@ public class PreferencesDialog extends javax.swing.JDialog { tabAvatarsLayout.setVerticalGroup( tabAvatarsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(tabAvatarsLayout.createSequentialGroup() - .add(avatarPane, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 484, Short.MAX_VALUE) + .add(avatarPane, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 584, Short.MAX_VALUE) .addContainerGap()) ); @@ -2319,7 +2320,7 @@ public class PreferencesDialog extends javax.swing.JDialog { .add(connection_serversLayout.createSequentialGroup() .add(141, 141, 141) .add(jLabel17))) - .addContainerGap(91, Short.MAX_VALUE)) + .addContainerGap(198, Short.MAX_VALUE)) ); connection_serversLayout.setVerticalGroup( connection_serversLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) @@ -2509,6 +2510,9 @@ public class PreferencesDialog extends javax.swing.JDialog { labelConfirm.setText("Confirm"); + controlsDescriptionLabel.setText("Click on a button and press a key to change a keybind.
Space and ESC are not available, and will set the keybind to nothing.
If you are currently playing a game, the changes will not take effect until you start a new game."); + controlsDescriptionLabel.setVerticalAlignment(javax.swing.SwingConstants.TOP); + org.jdesktop.layout.GroupLayout tabControlsLayout = new org.jdesktop.layout.GroupLayout(tabControls); tabControls.setLayout(tabControlsLayout); tabControlsLayout.setHorizontalGroup( @@ -2528,56 +2532,61 @@ public class PreferencesDialog extends javax.swing.JDialog { .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(keyConfirm, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(keySkipStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(keyCancelSkip, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(keyNextTurn, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .add(keySkipStack, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .add(keyYourTurn, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(keyNextTurn, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(keyCancelSkip, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(keyEndStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .add(keyMainStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(keyPriorEnd, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) - .addContainerGap(483, Short.MAX_VALUE)) + .add(keyPriorEnd, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(keySkipStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(keyEndStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(controlsDescriptionLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 498, Short.MAX_VALUE) + .addContainerGap()) ); tabControlsLayout.setVerticalGroup( tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(tabControlsLayout.createSequentialGroup() .addContainerGap() - .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(labelConfirm) - .add(keyConfirm, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) - .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(labelCancel) - .add(keyCancelSkip, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) - .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(labelNextTurn) - .add(keyNextTurn, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) - .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(labelEndStep) - .add(keyEndStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) - .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(labelSkipStep) - .add(keySkipStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) - .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(labelMainStep) - .add(keyMainStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) - .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(labelYourTurn) - .add(keyYourTurn, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) - .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(lebelSkip) - .add(keySkipStack, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) - .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(labelPriorEnd) - .add(keyPriorEnd, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) - .addContainerGap(263, Short.MAX_VALUE)) + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false) + .add(tabControlsLayout.createSequentialGroup() + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(labelConfirm) + .add(keyConfirm, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(labelCancel) + .add(keyCancelSkip, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(labelNextTurn) + .add(keyNextTurn, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(labelEndStep) + .add(keyEndStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(labelSkipStep) + .add(keySkipStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(labelMainStep) + .add(keyMainStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(labelYourTurn) + .add(keyYourTurn, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(lebelSkip) + .add(keySkipStack, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(labelPriorEnd) + .add(keyPriorEnd, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))) + .add(controlsDescriptionLabel)) + .add(263, 263, 263)) ); tabsPanel.addTab("Controls", tabControls); @@ -3732,6 +3741,7 @@ public class PreferencesDialog extends javax.swing.JDialog { private javax.swing.JCheckBox checkBoxUpkeepOthers; private javax.swing.JCheckBox checkBoxUpkeepYou; private javax.swing.JPanel connection_servers; + private javax.swing.JLabel controlsDescriptionLabel; private javax.swing.JButton exitButton; private javax.swing.JLabel fontSizeLabel; private javax.swing.JPanel guiSizeBasic; From cde9afa09186226445e6d99a89baff9ec523a876 Mon Sep 17 00:00:00 2001 From: Campbell Suter Date: Thu, 20 Oct 2016 12:49:58 +1300 Subject: [PATCH 20/35] Make keybound buttons cache their text, in case the keys are changed midgame --- .../src/main/java/mage/client/components/KeyboundButton.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Mage.Client/src/main/java/mage/client/components/KeyboundButton.java b/Mage.Client/src/main/java/mage/client/components/KeyboundButton.java index 3e0516f726e..c1f806cd712 100644 --- a/Mage.Client/src/main/java/mage/client/components/KeyboundButton.java +++ b/Mage.Client/src/main/java/mage/client/components/KeyboundButton.java @@ -12,11 +12,11 @@ import mage.client.dialog.PreferencesDialog; */ public class KeyboundButton extends JButton { - private final String key; + private final String text; private static final Font keyFont = new Font(Font.SANS_SERIF, Font.BOLD, 13); public KeyboundButton(String key) { - this.key = key; + text = PreferencesDialog.getCachedKeyText(key); } @Override @@ -28,7 +28,6 @@ public class KeyboundButton extends JButton { sg.setColor(Color.white); sg.setFont(keyFont); - String text = PreferencesDialog.getCachedKeyText(key); int textWidth = sg.getFontMetrics(keyFont).stringWidth(text); int centerX = (getWidth() - textWidth) / 2; From b6661ae79d42ca54b34025824f0d261b51f1b3bf Mon Sep 17 00:00:00 2001 From: spjspj Date: Thu, 20 Oct 2016 16:58:18 +1100 Subject: [PATCH 21/35] spjspj - Add Evangelize (TSP) - Also possibly a fix for Preacher which could target Narset, Enlightened Master when it shouldn't be able to --- Mage.Sets/src/mage/cards/e/Evangelize.java | 68 +++++++++++++++++++ Mage.Sets/src/mage/sets/TimeSpiral.java | 1 + .../TargetOpponentsChoicePermanent.java | 20 +++++- 3 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/e/Evangelize.java diff --git a/Mage.Sets/src/mage/cards/e/Evangelize.java b/Mage.Sets/src/mage/cards/e/Evangelize.java new file mode 100644 index 00000000000..4631c3a97c0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/Evangelize.java @@ -0,0 +1,68 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.e; + +import java.util.UUID; +import mage.abilities.effects.common.continuous.GainControlTargetEffect; +import mage.abilities.keyword.BuybackAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.target.common.TargetOpponentsChoicePermanent; + +/** + * + * @author spjspj + */ +public class Evangelize extends CardImpl { + + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); + private static final String staticText = "Gain control of target creature of an opponent's choice that he or she controls"; + + public Evangelize(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{W}"); + + // Buyback {2}{W}{W} + this.addAbility(new BuybackAbility("{2}{W}{W}")); + + // Gain control of target creature of an opponent's choice that he or she controls. + this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.EndOfGame)); + this.getSpellAbility().addTarget(new TargetOpponentsChoicePermanent(1, 1, filter, false)); + } + + public Evangelize(final Evangelize card) { + super(card); + } + + @Override + public Evangelize copy() { + return new Evangelize(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TimeSpiral.java b/Mage.Sets/src/mage/sets/TimeSpiral.java index 206faf76cec..89a8cecf563 100644 --- a/Mage.Sets/src/mage/sets/TimeSpiral.java +++ b/Mage.Sets/src/mage/sets/TimeSpiral.java @@ -86,6 +86,7 @@ public class TimeSpiral extends ExpansionSet { cards.add(new SetCardInfo("Errant Doomsayers", 15, Rarity.COMMON, mage.cards.e.ErrantDoomsayers.class)); cards.add(new SetCardInfo("Errant Ephemeron", 60, Rarity.COMMON, mage.cards.e.ErrantEphemeron.class)); cards.add(new SetCardInfo("Eternity Snare", 61, Rarity.COMMON, mage.cards.e.EternitySnare.class)); + cards.add(new SetCardInfo("Evangelize", 16, Rarity.RARE, mage.cards.e.Evangelize.class)); cards.add(new SetCardInfo("Evil Eye of Urborg", 107, Rarity.UNCOMMON, mage.cards.e.EvilEyeOfUrborg.class)); cards.add(new SetCardInfo("Faceless Devourer", 108, Rarity.UNCOMMON, mage.cards.f.FacelessDevourer.class)); cards.add(new SetCardInfo("Fallen Ideal", 109, Rarity.UNCOMMON, mage.cards.f.FallenIdeal.class)); diff --git a/Mage/src/main/java/mage/target/common/TargetOpponentsChoicePermanent.java b/Mage/src/main/java/mage/target/common/TargetOpponentsChoicePermanent.java index 46b934cd724..34cd992cd80 100644 --- a/Mage/src/main/java/mage/target/common/TargetOpponentsChoicePermanent.java +++ b/Mage/src/main/java/mage/target/common/TargetOpponentsChoicePermanent.java @@ -3,7 +3,6 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ - package mage.target.common; import java.util.UUID; @@ -11,6 +10,7 @@ import mage.abilities.Ability; import mage.constants.Outcome; import mage.filter.FilterPermanent; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPermanent; @@ -26,7 +26,7 @@ public class TargetOpponentsChoicePermanent extends TargetPermanent { super(1, 1, filter, false); this.targetName = filter.getMessage(); } - + public TargetOpponentsChoicePermanent(int minNumTargets, int maxNumTargets, FilterPermanent filter, boolean notTarget) { super(minNumTargets, maxNumTargets, filter, notTarget); this.targetName = filter.getMessage(); @@ -47,8 +47,22 @@ public class TargetOpponentsChoicePermanent extends TargetPermanent { @Override public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { + Permanent permanent = game.getPermanent(id); if (opponentId != null) { - return super.canTarget(opponentId, id, source, game); + if (permanent != null) { + if (source != null) { + boolean canSourceControllerTarget = true; + if (!isNotTarget()) { + if (!permanent.canBeTargetedBy(game.getObject(source.getId()), controllerId, game) + || !permanent.canBeTargetedBy(game.getObject(source.getSourceId()), controllerId, game)) { + canSourceControllerTarget = false; + } + } + canSourceControllerTarget &= super.canTarget(opponentId, id, source, game); + canSourceControllerTarget &= filter.match(permanent, source.getSourceId(), opponentId, game); + return canSourceControllerTarget; + } + } } return false; } From 70177492653cf1d9fc0b05ed2827e3e685c7fbfb Mon Sep 17 00:00:00 2001 From: spjspj Date: Thu, 20 Oct 2016 18:50:36 +1100 Subject: [PATCH 22/35] spjspj - Fix Evangelize (TSP) --- Mage.Sets/src/mage/cards/e/Evangelize.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Mage.Sets/src/mage/cards/e/Evangelize.java b/Mage.Sets/src/mage/cards/e/Evangelize.java index 4631c3a97c0..0ef72fa1de6 100644 --- a/Mage.Sets/src/mage/cards/e/Evangelize.java +++ b/Mage.Sets/src/mage/cards/e/Evangelize.java @@ -44,7 +44,6 @@ import mage.target.common.TargetOpponentsChoicePermanent; public class Evangelize extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); - private static final String staticText = "Gain control of target creature of an opponent's choice that he or she controls"; public Evangelize(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{W}"); @@ -53,7 +52,9 @@ public class Evangelize extends CardImpl { this.addAbility(new BuybackAbility("{2}{W}{W}")); // Gain control of target creature of an opponent's choice that he or she controls. - this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.EndOfGame)); + GainControlTargetEffect effect = new GainControlTargetEffect(Duration.EndOfGame); + effect.setText("Gain control of target creature of an opponent's choice that he or she controls"); + this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetOpponentsChoicePermanent(1, 1, filter, false)); } From 77729e892c8ae9f7b41da98eb4b6f75e62db4431 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 20 Oct 2016 15:04:27 +0200 Subject: [PATCH 23/35] * Prized Amalgam - Fixed that it also returned if it entered and left the battlefield after the trigger was created (fixes #2485). --- Mage.Sets/src/mage/cards/p/PrizedAmalgam.java | 29 ++++++++++++++----- ...romGraveyardToBattlefieldTargetEffect.java | 6 +++- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/Mage.Sets/src/mage/cards/p/PrizedAmalgam.java b/Mage.Sets/src/mage/cards/p/PrizedAmalgam.java index 620bfd6666e..2907b79a4e3 100644 --- a/Mage.Sets/src/mage/cards/p/PrizedAmalgam.java +++ b/Mage.Sets/src/mage/cards/p/PrizedAmalgam.java @@ -33,7 +33,7 @@ import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; -import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -45,6 +45,7 @@ import mage.filter.predicate.other.OwnerPredicate; import mage.game.Game; import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; +import mage.target.targetpointer.FixedTarget; import mage.watchers.common.CastFromGraveyardWatcher; /** @@ -60,14 +61,14 @@ public class PrizedAmalgam extends CardImpl { } public PrizedAmalgam(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{B}"); this.subtype.add("Zombie"); this.power = new MageInt(3); this.toughness = new MageInt(3); // Whenever a creature enters the battlefield, if it entered from your graveyard or you cast it from your graveyard, return Prized Amalgam from your graveyard to the battlefield tapped at the beginning of the next end step. this.addAbility(new PrizedAmalgamTriggerdAbility(new CreateDelayedTriggeredAbilityEffect( - new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new ReturnSourceFromGraveyardToBattlefieldEffect(true))), filter), + new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(true))), filter), new CastFromGraveyardWatcher()); } @@ -98,20 +99,32 @@ class PrizedAmalgamTriggerdAbility extends EntersBattlefieldAllTriggeredAbility @Override public boolean checkTrigger(GameEvent event, Game game) { + /** + * 4/8/2016 Prized Amalgam’s ability triggers only if it’s in your + * graveyard immediately after a creature enters the battlefield from + * your graveyard or you cast a creature from your graveyard. A Prized + * Amalgam that’s already on the battlefield won’t be returned at the + * beginning of the next end step if it’s put into your graveyard later. + */ + boolean result = false; if (super.checkTrigger(event, game)) { EntersTheBattlefieldEvent entersEvent = (EntersTheBattlefieldEvent) event; if (entersEvent.getFromZone().equals(Zone.GRAVEYARD)) { - return true; - } - if (entersEvent.getFromZone().equals(Zone.STACK) && entersEvent.getTarget().getControllerId().equals(getControllerId())) { + result = true; + } else if (entersEvent.getFromZone().equals(Zone.STACK) && entersEvent.getTarget().getControllerId().equals(getControllerId())) { CastFromGraveyardWatcher watcher = (CastFromGraveyardWatcher) game.getState().getWatchers().get(CastFromGraveyardWatcher.class.getName()); if (watcher != null) { int zcc = game.getState().getZoneChangeCounter(event.getSourceId()); - return watcher.spellWasCastFromGraveyard(event.getSourceId(), zcc - 1); + result = watcher.spellWasCastFromGraveyard(event.getSourceId(), zcc - 1); } } } - return false; + if (result) { + for (Effect effect : getEffects()) { + effect.setTargetPointer(new FixedTarget(getSourceId(), game.getState().getZoneChangeCounter(getSourceId()))); + } + } + return result; } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/ReturnFromGraveyardToBattlefieldTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ReturnFromGraveyardToBattlefieldTargetEffect.java index dd2e2797041..cc449d0cecb 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ReturnFromGraveyardToBattlefieldTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ReturnFromGraveyardToBattlefieldTargetEffect.java @@ -27,6 +27,8 @@ */ package mage.abilities.effects.common; +import java.util.HashSet; +import java.util.Set; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.Mode; @@ -70,12 +72,14 @@ public class ReturnFromGraveyardToBattlefieldTargetEffect extends OneShotEffect public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { + Set cardsToMove = new HashSet<>(); for (UUID targetId : getTargetPointer().getTargets(game, source)) { Card card = game.getCard(targetId); if (card != null) { - controller.moveCards(card, Zone.BATTLEFIELD, source, game, tapped, false, false, null); + cardsToMove.add(card); } } + controller.moveCards(cardsToMove, Zone.BATTLEFIELD, source, game, tapped, false, false, null); return true; } return false; From 89a739e9022f6d275d79bc93bbb4d5e1fbb2166e Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 20 Oct 2016 15:16:31 +0200 Subject: [PATCH 24/35] * Removed debug messages. --- .../java/mage/client/cards/DragCardGrid.java | 6 +- .../mage/client/components/KeyBindButton.java | 125 +++++++++--------- 2 files changed, 65 insertions(+), 66 deletions(-) diff --git a/Mage.Client/src/main/java/mage/client/cards/DragCardGrid.java b/Mage.Client/src/main/java/mage/client/cards/DragCardGrid.java index ee968304b7f..125023b4e5b 100644 --- a/Mage.Client/src/main/java/mage/client/cards/DragCardGrid.java +++ b/Mage.Client/src/main/java/mage/client/cards/DragCardGrid.java @@ -576,7 +576,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg void cardsSelected(); void hideCards(Collection card); - + void duplicateCards(Collection cards); void showAll(); @@ -1094,6 +1094,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg l.duplicateCards(toDuplicate); } } + private void showAll() { for (DragCardGridListener l : listeners) { l.showAll(); @@ -1381,7 +1382,6 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg while (m.find()) { System.out.println("0=" + m.group(0) + ",,,1=" + m.group(1) + ",,,2=" + m.group(2) + ",,,3=" + m.group(3)); str = "Add" + m.group(1) + m.group(3) + "to your mana pool"; - System.out.println("Found " + m.group(2) + " in " + card.getName()); int num = 1; if (manaCounts.get(m.group(2)) != null) { num = manaCounts.get(m.group(2)); @@ -1675,7 +1675,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg // And add it cardContent.add(cardPanel); cardViews.put(card.getId(), cardPanel); - + if (duplicated) { sortIntoGrid(card); eventSource.addSpecificCard(card, "add-specific-card"); diff --git a/Mage.Client/src/main/java/mage/client/components/KeyBindButton.java b/Mage.Client/src/main/java/mage/client/components/KeyBindButton.java index ff842f4a3b5..4946530eaf6 100644 --- a/Mage.Client/src/main/java/mage/client/components/KeyBindButton.java +++ b/Mage.Client/src/main/java/mage/client/components/KeyBindButton.java @@ -14,81 +14,80 @@ import javax.swing.JPopupMenu; */ public class KeyBindButton extends JButton implements ActionListener { - private final JPopupMenu menu; - private final PopupItem item; - private int keyCode; - private String text; + private final JPopupMenu menu; + private final PopupItem item; + private int keyCode; + private String text; - public KeyBindButton() { - menu = new JPopupMenu(); - menu.add(item = new PopupItem()); - addActionListener(this); + public KeyBindButton() { + menu = new JPopupMenu(); + menu.add(item = new PopupItem()); + addActionListener(this); - fixText(); - } + fixText(); + } - private void applyNewKeycode(int code) { - keyCode = code; - switch (keyCode) { - case KeyEvent.VK_ESCAPE: - case KeyEvent.VK_SPACE: - keyCode = 0; - } - fixText(); - menu.setVisible(false); - setSize(getPreferredSize()); - System.out.println("text: " + text); - } + private void applyNewKeycode(int code) { + keyCode = code; + switch (keyCode) { + case KeyEvent.VK_ESCAPE: + case KeyEvent.VK_SPACE: + keyCode = 0; + } + fixText(); + menu.setVisible(false); + setSize(getPreferredSize()); + } - private void fixText() { - if (keyCode == 0) { - text = ""; - } else { - text = KeyEvent.getKeyText(keyCode); - } - repaint(); - } + private void fixText() { + if (keyCode == 0) { + text = ""; + } else { + text = KeyEvent.getKeyText(keyCode); + } + repaint(); + } - public void setKeyCode(int keyCode) { - this.keyCode = keyCode; - fixText(); - } + public void setKeyCode(int keyCode) { + this.keyCode = keyCode; + fixText(); + } - public int getKeyCode() { - return keyCode; - } + public int getKeyCode() { + return keyCode; + } - @Override - public String getText() { - return text; - } + @Override + public String getText() { + return text; + } - @Override - public void actionPerformed(ActionEvent e) { - menu.show(this, 0, 0); - item.requestFocusInWindow(); - } + @Override + public void actionPerformed(ActionEvent e) { + menu.show(this, 0, 0); + item.requestFocusInWindow(); + } - private class PopupItem extends JLabel implements KeyListener { + private class PopupItem extends JLabel implements KeyListener { - public PopupItem() { - super("Press a key"); - addKeyListener(this); - setFocusable(true); - } + public PopupItem() { + super("Press a key"); + addKeyListener(this); + setFocusable(true); + } - @Override - public void keyTyped(KeyEvent e) { - } + @Override + public void keyTyped(KeyEvent e) { + } - @Override - public void keyPressed(KeyEvent e) { - applyNewKeycode(e.getKeyCode()); - } + @Override + public void keyPressed(KeyEvent e) { + applyNewKeycode(e.getKeyCode()); + } - @Override - public void keyReleased(KeyEvent e) { - } + @Override + public void keyReleased(KeyEvent e) { + } - } + } } From 712f19f4e6641b17f818395f77d7e59174d4e3a5 Mon Sep 17 00:00:00 2001 From: spjspj Date: Fri, 21 Oct 2016 00:28:41 +1100 Subject: [PATCH 25/35] spjspj - Update all TargetOpponentsChoicePermanent cards with whether they have to target an opponent. (There was a NPE when an opponent had hexproof) --- Mage.Sets/src/mage/cards/a/Arena.java | 2 +- Mage.Sets/src/mage/cards/d/DiaochanArtfulBeauty.java | 2 +- Mage.Sets/src/mage/cards/e/Evangelize.java | 2 +- Mage.Sets/src/mage/cards/m/MagusOfTheArena.java | 2 +- Mage.Sets/src/mage/cards/p/Preacher.java | 4 ++-- Mage.Sets/src/mage/cards/v/VolcanicOffering.java | 4 ++-- .../mage/target/common/TargetOpponentsChoicePermanent.java | 7 +++++-- 7 files changed, 13 insertions(+), 10 deletions(-) diff --git a/Mage.Sets/src/mage/cards/a/Arena.java b/Mage.Sets/src/mage/cards/a/Arena.java index 77897647db7..9bbd8eeef01 100644 --- a/Mage.Sets/src/mage/cards/a/Arena.java +++ b/Mage.Sets/src/mage/cards/a/Arena.java @@ -58,7 +58,7 @@ public class Arena extends CardImpl { Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ArenaEffect(), new GenericManaCost(3)); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetControlledCreaturePermanent()); - ability.addTarget(new TargetOpponentsChoicePermanent(new FilterControlledCreaturePermanent())); + ability.addTarget(new TargetOpponentsChoicePermanent(1, 1, new FilterControlledCreaturePermanent(), false, true)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DiaochanArtfulBeauty.java b/Mage.Sets/src/mage/cards/d/DiaochanArtfulBeauty.java index 079a72c15e9..00f50eb31d4 100644 --- a/Mage.Sets/src/mage/cards/d/DiaochanArtfulBeauty.java +++ b/Mage.Sets/src/mage/cards/d/DiaochanArtfulBeauty.java @@ -64,7 +64,7 @@ public class DiaochanArtfulBeauty extends CardImpl { // {tap}: Destroy target creature of your choice, then destroy target creature of an opponent's choice. Activate this ability only during your turn, before attackers are declared. Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new DiaochanArtfulBeautyDestroyEffect(), new TapSourceCost(), MyTurnBeforeAttackersDeclaredCondition.getInstance()); ability.addTarget(new TargetCreaturePermanent()); - ability.addTarget(new TargetOpponentsChoicePermanent(new FilterCreaturePermanent())); + ability.addTarget(new TargetOpponentsChoicePermanent(1, 1, new FilterCreaturePermanent(), false, true)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/Evangelize.java b/Mage.Sets/src/mage/cards/e/Evangelize.java index 0ef72fa1de6..74ad62887d9 100644 --- a/Mage.Sets/src/mage/cards/e/Evangelize.java +++ b/Mage.Sets/src/mage/cards/e/Evangelize.java @@ -55,7 +55,7 @@ public class Evangelize extends CardImpl { GainControlTargetEffect effect = new GainControlTargetEffect(Duration.EndOfGame); effect.setText("Gain control of target creature of an opponent's choice that he or she controls"); this.getSpellAbility().addEffect(effect); - this.getSpellAbility().addTarget(new TargetOpponentsChoicePermanent(1, 1, filter, false)); + this.getSpellAbility().addTarget(new TargetOpponentsChoicePermanent(1, 1, filter, false, true)); } public Evangelize(final Evangelize card) { diff --git a/Mage.Sets/src/mage/cards/m/MagusOfTheArena.java b/Mage.Sets/src/mage/cards/m/MagusOfTheArena.java index c772c80dfd4..79082571e4f 100644 --- a/Mage.Sets/src/mage/cards/m/MagusOfTheArena.java +++ b/Mage.Sets/src/mage/cards/m/MagusOfTheArena.java @@ -64,7 +64,7 @@ public class MagusOfTheArena extends CardImpl { Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new MagusOfTheArenaEffect(), new GenericManaCost(3)); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetControlledCreaturePermanent()); - ability.addTarget(new TargetOpponentsChoicePermanent(new FilterControlledCreaturePermanent())); + ability.addTarget(new TargetOpponentsChoicePermanent(1, 1, new FilterControlledCreaturePermanent(), false, true)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/p/Preacher.java b/Mage.Sets/src/mage/cards/p/Preacher.java index 706d6b23a0f..cf59a2aad1b 100644 --- a/Mage.Sets/src/mage/cards/p/Preacher.java +++ b/Mage.Sets/src/mage/cards/p/Preacher.java @@ -69,7 +69,7 @@ public class Preacher extends CardImpl { // {tap}: Gain control of target creature of an opponent's choice that he or she controls for as long as Preacher remains tapped. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PreacherEffect(), new TapSourceCost()); - ability.addTarget(new TargetOpponentsChoicePermanent(new FilterControlledCreaturePermanent())); + ability.addTarget(new TargetOpponentsChoicePermanent(1, 1, new FilterControlledCreaturePermanent(), false, true)); this.addAbility(ability); @@ -127,4 +127,4 @@ class PreacherEffect extends OneShotEffect { } return false; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/v/VolcanicOffering.java b/Mage.Sets/src/mage/cards/v/VolcanicOffering.java index ee3f2080f8b..2313bd7358f 100644 --- a/Mage.Sets/src/mage/cards/v/VolcanicOffering.java +++ b/Mage.Sets/src/mage/cards/v/VolcanicOffering.java @@ -86,12 +86,12 @@ public class VolcanicOffering extends CardImpl { FilterLandPermanent filterLandForOpponent = new FilterLandPermanent("nonbasic land not controlled by " + controller.getLogName()); filterLandForOpponent.add(Predicates.not(new SupertypePredicate("Basic"))); filterLandForOpponent.add(Predicates.not(new ControllerIdPredicate(controller.getId()))); - ability.addTarget(new TargetOpponentsChoicePermanent(filterLandForOpponent)); + ability.addTarget(new TargetOpponentsChoicePermanent(1, 1, filterLandForOpponent, false, true)); ability.addTarget(new TargetPermanent(filterCreature)); FilterCreaturePermanent filterCreatureForOpponent = new FilterCreaturePermanent("creature not controlled by " + controller.getLogName()); filterCreatureForOpponent.add(Predicates.not(new ControllerIdPredicate(controller.getId()))); - ability.addTarget(new TargetOpponentsChoicePermanent(filterCreatureForOpponent)); + ability.addTarget(new TargetOpponentsChoicePermanent(1, 1, filterCreatureForOpponent, false, true)); } } diff --git a/Mage/src/main/java/mage/target/common/TargetOpponentsChoicePermanent.java b/Mage/src/main/java/mage/target/common/TargetOpponentsChoicePermanent.java index 34cd992cd80..8169667f3b4 100644 --- a/Mage/src/main/java/mage/target/common/TargetOpponentsChoicePermanent.java +++ b/Mage/src/main/java/mage/target/common/TargetOpponentsChoicePermanent.java @@ -21,20 +21,23 @@ import mage.target.TargetPermanent; public class TargetOpponentsChoicePermanent extends TargetPermanent { protected UUID opponentId = null; + private boolean dontTargetPlayer = false; public TargetOpponentsChoicePermanent(FilterPermanent filter) { super(1, 1, filter, false); this.targetName = filter.getMessage(); } - public TargetOpponentsChoicePermanent(int minNumTargets, int maxNumTargets, FilterPermanent filter, boolean notTarget) { + public TargetOpponentsChoicePermanent(int minNumTargets, int maxNumTargets, FilterPermanent filter, boolean notTarget, boolean dontTargetPlayer) { super(minNumTargets, maxNumTargets, filter, notTarget); this.targetName = filter.getMessage(); + this.dontTargetPlayer = dontTargetPlayer; } public TargetOpponentsChoicePermanent(final TargetOpponentsChoicePermanent target) { super(target); this.opponentId = target.opponentId; + this.dontTargetPlayer = target.dontTargetPlayer; } @Override @@ -79,7 +82,7 @@ public class TargetOpponentsChoicePermanent extends TargetPermanent { private UUID getOpponentId(UUID playerId, Ability source, Game game) { if (opponentId == null) { - TargetOpponent target = new TargetOpponent(); + TargetOpponent target = new TargetOpponent(dontTargetPlayer); Player player = game.getPlayer(playerId); if (player != null) { if (player.chooseTarget(Outcome.Detriment, target, source, game)) { From 468eb4647169ce208c9412bb7332901035a283b9 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 20 Oct 2016 19:45:04 +0200 Subject: [PATCH 26/35] * Midnight Oil - Fixed that also one remaning counter was removed it from it's own effect. --- .../counter/RemoveCounterSourceEffect.java | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/Mage/src/main/java/mage/abilities/effects/common/counter/RemoveCounterSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/counter/RemoveCounterSourceEffect.java index a371859fc5a..6322b59d121 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/counter/RemoveCounterSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/counter/RemoveCounterSourceEffect.java @@ -57,20 +57,26 @@ public class RemoveCounterSourceEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null && permanent.getCounters(game).getCount(counter.getName()) >= counter.getCount()) { - permanent.removeCounters(counter.getName(), counter.getCount(), game); - if (!game.isSimulation()) { - game.informPlayers("Removed " + counter.getCount() + " " + counter.getName() + " counter from " + permanent.getLogName()); + if (permanent != null) { + int toRemove = Math.min(counter.getCount(), permanent.getCounters(game).getCount(counter.getName())); + if (toRemove > 0) { + permanent.removeCounters(counter.getName(), toRemove, game); + if (!game.isSimulation()) { + game.informPlayers("Removed " + toRemove + " " + counter.getName() + " counter from " + permanent.getLogName()); + } } return true; } Card card = game.getCard(source.getSourceId()); - if (card != null && card.getCounters(game).getCount(counter.getName()) >= counter.getCount()) { - card.removeCounters(counter.getName(), counter.getCount(), game); - if (!game.isSimulation()) { - game.informPlayers("Removed " + counter.getCount() + " " + counter.getName() - + " counter from " + card.getLogName() - + " (" + card.getCounters(game).getCount(counter.getName()) + " left)"); + if (card != null) { + int toRemove = Math.min(counter.getCount(), card.getCounters(game).getCount(counter.getName())); + if (toRemove > 0) { + card.removeCounters(counter.getName(), toRemove, game); + if (!game.isSimulation()) { + game.informPlayers("Removed " + toRemove + " " + counter.getName() + + " counter from " + card.getLogName() + + " (" + card.getCounters(game).getCount(counter.getName()) + " left)"); + } } return true; } From 4d0660b19f340c74320adda3a8576ca1c6253a55 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Thu, 20 Oct 2016 22:50:29 +0200 Subject: [PATCH 27/35] * Doubling Season - Fixed that tokens were not doubled because they were put onto the battlefield on Doubling Seasons controller's side but wrongly only if Doubling Seasons controller did controll the effect that put the tokens onto the battlefield. --- .../src/mage/cards/d/DoublingSeason.java | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/Mage.Sets/src/mage/cards/d/DoublingSeason.java b/Mage.Sets/src/mage/cards/d/DoublingSeason.java index 8cbd0a541e0..7e9f3671232 100644 --- a/Mage.Sets/src/mage/cards/d/DoublingSeason.java +++ b/Mage.Sets/src/mage/cards/d/DoublingSeason.java @@ -49,7 +49,7 @@ import mage.game.stack.StackObject; public class DoublingSeason extends CardImpl { public DoublingSeason(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{4}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{G}"); // If an effect would put one or more tokens onto the battlefield under your control, it puts twice that many of those tokens onto the battlefield instead. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DoublingSeasonTokenEffect())); @@ -91,16 +91,8 @@ class DoublingSeasonTokenEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - StackObject spell = game.getStack().getStackObject(event.getSourceId()); - if (spell != null && spell.getControllerId().equals(source.getControllerId())) { - return true; - } - return false; - } - - @Override - public boolean apply(Game game, Ability source) { - return true; + StackObject stackObject = game.getStack().getStackObject(event.getSourceId()); + return stackObject != null && event.getPlayerId().equals(source.getControllerId()); } @Override @@ -139,10 +131,7 @@ class DoublingSeasonCounterEffect extends ReplacementEffectImpl { if (permanent == null) { permanent = game.getPermanentEntering(event.getTargetId()); } - if (permanent != null && permanent.getControllerId().equals(source.getControllerId())) { - return true; - } - return false; + return permanent != null && permanent.getControllerId().equals(source.getControllerId()); } @Override From 4c292466c170d0a4772b47a0897b74f0f71c9a98 Mon Sep 17 00:00:00 2001 From: Campbell Suter Date: Fri, 21 Oct 2016 09:01:19 +1300 Subject: [PATCH 28/35] Make it impossible to have multiple actions bound to the same key. --- .../mage/client/components/KeyBindButton.java | 147 ++++++++++-------- .../mage/client/dialog/PreferencesDialog.form | 37 ++++- .../mage/client/dialog/PreferencesDialog.java | 92 ++++++----- 3 files changed, 172 insertions(+), 104 deletions(-) diff --git a/Mage.Client/src/main/java/mage/client/components/KeyBindButton.java b/Mage.Client/src/main/java/mage/client/components/KeyBindButton.java index 4946530eaf6..ea16158ad19 100644 --- a/Mage.Client/src/main/java/mage/client/components/KeyBindButton.java +++ b/Mage.Client/src/main/java/mage/client/components/KeyBindButton.java @@ -7,6 +7,7 @@ import java.awt.event.KeyListener; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPopupMenu; +import mage.client.dialog.PreferencesDialog; /** * @@ -14,80 +15,102 @@ import javax.swing.JPopupMenu; */ public class KeyBindButton extends JButton implements ActionListener { - private final JPopupMenu menu; - private final PopupItem item; - private int keyCode; - private String text; + private final PreferencesDialog preferences; + private final String key; + private PopupItem item; + private JPopupMenu menu; + private int keyCode; + private String text; - public KeyBindButton() { - menu = new JPopupMenu(); - menu.add(item = new PopupItem()); - addActionListener(this); + /** + * For the IDE only, do not use! + */ + public KeyBindButton() { + this(null, null); + } - fixText(); - } + public KeyBindButton(PreferencesDialog preferences, String key) { + this.preferences = preferences; + this.key = key; + addActionListener(this); + fixText(); + } - private void applyNewKeycode(int code) { - keyCode = code; - switch (keyCode) { - case KeyEvent.VK_ESCAPE: - case KeyEvent.VK_SPACE: - keyCode = 0; - } - fixText(); - menu.setVisible(false); - setSize(getPreferredSize()); - } + private JPopupMenu getMenu() { + menu = new JPopupMenu(); + menu.add(item = new PopupItem()); + return menu; + } - private void fixText() { - if (keyCode == 0) { - text = ""; - } else { - text = KeyEvent.getKeyText(keyCode); - } - repaint(); - } + private void applyNewKeycode(int code) { + preferences.getKeybindButtons().stream() + .filter(b -> b != KeyBindButton.this) + .filter(b -> b.getKeyCode() == code) + .forEach(b -> b.setKeyCode(0)); - public void setKeyCode(int keyCode) { - this.keyCode = keyCode; - fixText(); - } + setKeyCode(code); + menu.setVisible(false); + } - public int getKeyCode() { - return keyCode; - } + private void fixText() { + if (keyCode == 0) { + text = ""; + } else { + text = KeyEvent.getKeyText(keyCode); + } + repaint(); + } - @Override - public String getText() { - return text; - } + public void setKeyCode(int keyCode) { + this.keyCode = keyCode; + switch (keyCode) { + case KeyEvent.VK_ESCAPE: + case KeyEvent.VK_SPACE: + keyCode = 0; + } + fixText(); + setSize(getPreferredSize()); + } - @Override - public void actionPerformed(ActionEvent e) { - menu.show(this, 0, 0); - item.requestFocusInWindow(); - } + public int getKeyCode() { + return keyCode; + } - private class PopupItem extends JLabel implements KeyListener { + @Override + public String getText() { + return text; + } - public PopupItem() { - super("Press a key"); - addKeyListener(this); - setFocusable(true); - } + public String getKey() { + return key; + } - @Override - public void keyTyped(KeyEvent e) { - } + @Override + public void actionPerformed(ActionEvent e) { + getMenu().show(this, 0, 0); + item.requestFocusInWindow(); + } - @Override - public void keyPressed(KeyEvent e) { - applyNewKeycode(e.getKeyCode()); - } + private class PopupItem extends JLabel implements KeyListener { - @Override - public void keyReleased(KeyEvent e) { - } + public PopupItem() { + super("Press a key"); + addKeyListener(this); + setFocusable(true); + } - } + @Override + public void keyTyped(KeyEvent e) { + } + + @Override + public void keyPressed(KeyEvent e) { + applyNewKeycode(e.getKeyCode()); + } + + @Override + public void keyReleased(KeyEvent e) { + } + + } } diff --git a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form index 7a3e9afd3ee..3fbc4285fb7 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form +++ b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form @@ -5886,7 +5886,7 @@ - + @@ -5921,8 +5921,9 @@ - - + + + @@ -5968,9 +5969,8 @@ - - + @@ -6015,41 +6015,65 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + @@ -6060,6 +6084,9 @@ + + + diff --git a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java index f8a02a5cd03..ab49a95221a 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java @@ -42,7 +42,9 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.io.File; +import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; @@ -560,16 +562,16 @@ public class PreferencesDialog extends javax.swing.JDialog { lebelSkip = new javax.swing.JLabel(); labelPriorEnd = new javax.swing.JLabel(); labelCancel = new javax.swing.JLabel(); - keyCancelSkip = new mage.client.components.KeyBindButton(); - keyNextTurn = new mage.client.components.KeyBindButton(); - keyMainStep = new mage.client.components.KeyBindButton(); - keyEndStep = new mage.client.components.KeyBindButton(); - keyYourTurn = new mage.client.components.KeyBindButton(); - keySkipStack = new mage.client.components.KeyBindButton(); - keyPriorEnd = new mage.client.components.KeyBindButton(); - keySkipStep = new mage.client.components.KeyBindButton(); + keyCancelSkip = new KeyBindButton(this, KEY_CONTROL_CANCEL_SKIP); + keyNextTurn = new KeyBindButton(this, KEY_CONTROL_NEXT_TURN); + keyMainStep = new KeyBindButton(this, KEY_CONTROL_MAIN_STEP); + keyEndStep = new KeyBindButton(this, KEY_CONTROL_END_STEP); + keyYourTurn = new KeyBindButton(this, KEY_CONTROL_YOUR_TURN); + keySkipStack = new KeyBindButton(this, KEY_CONTROL_SKIP_STACK); + keyPriorEnd = new KeyBindButton(this, KEY_CONTROL_PRIOR_END); + keySkipStep = new KeyBindButton(this, KEY_CONTROL_SKIP_STEP); labelSkipStep = new javax.swing.JLabel(); - keyConfirm = new mage.client.components.KeyBindButton(); + keyConfirm = new KeyBindButton(this, KEY_CONTROL_CONFIRM); labelConfirm = new javax.swing.JLabel(); controlsDescriptionLabel = new javax.swing.JLabel(); saveButton = new javax.swing.JButton(); @@ -2548,8 +2550,9 @@ public class PreferencesDialog extends javax.swing.JDialog { tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(tabControlsLayout.createSequentialGroup() .addContainerGap() - .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false) - .add(tabControlsLayout.createSequentialGroup() + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING, false) + .add(org.jdesktop.layout.GroupLayout.LEADING, controlsDescriptionLabel) + .add(org.jdesktop.layout.GroupLayout.LEADING, tabControlsLayout.createSequentialGroup() .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(labelConfirm) .add(keyConfirm, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) @@ -2584,9 +2587,8 @@ public class PreferencesDialog extends javax.swing.JDialog { .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(labelPriorEnd) - .add(keyPriorEnd, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))) - .add(controlsDescriptionLabel)) - .add(263, 263, 263)) + .add(keyPriorEnd, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))) + .addContainerGap()) ); tabsPanel.addTab("Controls", tabControls); @@ -2780,15 +2782,15 @@ public class PreferencesDialog extends javax.swing.JDialog { save(prefs, dialog.txtURLServerList, KEY_CONNECTION_URL_SERVER_LIST); // controls - save(prefs, dialog.keyConfirm, KEY_CONTROL_CONFIRM); - save(prefs, dialog.keyCancelSkip, KEY_CONTROL_CANCEL_SKIP); - save(prefs, dialog.keyNextTurn, KEY_CONTROL_NEXT_TURN); - save(prefs, dialog.keyEndStep, KEY_CONTROL_END_STEP); - save(prefs, dialog.keySkipStep, KEY_CONTROL_SKIP_STEP); - save(prefs, dialog.keyMainStep, KEY_CONTROL_MAIN_STEP); - save(prefs, dialog.keyYourTurn, KEY_CONTROL_YOUR_TURN); - save(prefs, dialog.keySkipStack, KEY_CONTROL_SKIP_STACK); - save(prefs, dialog.keyPriorEnd, KEY_CONTROL_PRIOR_END); + save(prefs, dialog.keyConfirm); + save(prefs, dialog.keyCancelSkip); + save(prefs, dialog.keyNextTurn); + save(prefs, dialog.keyEndStep); + save(prefs, dialog.keySkipStep); + save(prefs, dialog.keyMainStep); + save(prefs, dialog.keyYourTurn); + save(prefs, dialog.keySkipStack); + save(prefs, dialog.keyPriorEnd); // Avatar if (selectedAvatarId < MIN_AVATAR_ID || selectedAvatarId > MAX_AVATAR_ID) { @@ -3327,15 +3329,15 @@ public class PreferencesDialog extends javax.swing.JDialog { } private static void loadControlSettings(Preferences prefs) { - load(prefs, dialog.keyConfirm, KEY_CONTROL_CONFIRM); - load(prefs, dialog.keyCancelSkip, KEY_CONTROL_CANCEL_SKIP); - load(prefs, dialog.keyNextTurn, KEY_CONTROL_NEXT_TURN); - load(prefs, dialog.keyEndStep, KEY_CONTROL_END_STEP); - load(prefs, dialog.keySkipStep, KEY_CONTROL_SKIP_STEP); - load(prefs, dialog.keyMainStep, KEY_CONTROL_MAIN_STEP); - load(prefs, dialog.keyYourTurn, KEY_CONTROL_YOUR_TURN); - load(prefs, dialog.keySkipStack, KEY_CONTROL_SKIP_STACK); - load(prefs, dialog.keyPriorEnd, KEY_CONTROL_PRIOR_END); + load(prefs, dialog.keyConfirm); + load(prefs, dialog.keyCancelSkip); + load(prefs, dialog.keyNextTurn); + load(prefs, dialog.keyEndStep); + load(prefs, dialog.keySkipStep); + load(prefs, dialog.keyMainStep); + load(prefs, dialog.keyYourTurn); + load(prefs, dialog.keySkipStack); + load(prefs, dialog.keyPriorEnd); } private static void loadSelectedAvatar(Preferences prefs) { @@ -3462,8 +3464,9 @@ public class PreferencesDialog extends javax.swing.JDialog { load(prefs, checkBox, propName, PHASE_ON); } - private static void load(Preferences prefs, KeyBindButton button, String propName) { - int prop = prefs.getInt(propName, getDefaultControlKey(propName)); + private static void load(Preferences prefs, KeyBindButton button) { + String key = button.getKey(); + int prop = prefs.getInt(key, getDefaultControlKey(key)); button.setKeyCode(prop); } @@ -3504,10 +3507,11 @@ public class PreferencesDialog extends javax.swing.JDialog { updateCache(propName, comboBox.getSelectedItem().toString().trim()); } - private static void save(Preferences prefs, KeyBindButton button, String propName) { + private static void save(Preferences prefs, KeyBindButton button) { int code = button.getKeyCode(); - prefs.putInt(propName, code); - updateCache(propName, Integer.toString(code)); + String key = button.getKey(); + prefs.putInt(key, code); + updateCache(key, Integer.toString(code)); } public void reset() { @@ -3688,6 +3692,20 @@ public class PreferencesDialog extends javax.swing.JDialog { ); } + public List getKeybindButtons() { + return Arrays.asList( + keyCancelSkip, + keyConfirm, + keyEndStep, + keyMainStep, + keyNextTurn, + keyPriorEnd, + keySkipStack, + keySkipStep, + keyYourTurn + ); + } + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JScrollPane avatarPane; private javax.swing.JPanel avatarPanel; From 0428f5bab3038aef8c6f378e8643e055d2eacdee Mon Sep 17 00:00:00 2001 From: Campbell Suter Date: Fri, 21 Oct 2016 09:33:56 +1300 Subject: [PATCH 29/35] Add reset keys to default button --- .../mage/client/dialog/PreferencesDialog.form | 66 +++++++++++------- .../mage/client/dialog/PreferencesDialog.java | 68 +++++++++++++------ 2 files changed, 88 insertions(+), 46 deletions(-) diff --git a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form index 3fbc4285fb7..763fa551592 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form +++ b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form @@ -5889,30 +5889,38 @@ - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - @@ -5970,7 +5978,9 @@ - + + + @@ -6099,6 +6109,14 @@ + + + + + + + + diff --git a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java index ab49a95221a..1b3978f35c9 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java @@ -574,6 +574,7 @@ public class PreferencesDialog extends javax.swing.JDialog { keyConfirm = new KeyBindButton(this, KEY_CONTROL_CONFIRM); labelConfirm = new javax.swing.JLabel(); controlsDescriptionLabel = new javax.swing.JLabel(); + bttnResetControls = new javax.swing.JButton(); saveButton = new javax.swing.JButton(); exitButton = new javax.swing.JButton(); @@ -2515,6 +2516,13 @@ public class PreferencesDialog extends javax.swing.JDialog { controlsDescriptionLabel.setText("Click on a button and press a key to change a keybind.
Space and ESC are not available, and will set the keybind to nothing.
If you are currently playing a game, the changes will not take effect until you start a new game."); controlsDescriptionLabel.setVerticalAlignment(javax.swing.SwingConstants.TOP); + bttnResetControls.setText("Reset to default"); + bttnResetControls.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + bttnResetControlsActionPerformed(evt); + } + }); + org.jdesktop.layout.GroupLayout tabControlsLayout = new org.jdesktop.layout.GroupLayout(tabControls); tabControls.setLayout(tabControlsLayout); tabControlsLayout.setHorizontalGroup( @@ -2522,28 +2530,33 @@ public class PreferencesDialog extends javax.swing.JDialog { .add(tabControlsLayout.createSequentialGroup() .addContainerGap() .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(labelCancel) - .add(labelNextTurn) - .add(labelEndStep) - .add(labelMainStep) - .add(labelYourTurn) - .add(lebelSkip) - .add(labelPriorEnd) - .add(labelSkipStep) - .add(labelConfirm)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) - .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(keyConfirm, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(keyCancelSkip, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(keyNextTurn, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(keySkipStack, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(keyYourTurn, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(keyMainStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(keyPriorEnd, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(keySkipStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(keyEndStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(controlsDescriptionLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 498, Short.MAX_VALUE) + .add(tabControlsLayout.createSequentialGroup() + .add(bttnResetControls) + .add(0, 0, Short.MAX_VALUE)) + .add(tabControlsLayout.createSequentialGroup() + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(labelCancel) + .add(labelNextTurn) + .add(labelEndStep) + .add(labelMainStep) + .add(labelYourTurn) + .add(lebelSkip) + .add(labelPriorEnd) + .add(labelSkipStep) + .add(labelConfirm)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(keyConfirm, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(keyCancelSkip, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(keyNextTurn, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(keySkipStack, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(keyYourTurn, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(keyMainStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(keyPriorEnd, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(keySkipStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(keyEndStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(controlsDescriptionLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 498, Short.MAX_VALUE))) .addContainerGap()) ); tabControlsLayout.setVerticalGroup( @@ -2588,6 +2601,8 @@ public class PreferencesDialog extends javax.swing.JDialog { .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(labelPriorEnd) .add(keyPriorEnd, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(bttnResetControls) .addContainerGap()) ); @@ -3081,6 +3096,14 @@ public class PreferencesDialog extends javax.swing.JDialog { // TODO add your handling code here: }//GEN-LAST:event_cbCardRenderHideSetSymbolActionPerformed + private void bttnResetControlsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bttnResetControlsActionPerformed + getKeybindButtons().stream().forEach((bttn) -> { + String id = bttn.getKey(); + int keyCode = getDefaultControlKey(id); + bttn.setKeyCode(keyCode); + }); + }//GEN-LAST:event_bttnResetControlsActionPerformed + private void showProxySettings() { Connection.ProxyType proxyType = (Connection.ProxyType) cbProxyType.getSelectedItem(); switch (proxyType) { @@ -3713,6 +3736,7 @@ public class PreferencesDialog extends javax.swing.JDialog { private javax.swing.JButton btnBrowseBackgroundImage; private javax.swing.JButton btnBrowseBattlefieldImage; private javax.swing.JButton btnBrowseImageLocation; + private javax.swing.JButton bttnResetControls; private javax.swing.JCheckBox cbAllowRequestToShowHandCards; private javax.swing.JCheckBox cbAskMoveToGraveOrder; private javax.swing.JCheckBox cbAutoOrderTrigger; From 72b23acf2317a7d49abcfd6d2ca02ee22ba12720 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 21 Oct 2016 00:13:32 +0200 Subject: [PATCH 30/35] * Prized Amalgam - Fixed a problem with Prized Amalgam. --- Mage.Sets/src/mage/cards/p/PrizedAmalgam.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/cards/p/PrizedAmalgam.java b/Mage.Sets/src/mage/cards/p/PrizedAmalgam.java index 2907b79a4e3..e0ac8f96fd6 100644 --- a/Mage.Sets/src/mage/cards/p/PrizedAmalgam.java +++ b/Mage.Sets/src/mage/cards/p/PrizedAmalgam.java @@ -67,8 +67,10 @@ public class PrizedAmalgam extends CardImpl { this.toughness = new MageInt(3); // Whenever a creature enters the battlefield, if it entered from your graveyard or you cast it from your graveyard, return Prized Amalgam from your graveyard to the battlefield tapped at the beginning of the next end step. + Effect effect = new ReturnFromGraveyardToBattlefieldTargetEffect(true); + effect.setText("return {this} from your graveyard to the battlefield tapped at the beginning of the next end step"); this.addAbility(new PrizedAmalgamTriggerdAbility(new CreateDelayedTriggeredAbilityEffect( - new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(true))), filter), + new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect)), filter), new CastFromGraveyardWatcher()); } From ee96531de5bb770c5b6e3e9678f46ba68661cc52 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 21 Oct 2016 00:15:41 +0200 Subject: [PATCH 31/35] * Fixed that a spell that becomes a permanent didn't had the colors of the spell (e.g. ERsatz Gnomes). --- Mage.Sets/src/mage/cards/e/ErsatzGnomes.java | 6 +- .../src/mage/cards/p/PaintersServant.java | 58 ++--------- .../cards/continuous/ErsatzGnomesTest.java | 99 +++++++++++++++++++ Mage/src/main/java/mage/ObjectColor.java | 25 ++++- Mage/src/main/java/mage/game/stack/Spell.java | 3 + 5 files changed, 135 insertions(+), 56 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/continuous/ErsatzGnomesTest.java diff --git a/Mage.Sets/src/mage/cards/e/ErsatzGnomes.java b/Mage.Sets/src/mage/cards/e/ErsatzGnomes.java index 9aa42cb980e..59bedb0ea96 100644 --- a/Mage.Sets/src/mage/cards/e/ErsatzGnomes.java +++ b/Mage.Sets/src/mage/cards/e/ErsatzGnomes.java @@ -49,17 +49,17 @@ import mage.target.TargetSpell; public class ErsatzGnomes extends CardImpl { public ErsatzGnomes(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{3}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}"); this.subtype.add("Gnome"); this.power = new MageInt(1); this.toughness = new MageInt(1); - // {tap}: Target spell becomes colorless. + // {T}: Target spell becomes colorless. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesColorTargetEffect(new ObjectColor(), Duration.Custom), new TapSourceCost()); ability.addTarget(new TargetSpell()); this.addAbility(ability); - // {tap}: Target permanent becomes colorless until end of turn. + // {T}: Target permanent becomes colorless until end of turn. ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesColorTargetEffect(new ObjectColor(), Duration.EndOfTurn), new TapSourceCost()); ability.addTarget(new TargetPermanent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/p/PaintersServant.java b/Mage.Sets/src/mage/cards/p/PaintersServant.java index 8fdb6e4750a..b84c9b18a61 100644 --- a/Mage.Sets/src/mage/cards/p/PaintersServant.java +++ b/Mage.Sets/src/mage/cards/p/PaintersServant.java @@ -59,7 +59,7 @@ import mage.sets.Commander; public class PaintersServant extends CardImpl { public PaintersServant(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{2}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}"); this.subtype.add("Scarecrow"); this.power = new MageInt(1); @@ -97,24 +97,23 @@ class PaintersServantEffect extends ContinuousEffectImpl { if (color == null) { return false; } - String colorString = color.toString(); for (Permanent perm : game.getBattlefield().getActivePermanents(source.getControllerId(), game)) { - setObjectColor(perm, colorString, game); + perm.getColor(game).addColor(color); } // Stack for (MageObject object : game.getStack()) { if (object instanceof Spell) { - setObjectColor(object, colorString, game); + object.getColor(game).addColor(color); } } // Exile for (Card card : game.getExile().getAllCards(game)) { - setCardColor(card, colorString, game); + game.getState().getCreateCardAttribute(card).getColor().addColor(color); } // Command for (CommandObject commandObject : game.getState().getCommand()) { if (commandObject instanceof Commander) { - setObjectColor(commandObject, colorString, game); + commandObject.getColor(game).addColor(color); } } @@ -123,15 +122,15 @@ class PaintersServantEffect extends ContinuousEffectImpl { if (player != null) { // Hand for (Card card : player.getHand().getCards(game)) { - setCardColor(card, colorString, game); + game.getState().getCreateCardAttribute(card).getColor().addColor(color); } // Library for (Card card : player.getLibrary().getCards(game)) { - setCardColor(card, colorString, game); + game.getState().getCreateCardAttribute(card).getColor().addColor(color); } // Graveyard for (Card card : player.getGraveyard().getCards(game)) { - setCardColor(card, colorString, game); + game.getState().getCreateCardAttribute(card).getColor().addColor(color); } } } @@ -140,47 +139,6 @@ class PaintersServantEffect extends ContinuousEffectImpl { return false; } - protected static void setCardColor(Card card, String colorString, Game game) { - ObjectColor color = game.getState().getCreateCardAttribute(card).getColor(); - switch (colorString) { - case "W": - color.setWhite(true); - break; - case "B": - color.setBlack(true); - break; - case "U": - color.setBlue(true); - break; - case "G": - color.setGreen(true); - break; - case "R": - color.setRed(true); - break; - } - } - - protected static void setObjectColor(MageObject obj, String colorString, Game game) { - switch (colorString) { - case "W": - obj.getColor(game).setWhite(true); - break; - case "B": - obj.getColor(game).setBlack(true); - break; - case "U": - obj.getColor(game).setBlue(true); - break; - case "G": - obj.getColor(game).setGreen(true); - break; - case "R": - obj.getColor(game).setRed(true); - break; - } - } - @Override public PaintersServantEffect copy() { return new PaintersServantEffect(this); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/ErsatzGnomesTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/ErsatzGnomesTest.java new file mode 100644 index 00000000000..5b1f330accc --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/ErsatzGnomesTest.java @@ -0,0 +1,99 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.cards.continuous; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.game.permanent.Permanent; +import org.junit.Assert; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class ErsatzGnomesTest extends CardTestPlayerBase { + + /** + * Ersatz Gnomes is incorrectly used I targeted a spell which is a permanent + * to colorless. When it enters the field its suppose to be colorless not go + * back to normal. It's colorless until it leaves the battlefield when you + * make a permanent spell colorless when you cast it. + */ + @Test + public void testColorlessSpellCreatesColorlessPermanent() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + addCard(Zone.HAND, playerA, "Silvercoat Lion", 1); + + // {T}: Target spell becomes colorless. + // {T}: Target permanent becomes colorless until end of turn. + addCard(Zone.BATTLEFIELD, playerA, "Ersatz Gnomes"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Silvercoat Lion"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Target spell", "Silvercoat Lion"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Silvercoat Lion", 1); + assertTapped("Ersatz Gnomes", true); + Permanent lion = getPermanent("Silvercoat Lion", playerA); + Assert.assertTrue("Silvercoat lion has to be colorless", lion.getColor(currentGame).isColorless()); + } + + @Test + public void testColorlessSpellCreatesColorlessPermanentUntilItBattlefieldLeft() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + addCard(Zone.HAND, playerA, "Silvercoat Lion", 1); + + // {T}: Target spell becomes colorless. + // {T}: Target permanent becomes colorless until end of turn. + addCard(Zone.BATTLEFIELD, playerA, "Ersatz Gnomes"); + + addCard(Zone.BATTLEFIELD, playerB, "Island", 1); + addCard(Zone.HAND, playerB, "Unsummon"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Silvercoat Lion"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Target spell", "Silvercoat Lion"); + + castSpell(1, PhaseStep.END_COMBAT, playerB, "Unsummon", "Silvercoat Lion"); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Silvercoat Lion"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertGraveyardCount(playerB, "Unsummon", 1); + assertPermanentCount(playerA, "Silvercoat Lion", 1); + assertTapped("Ersatz Gnomes", true); + Permanent lion = getPermanent("Silvercoat Lion", playerA); + Assert.assertTrue("Silvercoat lion has to be white", lion.getColor(currentGame).isWhite()); + } + +} diff --git a/Mage/src/main/java/mage/ObjectColor.java b/Mage/src/main/java/mage/ObjectColor.java index 60827481e64..4c4e1eb01fe 100644 --- a/Mage/src/main/java/mage/ObjectColor.java +++ b/Mage/src/main/java/mage/ObjectColor.java @@ -81,19 +81,20 @@ public class ObjectColor implements Serializable, Copyable, Compara red = color.red; green = color.green; } - + /** * Returns a new color which contains all of the colors of this ObjectColor * in addition to all of the colors of the other ObjectColor. + * * @param other The other ObjectColor to union with * @return A new color which is the union of this and other */ public ObjectColor union(ObjectColor other) { ObjectColor newColor = new ObjectColor(); newColor.white = white | other.white; - newColor.blue = blue | other.blue; + newColor.blue = blue | other.blue; newColor.black = black | other.black; - newColor.red = red | other.red; + newColor.red = red | other.red; newColor.green = green | other.green; return newColor; } @@ -146,6 +147,24 @@ public class ObjectColor implements Serializable, Copyable, Compara this.setWhite(color.isWhite()); } + public void addColor(ObjectColor color) { + if (color.isWhite()) { + setWhite(true); + } + if (color.isBlue()) { + setBlue(true); + } + if (color.isBlack()) { + setBlack(true); + } + if (color.isRed()) { + setRed(true); + } + if (color.isGreen()) { + setGreen(true); + } + } + public boolean isColorless() { return !(hasColor()); } diff --git a/Mage/src/main/java/mage/game/stack/Spell.java b/Mage/src/main/java/mage/game/stack/Spell.java index 69dfb83d4be..ed562d6b6cd 100644 --- a/Mage/src/main/java/mage/game/stack/Spell.java +++ b/Mage/src/main/java/mage/game/stack/Spell.java @@ -277,6 +277,9 @@ public class Spell extends StackObjImpl implements Card { } } else { updateOptionalCosts(0); + if (!getColor(game).equals(card.getColor(game))) { // if spell color was changed, the created permanent needs to be of that color + game.getState().getCreateCardAttribute(card).getColor().setColor(getColor(game)); + } return controller.moveCards(card, Zone.BATTLEFIELD, ability, game, false, faceDown, false, null); } } From 97b872d926a64cc9670d6e9bcfc59add222f2c3d Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 22 Oct 2016 10:38:10 +0200 Subject: [PATCH 32/35] * Fixed that a spell that becomes a permanent didn't had the colors of the spell (e.g. ERsatz Gnomes). --- .../src/mage/player/ai/ComputerPlayer7.java | 168 ++++++++---------- .../src/mage/player/human/HumanPlayer.java | 5 + .../abilities/keywords/BloodthirstTest.java | 2 +- .../cards/continuous/ErsatzGnomesTest.java | 63 +++++++ .../java/mage/verify/VerifyCardDataTest.java | 32 ++-- .../src/main/java/mage/game/ZonesHandler.java | 21 +++ .../mage/game/permanent/PermanentCard.java | 2 +- .../mage/game/permanent/PermanentMeld.java | 6 - Mage/src/main/java/mage/game/stack/Spell.java | 5 +- .../main/java/mage/game/turn/TurnMods.java | 23 ++- 10 files changed, 188 insertions(+), 139 deletions(-) diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java index a49c7ca7a07..c1ff29cb746 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,12 +20,11 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.player.ai; import java.util.LinkedList; @@ -53,9 +52,6 @@ import mage.game.turn.PostCombatMainStep; import mage.game.turn.Step; import org.apache.log4j.Logger; - - - /** * * @author ayratn @@ -91,10 +87,10 @@ public class ComputerPlayer7 extends ComputerPlayer6 { private boolean priorityPlay(Game game) { if (lastLoggedTurn != game.getTurnNum()) { lastLoggedTurn = game.getTurnNum(); - logger.info("======================= Turn: "+ game.getTurnNum() + " ["+ game.getPlayer(game.getActivePlayerId()).getName() +"] ========================================="); + logger.info("======================= Turn: " + game.getTurnNum() + " [" + game.getPlayer(game.getActivePlayerId()).getName() + "] ========================================="); } logState(game); - logger.debug("Priority -- Step: " + (game.getTurn().getStepType() + " ").substring(0,25) + " ActivePlayer-" + game.getPlayer(game.getActivePlayerId()).getName() + " PriorityPlayer-" + name); + logger.debug("Priority -- Step: " + (game.getTurn().getStepType() + " ").substring(0, 25) + " ActivePlayer-" + game.getPlayer(game.getActivePlayerId()).getName() + " PriorityPlayer-" + name); game.getState().setPriorityPlayerId(playerId); game.firePriorityEvent(playerId); switch (game.getTurn().getStepType()) { @@ -111,8 +107,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 { } act(game); return true; - } - else { + } else { pass(game); } return false; @@ -128,8 +123,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 { } act(game); return true; - } - else { + } else { pass(game); } return false; @@ -141,12 +135,12 @@ public class ComputerPlayer7 extends ComputerPlayer6 { return false; case POSTCOMBAT_MAIN: // if (game.getActivePlayerId().equals(playerId)) { - printOutState(game); - if (actions.isEmpty()) { - calculatePostCombatActions(game); - } - act(game); - return true; + printOutState(game); + if (actions.isEmpty()) { + calculatePostCombatActions(game); + } + act(game); + return true; // } // else { // pass(game); @@ -161,24 +155,24 @@ public class ComputerPlayer7 extends ComputerPlayer6 { return false; } - protected void calculatePreCombatActions(Game game) { + protected void calculatePreCombatActions(Game game) { if (!getNextAction(game)) { currentScore = GameStateEvaluator2.evaluate(playerId, game); Game sim = createSimulation(game); SimulationNode2.resetCount(); root = new SimulationNode2(null, sim, maxDepth, playerId); - + addActionsTimed(); logger.trace("After add actions timed: root.children.size = " + root.children.size()); if (root.children.size() > 0) { root = root.children.get(0); // int bestScore = root.getScore(); // if (bestScore > currentScore || allowBadMoves) { - + // prevent repeating always the same action with no cost boolean doThis = true; if (root.abilities.size() == 1) { - for (Ability ability:root.abilities) { + for (Ability ability : root.abilities) { if (ability.getManaCosts().convertedManaCost() == 0 && ability.getCosts().isEmpty()) { if (actionCache.contains(ability.getRule() + "_" + ability.getSourceId())) { doThis = false; // don't do it again @@ -217,7 +211,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 { actions = new LinkedList<>(root.abilities); combat = root.combat; } else { - logger.debug("[" + game.getPlayer(playerId).getName() + "] no better score current: " + currentScore + " bestScore: " + bestScore ); + logger.debug("[" + game.getPlayer(playerId).getName() + "] no better score current: " + currentScore + " bestScore: " + bestScore); } } else { logger.debug("[" + game.getPlayer(playerId).getName() + "][post] Action: skip"); @@ -229,7 +223,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 { protected int addActions(SimulationNode2 node, int depth, int alpha, int beta) { boolean stepFinished = false; int val; - if (logger.isTraceEnabled() && node !=null && node.getAbilities() != null && !node.getAbilities().toString().equals("[Pass]")){ + if (logger.isTraceEnabled() && node != null && node.getAbilities() != null && !node.getAbilities().toString().equals("[Pass]")) { logger.trace("Add Action [" + depth + "] " + node.getAbilities().toString() + " a: " + alpha + " b: " + beta); } Game game = node.getGame(); @@ -243,42 +237,39 @@ public class ComputerPlayer7 extends ComputerPlayer6 { val = GameStateEvaluator2.evaluate(playerId, game); if (logger.isTraceEnabled()) { StringBuilder sb = new StringBuilder("Add Actions -- reached end state <").append(val).append(">"); - SimulationNode2 logNode = node; + SimulationNode2 logNode = node; do { - sb.append(new StringBuilder(" <- ["+logNode.getDepth()+"]" + (logNode.getAbilities() != null ? logNode.getAbilities().toString():"[empty]"))); + sb.append(new StringBuilder(" <- [" + logNode.getDepth() + "]" + (logNode.getAbilities() != null ? logNode.getAbilities().toString() : "[empty]"))); logNode = logNode.getParent(); - } while((logNode.getParent() != null)); + } while ((logNode.getParent() != null)); logger.trace(sb); } } else if (node.getChildren().size() > 0) { if (logger.isDebugEnabled()) { StringBuilder sb = new StringBuilder("Add Action [").append(depth) .append("] -- something added children ") - .append(node.getAbilities() != null ? node.getAbilities().toString():"null") + .append(node.getAbilities() != null ? node.getAbilities().toString() : "null") .append(" added children: ").append(node.getChildren().size()).append(" ("); - for (SimulationNode2 logNode: node.getChildren()) { - sb.append(logNode.getAbilities() != null ? logNode.getAbilities().toString():"null").append(", "); + for (SimulationNode2 logNode : node.getChildren()) { + sb.append(logNode.getAbilities() != null ? logNode.getAbilities().toString() : "null").append(", "); } sb.append(")"); logger.debug(sb); } - val = minimaxAB(node, depth-1, alpha, beta); - } - else { + val = minimaxAB(node, depth - 1, alpha, beta); + } else { logger.trace("Add Action -- alpha: " + alpha + " beta: " + beta + " depth:" + depth + " step:" + game.getTurn().getStepType() + " for player:" + game.getPlayer(game.getPlayerList().get()).getName()); if (allPassed(game)) { if (!game.getStack().isEmpty()) { resolve(node, depth, game); - } - else { + } else { stepFinished = true; } } if (game.gameOver(null)) { val = GameStateEvaluator2.evaluate(playerId, game); - } - else if (stepFinished) { + } else if (stepFinished) { logger.debug("Step finished"); int testScore = GameStateEvaluator2.evaluate(playerId, game); if (game.getActivePlayerId().equals(playerId)) { @@ -286,8 +277,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 { // if score at end of step is worse than original score don't check further //logger.debug("Add Action -- abandoning check, no immediate benefit"); val = testScore; - } - else { + } else { /*switch (game.getTurn().getStepType()) { case PRECOMBAT_MAIN: val = simulateCombat(game, node, depth-1, alpha, beta, false); @@ -301,32 +291,29 @@ public class ComputerPlayer7 extends ComputerPlayer6 { }*/ val = GameStateEvaluator2.evaluate(playerId, game); } - } - else { + } else { val = GameStateEvaluator2.evaluate(playerId, game); /*if (game.getTurn().getStepType() == PhaseStep.DECLARE_ATTACKERS) val = simulateBlockers(game, node, playerId, depth-1, alpha, beta, true); else val = GameStateEvaluator2.evaluate(playerId, game); - */ + */ } - } - else if (node.getChildren().size() > 0) { + } else if (node.getChildren().size() > 0) { if (logger.isDebugEnabled()) { StringBuilder sb = new StringBuilder("Add Action [").append(depth) .append("] -- trigger ") - .append(node.getAbilities() != null ? node.getAbilities().toString():"null") + .append(node.getAbilities() != null ? node.getAbilities().toString() : "null") .append(" added children: ").append(node.getChildren().size()).append(" ("); - for (SimulationNode2 logNode: node.getChildren()) { - sb.append(logNode.getAbilities() != null ? logNode.getAbilities().toString():"null").append(", "); + for (SimulationNode2 logNode : node.getChildren()) { + sb.append(logNode.getAbilities() != null ? logNode.getAbilities().toString() : "null").append(", "); } sb.append(")"); logger.debug(sb); } val = minimaxAB(node, depth, alpha, beta); - } - else { + } else { val = simulatePriority(node, game, depth, alpha, beta); } } @@ -353,25 +340,20 @@ public class ComputerPlayer7 extends ComputerPlayer6 { if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DECLARING_ATTACKERS, game.getActivePlayerId(), game.getActivePlayerId()))) { val = simulateAttackers(game, node, game.getActivePlayerId(), depth, alpha, beta, counter); } - } - else if (!counter) { + } else if (!counter) { simulateToEnd(game); val = simulatePostCombatMain(game, node, depth, alpha, beta); } } - } - else { - if (!game.getStep().skipStep(game, game.getActivePlayerId())) { - game.fireEvent(new GameEvent(GameEvent.EventType.DECLARE_BLOCKERS_STEP_PRE, null, null, game.getActivePlayerId())); - if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DECLARING_BLOCKERS, game.getActivePlayerId(), game.getActivePlayerId()))) { - //only suitable for two player games - only simulates blocks for 1st defender - val = simulateBlockers(game, node, game.getCombat().getDefenders().iterator().next(), depth, alpha, beta, counter); - } - } - else if (!counter) { - finishCombat(game); - ///val = simulateCounterAttack(game, node, depth, alpha, beta); + } else if (!game.getStep().skipStep(game, game.getActivePlayerId())) { + game.fireEvent(new GameEvent(GameEvent.EventType.DECLARE_BLOCKERS_STEP_PRE, null, null, game.getActivePlayerId())); + if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DECLARING_BLOCKERS, game.getActivePlayerId(), game.getActivePlayerId()))) { + //only suitable for two player games - only simulates blocks for 1st defender + val = simulateBlockers(game, node, game.getCombat().getDefenders().iterator().next(), depth, alpha, beta, counter); } + } else if (!counter) { + finishCombat(game); + ///val = simulateCounterAttack(game, node, depth, alpha, beta); } if (val == null) { val = GameStateEvaluator2.evaluate(playerId, game); @@ -382,7 +364,6 @@ public class ComputerPlayer7 extends ComputerPlayer6 { return val; } - protected int simulateAttackers(Game game, SimulationNode2 node, UUID attackerId, int depth, int alpha, int beta, boolean counter) { if (ALLOW_INTERRUPT && Thread.interrupted()) { Thread.currentThread().interrupt(); @@ -396,7 +377,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 { if (logger.isDebugEnabled()) { logger.debug(attacker.getName() + "'s possible attackers: " + attacker.getAvailableAttackers(defenderId, game)); } - for (Combat engagement: attacker.addAttackers(game)) { + for (Combat engagement : attacker.addAttackers(game)) { if (logger.isDebugEnabled()) { logger.debug("Sim Attackers: " + engagement.getAttackers() + ", blockers: " + engagement.getBlockers()); } @@ -404,9 +385,9 @@ public class ComputerPlayer7 extends ComputerPlayer6 { logger.debug("Sim Attackers -- pruning attackers"); break; } - Game sim = game.copy(); - for (CombatGroup group: engagement.getGroups()) { - for (UUID attackId: group.getAttackers()) { + Game sim = game.copy(); + for (CombatGroup group : engagement.getGroups()) { + for (UUID attackId : group.getAttackers()) { sim.getPlayer(attackerId).declareAttacker(attackId, defenderId, sim, false); } } @@ -424,7 +405,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 { sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARE_ATTACKERS_STEP_POST, sim.getActivePlayerId(), sim.getActivePlayerId())); Combat simCombat = sim.getCombat().copy(); sim.getPhase().setStep(new DeclareBlockersStep()); - val = simulateCombat(sim, newNode, depth-1, alpha, beta, counter); + val = simulateCombat(sim, newNode, depth - 1, alpha, beta, counter); if (!attackerId.equals(playerId)) { if (val < beta) { beta = val; @@ -434,15 +415,12 @@ public class ComputerPlayer7 extends ComputerPlayer6 { bestNode.setCombat(newNode.getChildren().get(0).getCombat()); } } - } - else { - if (val > alpha) { - alpha = val; - bestNode = newNode; - bestNode.setScore(val); - if (newNode.getChildren().size() > 0) { - bestNode.setCombat(newNode.getChildren().get(0).getCombat()); - } + } else if (val > alpha) { + alpha = val; + bestNode = newNode; + bestNode.setScore(val); + if (newNode.getChildren().size() > 0) { + bestNode.setCombat(newNode.getChildren().get(0).getCombat()); } } } @@ -475,16 +453,16 @@ public class ComputerPlayer7 extends ComputerPlayer6 { logger.debug(defender.getName() + "'s possible blockers: " + defender.getAvailableBlockers(game)); } List combats = defender.addBlockers(game); - for (Combat engagement: combats) { + for (Combat engagement : combats) { if (alpha >= beta) { logger.debug("Sim blockers -- pruning blockers"); break; } Game sim = game.copy(); - for (CombatGroup group: engagement.getGroups()) { + for (CombatGroup group : engagement.getGroups()) { if (group.getAttackers().size() > 0) { UUID attackerId = group.getAttackers().get(0); - for (UUID blockerId: group.getBlockers()) { + for (UUID blockerId : group.getBlockers()) { sim.getPlayer(defenderId).declareBlocker(defenderId, blockerId, attackerId, sim); } } @@ -505,11 +483,9 @@ public class ComputerPlayer7 extends ComputerPlayer6 { finishCombat(sim); if (sim.gameOver(null)) { val = GameStateEvaluator2.evaluate(playerId, sim); - } - else if (!counter) { - val = simulatePostCombatMain(sim, newNode, depth-1, alpha, beta); - } - else { + } else if (!counter) { + val = simulatePostCombatMain(sim, newNode, depth - 1, alpha, beta); + } else { val = GameStateEvaluator2.evaluate(playerId, sim); } if (!defenderId.equals(playerId)) { @@ -519,14 +495,11 @@ public class ComputerPlayer7 extends ComputerPlayer6 { bestNode.setScore(val); bestNode.setCombat(simCombat); } - } - else { - if (val > alpha) { - alpha = val; - bestNode = newNode; - bestNode.setScore(val); - bestNode.setCombat(simCombat); - } + } else if (val > alpha) { + alpha = val; + bestNode = newNode; + bestNode.setScore(val); + bestNode.setCombat(simCombat); } } } @@ -570,7 +543,6 @@ public class ComputerPlayer7 extends ComputerPlayer6 { val = GameStateEvaluator2.evaluate(playerId, game); return val; }*/ - protected void simulateStep(Game game, Step step) { if (ALLOW_INTERRUPT && Thread.interrupted()) { Thread.currentThread().interrupt(); diff --git a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java index 03ca681e47f..c25a5c38453 100644 --- a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java @@ -65,9 +65,14 @@ import mage.constants.ManaType; import mage.constants.Outcome; import mage.constants.PhaseStep; import mage.constants.PlayerAction; +import static mage.constants.PlayerAction.HOLD_PRIORITY; +import static mage.constants.PlayerAction.REQUEST_AUTO_ANSWER_ID_NO; import static mage.constants.PlayerAction.REQUEST_AUTO_ANSWER_RESET_ALL; +import static mage.constants.PlayerAction.TRIGGER_AUTO_ORDER_NAME_LAST; import static mage.constants.PlayerAction.TRIGGER_AUTO_ORDER_RESET_ALL; import mage.constants.RangeOfInfluence; +import static mage.constants.SpellAbilityType.SPLIT; +import static mage.constants.SpellAbilityType.SPLIT_FUSED; import mage.constants.Zone; import mage.filter.common.FilterAttackingCreature; import mage.filter.common.FilterBlockingCreature; diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/BloodthirstTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/BloodthirstTest.java index dcafcdaf8be..7b64a638947 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/BloodthirstTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/BloodthirstTest.java @@ -67,7 +67,7 @@ public class BloodthirstTest extends CardTestPlayerBase { public void testBloodlord() { addCard(Zone.BATTLEFIELD, playerA, "Swamp", 8); addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); - // Bloodthirst 3 + // Bloodthirst 3 (If an opponent was dealt damage this turn, this creature enters the battlefield with 3 +1/+1 counters) // Whenever you cast a Vampire creature spell, it gains bloodthirst 3 addCard(Zone.HAND, playerA, "Bloodlord of Vaasgoth"); // {3}{B}{B} addCard(Zone.HAND, playerA, "Barony Vampire"); // 3/2 {2}{B} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/ErsatzGnomesTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/ErsatzGnomesTest.java index 5b1f330accc..3f0982b20c9 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/ErsatzGnomesTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/ErsatzGnomesTest.java @@ -90,10 +90,73 @@ public class ErsatzGnomesTest extends CardTestPlayerBase { execute(); assertGraveyardCount(playerB, "Unsummon", 1); + assertHandCount(playerA, "Silvercoat Lion", 0); assertPermanentCount(playerA, "Silvercoat Lion", 1); assertTapped("Ersatz Gnomes", true); Permanent lion = getPermanent("Silvercoat Lion", playerA); Assert.assertTrue("Silvercoat lion has to be white", lion.getColor(currentGame).isWhite()); } + @Test + public void testChangeColorOfBestowSpell() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion"); + // Bestow {3}{W} + // Lifelink + // Echanted creature gets +1/+1 and has lifelink. + addCard(Zone.HAND, playerA, "Hopeful Eidolon");// Creature {W} + + // {T}: Target spell becomes colorless. + // {T}: Target permanent becomes colorless until end of turn. + addCard(Zone.BATTLEFIELD, playerA, "Ersatz Gnomes"); + + addCard(Zone.BATTLEFIELD, playerB, "Island", 1); + addCard(Zone.HAND, playerB, "Unsummon"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Hopeful Eidolon using bestow", "Silvercoat Lion"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Target spell", "Hopeful Eidolon"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertHandCount(playerA, "Hopeful Eidolon", 0); + assertPermanentCount(playerA, "Hopeful Eidolon", 1); + assertPowerToughness(playerA, "Silvercoat Lion", 3, 3); + assertTapped("Ersatz Gnomes", true); + Permanent eidolon = getPermanent("Hopeful Eidolon", playerA); + Assert.assertTrue("Hopeful Eidolon Enchantment has to be colorless", eidolon.getColor(currentGame).isColorless()); + } + + @Test + public void testChangeColorOfBestowSpellUnsummon() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + // Bestow {3}{W} + // Lifelink + // Echanted creature gets +1/+1 and has lifelink. + addCard(Zone.HAND, playerA, "Hopeful Eidolon");// Creature {W} + + // {T}: Target spell becomes colorless. + // {T}: Target permanent becomes colorless until end of turn. + addCard(Zone.BATTLEFIELD, playerA, "Ersatz Gnomes"); + + addCard(Zone.BATTLEFIELD, playerB, "Island", 1); + addCard(Zone.HAND, playerB, "Unsummon"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Hopeful Eidolon"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Target spell", "Hopeful Eidolon"); + + castSpell(1, PhaseStep.END_COMBAT, playerB, "Unsummon", "Hopeful Eidolon"); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Hopeful Eidolon"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertGraveyardCount(playerB, "Unsummon", 1); + assertHandCount(playerA, "Hopeful Eidolon", 0); + assertPermanentCount(playerA, "Hopeful Eidolon", 1); + assertTapped("Ersatz Gnomes", true); + Permanent lion = getPermanent("Hopeful Eidolon", playerA); + Assert.assertTrue("Hopeful Eidolon has to be white", lion.getColor(currentGame).isWhite()); + } } diff --git a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java index 0fe8f7b7418..d2fd8a0d570 100644 --- a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java +++ b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java @@ -1,5 +1,13 @@ package mage.verify; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Paths; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import mage.ObjectColor; import mage.cards.Card; import mage.cards.CardImpl; @@ -12,15 +20,6 @@ import mage.constants.CardType; import org.junit.Assert; import org.junit.Test; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.NoSuchFileException; -import java.nio.file.Paths; -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - public class VerifyCardDataTest { // right now this is very noisy, and not useful enough to make any assertions on @@ -105,8 +104,7 @@ public class VerifyCardDataTest { if (!(token.equals(card.getName()) || containsInTypesOrText(ref, token) || containsInTypesOrText(ref, token.toLowerCase()) - || (ref2 != null && (containsInTypesOrText(ref2, token) || containsInTypesOrText(ref2, token.toLowerCase()))) - )) { + || (ref2 != null && (containsInTypesOrText(ref2, token) || containsInTypesOrText(ref2, token.toLowerCase()))))) { System.out.println("unexpected token " + token + " in " + card); } } @@ -143,12 +141,12 @@ public class VerifyCardDataTest { if (expected == null) { expected = Collections.emptyList(); } - if (expected.size() != color.getColorCount() || - (color.isBlack() && !expected.contains("Black")) || - (color.isBlue() && !expected.contains("Blue")) || - (color.isGreen() && !expected.contains("Green")) || - (color.isRed() && !expected.contains("Red")) || - (color.isWhite() && !expected.contains("White"))) { + if (expected.size() != color.getColorCount() + || (color.isBlack() && !expected.contains("Black")) + || (color.isBlue() && !expected.contains("Blue")) + || (color.isGreen() && !expected.contains("Green")) + || (color.isRed() && !expected.contains("Red")) + || (color.isWhite() && !expected.contains("White"))) { fail(card, "colors", color + " != " + expected); } } diff --git a/Mage/src/main/java/mage/game/ZonesHandler.java b/Mage/src/main/java/mage/game/ZonesHandler.java index a57df07facd..f78a74e9ee7 100644 --- a/Mage/src/main/java/mage/game/ZonesHandler.java +++ b/Mage/src/main/java/mage/game/ZonesHandler.java @@ -208,6 +208,8 @@ public class ZonesHandler { // If we can't find the card we can't remove it. return false; } + // If needed take attributes from the spell (e.g. color of spell was changed) + card = takeAttributesFromSpell(card, event, game); boolean success = false; if (info.faceDown) { card.setFaceDown(true, game); @@ -282,4 +284,23 @@ public class ZonesHandler { order.add(cards.getCards(game).iterator().next()); return order; } + + private static Card takeAttributesFromSpell(Card card, ZoneChangeEvent event, Game game) { + if (Zone.STACK.equals(event.getFromZone())) { + Spell spell = game.getStack().getSpell(event.getTargetId()); + if (spell != null) { + boolean doCopy = false; + if (!card.getColor(game).equals(spell.getColor(game))) { + doCopy = true; + } + if (doCopy) { + // the card that is referenced to in the permanent is copied and the spell attributes are set to this copied card + card = card.copy(); + card.getColor(game).setColor(spell.getColor(game)); + } + } + } + return card; + } + } diff --git a/Mage/src/main/java/mage/game/permanent/PermanentCard.java b/Mage/src/main/java/mage/game/permanent/PermanentCard.java index 017a5093866..9ff7eb7578a 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentCard.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentCard.java @@ -132,7 +132,7 @@ public class PermanentCard extends PermanentImpl { transformable = card.isTransformable(); if (transformable) { this.nightCard = card.isNightCard(); - if (! this.nightCard) { + if (!this.nightCard) { this.secondSideCard = card.getSecondCardFace(); this.secondSideCardClazz = this.secondSideCard.getClass(); } diff --git a/Mage/src/main/java/mage/game/permanent/PermanentMeld.java b/Mage/src/main/java/mage/game/permanent/PermanentMeld.java index dd28172322b..6cba02c680e 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentMeld.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentMeld.java @@ -27,15 +27,9 @@ */ package mage.game.permanent; -import java.util.ArrayList; import java.util.UUID; import mage.cards.Card; -import mage.cards.CardsImpl; -import mage.cards.MeldCard; -import mage.constants.Zone; import mage.game.Game; -import mage.game.events.ZoneChangeEvent; -import mage.players.Player; /** * diff --git a/Mage/src/main/java/mage/game/stack/Spell.java b/Mage/src/main/java/mage/game/stack/Spell.java index ed562d6b6cd..cc9b47a99e3 100644 --- a/Mage/src/main/java/mage/game/stack/Spell.java +++ b/Mage/src/main/java/mage/game/stack/Spell.java @@ -277,9 +277,6 @@ public class Spell extends StackObjImpl implements Card { } } else { updateOptionalCosts(0); - if (!getColor(game).equals(card.getColor(game))) { // if spell color was changed, the created permanent needs to be of that color - game.getState().getCreateCardAttribute(card).getColor().setColor(getColor(game)); - } return controller.moveCards(card, Zone.BATTLEFIELD, ability, game, false, faceDown, false, null); } } @@ -902,7 +899,7 @@ public class Spell extends StackObjImpl implements Card { @Override public void checkForCountersToAdd(Permanent permanent, Game game) { - throw new UnsupportedOperationException("Not supported for Spell"); + card.checkForCountersToAdd(permanent, game); } @Override diff --git a/Mage/src/main/java/mage/game/turn/TurnMods.java b/Mage/src/main/java/mage/game/turn/TurnMods.java index 932b6f2c366..ee9baa5b38d 100644 --- a/Mage/src/main/java/mage/game/turn/TurnMods.java +++ b/Mage/src/main/java/mage/game/turn/TurnMods.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,20 +20,18 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.game.turn; -import mage.constants.PhaseStep; -import mage.constants.TurnPhase; - import java.util.ArrayList; import java.util.ListIterator; import java.util.UUID; +import mage.constants.PhaseStep; +import mage.constants.TurnPhase; /** * @@ -41,10 +39,11 @@ import java.util.UUID; */ public class TurnMods extends ArrayList { - public TurnMods() {} + public TurnMods() { + } public TurnMods(final TurnMods mods) { - for (TurnMod mod: mods) { + for (TurnMod mod : mods) { this.add(mod.copy()); } } @@ -95,7 +94,7 @@ public class TurnMods extends ArrayList { it.remove(); } } - // now delete all other - control next turn effect is not cumulative + // now delete all other effects that control current active player - control next turn of player effects are not cumulative it = this.listIterator(this.size()); while (it.hasPrevious()) { TurnMod turnMod = it.previous(); From 13c8f3263f100156d705e5f677e95c9fc347bb5d Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 22 Oct 2016 11:14:47 +0200 Subject: [PATCH 33/35] * Glint-Next Crane - Fixed that it was not optional to reveal an artifact (fixes #2491). --- .../src/mage/cards/g/GlintNestCrane.java | 8 ++++--- .../src/mage/cards/s/SalvageSlasher.java | 12 ++++++----- .../src/mage/cards/t/TezzeretTheSeeker.java | 4 ++-- .../LookLibraryAndPickControllerEffect.java | 21 +++++++++++++++++++ 4 files changed, 35 insertions(+), 10 deletions(-) diff --git a/Mage.Sets/src/mage/cards/g/GlintNestCrane.java b/Mage.Sets/src/mage/cards/g/GlintNestCrane.java index fe6e83eb947..4261ffcaf2c 100644 --- a/Mage.Sets/src/mage/cards/g/GlintNestCrane.java +++ b/Mage.Sets/src/mage/cards/g/GlintNestCrane.java @@ -36,6 +36,7 @@ import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.CardTypePredicate; @@ -48,11 +49,11 @@ public class GlintNestCrane extends CardImpl { private static final FilterCard filter = new FilterCard("an artifact card"); static { - filter.add(new CardTypePredicate(CardType.ARTIFACT)); + filter.add(new CardTypePredicate(CardType.ARTIFACT)); } public GlintNestCrane(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); this.subtype.add("Bird"); this.power = new MageInt(1); this.toughness = new MageInt(3); @@ -62,7 +63,8 @@ public class GlintNestCrane extends CardImpl { // When Glint-Nest Crane enters the battlefield, look at the top four cards of your library. You may reveal an artifact card from among them and // put it into your hand. Put the rest on the bottom of your library in any order. - this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect(new StaticValue(4), false, new StaticValue(1), filter, false))); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new LookLibraryAndPickControllerEffect(new StaticValue(4), false, new StaticValue(1), filter, Zone.LIBRARY, false, true, false, Zone.HAND, true))); } public GlintNestCrane(final GlintNestCrane card) { diff --git a/Mage.Sets/src/mage/cards/s/SalvageSlasher.java b/Mage.Sets/src/mage/cards/s/SalvageSlasher.java index 2f449ad8630..6d691405d84 100644 --- a/Mage.Sets/src/mage/cards/s/SalvageSlasher.java +++ b/Mage.Sets/src/mage/cards/s/SalvageSlasher.java @@ -28,9 +28,6 @@ package mage.cards.s; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Zone; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; @@ -38,6 +35,9 @@ import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; import mage.filter.common.FilterArtifactCard; /** @@ -47,13 +47,15 @@ import mage.filter.common.FilterArtifactCard; public class SalvageSlasher extends CardImpl { public SalvageSlasher(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}{B}"); this.subtype.add("Human"); this.subtype.add("Rogue"); this.power = new MageInt(1); this.toughness = new MageInt(1); - BoostSourceEffect effect = new BoostSourceEffect(new CardsInControllerGraveyardCount(new FilterArtifactCard()), + + // Salvage Slasher gets +1/+0 for each artifact card in your graveyard. + BoostSourceEffect effect = new BoostSourceEffect(new CardsInControllerGraveyardCount(new FilterArtifactCard("artifact card")), new StaticValue(0), Duration.WhileOnBattlefield); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); diff --git a/Mage.Sets/src/mage/cards/t/TezzeretTheSeeker.java b/Mage.Sets/src/mage/cards/t/TezzeretTheSeeker.java index 8df2200fdbe..6b46fb04743 100644 --- a/Mage.Sets/src/mage/cards/t/TezzeretTheSeeker.java +++ b/Mage.Sets/src/mage/cards/t/TezzeretTheSeeker.java @@ -63,7 +63,7 @@ import mage.target.common.TargetCardInLibrary; public class TezzeretTheSeeker extends CardImpl { public TezzeretTheSeeker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.PLANESWALKER},"{3}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{3}{U}{U}"); this.subtype.add("Tezzeret"); this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(4)); @@ -118,7 +118,7 @@ class TezzeretTheSeekerEffect2 extends OneShotEffect { } } - FilterArtifactCard filter = new FilterArtifactCard(new StringBuilder("artifact card with converted mana cost ").append(cmc).append(" or less").toString()); + FilterArtifactCard filter = new FilterArtifactCard("artifact card with converted mana cost " + cmc + " or less"); filter.add(new ConvertedManaCostPredicate(ComparisonType.LessThan, cmc + 1)); TargetCardInLibrary target = new TargetCardInLibrary(filter); diff --git a/Mage/src/main/java/mage/abilities/effects/common/LookLibraryAndPickControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/LookLibraryAndPickControllerEffect.java index 33ec7787cc9..aea63e004de 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/LookLibraryAndPickControllerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/LookLibraryAndPickControllerEffect.java @@ -75,12 +75,33 @@ public class LookLibraryAndPickControllerEffect extends LookLibraryControllerEff this(new StaticValue(numberOfCards), false, new StaticValue(numberToPick), pickFilter, Zone.LIBRARY, false, true, upTo); } + /** + * + * @param numberOfCards + * @param numberToPick + * @param pickFilter + * @param reveal + * @param upTo + * @param targetZonePickedCards + * @param optional + */ public LookLibraryAndPickControllerEffect(int numberOfCards, int numberToPick, FilterCard pickFilter, boolean reveal, boolean upTo, Zone targetZonePickedCards, boolean optional) { this(new StaticValue(numberOfCards), false, new StaticValue(numberToPick), pickFilter, Zone.LIBRARY, false, reveal, upTo, targetZonePickedCards, optional); } + /** + * + * @param numberOfCards + * @param mayShuffleAfter + * @param numberToPick + * @param pickFilter + * @param targetZoneLookedCards + * @param putOnTop + * @param reveal + * @param upTo + */ public LookLibraryAndPickControllerEffect(DynamicValue numberOfCards, boolean mayShuffleAfter, DynamicValue numberToPick, FilterCard pickFilter, Zone targetZoneLookedCards, boolean putOnTop, boolean reveal, boolean upTo) { this(numberOfCards, mayShuffleAfter, numberToPick, pickFilter, targetZoneLookedCards, putOnTop, reveal, upTo, Zone.HAND, false); From bf43ea9936df0823eb729566ac54b88834a02989 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 22 Oct 2016 12:45:50 +0200 Subject: [PATCH 34/35] Added test and fixed some possible null pointer exception. --- Mage.Common/src/mage/utils/MageVersion.java | 2 +- .../src/mage/player/human/HumanPlayer.java | 9 ++- .../mage/cards/e/EmrakulThePromisedEnd.java | 4 +- Mage.Sets/src/mage/cards/g/Grindclock.java | 30 ++++---- .../org/mage/test/turnmod/ExtraTurnsTest.java | 70 +++++++++++++++++++ .../main/java/mage/abilities/AbilityImpl.java | 15 ++-- .../AddConditionalManaOfAnyColorEffect.java | 13 ++-- .../main/java/mage/cards/ExpansionSet.java | 5 +- .../mage/cards/repository/CardRepository.java | 2 +- Mage/src/main/java/mage/game/GameImpl.java | 11 +++ 10 files changed, 130 insertions(+), 31 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/turnmod/ExtraTurnsTest.java diff --git a/Mage.Common/src/mage/utils/MageVersion.java b/Mage.Common/src/mage/utils/MageVersion.java index 020bd898a61..70173cb480b 100644 --- a/Mage.Common/src/mage/utils/MageVersion.java +++ b/Mage.Common/src/mage/utils/MageVersion.java @@ -41,7 +41,7 @@ public class MageVersion implements Serializable, Comparable { public final static int MAGE_VERSION_MAJOR = 1; public final static int MAGE_VERSION_MINOR = 4; public final static int MAGE_VERSION_PATCH = 16; - public final static String MAGE_VERSION_MINOR_PATCH = "v3"; + public final static String MAGE_VERSION_MINOR_PATCH = "v4"; public final static String MAGE_VERSION_INFO = ""; private final int major; diff --git a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java index c25a5c38453..8d05903ba05 100644 --- a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java @@ -735,12 +735,14 @@ public class HumanPlayer extends PlayerImpl { } private boolean checkPassStep(Game game) { - if (game.getStep() != null) { + try { if (playerId.equals(game.getActivePlayerId())) { return !this.getUserData().getUserSkipPrioritySteps().getYourTurn().isPhaseStepSet(game.getStep().getType()); } else { return !this.getUserData().getUserSkipPrioritySteps().getOpponentTurn().isPhaseStepSet(game.getStep().getType()); } + } catch (NullPointerException ex) { + logger.error("null pointer exception UserData = " + userData == null ? "null" : "not null"); } return true; } @@ -1464,6 +1466,11 @@ public class HumanPlayer extends PlayerImpl { protected void updateGameStatePriority(String methodName, Game game) { if (game.getState().getPriorityPlayerId() != null) { // don't do it if priority was set to null before (e.g. discard in cleanaup) + if (getId() == null) { + logger.fatal("Player with no ID: " + name); + this.quit(game); + return; + } logger.debug("Setting game priority to " + getId() + " [" + methodName + "]"); game.getState().setPriorityPlayerId(getId()); } diff --git a/Mage.Sets/src/mage/cards/e/EmrakulThePromisedEnd.java b/Mage.Sets/src/mage/cards/e/EmrakulThePromisedEnd.java index cda0e45b44d..175adfd6be0 100644 --- a/Mage.Sets/src/mage/cards/e/EmrakulThePromisedEnd.java +++ b/Mage.Sets/src/mage/cards/e/EmrakulThePromisedEnd.java @@ -34,7 +34,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CastSourceTriggeredAbility; import mage.abilities.effects.common.cost.CostModificationEffectImpl; import mage.abilities.effects.common.turn.ControlTargetPlayerNextTurnEffect; @@ -64,12 +63,13 @@ import mage.util.CardUtil; public class EmrakulThePromisedEnd extends CardImpl { private static final FilterCard filter = new FilterCard("instants"); + static { filter.add(new CardTypePredicate(CardType.INSTANT)); } public EmrakulThePromisedEnd(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{13}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{13}"); this.supertype.add("Legendary"); this.subtype.add("Eldrazi"); this.power = new MageInt(13); diff --git a/Mage.Sets/src/mage/cards/g/Grindclock.java b/Mage.Sets/src/mage/cards/g/Grindclock.java index fae092d35fa..8a3acf2e2c8 100644 --- a/Mage.Sets/src/mage/cards/g/Grindclock.java +++ b/Mage.Sets/src/mage/cards/g/Grindclock.java @@ -25,13 +25,9 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.cards.g; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; @@ -39,9 +35,12 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPlayer; @@ -51,15 +50,16 @@ import mage.target.TargetPlayer; */ public class Grindclock extends CardImpl { - public Grindclock (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); + public Grindclock(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.CHARGE.createInstance()), new TapSourceCost())); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GrindclockEffect(), new TapSourceCost()); ability.addTarget(new TargetPlayer()); this.addAbility(ability); } - public Grindclock (final Grindclock card) { + public Grindclock(final Grindclock card) { super(card); } @@ -71,6 +71,7 @@ public class Grindclock extends CardImpl { } class GrindclockEffect extends OneShotEffect { + public GrindclockEffect() { super(Outcome.Detriment); staticText = "Target player puts the top X cards of his or her library into his or her graveyard, where X is the number of charge counters on {this}"; @@ -82,11 +83,14 @@ class GrindclockEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - int amount = game.getPermanent(source.getSourceId()).getCounters(game).getCount(CounterType.CHARGE); - Player targetPlayer = game.getPlayer(source.getFirstTarget()); - if (targetPlayer != null) { - targetPlayer.moveCards(targetPlayer.getLibrary().getTopCards(game, amount), Zone.GRAVEYARD, source, game); - return true; + Permanent sourceObject = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (sourceObject != null) { + int amount = sourceObject.getCounters(game).getCount(CounterType.CHARGE); + Player targetPlayer = game.getPlayer(source.getFirstTarget()); + if (targetPlayer != null) { + targetPlayer.moveCards(targetPlayer.getLibrary().getTopCards(game, amount), Zone.GRAVEYARD, source, game); + return true; + } } return false; } @@ -96,4 +100,4 @@ class GrindclockEffect extends OneShotEffect { return new GrindclockEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Tests/src/test/java/org/mage/test/turnmod/ExtraTurnsTest.java b/Mage.Tests/src/test/java/org/mage/test/turnmod/ExtraTurnsTest.java new file mode 100644 index 00000000000..347e271c08e --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/turnmod/ExtraTurnsTest.java @@ -0,0 +1,70 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.turnmod; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Assert; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class ExtraTurnsTest extends CardTestPlayerBase { + + /** + * Emrakul, the Promised End not giving an extra turn when cast in the + * opponent's turn + */ + @Test + public void testEmrakulCastOnOpponentsTurn() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 12); + addCard(Zone.GRAVEYARD, playerA, "Island", 1); + // Emrakul, the Promised End costs {1} less to cast for each card type among cards in your graveyard. + // When you cast Emrakul, you gain control of target opponent during that player's next turn. After that turn, that player takes an extra turn. + // Flying + // Trample + // Protection from instants + addCard(Zone.HAND, playerA, "Emrakul, the Promised End", 1); // {13} + // Flash (You may cast this spell any time you could cast an instant.) + // Creature cards you own that aren't on the battlefield have flash. + // Each opponent can cast spells only any time he or she could cast a sorcery. + addCard(Zone.BATTLEFIELD, playerA, "Teferi, Mage of Zhalfir", 1); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Emrakul, the Promised End"); + + setStopAt(3, PhaseStep.UPKEEP); + execute(); + + assertPermanentCount(playerA, "Emrakul, the Promised End", 1); + + Assert.assertTrue("For extra turn, playerB has to be the active player ", currentGame.getActivePlayerId().equals(playerB.getId())); + } +} diff --git a/Mage/src/main/java/mage/abilities/AbilityImpl.java b/Mage/src/main/java/mage/abilities/AbilityImpl.java index cf82795eff0..3e4ecc12036 100644 --- a/Mage/src/main/java/mage/abilities/AbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/AbilityImpl.java @@ -328,13 +328,16 @@ public abstract class AbilityImpl implements Ability { if (sourceObject != null && !this.getAbilityType().equals(AbilityType.TRIGGERED)) { // triggered abilities check this already in playerImpl.triggerAbility sourceObject.adjustTargets(this, game); } - // Flashback abilities haven't made the choices the underlying spell might need for targetting. - if (!(this instanceof FlashbackAbility) && getTargets().size() > 0 && getTargets().chooseTargets( - getEffects().get(0).getOutcome(), this.controllerId, this, noMana, game) == false) { - if ((variableManaCost != null || announceString != null) && !game.isSimulation()) { - game.informPlayer(controller, (sourceObject != null ? sourceObject.getIdName() : "") + ": no valid targets with this value of X"); + // Flashback abilities haven't made the choices the underlying spell might need for targeting. + if (!(this instanceof FlashbackAbility) + && getTargets().size() > 0) { + Outcome outcome = getEffects().isEmpty() ? Outcome.Detriment : getEffects().get(0).getOutcome(); + if (getTargets().chooseTargets(outcome, this.controllerId, this, noMana, game) == false) { + if ((variableManaCost != null || announceString != null) && !game.isSimulation()) { + game.informPlayer(controller, (sourceObject != null ? sourceObject.getIdName() : "") + ": no valid targets with this value of X"); + } + return false; // when activation of ability is canceled during target selection } - return false; // when activation of ability is canceled during target selection } } // end modes diff --git a/Mage/src/main/java/mage/abilities/effects/common/AddConditionalManaOfAnyColorEffect.java b/Mage/src/main/java/mage/abilities/effects/common/AddConditionalManaOfAnyColorEffect.java index e0275a85c62..bd2cc3227c6 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/AddConditionalManaOfAnyColorEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/AddConditionalManaOfAnyColorEffect.java @@ -85,13 +85,14 @@ public class AddConditionalManaOfAnyColorEffect extends ManaEffect { int value = amount.calculate(game, source, this); boolean result = false; - ChoiceColor choice = new ChoiceColor(false); - for (int i = 0; i < value; i++) { - if (!choice.isChosen()) { - if (!controller.choose(outcome, choice, game)) { - return false; - } + ChoiceColor choice = new ChoiceColor(true); + while (!choice.isChosen()) { + controller.choose(outcome, choice, game); + if (!controller.isInGame()) { + return false; } + } + for (int i = 0; i < value; i++) { Mana mana = null; if (choice.getColor().isBlack()) { mana = manaBuilder.setMana(Mana.BlackMana(1), source, game).build(); diff --git a/Mage/src/main/java/mage/cards/ExpansionSet.java b/Mage/src/main/java/mage/cards/ExpansionSet.java index 4ea414f18bd..8a94962d239 100644 --- a/Mage/src/main/java/mage/cards/ExpansionSet.java +++ b/Mage/src/main/java/mage/cards/ExpansionSet.java @@ -193,8 +193,11 @@ public abstract class ExpansionSet implements Serializable { if (15 > theBooster.size()) { List commons = getCardsByRarity(Rarity.COMMON); - while (15 > theBooster.size()) { + while (15 > theBooster.size() && !commons.isEmpty()) { addToBooster(theBooster, commons); + if (commons.isEmpty()) { + commons = getCardsByRarity(Rarity.COMMON); + } } } diff --git a/Mage/src/main/java/mage/cards/repository/CardRepository.java b/Mage/src/main/java/mage/cards/repository/CardRepository.java index f1108943dd4..35f30921e8c 100644 --- a/Mage/src/main/java/mage/cards/repository/CardRepository.java +++ b/Mage/src/main/java/mage/cards/repository/CardRepository.java @@ -64,7 +64,7 @@ public enum CardRepository { // raise this if db structure was changed private static final long CARD_DB_VERSION = 47; // raise this if new cards were added to the server - private static final long CARD_CONTENT_VERSION = 63; + private static final long CARD_CONTENT_VERSION = 64; private Dao cardDao; private Set classNames; diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index 9fd14a95530..eecb0914418 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -1499,6 +1499,17 @@ public abstract class GameImpl implements Game, Serializable { @Override public void addTriggeredAbility(TriggeredAbility ability) { + if (ability.getControllerId() == null) { + String sourceName = "no sourceId"; + if (ability.getSourceId() != null) { + MageObject mageObject = getObject(ability.getSourceId()); + if (mageObject != null) { + sourceName = mageObject.getName(); + } + } + logger.fatal("Added triggered ability without controller: " + sourceName + " rule: " + ability.getRule()); + return; + } if (ability instanceof TriggeredManaAbility || ability instanceof DelayedTriggeredManaAbility) { // 20110715 - 605.4 Ability manaAbiltiy = ability.copy(); From 07a7afa285ccaf67fba6161d3683bd8f8c7e6deb Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 22 Oct 2016 13:06:41 +0200 Subject: [PATCH 35/35] Added test and fixed some possible null pointer exception. --- Mage.Client/serverlist.txt | 2 +- .../common/AddConditionalManaOfAnyColorEffect.java | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Mage.Client/serverlist.txt b/Mage.Client/serverlist.txt index a049832b42d..e4c7e0a490c 100644 --- a/Mage.Client/serverlist.txt +++ b/Mage.Client/serverlist.txt @@ -1,6 +1,6 @@ XMage.de 1 (Europe/Germany) fast :xmage.de:17171 woogerworks (North America/USA) :xmage.woogerworks.com:17171 -woogerworks replacement (North America/USA) :158.69.192.238:17171 +woogerworks replacment (North America/USA) :158.69.192.238:17171 XMage.tahiti :xmage.tahiti.one:443 Seedds Server (Asia) :115.29.203.80:17171 localhost -> connect to your local server (must be started):localhost:17171 diff --git a/Mage/src/main/java/mage/abilities/effects/common/AddConditionalManaOfAnyColorEffect.java b/Mage/src/main/java/mage/abilities/effects/common/AddConditionalManaOfAnyColorEffect.java index bd2cc3227c6..8259edb065d 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/AddConditionalManaOfAnyColorEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/AddConditionalManaOfAnyColorEffect.java @@ -86,13 +86,14 @@ public class AddConditionalManaOfAnyColorEffect extends ManaEffect { int value = amount.calculate(game, source, this); boolean result = false; ChoiceColor choice = new ChoiceColor(true); - while (!choice.isChosen()) { - controller.choose(outcome, choice, game); - if (!controller.isInGame()) { - return false; - } - } + for (int i = 0; i < value; i++) { + while (!choice.isChosen()) { + controller.choose(outcome, choice, game); + if (!controller.isInGame()) { + return false; + } + } Mana mana = null; if (choice.getColor().isBlack()) { mana = manaBuilder.setMana(Mana.BlackMana(1), source, game).build();