mirror of
https://github.com/correl/mage.git
synced 2024-11-25 03:00:11 +00:00
Tests: added many verify checks for missing cards, names, numbers, download settings:
* check wrong card numbers in sets; * check missing cards from set; * check wrong full art settings; * check missing and unknown sets in scryfall download settings; * check missing and unknown direct download links in scryfall download settings; * improved ability text check results; * removed unused tests for word checks;
This commit is contained in:
parent
b083dd48e6
commit
7aac355f4a
7 changed files with 533 additions and 128 deletions
|
@ -5,7 +5,6 @@ import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
import mage.client.util.CardLanguage;
|
import mage.client.util.CardLanguage;
|
||||||
import mage.util.CardUtil;
|
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.mage.plugins.card.dl.DownloadServiceInfo;
|
import org.mage.plugins.card.dl.DownloadServiceInfo;
|
||||||
import org.mage.plugins.card.images.CardDownloadData;
|
import org.mage.plugins.card.images.CardDownloadData;
|
||||||
|
@ -87,19 +86,6 @@ public enum ScryfallImageSource implements CardImageSource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ARN and POR uses † notation for art variation cards
|
|
||||||
if (baseUrl == null && card.getUsesVariousArt() && card.getSet().matches("ARN|POR")) {
|
|
||||||
String collectorId = card.getCollectorId();
|
|
||||||
if (collectorId.endsWith("b"))
|
|
||||||
collectorId = collectorId.replace("b", "†");
|
|
||||||
|
|
||||||
final String scryfallCollectorId = CardUtil.urlEncode(collectorId);
|
|
||||||
baseUrl = "https://api.scryfall.com/cards/" + formatSetName(card.getSet(), isToken) + "/"
|
|
||||||
+ scryfallCollectorId + "/" + localizedCode + "?format=image";
|
|
||||||
alternativeUrl = "https://api.scryfall.com/cards/" + formatSetName(card.getSet(), isToken) + "/"
|
|
||||||
+ scryfallCollectorId + "/" + defaultCode + "?format=image";
|
|
||||||
}
|
|
||||||
|
|
||||||
// double faced card
|
// double faced card
|
||||||
// the front face can be downloaded normally
|
// the front face can be downloaded normally
|
||||||
// the back face is prepared beforehand
|
// the back face is prepared beforehand
|
||||||
|
|
|
@ -7,6 +7,8 @@ import java.util.HashMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -14,9 +16,12 @@ import java.util.Set;
|
||||||
*/
|
*/
|
||||||
public class ScryfallImageSupportCards {
|
public class ScryfallImageSupportCards {
|
||||||
|
|
||||||
private static final Map<String, String> xmageSetsToScryfall = ImmutableMap.<String, String>builder().
|
private static final Map<String, String> xmageSetsToScryfall = ImmutableMap.<String, String>builder()
|
||||||
//put("xmage", "scryfall").
|
.put("8EB", "8ED")
|
||||||
build();
|
.put("9EB", "9ED")
|
||||||
|
.build();
|
||||||
|
static final Pattern REGEXP_DIRECT_KEY_SET_CODE_PATTERN = Pattern.compile("(\\w+)\\/", Pattern.MULTILINE);
|
||||||
|
static final Pattern REGEXP_DIRECT_KEY_CARD_NAME_PATTERN = Pattern.compile("\\/(.+?)\\/", Pattern.MULTILINE);
|
||||||
|
|
||||||
private static final Set<String> supportedSets = new ArraySet<String>() {
|
private static final Set<String> supportedSets = new ArraySet<String>() {
|
||||||
{
|
{
|
||||||
|
@ -504,26 +509,214 @@ public class ScryfallImageSupportCards {
|
||||||
// set/card_name/card_number
|
// set/card_name/card_number
|
||||||
|
|
||||||
// Cards with non-ASCII collector numbers must use direct download (cause xmage uses different card number)
|
// Cards with non-ASCII collector numbers must use direct download (cause xmage uses different card number)
|
||||||
|
// Verify checks must check and show missing data from that list
|
||||||
|
// 10E
|
||||||
|
put("10E/Air Elemental/64*", "https://api.scryfall.com/cards/10e/64★/");
|
||||||
|
put("10E/Anaba Bodyguard/187*", "https://api.scryfall.com/cards/10e/187★/");
|
||||||
|
put("10E/Ancestor's Chosen/1*", "https://api.scryfall.com/cards/10e/1★/");
|
||||||
|
put("10E/Angel of Mercy/2*", "https://api.scryfall.com/cards/10e/2★/");
|
||||||
|
put("10E/Angelic Blessing/3*", "https://api.scryfall.com/cards/10e/3★/");
|
||||||
|
put("10E/Angelic Wall/5*", "https://api.scryfall.com/cards/10e/5★/");
|
||||||
|
put("10E/Arcane Teachings/188*", "https://api.scryfall.com/cards/10e/188★/");
|
||||||
|
put("10E/Ascendant Evincar/127*", "https://api.scryfall.com/cards/10e/127★/");
|
||||||
|
put("10E/Avatar of Might/251*", "https://api.scryfall.com/cards/10e/251★/");
|
||||||
|
put("10E/Aven Cloudchaser/7*", "https://api.scryfall.com/cards/10e/7★/");
|
||||||
|
put("10E/Aven Fisher/68*", "https://api.scryfall.com/cards/10e/68★/");
|
||||||
|
put("10E/Aven Windreader/69*", "https://api.scryfall.com/cards/10e/69★/");
|
||||||
|
put("10E/Benalish Knight/11*", "https://api.scryfall.com/cards/10e/11★/");
|
||||||
|
put("10E/Birds of Paradise/252*", "https://api.scryfall.com/cards/10e/252★/");
|
||||||
|
put("10E/Blanchwood Armor/253*", "https://api.scryfall.com/cards/10e/253★/");
|
||||||
|
put("10E/Bog Wraith/130*", "https://api.scryfall.com/cards/10e/130★/");
|
||||||
|
put("10E/Canopy Spider/254*", "https://api.scryfall.com/cards/10e/254★/");
|
||||||
|
put("10E/Cloud Elemental/74*", "https://api.scryfall.com/cards/10e/74★/");
|
||||||
|
put("10E/Cloud Sprite/75*", "https://api.scryfall.com/cards/10e/75★/");
|
||||||
|
put("10E/Coat of Arms/316*", "https://api.scryfall.com/cards/10e/316★/");
|
||||||
|
put("10E/Colossus of Sardia/317*", "https://api.scryfall.com/cards/10e/317★/");
|
||||||
|
put("10E/Contaminated Bond/132*", "https://api.scryfall.com/cards/10e/132★/");
|
||||||
|
put("10E/Dehydration/78*", "https://api.scryfall.com/cards/10e/78★/");
|
||||||
|
put("10E/Dragon Roost/197*", "https://api.scryfall.com/cards/10e/197★/");
|
||||||
|
put("10E/Drudge Skeletons/139*", "https://api.scryfall.com/cards/10e/139★/");
|
||||||
|
put("10E/Dusk Imp/140*", "https://api.scryfall.com/cards/10e/140★/");
|
||||||
|
put("10E/Elvish Champion/261*", "https://api.scryfall.com/cards/10e/261★/");
|
||||||
|
put("10E/Faerie Conclave/351*", "https://api.scryfall.com/cards/10e/351★/");
|
||||||
|
put("10E/Fear/142*", "https://api.scryfall.com/cards/10e/142★/");
|
||||||
|
put("10E/Field Marshal/15*", "https://api.scryfall.com/cards/10e/15★/");
|
||||||
|
put("10E/Firebreathing/200*", "https://api.scryfall.com/cards/10e/200★/");
|
||||||
|
put("10E/Fog Elemental/85*", "https://api.scryfall.com/cards/10e/85★/");
|
||||||
|
put("10E/Furnace Whelp/205*", "https://api.scryfall.com/cards/10e/205★/");
|
||||||
|
put("10E/Ghitu Encampment/353*", "https://api.scryfall.com/cards/10e/353★/");
|
||||||
|
put("10E/Giant Spider/267*", "https://api.scryfall.com/cards/10e/267★/");
|
||||||
|
put("10E/Goblin King/207*", "https://api.scryfall.com/cards/10e/207★/");
|
||||||
|
put("10E/Goblin Sky Raider/210*", "https://api.scryfall.com/cards/10e/210★/");
|
||||||
|
put("10E/Heart of Light/19*", "https://api.scryfall.com/cards/10e/19★/");
|
||||||
|
put("10E/Holy Strength/22*", "https://api.scryfall.com/cards/10e/22★/");
|
||||||
|
put("10E/Hypnotic Specter/151*", "https://api.scryfall.com/cards/10e/151★/");
|
||||||
|
put("10E/Kamahl, Pit Fighter/214*", "https://api.scryfall.com/cards/10e/214★/");
|
||||||
|
put("10E/Leonin Scimitar/331*", "https://api.scryfall.com/cards/10e/331★/");
|
||||||
|
put("10E/Lightning Elemental/217*", "https://api.scryfall.com/cards/10e/217★/");
|
||||||
|
put("10E/Lord of the Pit/154*", "https://api.scryfall.com/cards/10e/154★/");
|
||||||
|
put("10E/Loxodon Warhammer/332*", "https://api.scryfall.com/cards/10e/332★/");
|
||||||
|
put("10E/Lure/276*", "https://api.scryfall.com/cards/10e/276★/");
|
||||||
|
put("10E/Mahamoti Djinn/90*", "https://api.scryfall.com/cards/10e/90★/");
|
||||||
|
put("10E/Mantis Engine/333*", "https://api.scryfall.com/cards/10e/333★/");
|
||||||
|
put("10E/March of the Machines/91*", "https://api.scryfall.com/cards/10e/91★/");
|
||||||
|
put("10E/Might Weaver/278*", "https://api.scryfall.com/cards/10e/278★/");
|
||||||
|
//put("10E/Mind Bend/93*", "https://api.scryfall.com/cards/10e/93★/"); // not implemented
|
||||||
|
put("10E/Mirri, Cat Warrior/279*", "https://api.scryfall.com/cards/10e/279★/");
|
||||||
|
put("10E/Mobilization/29*", "https://api.scryfall.com/cards/10e/29★/");
|
||||||
|
put("10E/Molimo, Maro-Sorcerer/280*", "https://api.scryfall.com/cards/10e/280★/");
|
||||||
|
put("10E/Mortivore/161*", "https://api.scryfall.com/cards/10e/161★/");
|
||||||
|
put("10E/Nekrataal/163*", "https://api.scryfall.com/cards/10e/163★/");
|
||||||
|
put("10E/Nightmare/164*", "https://api.scryfall.com/cards/10e/164★/");
|
||||||
|
put("10E/Nomad Mythmaker/30*", "https://api.scryfall.com/cards/10e/30★/");
|
||||||
|
put("10E/Ornithopter/336*", "https://api.scryfall.com/cards/10e/336★/");
|
||||||
|
put("10E/Overgrowth/283*", "https://api.scryfall.com/cards/10e/283★/");
|
||||||
|
put("10E/Overrun/284*", "https://api.scryfall.com/cards/10e/284★/");
|
||||||
|
put("10E/Pacifism/31*", "https://api.scryfall.com/cards/10e/31★/");
|
||||||
|
put("10E/Paladin en-Vec/32*", "https://api.scryfall.com/cards/10e/32★/");
|
||||||
|
put("10E/Pariah/33*", "https://api.scryfall.com/cards/10e/33★/");
|
||||||
|
put("10E/Persuasion/95*", "https://api.scryfall.com/cards/10e/95★/");
|
||||||
|
put("10E/Pincher Beetles/285*", "https://api.scryfall.com/cards/10e/285★/");
|
||||||
|
put("10E/Plague Beetle/168*", "https://api.scryfall.com/cards/10e/168★/");
|
||||||
|
put("10E/Platinum Angel/339*", "https://api.scryfall.com/cards/10e/339★/");
|
||||||
|
put("10E/Primal Rage/286*", "https://api.scryfall.com/cards/10e/286★/");
|
||||||
|
put("10E/Rage Weaver/223*", "https://api.scryfall.com/cards/10e/223★/");
|
||||||
|
put("10E/Raging Goblin/224*", "https://api.scryfall.com/cards/10e/224★/");
|
||||||
|
put("10E/Razormane Masticore/340*", "https://api.scryfall.com/cards/10e/340★/");
|
||||||
|
put("10E/Regeneration/290*", "https://api.scryfall.com/cards/10e/290★/");
|
||||||
|
put("10E/Reya Dawnbringer/35*", "https://api.scryfall.com/cards/10e/35★/");
|
||||||
|
put("10E/Rhox/291*", "https://api.scryfall.com/cards/10e/291★/");
|
||||||
|
put("10E/Robe of Mirrors/101*", "https://api.scryfall.com/cards/10e/101★/");
|
||||||
|
put("10E/Rock Badger/226*", "https://api.scryfall.com/cards/10e/226★/");
|
||||||
|
put("10E/Rootwater Commando/102*", "https://api.scryfall.com/cards/10e/102★/");
|
||||||
|
put("10E/Rushwood Dryad/294*", "https://api.scryfall.com/cards/10e/294★/");
|
||||||
|
put("10E/Sage Owl/104*", "https://api.scryfall.com/cards/10e/104★/");
|
||||||
|
put("10E/Scalpelexis/105*", "https://api.scryfall.com/cards/10e/105★/");
|
||||||
|
put("10E/Sengir Vampire/176*", "https://api.scryfall.com/cards/10e/176★/");
|
||||||
|
put("10E/Serra Angel/39*", "https://api.scryfall.com/cards/10e/39★/");
|
||||||
|
put("10E/Serra's Embrace/40*", "https://api.scryfall.com/cards/10e/40★/");
|
||||||
|
put("10E/Severed Legion/177*", "https://api.scryfall.com/cards/10e/177★/");
|
||||||
|
put("10E/Shimmering Wings/107*", "https://api.scryfall.com/cards/10e/107★/");
|
||||||
|
put("10E/Shivan Dragon/230*", "https://api.scryfall.com/cards/10e/230★/");
|
||||||
|
put("10E/Shivan Hellkite/231*", "https://api.scryfall.com/cards/10e/231★/");
|
||||||
|
put("10E/Sky Weaver/109*", "https://api.scryfall.com/cards/10e/109★/");
|
||||||
|
put("10E/Skyhunter Patrol/41*", "https://api.scryfall.com/cards/10e/41★/");
|
||||||
|
put("10E/Skyhunter Prowler/42*", "https://api.scryfall.com/cards/10e/42★/");
|
||||||
|
put("10E/Skyhunter Skirmisher/43*", "https://api.scryfall.com/cards/10e/43★/");
|
||||||
|
put("10E/Snapping Drake/110*", "https://api.scryfall.com/cards/10e/110★/");
|
||||||
|
put("10E/Spark Elemental/237*", "https://api.scryfall.com/cards/10e/237★/");
|
||||||
|
put("10E/Spawning Pool/358*", "https://api.scryfall.com/cards/10e/358★/");
|
||||||
|
put("10E/Spiketail Hatchling/111*", "https://api.scryfall.com/cards/10e/111★/");
|
||||||
|
put("10E/Spirit Link/45*", "https://api.scryfall.com/cards/10e/45★/");
|
||||||
|
put("10E/Stampeding Wildebeests/300*", "https://api.scryfall.com/cards/10e/300★/");
|
||||||
|
put("10E/Steadfast Guard/48*", "https://api.scryfall.com/cards/10e/48★/");
|
||||||
|
put("10E/Suntail Hawk/50*", "https://api.scryfall.com/cards/10e/50★/");
|
||||||
|
put("10E/Tangle Spider/303*", "https://api.scryfall.com/cards/10e/303★/");
|
||||||
|
put("10E/The Hive/324*", "https://api.scryfall.com/cards/10e/324★/");
|
||||||
|
put("10E/Thieving Magpie/115*", "https://api.scryfall.com/cards/10e/115★/");
|
||||||
|
put("10E/Threaten/242*", "https://api.scryfall.com/cards/10e/242★/");
|
||||||
|
put("10E/Thundering Giant/243*", "https://api.scryfall.com/cards/10e/243★/");
|
||||||
|
put("10E/Time Stop/117*", "https://api.scryfall.com/cards/10e/117★/");
|
||||||
|
put("10E/Treetop Bracers/304*", "https://api.scryfall.com/cards/10e/304★/");
|
||||||
|
put("10E/Treetop Village/361*", "https://api.scryfall.com/cards/10e/361★/");
|
||||||
|
put("10E/Troll Ascetic/305*", "https://api.scryfall.com/cards/10e/305★/");
|
||||||
|
put("10E/True Believer/53*", "https://api.scryfall.com/cards/10e/53★/");
|
||||||
|
put("10E/Tundra Wolves/54*", "https://api.scryfall.com/cards/10e/54★/");
|
||||||
|
put("10E/Uncontrollable Anger/244*", "https://api.scryfall.com/cards/10e/244★/");
|
||||||
|
put("10E/Unholy Strength/185*", "https://api.scryfall.com/cards/10e/185★/");
|
||||||
|
put("10E/Upwelling/306*", "https://api.scryfall.com/cards/10e/306★/");
|
||||||
|
put("10E/Vampire Bats/186*", "https://api.scryfall.com/cards/10e/186★/");
|
||||||
|
put("10E/Viashino Sandscout/246*", "https://api.scryfall.com/cards/10e/246★/");
|
||||||
|
put("10E/Voice of All/56*", "https://api.scryfall.com/cards/10e/56★/");
|
||||||
|
put("10E/Wall of Air/124*", "https://api.scryfall.com/cards/10e/124★/");
|
||||||
|
put("10E/Wall of Fire/247*", "https://api.scryfall.com/cards/10e/247★/");
|
||||||
|
put("10E/Wall of Swords/57*", "https://api.scryfall.com/cards/10e/57★/");
|
||||||
|
put("10E/Wall of Wood/309*", "https://api.scryfall.com/cards/10e/309★/");
|
||||||
|
put("10E/Whispersilk Cloak/345*", "https://api.scryfall.com/cards/10e/345★/");
|
||||||
|
put("10E/Wild Griffin/59*", "https://api.scryfall.com/cards/10e/59★/");
|
||||||
|
put("10E/Windborn Muse/60*", "https://api.scryfall.com/cards/10e/60★/");
|
||||||
|
put("10E/Youthful Knight/62*", "https://api.scryfall.com/cards/10e/62★/");
|
||||||
|
// 4ED
|
||||||
|
put("4ED/El-Hajjaj/134+", "https://api.scryfall.com/cards/4ed/134†/");
|
||||||
|
// 5ED
|
||||||
|
put("5ED/Game of Chaos/232+", "https://api.scryfall.com/cards/5ed/232†/");
|
||||||
|
put("5ED/Inferno/243+", "https://api.scryfall.com/cards/5ed/243†/");
|
||||||
|
put("5ED/Ironclaw Curse/244+", "https://api.scryfall.com/cards/5ed/244†/");
|
||||||
|
put("5ED/Manabarbs/250+", "https://api.scryfall.com/cards/5ed/250†/");
|
||||||
|
put("5ED/Shivan Dragon/267+", "https://api.scryfall.com/cards/5ed/267†/");
|
||||||
|
// AER
|
||||||
|
put("AER/Alley Strangler/52+", "https://api.scryfall.com/cards/aer/52†/");
|
||||||
|
put("AER/Dawnfeather Eagle/14+", "https://api.scryfall.com/cards/aer/14†/");
|
||||||
|
put("AER/Wrangle/101+", "https://api.scryfall.com/cards/aer/101†/");
|
||||||
|
// ARN
|
||||||
|
put("ARN/Army of Allah/2+", "https://api.scryfall.com/cards/arn/2†/");
|
||||||
|
put("ARN/Bird Maiden/37+", "https://api.scryfall.com/cards/arn/37†/");
|
||||||
|
put("ARN/Erg Raiders/25+", "https://api.scryfall.com/cards/arn/25†/");
|
||||||
|
put("ARN/Fishliver Oil/13+", "https://api.scryfall.com/cards/arn/13†/");
|
||||||
|
put("ARN/Giant Tortoise/15+", "https://api.scryfall.com/cards/arn/15†/");
|
||||||
|
put("ARN/Hasran Ogress/27+", "https://api.scryfall.com/cards/arn/27†/");
|
||||||
|
put("ARN/Moorish Cavalry/7+", "https://api.scryfall.com/cards/arn/7†/");
|
||||||
|
put("ARN/Nafs Asp/52+", "https://api.scryfall.com/cards/arn/52†/");
|
||||||
|
put("ARN/Oubliette/31+", "https://api.scryfall.com/cards/arn/31†/");
|
||||||
|
put("ARN/Piety/8+", "https://api.scryfall.com/cards/arn/8†/");
|
||||||
|
put("ARN/Rukh Egg/43+", "https://api.scryfall.com/cards/arn/43†/");
|
||||||
|
put("ARN/Stone-Throwing Devils/33+", "https://api.scryfall.com/cards/arn/33†/");
|
||||||
|
put("ARN/War Elephant/11+", "https://api.scryfall.com/cards/arn/11†/");
|
||||||
|
put("ARN/Wyluli Wolf/55+", "https://api.scryfall.com/cards/arn/55†/");
|
||||||
|
// ATQ
|
||||||
|
put("ATQ/Tawnos's Weaponry/70+", "https://api.scryfall.com/cards/atq/70†/");
|
||||||
|
// DD2
|
||||||
|
put("DD2/Chandra Nalaar/34*", "https://api.scryfall.com/cards/dd2/34★/");
|
||||||
|
put("DD2/Jace Beleren/1*", "https://api.scryfall.com/cards/dd2/1★/");
|
||||||
|
// DKM
|
||||||
|
put("DKM/Icy Manipulator/36*", "https://api.scryfall.com/cards/dkm/36★/");
|
||||||
|
put("DKM/Incinerate/14*", "https://api.scryfall.com/cards/dkm/14★/");
|
||||||
|
put("DKM/Icy Manipulator/36s", "https://api.scryfall.com/cards/dkm/36★/");
|
||||||
|
put("DKM/Incinerate/14s", "https://api.scryfall.com/cards/dkm/14★/");
|
||||||
|
// DRK
|
||||||
|
put("DRK/Fountain of Youth/103+", "https://api.scryfall.com/cards/drk/103†/");
|
||||||
|
put("DRK/Gaea's Touch/77+", "https://api.scryfall.com/cards/drk/77†/");
|
||||||
|
put("DRK/Runesword/107+", "https://api.scryfall.com/cards/drk/107†/");
|
||||||
// J14
|
// J14
|
||||||
put("J14/Plains/1*", "https://api.scryfall.com/cards/j14/1★/");
|
put("J14/Plains/1*", "https://api.scryfall.com/cards/j14/1★/");
|
||||||
put("J14/Island/2*", "https://api.scryfall.com/cards/j14/2★/");
|
put("J14/Island/2*", "https://api.scryfall.com/cards/j14/2★/");
|
||||||
put("J14/Swamp/3*", "https://api.scryfall.com/cards/j14/3★/");
|
put("J14/Swamp/3*", "https://api.scryfall.com/cards/j14/3★/");
|
||||||
put("J14/Mountain/4*", "https://api.scryfall.com/cards/j14/4★/");
|
put("J14/Mountain/4*", "https://api.scryfall.com/cards/j14/4★/");
|
||||||
put("J14/Forest/5*", "https://api.scryfall.com/cards/j14/5★/");
|
put("J14/Forest/5*", "https://api.scryfall.com/cards/j14/5★/");
|
||||||
|
// KLD
|
||||||
|
put("KLD/Arborback Stomper/142+", "https://api.scryfall.com/cards/kld/142†/");
|
||||||
|
put("KLD/Brazen Scourge/107+", "https://api.scryfall.com/cards/kld/107†/");
|
||||||
|
put("KLD/Terrain Elemental/272+", "https://api.scryfall.com/cards/kld/272†/");
|
||||||
|
put("KLD/Wind Drake/70+", "https://api.scryfall.com/cards/kld/70†/");
|
||||||
|
// M20
|
||||||
|
put("M20/Corpse Knight/206+", "https://api.scryfall.com/cards/m20/206†/");
|
||||||
|
// MIR
|
||||||
|
put("MIR/Reality Ripple/87+", "https://api.scryfall.com/cards/mir/87†/");
|
||||||
|
// ODY
|
||||||
|
put("ODY/Cephalid Looter/72+", "https://api.scryfall.com/cards/ody/72†/");
|
||||||
|
put("ODY/Seafloor Debris/325+", "https://api.scryfall.com/cards/ody/325†/");
|
||||||
|
// PAL99
|
||||||
|
put("PAL99/Island/3+", "https://api.scryfall.com/cards/pal99/3†/");
|
||||||
// PLS
|
// PLS
|
||||||
put("PLS/Tahngarth, Talruum Hero/74*", "https://api.scryfall.com/cards/pls/74★/");
|
|
||||||
put("PLS/Ertai, the Corrupted/107*", "https://api.scryfall.com/cards/pls/107★/");
|
put("PLS/Ertai, the Corrupted/107*", "https://api.scryfall.com/cards/pls/107★/");
|
||||||
put("PLS/Skyship Weatherlight/133*", "https://api.scryfall.com/cards/pls/133★/");
|
put("PLS/Skyship Weatherlight/133*", "https://api.scryfall.com/cards/pls/133★/");
|
||||||
|
put("PLS/Tahngarth, Talruum Hero/74*", "https://api.scryfall.com/cards/pls/74★/");
|
||||||
|
// POR
|
||||||
|
put("POR/Anaconda/158+", "https://api.scryfall.com/cards/por/158†/");
|
||||||
|
put("POR/Blaze/118+", "https://api.scryfall.com/cards/por/118†/");
|
||||||
|
put("POR/Elite Cat Warrior/163+", "https://api.scryfall.com/cards/por/163†/");
|
||||||
|
put("POR/Hand of Death/96+", "https://api.scryfall.com/cards/por/96†/");
|
||||||
|
put("POR/Monstrous Growth/173+", "https://api.scryfall.com/cards/por/173†/");
|
||||||
|
put("POR/Raging Goblin/145+", "https://api.scryfall.com/cards/por/145†/");
|
||||||
|
put("POR/Warrior's Charge/38+", "https://api.scryfall.com/cards/por/38†/");
|
||||||
// PROE
|
// PROE
|
||||||
put("PROE/Emrakul, the Aeons Torn/*4", "https://api.scryfall.com/cards/proe/★4/");
|
put("PROE/Emrakul, the Aeons Torn/*4", "https://api.scryfall.com/cards/proe/★4/");
|
||||||
put("PROE/Lord of Shatterskull Pass/*156", "https://api.scryfall.com/cards/proe/★156/");
|
put("PROE/Lord of Shatterskull Pass/*156", "https://api.scryfall.com/cards/proe/★156/");
|
||||||
// PAL99
|
//
|
||||||
put("PAL99/Island/3+", "https://api.scryfall.com/cards/pal99/3†/");
|
// PPRE
|
||||||
|
put("PPRE/Beast of Burden/5+", "https://api.scryfall.com/cards/ppre/5†/");
|
||||||
// PSOI
|
// PSOI
|
||||||
put("PSOI/Tamiyo's Journal/265s+", "https://api.scryfall.com/cards/psoi/265s†/");
|
put("PSOI/Tamiyo's Journal/265s+", "https://api.scryfall.com/cards/psoi/265s†/");
|
||||||
// DKM
|
|
||||||
put("DKM/Icy Manipulator/36s", "https://api.scryfall.com/cards/dkm/36★/");
|
|
||||||
put("DKM/Incinerate/14s", "https://api.scryfall.com/cards/dkm/14★/");
|
|
||||||
// PWAR
|
// PWAR
|
||||||
put("PWAR/Ajani, the Greathearted/184s*", "https://api.scryfall.com/cards/pwar/184s★/");
|
put("PWAR/Ajani, the Greathearted/184s*", "https://api.scryfall.com/cards/pwar/184s★/");
|
||||||
put("PWAR/Angrath, Captain of Chaos/227s*", "https://api.scryfall.com/cards/pwar/227s★/");
|
put("PWAR/Angrath, Captain of Chaos/227s*", "https://api.scryfall.com/cards/pwar/227s★/");
|
||||||
|
@ -561,25 +754,81 @@ public class ScryfallImageSupportCards {
|
||||||
put("PWAR/Ugin, the Ineffable/2s*", "https://api.scryfall.com/cards/pwar/2s★/");
|
put("PWAR/Ugin, the Ineffable/2s*", "https://api.scryfall.com/cards/pwar/2s★/");
|
||||||
put("PWAR/Vivien, Champion of the Wilds/180s*", "https://api.scryfall.com/cards/pwar/180s★/");
|
put("PWAR/Vivien, Champion of the Wilds/180s*", "https://api.scryfall.com/cards/pwar/180s★/");
|
||||||
put("PWAR/Vraska, Swarm's Eminence/236s*", "https://api.scryfall.com/cards/pwar/236s★/");
|
put("PWAR/Vraska, Swarm's Eminence/236s*", "https://api.scryfall.com/cards/pwar/236s★/");
|
||||||
|
// SHM
|
||||||
// 8th Edition box set and 9th Edition box set
|
put("SHM/Reflecting Pool/278*", "https://api.scryfall.com/cards/shm/278★/");
|
||||||
// scryfall stores it with one set, by xmage split into two -- 8ED and 8EB, 9ED and 9EB
|
// SOI
|
||||||
put("8EB/Eager Cadet", "https://api.scryfall.com/cards/8ed/S1/");
|
put("SOI/Tamiyo's Journal/265+", "https://api.scryfall.com/cards/soi/265†/");
|
||||||
put("8EB/Vengeance", "https://api.scryfall.com/cards/8ed/S2/");
|
put("SOI/Tamiyo's Journal/265+a", "https://api.scryfall.com/cards/soi/265†a/");
|
||||||
put("8EB/Giant Octopus", "https://api.scryfall.com/cards/8ed/S3/");
|
put("SOI/Tamiyo's Journal/265+b", "https://api.scryfall.com/cards/soi/265†b/");
|
||||||
put("8EB/Sea Eagle", "https://api.scryfall.com/cards/8ed/S4/");
|
put("SOI/Tamiyo's Journal/265+c", "https://api.scryfall.com/cards/soi/265†c/");
|
||||||
put("8EB/Vizzerdrix", "https://api.scryfall.com/cards/8ed/S5/");
|
put("SOI/Tamiyo's Journal/265+d", "https://api.scryfall.com/cards/soi/265†d/");
|
||||||
put("8EB/Enormous Baloth", "https://api.scryfall.com/cards/8ed/S6/");
|
// THB
|
||||||
put("8EB/Silverback Ape", "https://api.scryfall.com/cards/8ed/S7/");
|
put("THB/Temple of Abandon/347*", "https://api.scryfall.com/cards/thb/347★/");
|
||||||
put("9EB/Eager Cadet", "https://api.scryfall.com/cards/9ed/S1/");
|
// UNH
|
||||||
put("9EB/Vengeance", "https://api.scryfall.com/cards/9ed/S3/");
|
put("UNH/Aesthetic Consultation/48*", "https://api.scryfall.com/cards/unh/48★/");
|
||||||
put("9EB/Coral Eel", "https://api.scryfall.com/cards/9ed/S3/");
|
put("UNH/AWOL/2*", "https://api.scryfall.com/cards/unh/2★/");
|
||||||
put("9EB/Giant Octopus", "https://api.scryfall.com/cards/9ed/S4/");
|
put("UNH/Bad Ass/49*", "https://api.scryfall.com/cards/unh/49★/");
|
||||||
put("9EB/Index", "https://api.scryfall.com/cards/9ed/S5/");
|
put("UNH/Blast from the Past/72*", "https://api.scryfall.com/cards/unh/72★/");
|
||||||
put("9EB/Vizzerdrix", "https://api.scryfall.com/cards/9ed/S7/");
|
put("UNH/Cardpecker/4*", "https://api.scryfall.com/cards/unh/4★/");
|
||||||
put("9EB/Goblin Raider", "https://api.scryfall.com/cards/9ed/S8/");
|
put("UNH/Emcee/9*", "https://api.scryfall.com/cards/unh/9★/");
|
||||||
put("9EB/Enormous Baloth", "https://api.scryfall.com/cards/9ed/S9/");
|
put("UNH/Farewell to Arms/56*", "https://api.scryfall.com/cards/unh/56★/");
|
||||||
put("9EB/Spined Wurm", "https://api.scryfall.com/cards/9ed/S10/");
|
put("UNH/Frazzled Editor/77*", "https://api.scryfall.com/cards/unh/77★/");
|
||||||
|
put("UNH/Gleemax/121*", "https://api.scryfall.com/cards/unh/121★/");
|
||||||
|
put("UNH/Goblin Mime/78*", "https://api.scryfall.com/cards/unh/78★/");
|
||||||
|
put("UNH/Greater Morphling/34*", "https://api.scryfall.com/cards/unh/34★/");
|
||||||
|
put("UNH/Keeper of the Sacred Word/101*", "https://api.scryfall.com/cards/unh/101★/");
|
||||||
|
put("UNH/Laughing Hyena/103*", "https://api.scryfall.com/cards/unh/103★/");
|
||||||
|
put("UNH/Letter Bomb/122*", "https://api.scryfall.com/cards/unh/122★/");
|
||||||
|
put("UNH/Mana Screw/123*", "https://api.scryfall.com/cards/unh/123★/");
|
||||||
|
put("UNH/Monkey Monkey Monkey/104*", "https://api.scryfall.com/cards/unh/104★/");
|
||||||
|
put("UNH/Mons's Goblin Waiters/82*", "https://api.scryfall.com/cards/unh/82★/");
|
||||||
|
put("UNH/Mox Lotus/124*", "https://api.scryfall.com/cards/unh/124★/");
|
||||||
|
put("UNH/My First Tome/125*", "https://api.scryfall.com/cards/unh/125★/");
|
||||||
|
put("UNH/Old Fogey/106*", "https://api.scryfall.com/cards/unh/106★/");
|
||||||
|
put("UNH/Question Elemental?/43*", "https://api.scryfall.com/cards/unh/43★/");
|
||||||
|
put("UNH/Richard Garfield, Ph.D./44*", "https://api.scryfall.com/cards/unh/44★/");
|
||||||
|
put("UNH/Shoe Tree/109*", "https://api.scryfall.com/cards/unh/109★/");
|
||||||
|
put("UNH/Standing Army/20*", "https://api.scryfall.com/cards/unh/20★/");
|
||||||
|
put("UNH/Time Machine/128*", "https://api.scryfall.com/cards/unh/128★/");
|
||||||
|
put("UNH/Touch and Go/90*", "https://api.scryfall.com/cards/unh/90★/");
|
||||||
|
put("UNH/When Fluffy Bunnies Attack/67*", "https://api.scryfall.com/cards/unh/67★/");
|
||||||
|
// WAR
|
||||||
|
put("WAR/Ajani, the Greathearted/184*", "https://api.scryfall.com/cards/war/184★/");
|
||||||
|
put("WAR/Angrath, Captain of Chaos/227*", "https://api.scryfall.com/cards/war/227★/");
|
||||||
|
put("WAR/Arlinn, Voice of the Pack/150*", "https://api.scryfall.com/cards/war/150★/");
|
||||||
|
put("WAR/Ashiok, Dream Render/228*", "https://api.scryfall.com/cards/war/228★/");
|
||||||
|
put("WAR/Chandra, Fire Artisan/119*", "https://api.scryfall.com/cards/war/119★/");
|
||||||
|
put("WAR/Davriel, Rogue Shadowmage/83*", "https://api.scryfall.com/cards/war/83★/");
|
||||||
|
put("WAR/Domri, Anarch of Bolas/191*", "https://api.scryfall.com/cards/war/191★/");
|
||||||
|
put("WAR/Dovin, Hand of Control/229*", "https://api.scryfall.com/cards/war/229★/");
|
||||||
|
put("WAR/Gideon Blackblade/13*", "https://api.scryfall.com/cards/war/13★/");
|
||||||
|
put("WAR/Huatli, the Sun's Heart/230*", "https://api.scryfall.com/cards/war/230★/");
|
||||||
|
put("WAR/Jace, Wielder of Mysteries/54*", "https://api.scryfall.com/cards/war/54★/");
|
||||||
|
put("WAR/Jaya, Venerated Firemage/135*", "https://api.scryfall.com/cards/war/135★/");
|
||||||
|
put("WAR/Jiang Yanggu, Wildcrafter/164*", "https://api.scryfall.com/cards/war/164★/");
|
||||||
|
put("WAR/Karn, the Great Creator/1*", "https://api.scryfall.com/cards/war/1★/");
|
||||||
|
put("WAR/Kasmina, Enigmatic Mentor/56*", "https://api.scryfall.com/cards/war/56★/");
|
||||||
|
put("WAR/Kaya, Bane of the Dead/231*", "https://api.scryfall.com/cards/war/231★/");
|
||||||
|
put("WAR/Kiora, Behemoth Beckoner/232*", "https://api.scryfall.com/cards/war/232★/");
|
||||||
|
put("WAR/Liliana, Dreadhorde General/97*", "https://api.scryfall.com/cards/war/97★/");
|
||||||
|
put("WAR/Nahiri, Storm of Stone/233*", "https://api.scryfall.com/cards/war/233★/");
|
||||||
|
put("WAR/Narset, Parter of Veils/61*", "https://api.scryfall.com/cards/war/61★/");
|
||||||
|
put("WAR/Nicol Bolas, Dragon-God/207*", "https://api.scryfall.com/cards/war/207★/");
|
||||||
|
put("WAR/Nissa, Who Shakes the World/169*", "https://api.scryfall.com/cards/war/169★/");
|
||||||
|
put("WAR/Ob Nixilis, the Hate-Twisted/100*", "https://api.scryfall.com/cards/war/100★/");
|
||||||
|
put("WAR/Ral, Storm Conduit/211*", "https://api.scryfall.com/cards/war/211★/");
|
||||||
|
put("WAR/Saheeli, Sublime Artificer/234*", "https://api.scryfall.com/cards/war/234★/");
|
||||||
|
put("WAR/Samut, Tyrant Smasher/235*", "https://api.scryfall.com/cards/war/235★/");
|
||||||
|
put("WAR/Sarkhan the Masterless/143*", "https://api.scryfall.com/cards/war/143★/");
|
||||||
|
put("WAR/Sorin, Vengeful Bloodlord/217*", "https://api.scryfall.com/cards/war/217★/");
|
||||||
|
put("WAR/Tamiyo, Collector of Tales/220*", "https://api.scryfall.com/cards/war/220★/");
|
||||||
|
put("WAR/Teferi, Time Raveler/221*", "https://api.scryfall.com/cards/war/221★/");
|
||||||
|
put("WAR/Teyo, the Shieldmage/32*", "https://api.scryfall.com/cards/war/32★/");
|
||||||
|
put("WAR/The Wanderer/37*", "https://api.scryfall.com/cards/war/37★/");
|
||||||
|
put("WAR/Tibalt, Rakish Instigator/146*", "https://api.scryfall.com/cards/war/146★/");
|
||||||
|
put("WAR/Ugin, the Ineffable/2*", "https://api.scryfall.com/cards/war/2★/");
|
||||||
|
put("WAR/Vivien, Champion of the Wilds/180*", "https://api.scryfall.com/cards/war/180★/");
|
||||||
|
put("WAR/Vraska, Swarm's Eminence/236*", "https://api.scryfall.com/cards/war/236★/");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -591,21 +840,49 @@ public class ScryfallImageSupportCards {
|
||||||
return supportedSets;
|
return supportedSets;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String findDirectDownloadLink(String setCode, String cardName, String cardNumber) {
|
public static String findDirectDownloadKey(String setCode, String cardName, String cardNumber) {
|
||||||
|
|
||||||
// set/card/number
|
// set/card/number
|
||||||
String linkCode1 = setCode + "/" + cardName + "/" + cardNumber;
|
String linkCode1 = setCode + "/" + cardName + "/" + cardNumber;
|
||||||
if (directDownloadLinks.containsKey(linkCode1)) {
|
if (directDownloadLinks.containsKey(linkCode1)) {
|
||||||
return directDownloadLinks.get(linkCode1);
|
return linkCode1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set/card
|
// set/card
|
||||||
String linkCode2 = setCode + "/" + cardName;
|
String linkCode2 = setCode + "/" + cardName;
|
||||||
if (directDownloadLinks.containsKey(linkCode2)) {
|
if (directDownloadLinks.containsKey(linkCode2)) {
|
||||||
return directDownloadLinks.get(linkCode2);
|
return linkCode2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// default
|
// default
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String findDirectDownloadLink(String setCode, String cardName, String cardNumber) {
|
||||||
|
String key = findDirectDownloadKey(setCode, cardName, cardNumber);
|
||||||
|
return directDownloadLinks.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String extractSetCodeFromDirectKey(String key) {
|
||||||
|
// from: 8EB/Giant Octopus
|
||||||
|
// to: 8EB
|
||||||
|
Matcher matcher = REGEXP_DIRECT_KEY_SET_CODE_PATTERN.matcher(key);
|
||||||
|
if (matcher.find()) {
|
||||||
|
return matcher.group(1);
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String extractCardNameFromDirectKey(String key) {
|
||||||
|
// from: 8EB/Giant Octopus/
|
||||||
|
// to: Giant Octopus
|
||||||
|
Matcher matcher = REGEXP_DIRECT_KEY_CARD_NAME_PATTERN.matcher(key + "/"); // add / for regexp workaround
|
||||||
|
if (matcher.find()) {
|
||||||
|
return matcher.group(1);
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<String, String> getDirectDownloadLinks() {
|
||||||
|
return directDownloadLinks;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,7 @@ class DawnEvangelAbility extends DiesCreatureTriggeredAbility {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getRule() {
|
public String getRule() {
|
||||||
return "Whenever a creature dies, if an Aura you control was attached to it, " +
|
return "Whenever a creature dies, if an Aura you controlled was attached to it, " +
|
||||||
"return target creature card with converted mana cost 2 or less from your graveyard to your hand.";
|
"return target creature card with converted mana cost 2 or less from your graveyard to your hand.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@ public final class MtgJsonCard {
|
||||||
// contains only used fields, if you need more for tests then just add it here
|
// contains only used fields, if you need more for tests then just add it here
|
||||||
|
|
||||||
public String name;
|
public String name;
|
||||||
|
public String asciiName; // mtgjson uses it for some cards like El-Hajjaj
|
||||||
|
public String number; // from sets source only, see https://mtgjson.com/data-models/card/
|
||||||
|
|
||||||
public String faceName;
|
public String faceName;
|
||||||
public String side;
|
public String side;
|
||||||
|
@ -28,5 +30,6 @@ public final class MtgJsonCard {
|
||||||
|
|
||||||
public Integer edhrecRank;
|
public Integer edhrecRank;
|
||||||
public String layout;
|
public String layout;
|
||||||
|
public boolean isFullArt;
|
||||||
public List<String> printings; // set codes with that card
|
public List<String> printings; // set codes with that card
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,8 @@ public final class MtgJsonService {
|
||||||
for (Map.Entry<String, String> entry : mtgJsonToXMageCodes.entrySet()) {
|
for (Map.Entry<String, String> entry : mtgJsonToXMageCodes.entrySet()) {
|
||||||
xMageToMtgJsonCodes.put(entry.getValue(), entry.getKey());
|
xMageToMtgJsonCodes.put(entry.getValue(), entry.getKey());
|
||||||
}
|
}
|
||||||
|
xMageToMtgJsonCodes.put("8EB", "8ED");
|
||||||
|
xMageToMtgJsonCodes.put("9EB", "9ED");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<String, MtgJsonCard> loadAllCards() throws IOException {
|
private static Map<String, MtgJsonCard> loadAllCards() throws IOException {
|
||||||
|
@ -68,20 +70,58 @@ public final class MtgJsonService {
|
||||||
return findReference(CardHolder.cards, name);
|
return findReference(CardHolder.cards, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<MtgJsonCard> cardsFromSet(String setCode, String name) {
|
||||||
|
MtgJsonSet set = findReference(SetHolder.sets, setCode);
|
||||||
|
if (set == null) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
String needName = convertXmageToMtgJsonCardName(name);
|
||||||
|
return set.cards.stream()
|
||||||
|
.filter(c -> needName.equals(c.name) || needName.equals(c.asciiName) || needName.equals(c.faceName))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MtgJsonCard cardFromSet(String setCode, String name, String number) {
|
||||||
|
String jsonSetCode = xMageToMtgJsonCodes.getOrDefault(setCode, setCode);
|
||||||
|
List<MtgJsonCard> list = cardsFromSet(jsonSetCode, name);
|
||||||
|
return list.stream()
|
||||||
|
.filter(c -> convertMtgJsonToXmageCardNumber(c.number).equals(number))
|
||||||
|
.findFirst().orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
private static <T> T findReference(Map<String, T> reference, String name) {
|
private static <T> T findReference(Map<String, T> reference, String name) {
|
||||||
T ref = reference.get(name);
|
T ref = reference.get(name);
|
||||||
if (ref == null) {
|
if (ref == null) {
|
||||||
name = name.replaceFirst("\\bA[Ee]", "Æ");
|
//name = name.replaceFirst("\\bA[Ee]", "Æ");
|
||||||
ref = reference.get(name);
|
//ref = reference.get(name);
|
||||||
}
|
}
|
||||||
if (ref == null) {
|
if (ref == null) {
|
||||||
name = name.replace("'", "\""); // for Kongming, "Sleeping Dragon" & Pang Tong, "Young Phoenix"
|
//name = name.replace("'", "\""); // for Kongming, "Sleeping Dragon" & Pang Tong, "Young Phoenix"
|
||||||
|
//ref = reference.get(name);
|
||||||
|
}
|
||||||
|
if (ref == null) {
|
||||||
|
name = convertXmageToMtgJsonCardName(name);
|
||||||
ref = reference.get(name);
|
ref = reference.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String convertXmageToMtgJsonCardName(String cardName) {
|
||||||
|
return cardName;
|
||||||
|
//.replaceFirst("Aether", "Æther")
|
||||||
|
//.replace("'", "\""); // for Kongming, "Sleeping Dragon" & Pang Tong, "Young Phoenix"
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String convertMtgJsonToXmageCardNumber(String number) {
|
||||||
|
// card number notation must be same for all sets (replace non-ascii symbols)
|
||||||
|
// so your set generation tools must use same replaces
|
||||||
|
return number
|
||||||
|
.replace("★", "*")
|
||||||
|
.replace("†", "+");
|
||||||
|
}
|
||||||
|
|
||||||
private static <T> void addAliases(Map<String, T> reference) {
|
private static <T> void addAliases(Map<String, T> reference) {
|
||||||
Map<String, String> aliases = new HashMap<>();
|
Map<String, String> aliases = new HashMap<>();
|
||||||
for (String name : reference.keySet()) {
|
for (String name : reference.keySet()) {
|
||||||
|
|
|
@ -1,25 +1,12 @@
|
||||||
package mage.verify;
|
package mage.verify;
|
||||||
|
|
||||||
import com.google.common.base.CharMatcher;
|
import com.google.common.base.CharMatcher;
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.nio.file.*;
|
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import mage.ObjectColor;
|
import mage.ObjectColor;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.effects.keyword.ScryEffect;
|
import mage.abilities.effects.keyword.ScryEffect;
|
||||||
import mage.abilities.keyword.MenaceAbility;
|
import mage.abilities.keyword.MenaceAbility;
|
||||||
import mage.abilities.keyword.MultikickerAbility;
|
import mage.abilities.keyword.MultikickerAbility;
|
||||||
import mage.cards.*;
|
import mage.cards.*;
|
||||||
import mage.cards.basiclands.BasicLand;
|
|
||||||
import mage.cards.decks.DeckCardLists;
|
import mage.cards.decks.DeckCardLists;
|
||||||
import mage.cards.decks.importer.DeckImporter;
|
import mage.cards.decks.importer.DeckImporter;
|
||||||
import mage.cards.repository.CardInfo;
|
import mage.cards.repository.CardInfo;
|
||||||
|
@ -47,6 +34,16 @@ import org.mage.plugins.card.images.CardDownloadData;
|
||||||
import org.mage.plugins.card.images.DownloadPicturesService;
|
import org.mage.plugins.card.images.DownloadPicturesService;
|
||||||
import org.reflections.Reflections;
|
import org.reflections.Reflections;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.nio.file.*;
|
||||||
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author JayDi85
|
* @author JayDi85
|
||||||
*/
|
*/
|
||||||
|
@ -57,9 +54,6 @@ public class VerifyCardDataTest {
|
||||||
private static final String FULL_ABILITIES_CHECK_SET_CODE = "THB"; // check all abilities and output cards with wrong abilities texts;
|
private static final String FULL_ABILITIES_CHECK_SET_CODE = "THB"; // check all abilities and output cards with wrong abilities texts;
|
||||||
private static final boolean AUTO_FIX_SAMPLE_DECKS = false; // debug only: fix sample decks if it contains errors like wrong card numbers
|
private static final boolean AUTO_FIX_SAMPLE_DECKS = false; // debug only: fix sample decks if it contains errors like wrong card numbers
|
||||||
|
|
||||||
// right now this is very noisy, and not useful enough to make any assertions on
|
|
||||||
private static final boolean CHECK_SOURCE_TOKENS = false;
|
|
||||||
|
|
||||||
private static final HashMap<String, Set<String>> skipCheckLists = new HashMap<>();
|
private static final HashMap<String, Set<String>> skipCheckLists = new HashMap<>();
|
||||||
private static final Set<String> subtypesToIgnore = new HashSet<>();
|
private static final Set<String> subtypesToIgnore = new HashSet<>();
|
||||||
private static final String SKIP_LIST_PT = "PT";
|
private static final String SKIP_LIST_PT = "PT";
|
||||||
|
@ -73,8 +67,8 @@ public class VerifyCardDataTest {
|
||||||
private static final String SKIP_LIST_DOUBLE_RARE = "DOUBLE_RARE";
|
private static final String SKIP_LIST_DOUBLE_RARE = "DOUBLE_RARE";
|
||||||
private static final String SKIP_LIST_UNSUPPORTED_SETS = "UNSUPPORTED_SETS";
|
private static final String SKIP_LIST_UNSUPPORTED_SETS = "UNSUPPORTED_SETS";
|
||||||
private static final String SKIP_LIST_SCRYFALL_DOWNLOAD_SETS = "SCRYFALL_DOWNLOAD_SETS";
|
private static final String SKIP_LIST_SCRYFALL_DOWNLOAD_SETS = "SCRYFALL_DOWNLOAD_SETS";
|
||||||
|
private static final String SKIP_LIST_WRONG_CARD_NUMBERS = "WRONG_CARD_NUMBERS";
|
||||||
private static final String SKIP_LIST_SAMPLE_DECKS = "SAMPLE_DECKS";
|
private static final String SKIP_LIST_SAMPLE_DECKS = "SAMPLE_DECKS";
|
||||||
private static final Pattern SHORT_JAVA_STRING = Pattern.compile("(?<=\")[A-Z][a-z]+(?=\")");
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
// skip lists for checks (example: unstable cards with same name may have different stats)
|
// skip lists for checks (example: unstable cards with same name may have different stats)
|
||||||
|
@ -190,9 +184,20 @@ public class VerifyCardDataTest {
|
||||||
skipListAddName(SKIP_LIST_UNSUPPORTED_SETS, "AMH1"); // Modern Horizons Art Series
|
skipListAddName(SKIP_LIST_UNSUPPORTED_SETS, "AMH1"); // Modern Horizons Art Series
|
||||||
skipListAddName(SKIP_LIST_UNSUPPORTED_SETS, "PTG"); // Ponies: The Galloping
|
skipListAddName(SKIP_LIST_UNSUPPORTED_SETS, "PTG"); // Ponies: The Galloping
|
||||||
|
|
||||||
|
// wrond card numbers skip list
|
||||||
|
skipListCreate(SKIP_LIST_WRONG_CARD_NUMBERS);
|
||||||
|
skipListAddName(SKIP_LIST_WRONG_CARD_NUMBERS, "SWS"); // Star Wars
|
||||||
|
skipListAddName(SKIP_LIST_WRONG_CARD_NUMBERS, "POR"); // Portal, TODO: remove after bug fixed https://github.com/mtgjson/mtgjson/issues/660
|
||||||
|
skipListAddName(SKIP_LIST_WRONG_CARD_NUMBERS, "UND"); // un-sets don't have full implementation of card variations
|
||||||
|
skipListAddName(SKIP_LIST_WRONG_CARD_NUMBERS, "UST"); // un-sets don't have full implementation of card variations
|
||||||
|
skipListAddName(SKIP_LIST_WRONG_CARD_NUMBERS, "SOI", "Tamiyo's Journal"); // not all variations implemented
|
||||||
|
|
||||||
|
|
||||||
// scryfall download sets (missing from scryfall website)
|
// scryfall download sets (missing from scryfall website)
|
||||||
skipListCreate(SKIP_LIST_SCRYFALL_DOWNLOAD_SETS);
|
skipListCreate(SKIP_LIST_SCRYFALL_DOWNLOAD_SETS);
|
||||||
skipListAddName(SKIP_LIST_SCRYFALL_DOWNLOAD_SETS, "SWS"); // Star Wars
|
skipListAddName(SKIP_LIST_SCRYFALL_DOWNLOAD_SETS, "SWS"); // Star Wars
|
||||||
|
//skipListAddName(SKIP_LIST_SCRYFALL_DOWNLOAD_SETS, "8EB"); // Eighth Edition Box - inner xmage set, split from 8ED
|
||||||
|
//skipListAddName(SKIP_LIST_SCRYFALL_DOWNLOAD_SETS, "9EB"); // Ninth Edition Box - inner xmage set, split from 9ED
|
||||||
|
|
||||||
// sample decks checking - some decks can contains unimplemented cards, so ignore it
|
// sample decks checking - some decks can contains unimplemented cards, so ignore it
|
||||||
// file name must be related to sample-decks folder
|
// file name must be related to sample-decks folder
|
||||||
|
@ -246,12 +251,11 @@ public class VerifyCardDataTest {
|
||||||
int cardIndex = 0;
|
int cardIndex = 0;
|
||||||
for (Card card : CardScanner.getAllCards()) {
|
for (Card card : CardScanner.getAllCards()) {
|
||||||
cardIndex++;
|
cardIndex++;
|
||||||
Set<String> tokens = findSourceTokens(card.getClass());
|
|
||||||
if (card.isSplitCard()) {
|
if (card.isSplitCard()) {
|
||||||
check(((SplitCard) card).getLeftHalfCard(), null, cardIndex);
|
check(((SplitCard) card).getLeftHalfCard(), cardIndex);
|
||||||
check(((SplitCard) card).getRightHalfCard(), null, cardIndex);
|
check(((SplitCard) card).getRightHalfCard(), cardIndex);
|
||||||
} else {
|
} else {
|
||||||
check(card, tokens, cardIndex);
|
check(card, cardIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -544,13 +548,87 @@ public class VerifyCardDataTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_checkMissingScryfallSettings() {
|
@Ignore // TODO: enable after all missing cards and settings fixes
|
||||||
|
public void test_checkWrongCardsDataInSets() {
|
||||||
|
Collection<String> errorsList = new ArrayList<>();
|
||||||
|
Collection<String> warningsList = new ArrayList<>();
|
||||||
|
Collection<ExpansionSet> xmageSets = Sets.getInstance().values();
|
||||||
|
Set<String> foundedJsonCards = new HashSet<>();
|
||||||
|
|
||||||
|
// CHECK: wrong card numbers
|
||||||
|
for (ExpansionSet set : xmageSets) {
|
||||||
|
if (skipListHaveName(SKIP_LIST_WRONG_CARD_NUMBERS, set.getCode())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ExpansionSet.SetCardInfo card : set.getSetCardInfo()) {
|
||||||
|
MtgJsonCard jsonCard = MtgJsonService.cardFromSet(set.getCode(), card.getName(), card.getCardNumber());
|
||||||
|
if (jsonCard == null) {
|
||||||
|
// see convertMtgJsonToXmageCardNumber for card number convert notation
|
||||||
|
errorsList.add("Error: unknown card number, use standard number notations: "
|
||||||
|
+ set.getCode() + " - " + set.getName() + " - " + card.getName() + " - " + card.getCardNumber());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// index for missing cards
|
||||||
|
String code = MtgJsonService.xMageToMtgJsonCodes.getOrDefault(set.getCode(), set.getCode()) + " - " + jsonCard.name + " - " + jsonCard.number;
|
||||||
|
foundedJsonCards.add(code);
|
||||||
|
|
||||||
|
// CHECK: must use full art setting
|
||||||
|
if (jsonCard.isFullArt && !card.isFullArt()) {
|
||||||
|
errorsList.add("Error: card must use full art setting: "
|
||||||
|
+ set.getCode() + " - " + set.getName() + " - " + card.getName() + " - " + card.getCardNumber());
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: must not use full art setting
|
||||||
|
if (!jsonCard.isFullArt && card.isFullArt()) {
|
||||||
|
errorsList.add("Error: card must NOT use full art setting: "
|
||||||
|
+ set.getCode() + " - " + set.getName() + " - " + card.getName() + " - " + card.getCardNumber());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: missing cards from set
|
||||||
|
for (MtgJsonSet jsonSet : MtgJsonService.sets().values()) {
|
||||||
|
if (skipListHaveName(SKIP_LIST_UNSUPPORTED_SETS, jsonSet.code)
|
||||||
|
|| skipListHaveName(SKIP_LIST_WRONG_CARD_NUMBERS, jsonSet.code)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpansionSet xmageSet = Sets.findSet(jsonSet.code);
|
||||||
|
if (xmageSet == null) {
|
||||||
|
warningsList.add("Warning: found un-implemented set from mtgjson database: " + jsonSet.code + " - " + jsonSet.name + " - " + jsonSet.releaseDate);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (MtgJsonCard jsonCard : jsonSet.cards) {
|
||||||
|
String code = jsonSet.code + " - " + jsonCard.name + " - " + jsonCard.number;
|
||||||
|
if (!foundedJsonCards.contains(code)) {
|
||||||
|
if (CardRepository.instance.findCard(jsonCard.name) == null) {
|
||||||
|
// ignore non-implemented cards
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
errorsList.add("Error: missing card from xmage's set: " + jsonSet.code + " - " + jsonCard.name + " - " + jsonCard.number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printMessages(warningsList);
|
||||||
|
printMessages(errorsList);
|
||||||
|
if (errorsList.size() > 0) {
|
||||||
|
Assert.fail("Found wrong cards data in sets, errors: " + errorsList.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Ignore // TODO: enable after all missing cards and settings fixes
|
||||||
|
public void test_checkMissingScryfallSettingsAndCardNumbers() {
|
||||||
Collection<String> errorsList = new ArrayList<>();
|
Collection<String> errorsList = new ArrayList<>();
|
||||||
|
|
||||||
Collection<ExpansionSet> xmageSets = Sets.getInstance().values();
|
Collection<ExpansionSet> xmageSets = Sets.getInstance().values();
|
||||||
Set<String> scryfallSets = ScryfallImageSupportCards.getSupportedSets();
|
Set<String> scryfallSets = ScryfallImageSupportCards.getSupportedSets();
|
||||||
|
|
||||||
// missing
|
// CHECK: missing sets in supported list
|
||||||
for (ExpansionSet set : xmageSets) {
|
for (ExpansionSet set : xmageSets) {
|
||||||
if (skipListHaveName(SKIP_LIST_SCRYFALL_DOWNLOAD_SETS, set.getCode())) {
|
if (skipListHaveName(SKIP_LIST_SCRYFALL_DOWNLOAD_SETS, set.getCode())) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -561,13 +639,64 @@ public class VerifyCardDataTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// unknown
|
// CHECK: unknown sets in supported list
|
||||||
for (String scryfallCode : scryfallSets) {
|
for (String scryfallCode : scryfallSets) {
|
||||||
if (xmageSets.stream().noneMatch(e -> e.getCode().equals(scryfallCode))) {
|
if (xmageSets.stream().noneMatch(e -> e.getCode().equals(scryfallCode))) {
|
||||||
errorsList.add("Error: scryfall download unknown setting: " + scryfallCode);
|
errorsList.add("Error: scryfall download unknown setting: " + scryfallCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// card numbers
|
||||||
|
// all cards with non-ascii numbers must be downloaded by direct links (api)
|
||||||
|
Set<String> foundedDirectDownloadKeys = new HashSet<>();
|
||||||
|
for (ExpansionSet set : xmageSets) {
|
||||||
|
if (skipListHaveName(SKIP_LIST_SCRYFALL_DOWNLOAD_SETS, set.getCode())
|
||||||
|
|| skipListHaveName(SKIP_LIST_WRONG_CARD_NUMBERS, set.getCode())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ExpansionSet.SetCardInfo card : set.getSetCardInfo()) {
|
||||||
|
MtgJsonCard jsonCard = MtgJsonService.cardFromSet(set.getCode(), card.getName(), card.getCardNumber());
|
||||||
|
if (jsonCard == null) {
|
||||||
|
// see convertMtgJsonToXmageCardNumber for card number convert notation
|
||||||
|
errorsList.add("Error: scryfall download can't find card from mtgjson " + set.getCode() + " - " + set.getName() + " - " + card.getName() + " - " + card.getCardNumber());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: non-ascii numbers and direct download list
|
||||||
|
if (!CharMatcher.ascii().matchesAllOf(jsonCard.number)) {
|
||||||
|
// non-ascii numbers
|
||||||
|
// xmage card numbers can't have non-ascii numbers (it checked by test_checkMissingCardData)
|
||||||
|
String key = ScryfallImageSupportCards.findDirectDownloadKey(set.getCode(), card.getName(), card.getCardNumber());
|
||||||
|
if (key != null) {
|
||||||
|
foundedDirectDownloadKeys.add(key);
|
||||||
|
} else {
|
||||||
|
errorsList.add("Error: scryfall download can't find non-ascii card link in direct download list " + set.getCode() + " - " + set.getName() + " - " + card.getName() + " - " + jsonCard.number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: unknown direct download links
|
||||||
|
for (Map.Entry<String, String> direct : ScryfallImageSupportCards.getDirectDownloadLinks().entrySet()) {
|
||||||
|
// skip custom sets
|
||||||
|
String setCode = ScryfallImageSupportCards.extractSetCodeFromDirectKey(direct.getKey());
|
||||||
|
String cardName = ScryfallImageSupportCards.extractCardNameFromDirectKey(direct.getKey());
|
||||||
|
if (skipListHaveName(SKIP_LIST_SCRYFALL_DOWNLOAD_SETS, setCode)
|
||||||
|
|| skipListHaveName(SKIP_LIST_WRONG_CARD_NUMBERS, setCode)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip non implemented cards list
|
||||||
|
if (CardRepository.instance.findCard(cardName) == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!foundedDirectDownloadKeys.contains(direct.getKey())) {
|
||||||
|
errorsList.add("Error: scryfall download found unknown direct download link " + direct.getKey() + " - " + direct.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
printMessages(errorsList);
|
printMessages(errorsList);
|
||||||
if (errorsList.size() > 0) {
|
if (errorsList.size() > 0) {
|
||||||
Assert.fail("Found scryfall download errors: " + errorsList.size());
|
Assert.fail("Found scryfall download errors: " + errorsList.size());
|
||||||
|
@ -646,12 +775,7 @@ public class VerifyCardDataTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CHECK: wrong basic lands settings (it's for lands search, not booster construct)
|
// CHECK: wrong basic lands settings (it's for lands search, not booster construct)
|
||||||
Map<String, Boolean> skipLandCheck = new HashMap<>();
|
|
||||||
for (ExpansionSet set : sets) {
|
for (ExpansionSet set : sets) {
|
||||||
if (skipLandCheck.containsKey(set.getName())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Boolean needLand = set.hasBasicLands();
|
Boolean needLand = set.hasBasicLands();
|
||||||
Boolean foundedLand = false;
|
Boolean foundedLand = false;
|
||||||
Map<String, Integer> foundLandsList = new HashMap<>();
|
Map<String, Integer> foundLandsList = new HashMap<>();
|
||||||
|
@ -983,53 +1107,13 @@ public class VerifyCardDataTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<String> findSourceTokens(Class c) throws IOException {
|
private void check(Card card, int cardIndex) {
|
||||||
if (!CHECK_SOURCE_TOKENS || BasicLand.class.isAssignableFrom(c)) {
|
MtgJsonCard ref = MtgJsonService.cardFromSet(card.getExpansionSetCode(), card.getName(), card.getCardNumber());
|
||||||
return null;
|
|
||||||
}
|
|
||||||
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<String> tokens = new HashSet<>();
|
|
||||||
while (matcher.find()) {
|
|
||||||
tokens.add(matcher.group());
|
|
||||||
}
|
|
||||||
return tokens;
|
|
||||||
} catch (NoSuchFileException e) {
|
|
||||||
System.out.println("failed to read " + path);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void check(Card card, Set<String> tokens, int cardIndex) {
|
|
||||||
MtgJsonCard ref = MtgJsonService.card(card.getName());
|
|
||||||
if (ref == null) {
|
if (ref == null) {
|
||||||
warn(card, "Missing card reference");
|
warn(card, "Missing card reference");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
checkAll(card, ref, cardIndex);
|
checkAll(card, ref, cardIndex);
|
||||||
if (tokens != null) {
|
|
||||||
MtgJsonCard ref2 = null;
|
|
||||||
if (card.isFlipCard()) {
|
|
||||||
ref2 = MtgJsonService.card(card.getFlipCardName());
|
|
||||||
}
|
|
||||||
for (String token : tokens) {
|
|
||||||
if (!(token.equals(card.getName())
|
|
||||||
|| containsInTypesOrText(ref, token)
|
|
||||||
|| containsInTypesOrText(ref, token.toLowerCase(Locale.ENGLISH))
|
|
||||||
|| (ref2 != null && (containsInTypesOrText(ref2, token) || containsInTypesOrText(ref2, token.toLowerCase(Locale.ENGLISH)))))) {
|
|
||||||
System.out.println("unexpected token " + token + " in " + card);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean containsInTypesOrText(MtgJsonCard ref, String token) {
|
|
||||||
return contains(ref.types, token)
|
|
||||||
|| contains(ref.subtypes, token)
|
|
||||||
|| contains(ref.supertypes, token)
|
|
||||||
|| ref.text.contains(token);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean contains(Collection<String> options, String value) {
|
private boolean contains(Collection<String> options, String value) {
|
||||||
|
@ -1043,7 +1127,6 @@ public class VerifyCardDataTest {
|
||||||
checkSupertypes(card, ref);
|
checkSupertypes(card, ref);
|
||||||
checkTypes(card, ref);
|
checkTypes(card, ref);
|
||||||
checkColors(card, ref);
|
checkColors(card, ref);
|
||||||
//checkNumbers(card, ref); // TODO: load data from AllPrintings.json and check it (allcards.json do not have card numbers)
|
|
||||||
checkBasicLands(card, ref);
|
checkBasicLands(card, ref);
|
||||||
checkMissingAbilities(card, ref);
|
checkMissingAbilities(card, ref);
|
||||||
checkWrongSymbolsInRules(card);
|
checkWrongSymbolsInRules(card);
|
||||||
|
@ -1085,7 +1168,7 @@ public class VerifyCardDataTest {
|
||||||
// fix names (e.g. Urza’s to Urza's)
|
// fix names (e.g. Urza’s to Urza's)
|
||||||
if (expected != null && expected.contains("Urza’s")) {
|
if (expected != null && expected.contains("Urza’s")) {
|
||||||
expected = new ArrayList<>(expected);
|
expected = new ArrayList<>(expected);
|
||||||
for (ListIterator<String> it = ((List<String>) expected).listIterator(); it.hasNext();) {
|
for (ListIterator<String> it = ((List<String>) expected).listIterator(); it.hasNext(); ) {
|
||||||
if (it.next().equals("Urza’s")) {
|
if (it.next().equals("Urza’s")) {
|
||||||
it.set("Urza's");
|
it.set("Urza's");
|
||||||
}
|
}
|
||||||
|
@ -1333,9 +1416,11 @@ public class VerifyCardDataTest {
|
||||||
boolean isFine = true;
|
boolean isFine = true;
|
||||||
for (int i = 0; i <= cardRules.length - 1; i++) {
|
for (int i = 0; i <= cardRules.length - 1; i++) {
|
||||||
boolean isAbilityFounded = false;
|
boolean isAbilityFounded = false;
|
||||||
for (String refRule : refRules) {
|
for (int j = 0; j <= refRules.length - 1; j++) {
|
||||||
|
String refRule = refRules[j];
|
||||||
if (cardRules[i].equals(refRule)) {
|
if (cardRules[i].equals(refRule)) {
|
||||||
cardRules[i] = "+ " + cardRules[i];
|
cardRules[i] = "+ " + cardRules[i];
|
||||||
|
refRules[j] = "+ " + refRules[j];
|
||||||
isAbilityFounded = true;
|
isAbilityFounded = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1348,6 +1433,14 @@ public class VerifyCardDataTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mark ref rules as unknown
|
||||||
|
for (int j = 0; j <= refRules.length - 1; j++) {
|
||||||
|
String refRule = refRules[j];
|
||||||
|
if (!refRule.startsWith("+ ")) {
|
||||||
|
refRules[j] = "- " + refRules[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// extra message for easy checks
|
// extra message for easy checks
|
||||||
if (!isFine) {
|
if (!isFine) {
|
||||||
System.out.println();
|
System.out.println();
|
||||||
|
@ -1361,7 +1454,7 @@ public class VerifyCardDataTest {
|
||||||
System.out.println("ref:");
|
System.out.println("ref:");
|
||||||
Arrays.sort(refRules);
|
Arrays.sort(refRules);
|
||||||
for (String s : refRules) {
|
for (String s : refRules) {
|
||||||
System.out.println(" " + s);
|
System.out.println(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
System.out.println();
|
System.out.println();
|
||||||
|
|
|
@ -77,6 +77,12 @@ public abstract class ExpansionSet implements Serializable {
|
||||||
public CardGraphicInfo getGraphicInfo() {
|
public CardGraphicInfo getGraphicInfo() {
|
||||||
return this.graphicInfo;
|
return this.graphicInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isFullArt() {
|
||||||
|
return this.graphicInfo != null
|
||||||
|
&& this.graphicInfo.getFrameStyle() != null
|
||||||
|
&& this.graphicInfo.getFrameStyle().isFullArt();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final List<SetCardInfo> cards = new ArrayList<>();
|
protected final List<SetCardInfo> cards = new ArrayList<>();
|
||||||
|
|
Loading…
Reference in a new issue