diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/TokensMtgImageSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/TokensMtgImageSource.java index 7f932f35360..95f4294a055 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/TokensMtgImageSource.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/TokensMtgImageSource.java @@ -36,6 +36,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.logging.Level; import org.apache.log4j.Logger; import org.mage.plugins.card.images.CardDownloadData; @@ -48,7 +49,8 @@ public enum TokensMtgImageSource implements CardImageSource { instance; private static final Logger logger = Logger.getLogger(TokensMtgImageSource.class); - private List tokensData; + // [[EXP/Name, TokenData> + private HashMap> tokensData; private final Object tokensDataSync = new Object(); @@ -98,7 +100,12 @@ public enum TokensMtgImageSource implements CardImageSource { "Sorin", "Tamiyo", "Teferi", - "Venser",}; + "Venser", + // Custom Emblems + "Yoda", + "Obi-Wan Kenobi", + "Aurra Sing" + }; private static final Map SET_NAMES_REPLACEMENT = new HashMap() { { @@ -132,38 +139,31 @@ public enum TokensMtgImageSource implements CardImageSource { // e.g. http://tokens.mtg.onl/tokens/ORI_010-Thopter.jpg -- token number 010 // We don't know these numbers, but we can take them from a file // with tokens information that can be downloaded from the site. - List newTokensData = getTokensData(); - - if (newTokensData.isEmpty()) { + if (tokensData.isEmpty()) { logger.info("Source " + getSourceName() + " provides no token data."); return null; } - List matchedTokens = new ArrayList<>(); - for (TokenData token : newTokensData) { - if (name.equalsIgnoreCase(token.getName()) && set.equalsIgnoreCase(token.getExpansionSetCode())) { - matchedTokens.add(token); - } - } - - if (matchedTokens.isEmpty()) { + String key = set + "/" + name; + List list = tokensData.get(key); + if (list == null) { logger.info("Could not find data for token " + name + ", set " + set + "."); return null; } TokenData tokenData; if (type == 0) { - if (matchedTokens.size() > 1) { + if (list.size() > 1) { logger.info("Multiple images were found for token " + name + ", set " + set + '.'); } logger.info("Token found: " + name + ", set " + set + '.'); - tokenData = matchedTokens.get(0); + tokenData = list.get(0); } else { - if (type > matchedTokens.size()) { + if (type > list.size()) { logger.warn("Not enough images for token with type " + type + ", name " + name + ", set " + set + '.'); return null; } - tokenData = matchedTokens.get(card.getType() - 1); + tokenData = list.get(card.getType() - 1); } String url = "http://tokens.mtg.onl/tokens/" + tokenData.getExpansionSetCode().trim() + '_' @@ -172,15 +172,24 @@ public enum TokensMtgImageSource implements CardImageSource { return url; } - private List getTokensData() throws IOException { + private HashMap> getTokensData() throws IOException { synchronized (tokensDataSync) { if (tokensData == null) { - tokensData = new ArrayList<>(); + tokensData = new HashMap<>(); // get tokens data from resource file try (InputStream inputStream = this.getClass().getResourceAsStream("/tokens-mtg-onl-list.csv")) { List fileTokensData = parseTokensData(inputStream); - tokensData.addAll(fileTokensData); + for (TokenData tokenData : fileTokensData) { + String key = tokenData.getExpansionSetCode() + "/" + tokenData.getName(); + ArrayList list = tokensData.get(key); + if (list == null) { + list = new ArrayList<>(); + tokensData.put(key, list); + logger.info("Added key: " + key); + } + list.add(tokenData); + } } catch (Exception exception) { logger.warn("Failed to get tokens description from resource file tokens-mtg-onl-list.csv", exception); } @@ -190,23 +199,26 @@ public enum TokensMtgImageSource implements CardImageSource { URL url = new URL("http://tokens.mtg.onl/data/SetsWithTokens.csv"); try (InputStream inputStream = url.openStream()) { List siteTokensData = parseTokensData(inputStream); - List newTokensData = new ArrayList<>(); for (TokenData siteData : siteTokensData) { - boolean isNew = true; - for (TokenData fileData : tokensData) { - if (siteData.getName().equalsIgnoreCase(fileData.getName()) - && siteData.getNumber().equalsIgnoreCase(fileData.getNumber()) - && siteData.getExpansionSetCode().equalsIgnoreCase(fileData.getExpansionSetCode())) { - isNew = false; - break; + String key = siteData.getExpansionSetCode() + "/" + siteData.getName(); + ArrayList list = tokensData.get(key); + if (list == null) { + list = new ArrayList<>(); + tokensData.put(key, list); + list.add(siteData); + } else { + boolean newToken = true; + for (TokenData tokenData : list) { + if (siteData.getNumber().equals(tokenData.number)) { + newToken = false; + break; + } + } + if (newToken) { + list.add(siteData); } } - if (isNew) { - newTokensData.add(siteData); - } } - - tokensData.addAll(newTokensData); } catch (Exception exception) { logger.warn("Failed to get tokens description from tokens.mtg.onl", exception); } @@ -290,14 +302,12 @@ public enum TokensMtgImageSource implements CardImageSource { @Override public int getTokenImages() { - int number = 0; try { - List newTokensData = getTokensData(); - number = newTokensData.size(); + getTokensData(); } catch (IOException ex) { logger.error(getSourceName() + ": Loading available data failed. " + ex.getMessage()); } - return number; + return tokensData.size(); } @Override @@ -308,4 +318,21 @@ public enum TokensMtgImageSource implements CardImageSource { @Override public void doPause(String httpImageUrl) { } + + @Override + public boolean isImageProvided(String setCode, String cardName) { + try { + getTokensData(); + } catch (IOException ex) { + java.util.logging.Logger.getLogger(TokensMtgImageSource.class.getName()).log(Level.SEVERE, null, ex); + } + String key = setCode + "/" + cardName; + return (tokensData.containsKey(key)); + } + + @Override + public boolean isSetSupportedComplete(String setCode) { + return false; + } + } diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java b/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java index ee30aa0f710..2e81ebd36c1 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java @@ -46,9 +46,9 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab private static final Logger logger = Logger.getLogger(DownloadPictures.class); - public static final String ALL_CARDS = "- All cards from that source"; - public static final String ALL_STANDARD_CARDS = "- All cards from standard from that source"; - public static final String ALL_TOKENS = "- All token images from that source"; + public static final String ALL_IMAGES = "- All images from that source"; + public static final String ALL_STANDARD_IMAGES = "- All images from standard from that source"; + public static final String ALL_TOKENS = "- Only all token images from that source"; private final JProgressBar bar; private final JOptionPane dlg; @@ -204,7 +204,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab bar.setStringPainted(true); Dimension d = bar.getPreferredSize(); - d.width = 300; + d.width = 400; bar.setPreferredSize(d); // JOptionPane @@ -232,8 +232,8 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab ArrayList supportedSets = cardImageSource.getSupportedSets(); List setNames = new ArrayList<>(); if (supportedSets != null) { - setNames.add(ALL_CARDS); - setNames.add(ALL_STANDARD_CARDS); + setNames.add(ALL_IMAGES); + setNames.add(ALL_STANDARD_IMAGES); } if (cardImageSource.isTokenSource()) { setNames.add(ALL_TOKENS); @@ -258,16 +258,15 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab private void updateCardsToDownload(String itemText) { selectedSetCodes.clear(); - boolean tokens = false; switch (itemText) { - case ALL_CARDS: + case ALL_IMAGES: if (cardImageSource.getSupportedSets() == null) { selectedSetCodes = cardImageSource.getSupportedSets(); } else { selectedSetCodes.addAll(cardImageSource.getSupportedSets()); } break; - case ALL_STANDARD_CARDS: + case ALL_STANDARD_IMAGES: List standardSets = ConstructedFormats.getSetsByFormat(ConstructedFormats.STANDARD); for (String setCode : cardImageSource.getSupportedSets()) { if (standardSets.contains(setCode)) { @@ -277,9 +276,6 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab } } break; - case ALL_TOKENS: - tokens = true; - break; default: int nonSetEntries = 0; if (cardImageSource.getSupportedSets() != null) { @@ -291,19 +287,24 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab selectedSetCodes.add(cardImageSource.getSupportedSets().get(jComboBoxSet.getSelectedIndex() - nonSetEntries)); } cardsToDownload.clear(); + int numberTokenImagesAvailable = 0; + int numberCardImagesAvailable = 0; for (CardDownloadData data : allCardsMissingImage) { - if ((data.isToken() && tokens) - || (!data.isToken() && selectedSetCodes != null && selectedSetCodes.contains(data.getSet()))) { - if (cardImageSource.isSetSupportedComplete(data.getSet()) || cardImageSource.isImageProvided(data.getSet(), data.getName())) { + if (data.isToken() && cardImageSource.isTokenSource()) { + if (cardImageSource.isImageProvided(data.getSet(), data.getName())) { + numberTokenImagesAvailable++; cardsToDownload.add(data); } + } else { + if (selectedSetCodes != null && selectedSetCodes.contains(data.getSet())) { + if (cardImageSource.isSetSupportedComplete(data.getSet()) || cardImageSource.isImageProvided(data.getSet(), data.getName())) { + numberCardImagesAvailable++; + cardsToDownload.add(data); + } + } } } - int numberTokenImagesAvailable = 0; - if (tokens) { - cardImageSource.getTokenImages(); - } - updateProgressText(cardsToDownload.size() + numberTokenImagesAvailable); + updateProgressText(numberCardImagesAvailable, numberTokenImagesAvailable); } private void comboBoxSetItemSelected(ItemEvent event) { @@ -311,7 +312,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab updateCardsToDownload(event.getItem().toString()); } - private void updateProgressText(int cardCount) { + private void updateProgressText(int cardCount, int tokenCount) { missingTokens = 0; for (CardDownloadData card : allCardsMissingImage) { if (card.isToken()) { @@ -320,10 +321,10 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab } missingCards = allCardsMissingImage.size() - missingTokens; jLabelAllMissing.setText("Missing: " + missingCards + " card images / " + missingTokens + " token images"); - - float mb = (cardCount * cardImageSource.getAverageSize()) / 1024; - bar.setString(String.format(cardIndex == cardCount ? "%d of %d image downloads finished! Please close!" - : "%d of %d image downloads finished! Please wait! [%.1f Mb]", 0, cardCount, mb)); + int imageSum = cardCount + tokenCount; + float mb = (imageSum * cardImageSource.getAverageSize()) / 1024; + bar.setString(String.format(cardIndex == imageSum ? "%d of %d (%d cards/%d tokens) image downloads finished! Please close!" + : "%d of %d (%d cards/%d tokens) image downloads finished! Please wait! [%.1f Mb]", 0, imageSum, cardCount, tokenCount, mb)); } private static String createDownloadName(CardInfo card) { diff --git a/Mage.Client/src/main/resources/tokens-mtg-onl-list.csv b/Mage.Client/src/main/resources/tokens-mtg-onl-list.csv index 1d2ea50d5c9..4343e5257e3 100644 --- a/Mage.Client/src/main/resources/tokens-mtg-onl-list.csv +++ b/Mage.Client/src/main/resources/tokens-mtg-onl-list.csv @@ -222,7 +222,7 @@ Eldrazi Spawn, 1a, -, -, -, Creature - Eldrazi Spawn, Aleksi Briclot, Sacrifice Eldrazi Spawn, 1b, -, -, -, Creature - Eldrazi Spawn, Mark Tedin, Sacrifice this creature: Add {1} to your mana pool. Eldrazi Spawn, 1c, -, -, -, Creature - Eldrazi Spawn, Veronique Meignaud, Sacrifice this creature: Add {1} to your mana pool. Elemental, 2, R, *|*, -, Creature - Elemental, Jung Park, - -Hellion, 3, R, 4|4, -, Creature - Hellion, Anthony Francisco, - +Hellion, 1, R, 4|4, -, Creature - Hellion, Anthony Francisco, - Ooze, 4, G, *|*, -, Creature - Ooze, Daniel Ljunggren, - Tuktuk The Returned, 5, -, 5|5, -, Legendary Artifact Creature - Goblin Golem, Franz Vohwinkel, - @@ -344,7 +344,7 @@ Soldier, 3, W, 1|1, -, Creature - Soldier, Greg Staples, - Drake, 4, U, 2|2, -, Creature - Drake, Svetlin Velinov, Flying Zombie, 5, B, 2|2, -, Creature - Zombie, Lucas Graciano, - Goblin, 6, R, 1|1, -, Creature - Goblin, Karl Kopinski, - -Hellion, 7, R, 4|4, -, Creature - Hellion, Anthony Francisco, - +Hellion, 1, R, 4|4, -, Creature - Hellion, Anthony Francisco, - Beast, 8, G, 3|3, -, Creature - Beast, John Donahue, - Saproling, 9, G, 1|1, -, Creature - Saproling, Brad Rigney, - Wurm, 10, G, 6|6, -, Creature - Wurm, Anthony Francisco, - @@ -664,7 +664,7 @@ DDP - Duel Decks: Zendikar vs. Eldrazi (2015-08-28) Eldrazi Spawn, 076, -, -, -, Creature - Eldrazi Spawn, Aleksi Briclot, Sacrifice this creature: Add {1} to your mana pool. Eldrazi Spawn, 077, -, -, -, Creature - Eldrazi Spawn, Veronique Meignaud, Sacrifice this creature: Add {1} to your mana pool. Eldrazi Spawn, 078, -, -, -, Creature - Eldrazi Spawn, Mark Tedin, Sacrifice this creature: Add {1} to your mana pool. -Hellion, 079, R, 4|4, -, Creature - Hellion, Anthony Francisco, - +Hellion, 1, R, 4|4, -, Creature - Hellion, Anthony Francisco, - Plant, 080, G, -, -, Creature - Plant, Daren Bader, - BFZ - Battle for Zendikar (2015-10-09) @@ -745,3 +745,20 @@ Clue, 015, -, -, -, Artifact - Clue, James Paick, {2}‚ Sacrifice this Artifact Clue, 016, -, -, -, Artifact - Clue, Franz Vohwinkel, {2}‚ Sacrifice this Artifact: Draw a card. Jace Emblem, 017, -, -, -, Emblem - Jace, Tyler Jacobson, Whenever an opponent casts his or her first spell each turn� counter that spell. Arlinn Emblem, 018, -, -, -, Emblem - Arlinn, Winona Nelson, Creatures you control have haste and '{T}: This creature deals damage equal to its power to target creature or player.' + + +SWS - Star Wars Custom set + +Rebel, 001, W, 1|1, -, Creature - Rebel, Alex Konstad, - +Trooper, 002, W, 1|1, -, Creature - Trooper, Darren Tan, - +Tusken Raider, 003, W, 1|1, -, Creature - Tusken Raider, William O'Connor, - +Ewok, 004, G, 1|1, -, Creature - Ewok, Chris NG, - +Hunter, 005, R, 4|4, -, Creature - Hunter, Steve Argyle, - +Royal Guard, 006, R, 2|2, -, Creature - Soldier, Aldo Katayanagi, First Strike +AT-AT, 007, -, 5|5, -, Artifact Creature - AT-AT, Prokhoda, When this creature dies� create two 1/1 white Trooper creature tokens. +B-Wing, 008, -, 1|1, -, Artifact Creature - Rebel Starship, Anthony Devine, Spaceflight +Droid, 009, -, 1|1, -, Artifact Creature - Droid, PeetuGee, - +TIE Fighter, 010, -, 1|1, -, Artifact Creature - Starship, Darren Tan, Spaceflight +Yoda Emblem, 011, -, -, -, Emblem - Yoda, Jerry Vanderstelt, Hexproof� you and your creatures have. +Obi-Wan Kenobi Emblem, 012, -, -, -, Emblem - Obi-Wan Kenobi, Jerry Vanderstelt, Creatures you control get +1/+1 and have vigilance� first strike� and lifelink. +Aurra Sing Emblem, 013, -, -, -, Emblem - Aurra Sing, Willman1701, Whenever a nontoken creature you control leaves the battlefield� discard a card. diff --git a/Mage/src/main/java/mage/game/permanent/token/HellionToken.java b/Mage/src/main/java/mage/game/permanent/token/HellionToken.java index a4672fb64ef..31eed72112b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/HellionToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/HellionToken.java @@ -29,6 +29,7 @@ package mage.game.permanent.token; import mage.MageInt; import mage.constants.CardType; +import mage.constants.SubType; /** * @@ -40,7 +41,7 @@ public class HellionToken extends Token { super("Hellion", "4/4 red Hellion creature token"); cardType.add(CardType.CREATURE); color.setRed(true); - subtype.add("Hellion"); + subtype.add(SubType.HELLION); power = new MageInt(4); toughness = new MageInt(4); }