Merge pull request #70 from magefree/master

Merge https://github.com/magefree/mage
This commit is contained in:
L_J 2018-08-26 22:32:05 +02:00 committed by GitHub
commit 609cb2286b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2212 changed files with 47208 additions and 9150 deletions

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.30</version>
<version>1.4.31</version>
</parent>
<groupId>org.mage</groupId>

View file

@ -0,0 +1,86 @@
1 [C18:61] Ajani's Chosen
1 [C18:81] Archetype of Imagination
1 [C18:38] Arixmethes, Slumbering Isle
1 [C18:128] Aura Gnarlid
1 [C18:233] Azorius Chancery
1 [C18:169] Bant Charm
1 [C18:131] Bear Umbra
1 [C18:237] Blossoming Sands
1 [C18:132] Boon Satyr
1 [C18:170] Bruna, Light of Alabaster
1 [C18:64] Celestial Archon
1 [C18:172] Cold-Eyed Selkie
1 [C18:240] Command Tower
1 [C18:137] Creeping Renaissance
1 [C18:139] Dawn's Reflection
1 [C18:173] Daxos of Meletis
1 [C18:86] Dictate of Kruphix
1 [C18:66] Dismantling Blow
1 [C18:89] Eel Umbra
1 [C18:140] Eidolon of Blossoms
1 [C18:177] Elderwood Scion
1 [C18:2] Empyrial Storm
1 [C18:141] Enchantress's Presence
1 [C18:142] Epic Proportions
1 [C18:8] Estrid's Invocation
1 [C18:9] Ever-Watching Threshold
1 [C18:245] Evolving Wilds
1 [C18:147] Fertile Ground
1 [C18:180] Finest Hour
1 [C18:58] Forge of Heroes
1 [C18:30] Genesis Storm
1 [C18:149] Ground Seal
1 [C18:3] Heavenly Blademaster
1 [C18:151] Herald of the Pantheon
1 [C18:153] Hydra Omnivore
1 [C18:42] Kestia, the Cultivator
1 [C18:263] Krosan Verge
1 [C18:155] Kruphix's Insight
1 [C18:10] Loyal Drake
1 [C18:31] Loyal Guardian
1 [C18:4] Loyal Unicorn
1 [C18:69] Martial Coup
1 [C18:265] Meandering River
1 [C18:267] Mosswort Bridge
1 [C18:32] Myth Unbound
1 [C18:33] Nylea's Colossus
1 [C18:11] Octopus Umbra
1 [C18:157] Overgrowth
1 [C18:70] Phyrexian Rebirth
1 [C18:34] Ravenous Slime
1 [C18:159] Reclamation Sage
1 [C18:188] Righteous Authority
1 [C18:72] Sage's Reverie
1 [C18:277] Seaside Citadel
1 [C18:281] Selesnya Sanctuary
1 [C18:74] Sigil of the Empty Throne
1 [C18:75] Silent Sentinel
1 [C18:282] Simic Growth Chamber
1 [C18:162] Snake Umbra
1 [C18:222] Sol Ring
1 [C18:76] Soul Snare
1 [C18:163] Spawning Grounds
1 [C18:286] Terramorphic Expanse
1 [C18:287] Thornwood Falls
1 [C18:288] Tranquil Cove
1 [C18:289] Tranquil Expanse
1 [C18:47] Tuvasa the Sunlit
1 [C18:192] Unflinching Courage
1 [C18:78] Unquestioned Authority
1 [C18:110] Vow of Flight
1 [C18:164] Vow of Wildness
1 [C18:112] Whitewater Naiads
1 [C18:165] Wild Growth
1 [C18:79] Winds of Rath
1 [C18:292] Woodland Stream
1 [C18:167] Yavimaya Enchantress
2 [C18:307] Forest
2 [C18:296] Island
2 [C18:297] Island
2 [C18:298] Island
3 [C18:305] Forest
3 [C18:306] Forest
3 [C18:293] Plains
3 [C18:294] Plains
3 [C18:295] Plains
SB:1 [C18:40] Estrid, the Masked

View file

@ -0,0 +1,79 @@
1 [C18:197] Blinkmoth Urn
1 [C18:92] Into the Roil
1 [C18:230] Worn Powerstone
1 [C18:91] Inkwell Leviathan
1 [C18:199] Chief of the Foundry
1 [C18:90] Etherium Sculptor
1 [C18:111] Whirler Rogue
1 [C18:198] Bosh, Iron Golem
1 [C18:278] Seat of the Synod
1 [C18:58] Forge of Heroes
1 [C18:57] Retrofitter Foundry
1 [C18:13] Vedalken Humiliator
1 [C18:56] Geode Golem
1 [C18:55] Endless Atlas
1 [C18:99] Reverse Engineer
1 [C18:54] Coveted Jewel
1 [C18:10] Loyal Drake
1 [C18:53] Ancient Stone Idol
1 [C18:239] Buried Ruin
1 [C18:185] Maverick Thopterist
1 [C18:100] Saheeli's Artistry
1 [C18:223] Soul of New Phyrexia
1 [C18:27] Treasure Nabber
1 [C18:26] Saheeli's Directive
1 [C18:101] Sharding Sphinx
1 [C18:222] Sol Ring
1 [C18:225] Swiftfoot Boots
4 [C18:302] Mountain
1 [C18:224] Steel Hellkite
1 [C18:23] Loyal Apprentice
1 [C18:106] Thirst for Knowledge
1 [C18:227] Unstable Obelisk
4 [C18:304] Mountain
1 [C18:226] Thopter Assembly
4 [C18:303] Mountain
1 [C18:21] Enchanter's Bane
1 [C18:108] Tidings
1 [C18:229] Vessel of Endless Rest
1 [C18:107] Thopter Spy Network
1 [C18:228] Unwinding Clock
1 [C18:28] Varchild, Betrayer of Kjeldor
1 [C18:250] Great Furnace
5 [C18:296] Island
1 [C18:210] Mind Stone
5 [C18:298] Island
5 [C18:297] Island
1 [C18:256] Izzet Boilerworks
1 [C18:212] Myr Battlesphere
1 [C18:255] Highland Lake
1 [C18:211] Mirrorworks
1 [C18:214] Pilgrim's Eye
1 [C18:257] Izzet Guildgate
1 [C18:216] Prototype Portal
1 [C18:215] Prismatic Lens
1 [C18:218] Scrabbling Claws
1 [C18:217] Psychosis Crawler
1 [C18:219] Scuttling Doom Engine
1 [C18:7] Echo Storm
1 [C18:39] Brudiclad, Telchor Engineer
1 [C18:120] Blasphemous Act
1 [C18:241] Darksteel Citadel
1 [C18:80] Aether Gale
1 [C18:240] Command Tower
1 [C18:284] Swiftwater Cliffs
1 [C18:122] Chaos Warp
1 [C18:124] Hellkite Igniter
1 [C18:200] Commander's Sphere
1 [C18:126] Thopter Engineer
1 [C18:202] Darksteel Juggernaut
1 [C18:125] Magmaquake
1 [C18:205] Duplicant
1 [C18:45] Tawnos, Urza's Apprentice
1 [C18:204] Dreamstone Hedron
1 [C18:248] Foundry of the Consuls
1 [C18:207] Izzet Signet
1 [C18:206] Hedron Archive
1 [C18:209] Mimic Vat
1 [C18:208] Magnifying Glass
SB: 1 [C18:44] Saheeli, the Gifted

View file

@ -0,0 +1,91 @@
1 [C18:114] Moonlight Bargain
1 [C18:116] Retreat to Hagra
1 [C18:117] Ruinous Path
1 [C18:118] Soul of Innistrad
1 [C18:119] Stitch Together
1 [C18:121] Chain Reaction
1 [C18:123] Flameblast Dragon
1 [C18:127] Acidic Slime
1 [C18:129] Avenger of Zendikar
1 [C18:130] Baloth Woodcrasher
1 [C18:133] Borderland Explorer
1 [C18:134] Budoka Gardener
1 [C18:135] Centaur Vinecrasher
1 [C18:136] Consign to Dust
1 [C18:138] Cultivate
1 [C18:143] Explore
1 [C18:144] Explosive Vegetation
1 [C18:145] Far Wanderings
1 [C18:146] Farhaven Elf
1 [C18:148] Grapple with the Past
1 [C18:14] Bloodtracker
1 [C18:150] Harrow
1 [C18:152] Hunting Wilds
1 [C18:154] Khalni Heart Expedition
1 [C18:156] Moldgraf Monstrosity
1 [C18:158] Rampaging Baloths
1 [C18:160] Sakura-Tribe Elder
1 [C18:161] Scute Mob
1 [C18:166] Yavimaya Elder
1 [C18:16] Loyal Subordinate
1 [C18:171] Charnelhoard Wurm
1 [C18:174] Deathreap Ritual
1 [C18:175] Decimate
1 [C18:181] Gaze of Granite
1 [C18:182] Grisly Salvage
1 [C18:184] Lavalanche
1 [C18:187] Putrefy
1 [C18:189] Rubblehulk
1 [C18:190] Savage Twister
1 [C18:194] Worm Harvest
1 [C18:195] Zendikar Incarnate
1 [C18:221] Seer's Sundial
1 [C18:222] Sol Ring
1 [C18:22] Fury Storm
1 [C18:231] Akoum Refuge
1 [C18:235] Barren Moor
1 [C18:236] Blighted Woodland
1 [C18:238] Bojuka Bog
1 [C18:23] Loyal Apprentice
1 [C18:240] Command Tower
1 [C18:245] Evolving Wilds
1 [C18:246] Forgotten Cave
1 [C18:249] Golgari Rot Farm
1 [C18:24] Nesting Dragon
1 [C18:251] Grim Backwoods
1 [C18:252] Gruul Turf
1 [C18:254] Haunted Fengraf
1 [C18:258] Jund Panorama
1 [C18:259] Jungle Hollow
1 [C18:25] Reality Scramble
1 [C18:261] Kazandu Refuge
1 [C18:262] Khalni Garden
1 [C18:268] Mountain Valley
1 [C18:269] Myriad Landscape
1 [C18:273] Rakdos Carnarium
1 [C18:274] Rocky Tar Pit
1 [C18:275] Savage Lands
1 [C18:285] Temple of the False God
1 [C18:286] Terramorphic Expanse
1 [C18:290] Tranquil Thicket
1 [C18:29] Crash of Rhino Beetles
1 [C18:31] Loyal Guardian
1 [C18:35] Turntimber Sower
1 [C18:36] Whiptongue Hydra
1 [C18:41] Gyrus, Waker of Corpses
1 [C18:49] Windgrace's Judgment
1 [C18:58] Forge of Heroes
1 [C18:20] Emissary of Grudges
1 [C18:46] Thantis, the Warweaver
1 [C18:291] Warped Landscape
1 [C18:50] Xantcha, Sleeper Agent
2 [C18:299] Swamp
2 [C18:300] Swamp
2 [C18:301] Swamp
2 [C18:302] Mountain
2 [C18:303] Mountain
1 [C18:304] Mountain
2 [C18:306] Forest
2 [C18:307] Forest
3 [C18:305] Forest
SB: 1 [C18:43] Lord Windgrace

View file

@ -0,0 +1,93 @@
1 [C18:102] Sigiled Starfish
1 [C18:103] Sphinx of Jwar Isle
1 [C18:104] Sphinx of Uthuun
1 [C18:105] Telling Time
1 [C18:109] Treasure Hunt
1 [C18:113] Army of the Damned
1 [C18:115] Phyrexian Delver
1 [C18:12] Primordial Mist
1 [C18:15] Entreat the Dead
1 [C18:168] Aethermage's Touch
1 [C18:16] Loyal Subordinate
1 [C18:176] Duskmantle Seer
1 [C18:178] Enigma Sphinx
1 [C18:179] Esper Charm
1 [C18:17] Night Incarnate
1 [C18:183] High Priest of Penance
1 [C18:186] Mortify
1 [C18:18] Skull Storm
1 [C18:191] Silent-Blade Oni
1 [C18:193] Utter End
1 [C18:196] Azorius Signet
1 [C18:19] Sower of Discord
1 [C18:1] Boreas Charger
1 [C18:200] Commander's Sphere
1 [C18:201] Crystal Ball
1 [C18:203] Dimir Signet
1 [C18:210] Mind Stone
1 [C18:213] Orzhov Signet
1 [C18:214] Pilgrim's Eye
1 [C18:220] Seer's Lantern
1 [C18:222] Sol Ring
1 [C18:232] Arcane Sanctum
1 [C18:233] Azorius Chancery
1 [C18:234] Azorius Guildgate
1 [C18:235] Barren Moor
1 [C18:240] Command Tower
1 [C18:242] Dimir Aqueduct
1 [C18:243] Dimir Guildgate
1 [C18:244] Dismal Backwater
1 [C18:247] Forsaken Sanctuary
1 [C18:253] Halimar Depths
1 [C18:260] Jwar Isle Refuge
1 [C18:264] Lonely Sandbar
1 [C18:265] Meandering River
1 [C18:266] Mortuary Mire
1 [C18:270] New Benalia
1 [C18:271] Orzhov Basilica
1 [C18:272] Orzhov Guildgate
1 [C18:276] Scoured Barrens
1 [C18:279] Secluded Steppe
1 [C18:280] Sejiri Refuge
1 [C18:283] Submerged Boneyard
1 [C18:48] Varina, Lich Queen
1 [C18:4] Loyal Unicorn
1 [C18:56] Geode Golem
1 [C18:58] Forge of Heroes
1 [C18:59] Isolated Watchtower
1 [C18:5] Magus of the Balance
1 [C18:60] Adarkar Valkyrie
1 [C18:62] Akroma's Vengeance
1 [C18:63] Banishing Stroke
1 [C18:65] Crib Swap
1 [C18:67] Entreat the Angels
1 [C18:68] Lightform
1 [C18:71] Return to Dust
1 [C18:73] Serra Avatar
1 [C18:77] Terminus
1 [C18:82] Brainstorm
1 [C18:83] Cloudform
1 [C18:84] Conundrum Sphinx
1 [C18:85] Devastation Tide
1 [C18:87] Djinn of Wishes
1 [C18:88] Dream Cache
1 [C18:93] Jeskai Infiltrator
1 [C18:94] Mulldrifter
1 [C18:95] Ninja of the Deep Hours
1 [C18:96] Ponder
1 [C18:97] Portent
1 [C18:98] Predict
1 [C18:298] Island
1 [C18:299] Swamp
1 [C18:300] Swamp
1 [C18:301] Swamp
1 [C18:006] Aminatou's Augury
1 [C18:288] Tranquil Cove
1 [C18:51] Yennett, Cryptic Sovereign
1 [C18:52] Yuriko, the Tiger's Shadow
2 [C18:296] Island
2 [C18:297] Island
2 [C18:295] Plains
3 [C18:293] Plains
3 [C18:294] Plains
SB: 1 [C18:37] Aminatou, the Fateshifter

View file

@ -1083,10 +1083,10 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
}
repaint();
}
private void chooseMatching() {
Collection<CardView> toMatch = dragCardList();
for (DragCardGridListener l : listeners) {
for (CardView card : allCards) {
for (CardView aMatch : toMatch) {
@ -1337,6 +1337,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
public void analyseDeck() {
HashMap<String, Integer> qtys = new HashMap<>();
HashMap<String, Integer> pips = new HashMap<>();
HashMap<String, Integer> pips_at_cmcs = new HashMap<>();
HashMap<String, Integer> sourcePips = new HashMap<>();
HashMap<String, Integer> manaCounts = new HashMap<>();
pips.put("#w}", 0);
@ -1396,11 +1397,40 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
}
mc = mc.replaceAll("\\{([WUBRG]).([WUBRG])\\}", "{$1}{$2}");
mc = mc.replaceAll("\\{", "#");
mc = mc.replaceAll("#2\\/", "#");
mc = mc.replaceAll("p}", "}");
mc = mc.toLowerCase(Locale.ENGLISH);
int cmc = card.getConvertedManaCost();
// Do colorless mana pips
Pattern regex = Pattern.compile("#([0-9]+)}");
Matcher regexMatcher = regex.matcher(mc);
while (regexMatcher.find()) {
String val = regexMatcher.group(1);
int colorless_val = Integer.parseInt(val);
int total_c_pip = 0;
if (pips.get("#c}") != null) {
total_c_pip = pips.get("#c}");
}
pips.put("#c}", colorless_val + total_c_pip);
int cmc_pip_value = 0;
if (pips_at_cmcs.get(cmc + "##c}") != null) {
cmc_pip_value = pips_at_cmcs.get(cmc + "##c}");
}
pips_at_cmcs.put(cmc + "##c}", colorless_val + cmc_pip_value);
}
for (String pip : pips.keySet()) {
int value = pips.get(pip);
while (mc.toLowerCase(Locale.ENGLISH).contains(pip)) {
pips.put(pip, ++value);
int pip_value = 0;
if (pips_at_cmcs.get(cmc + "#" + pip) != null) {
pip_value = pips_at_cmcs.get(cmc + "#" + pip);
}
pips_at_cmcs.put(cmc + "#" + pip, ++pip_value);
mc = mc.replaceFirst(pip, "");
}
}
@ -1448,9 +1478,17 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
panel4.add(new JLabel("Mana sources found:"));
panel4.add(chart3);
JPanel panel5 = new JPanel();
panel5.setLayout(new BoxLayout(panel5, BoxLayout.Y_AXIS));
ManaBarChart chart4 = new ManaBarChart(pips_at_cmcs);
chart4.setMinimumSize(new Dimension(200, 200));
panel5.add(new JLabel("Mana distribution:"));
panel5.add(chart4);
panel.add(panel2);
panel.add(panel3);
panel.add(panel4);
panel.add(panel5);
JFrame frame = new JFrame("JOptionPane showMessageDialog component example");
JOptionPane.showMessageDialog(frame, panel, "This is the distribution of colors found", JOptionPane.INFORMATION_MESSAGE);
@ -1719,7 +1757,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
JMenuItem invertSelection = new JMenuItem("Invert Selection");
invertSelection.addActionListener(e2 -> invertSelection());
menu.add(invertSelection);
JMenuItem chooseMatching = new JMenuItem("Choose Matching");
chooseMatching.addActionListener(e2 -> chooseMatching());
menu.add(chooseMatching);

View file

@ -0,0 +1,151 @@
package mage.client.cards;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.awt.geom.Rectangle2D;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.JComponent;
public class ManaBarChart extends JComponent {
HashMap<String, Integer> pips_at_cmcs = new HashMap<String, Integer>();
ManaBarChart() {
}
ManaBarChart(HashMap<String, Integer> pips_at_cmcs) {
this.pips_at_cmcs = pips_at_cmcs;
}
@Override
public Dimension getPreferredSize() {
Dimension preferred = super.getPreferredSize();
Dimension minimum = getMinimumSize();
Dimension maximum = getMaximumSize();
preferred.width = Math.min(Math.max(preferred.width, minimum.width), maximum.width);
preferred.height = Math.min(Math.max(preferred.height, minimum.height), maximum.height);
return preferred;
}
public void paint(Graphics g) {
drawBar((Graphics2D) g, getBounds());
}
void drawBar(Graphics2D g, Rectangle area) {
Pattern regex = Pattern.compile("^([0-9]+)##(.)}");
HashMap<Integer, Integer> totals_at_cmcs = new HashMap<Integer, Integer>();
int max_num_pips = 0;
int max_cmc = 0;
for (String key : pips_at_cmcs.keySet()) {
Matcher regexMatcher = regex.matcher(key);
int num_pips = pips_at_cmcs.get(key);
while (regexMatcher.find()) {
String cmc = regexMatcher.group(1);
int cmc_num = Integer.parseInt(cmc);
if (max_cmc < cmc_num) {
max_cmc = cmc_num;
}
int total_at_cmc = 0;
if (totals_at_cmcs.get(cmc_num) != null) {
total_at_cmc = totals_at_cmcs.get(cmc_num);
}
totals_at_cmcs.put(cmc_num, total_at_cmc + num_pips);
if (max_num_pips < total_at_cmc + num_pips) {
max_num_pips = total_at_cmc + num_pips;
}
}
}
if (max_num_pips <= 0) {
max_num_pips = 1;
}
int height_factor = 200 / max_num_pips;
int width_factor = 200 / (max_cmc + 2);
if (width_factor > 20) {
width_factor = 20;
}
if (width_factor < 11) {
width_factor = 11;
}
g.setColor(new Color(130, 130, 130));
for (int i = 0; i < max_num_pips; i++) {
if (max_num_pips > 10) {
if (i % 10 == 0) {
g.drawLine(0, 200 - 1 - i * height_factor, 400, 200 - 1 - i * height_factor);
} else if (i % 10 == 5) {
Stroke dashed = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, new float[]{5}, 0);
Stroke oldstroke = g.getStroke();
g.setStroke(dashed);
g.drawLine(0, 200 - 1 - i * height_factor, 400, 200 - 1 - i * height_factor);
g.setStroke(oldstroke);
}
} else if (i % 2 == 0) {
g.drawLine(0, 200 - 1 - i * height_factor, 400, 200 - 1 - i * height_factor);
} else if (i % 2 == 1) {
Stroke dashed = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, new float[]{5}, 0);
Stroke oldstroke = g.getStroke();
g.setStroke(dashed);
g.drawLine(0, 200 - 1 - i * height_factor, 400, 200 - 1 - i * height_factor);
g.setStroke(oldstroke);
}
}
for (int i = 0; i < 17; i++) {
if (i % 5 == 0) {
g.drawLine(width_factor * i, 200, width_factor * i, 190);
} else {
g.drawLine(width_factor * i, 200, width_factor * i, 195);
}
}
HashMap<Integer, Integer> running_totals_at_cmcs = new HashMap<Integer, Integer>();
for (String key : pips_at_cmcs.keySet()) {
Matcher regexMatcher = regex.matcher(key);
int num_pips = pips_at_cmcs.get(key);
while (regexMatcher.find()) {
String cmc = regexMatcher.group(1);
int cmc_num = Integer.parseInt(cmc);
String color = regexMatcher.group(2);
int total_at_cmc = 0;
if (running_totals_at_cmcs.get(cmc_num) != null) {
total_at_cmc = running_totals_at_cmcs.get(cmc_num);
}
if (color.equalsIgnoreCase("w")) {
g.setColor(Color.WHITE);
}
if (color.equalsIgnoreCase("u")) {
g.setColor(Color.BLUE);
}
if (color.equalsIgnoreCase("b")) {
g.setColor(Color.BLACK);
}
if (color.equalsIgnoreCase("r")) {
g.setColor(Color.RED);
}
if (color.equalsIgnoreCase("g")) {
g.setColor(Color.GREEN);
}
if (color.equalsIgnoreCase("c")) {
g.setColor(Color.DARK_GRAY);
}
g.fill(new Rectangle2D.Double(cmc_num * width_factor, 200 - 1 - total_at_cmc - num_pips * height_factor, 10, num_pips * height_factor));
running_totals_at_cmcs.put(cmc_num, total_at_cmc + num_pips * height_factor);
}
}
}
}

View file

@ -325,6 +325,7 @@ public class DeckGeneratorDialog {
// Generated deck has a nice unique name which corresponds to the timestamp at which it was created.
String deckName = "Generated-Deck-" + dateFormat.format(new Date());
File tmp = new File(tempDir + File.separator + deckName + ".dck");
tmp.getParentFile().mkdirs();
tmp.createNewFile();
deck.setName(deckName);
Sets.saveDeck(tmp.getAbsolutePath(), deck.getDeckCardLists());

View file

@ -341,7 +341,7 @@
<Image iconType="3" name="/flags/us.png"/>
</Property>
<Property name="text" type="java.lang.String" value="W"/>
<Property name="toolTipText" type="java.lang.String" value="Connect to xmage.us (USA)"/>
<Property name="toolTipText" type="java.lang.String" value="Connect to vaporservermtg.com (USA)"/>
<Property name="actionCommand" type="java.lang.String" value="connectXmageus"/>
<Property name="alignmentY" type="float" value="0.0"/>
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">

View file

@ -1,6 +1,4 @@
/*
/*
* ConnectDialog.java
*
* Created on 20-Jan-2010, 9:37:07 PM
@ -17,7 +15,6 @@ import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.io.Writer;
import java.io.Closeable;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.SocketException;
@ -273,8 +270,8 @@ public class ConnectDialog extends MageDialog {
});
btnFind3.setIcon(new javax.swing.ImageIcon(getClass().getResource("/flags/us.png"))); // NOI18N
btnFind3.setText("U");
btnFind3.setToolTipText("Connect to xmage.us (USA)");
btnFind3.setText("W");
btnFind3.setToolTipText("Connect to vaporservermtg.com (USA)");
btnFind3.setActionCommand("connectXmageus");
btnFind3.setAlignmentY(0.0F);
btnFind3.setMargin(new java.awt.Insets(2, 2, 2, 2));
@ -646,7 +643,6 @@ public class ConnectDialog extends MageDialog {
}
}//GEN-LAST:event_jButton1ActionPerformed
private void jProxySettingsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jProxySettingsButtonActionPerformed
PreferencesDialog.main(new String[]{PreferencesDialog.OPEN_CONNECTION_TAB});
}//GEN-LAST:event_jProxySettingsButtonActionPerformed
@ -691,54 +687,54 @@ public class ConnectDialog extends MageDialog {
}//GEN-LAST:event_btnFind2findPublicServerActionPerformed
private void connectXmageus(java.awt.event.ActionEvent evt) {
String serverAddress = "xmage.us";
private void connectXmageus(java.awt.event.ActionEvent evt) {
String serverAddress = "vapormtgserver.com";
this.txtServer.setText(serverAddress);
this.txtPort.setText("17171");
// Update userName and password according to the chosen server.
this.txtUserName.setText(MagePreferences.getUserName(serverAddress));
this.txtPassword.setText(MagePreferences.getPassword(serverAddress));
}
}
private void btnFlagSearchActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnFlagSearchActionPerformed
doFastFlagSearch();
}//GEN-LAST:event_btnFlagSearchActionPerformed
private void doFastFlagSearch(){
private void doFastFlagSearch() {
Choice choice = new ChoiceImpl(false);
// collect data from country combobox String[name][code]
Map<String, String> choiceItems = new LinkedHashMap<>();
DefaultComboBoxModel flagModel = (DefaultComboBoxModel)cbFlag.getModel();
DefaultComboBoxModel flagModel = (DefaultComboBoxModel) cbFlag.getModel();
String[] flagItem;
for(int i = 0; i < flagModel.getSize(); i++){
flagItem = (String[])flagModel.getElementAt(i);
for (int i = 0; i < flagModel.getSize(); i++) {
flagItem = (String[]) flagModel.getElementAt(i);
choiceItems.put(flagItem[1], flagItem[0]);
}
choice.setKeyChoices(choiceItems);
choice.setMessage("Select your country");
// current selection value restore
String needSelectValue = null;
flagItem = (String[])flagModel.getSelectedItem();
if (flagItem != null){
needSelectValue = flagItem[1];
flagItem = (String[]) flagModel.getSelectedItem();
if (flagItem != null) {
needSelectValue = flagItem[1];
}
// ask for new value
PickChoiceDialog dlg = new PickChoiceDialog();
dlg.setWindowSize(300, 500);
dlg.showDialog(choice, needSelectValue);
if(choice.isChosen()){
if (choice.isChosen()) {
flagItem = new String[2];
flagItem[0] = choice.getChoiceValue();
flagItem[1] = choice.getChoiceKey();
flagModel.setSelectedItem(flagItem);
flagItem[1] = choice.getChoiceKey();
flagModel.setSelectedItem(flagItem);
}
}
public String getServer() {
return this.txtServer.getText();
}

View file

@ -9,6 +9,8 @@ package mage.client.table;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyVetoException;
import java.io.File;
import java.text.DateFormat;
@ -316,6 +318,20 @@ public class TablesPanel extends javax.swing.JPanel {
actionButton1 = new ButtonColumn(tableTables, openTableAction, tableTables.convertColumnIndexToView(TableTableModel.ACTION_COLUMN));
actionButton2 = new ButtonColumn(tableCompleted, closedTableAction, tableCompleted.convertColumnIndexToView(MatchesTableModel.COLUMN_ACTION));
// !!!!
addTableDoubleClickListener(tableTables, openTableAction);
addTableDoubleClickListener(tableCompleted, closedTableAction);
}
private void addTableDoubleClickListener(JTable table, Action action) {
table.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
int row = table.rowAtPoint(e.getPoint());
if (e.getClickCount() == 2 && row != -1) {
action.actionPerformed(new ActionEvent(e.getSource(), e.getID(), "" + row));
}
}
});
}
public void cleanUp() {

View file

@ -11,7 +11,7 @@ import mage.view.CardView;
*/
public class CardViewEDHPowerLevelComparator implements Comparator<CardView> {
public int getPowerLevel(CardView card) {
private int getPowerLevel(CardView card) {
int thisMaxPower = 0;
@ -306,7 +306,7 @@ public class CardViewEDHPowerLevelComparator implements Comparator<CardView> {
thisMaxPower = Math.max(thisMaxPower, 1);
}
if (card.getCardTypes().contains("Plainswalker")) {
if (card.isPlanesWalker()) {
if (card.getName().toLowerCase(Locale.ENGLISH).equals("jace, the mind sculptor")) {
thisMaxPower = Math.max(thisMaxPower, 6);
}
@ -509,7 +509,7 @@ public class CardViewEDHPowerLevelComparator implements Comparator<CardView> {
@Override
public int compare(CardView o1, CardView o2) {
return Integer.valueOf(getPowerLevel(o1)).compareTo(getPowerLevel(o2));
return Integer.compare(getPowerLevel(o1), getPowerLevel(o2));
}
}

View file

@ -57,6 +57,7 @@ public final class SaveObjectUtil {
String time = now(DATE_PATTERN);
File f = new File("income" + File.separator + name + '_' + time + ".save");
if (!f.exists()) {
f.getParentFile().mkdirs();
f.createNewFile();
}
oos = new ObjectOutputStream(new FileOutputStream(f));

View file

@ -37,6 +37,7 @@ import java.util.regex.Pattern;
import java.util.stream.IntStream;
import javax.imageio.ImageIO;
import javax.swing.*;
import mage.cards.repository.ExpansionRepository;
import mage.client.MageFrame;
import mage.client.constants.Constants;
@ -56,6 +57,8 @@ import org.apache.batik.util.SVGConstants;
import org.apache.log4j.Logger;
import org.mage.plugins.card.utils.CardImageUtils;
import static org.mage.plugins.card.utils.CardImageUtils.getImagesDir;
public final class ManaSymbols {
private static final Logger LOGGER = Logger.getLogger(ManaSymbols.class);
@ -79,21 +82,59 @@ public final class ManaSymbols {
withoutSymbols.add("MPRP");
}
private static final Map<String, Dimension> setImagesExist = new HashMap<>();
private static final Pattern REPLACE_SYMBOLS_PATTERN = Pattern.compile("\\{([^}/]*)/?([^}]*)\\}");
private static final String[] symbols = new String[]{"0", "1", "10", "11", "12", "15", "16", "2", "3", "4", "5", "6", "7", "8", "9",
"B", "BG", "BR", "BP", "2B",
"G", "GU", "GW", "GP", "2G",
"R", "RG", "RW", "RP", "2R",
"S", "T",
"U", "UB", "UR", "UP", "2U",
"W", "WB", "WU", "WP", "2W",
"X", "C", "E"};
"B", "BG", "BR", "BP", "2B",
"G", "GU", "GW", "GP", "2G",
"R", "RG", "RW", "RP", "2R",
"S", "T",
"U", "UB", "UR", "UP", "2U",
"W", "WB", "WU", "WP", "2W",
"X", "C", "E"};
private static final JLabel labelRender = new JLabel(); // render mana text
private static String getSvgPathToCss() {
return getImagesDir() + File.separator + "temp" + File.separator + "batic-svg-settings.css";
}
private static void prepareSvg(Boolean forceToCreateCss) {
File f = new File(getSvgPathToCss());
if (forceToCreateCss || !f.exists()) {
// Rendering hints can't be set programatically, so
// we override defaults with a temporary stylesheet.
// These defaults emphasize quality and precision, and
// are more similar to the defaults of other SVG viewers.
// SVG documents can still override these defaults.
String css = "svg {"
+ "shape-rendering: geometricPrecision;"
+ "text-rendering: geometricPrecision;"
+ "color-rendering: optimizeQuality;"
+ "image-rendering: optimizeQuality;"
+ "}";
FileWriter w = null;
try {
f.getParentFile().mkdirs();
f.createNewFile();
w = new FileWriter(f);
w.write(css);
} catch (Throwable e) {
LOGGER.error("Can't create css file for svg", e);
} finally {
StreamUtils.closeQuietly(w);
}
}
}
public static void loadImages() {
LOGGER.info("Loading symbols...");
// TODO: delete files rename jpg->gif (it was for backward compatibility for one of the old version?)
renameSymbols(getResourceSymbolsPath(ResourceSymbolSize.SMALL));
renameSymbols(getResourceSymbolsPath(ResourceSymbolSize.MEDIUM));
@ -101,6 +142,9 @@ public final class ManaSymbols {
//renameSymbols(getSymbolsPath(ResourceSymbolSize.SVG)); // not need
// TODO: remove medium sets files to "medium" folder like symbols above?
// prepare svg settings
prepareSvg(true);
// preload symbol images
loadSymbolImages(15);
loadSymbolImages(25);
@ -171,7 +215,7 @@ public final class ManaSymbols {
} catch (Exception e) {
}
}
// generate small size
try {
File file = new File(getResourceSetsPath(ResourceSetSize.MEDIUM));
@ -181,7 +225,7 @@ public final class ManaSymbols {
String pathRoot = getResourceSetsPath(ResourceSetSize.SMALL) + set;
for (String code : codes) {
File newFile = new File(pathRoot + '-' + code + ".png");
if(!(MageFrame.isSkipSmallSymbolGenerationForExisting() && newFile.exists())){// skip if option enabled and file already exists
if (!(MageFrame.isSkipSmallSymbolGenerationForExisting() && newFile.exists())) {// skip if option enabled and file already exists
file = new File(getResourceSetsPath(ResourceSetSize.MEDIUM) + set + '-' + code + ".png");
if (file.exists()) {
continue;
@ -243,26 +287,9 @@ public final class ManaSymbols {
final BufferedImage[] imagePointer = new BufferedImage[1];
// Rendering hints can't be set programatically, so
// we override defaults with a temporary stylesheet.
// These defaults emphasize quality and precision, and
// are more similar to the defaults of other SVG viewers.
// SVG documents can still override these defaults.
String css = "svg {"
+ "shape-rendering: geometricPrecision;"
+ "text-rendering: geometricPrecision;"
+ "color-rendering: optimizeQuality;"
+ "image-rendering: optimizeQuality;"
+ "}";
File cssFile = File.createTempFile("batik-default-override-", ".css");
FileWriter w = null;
try {
w = new FileWriter(cssFile);
w.write(css);
} finally {
StreamUtils.closeQuietly(w);
}
// css settings for svg
prepareSvg(false);
File cssFile = new File(getSvgPathToCss());
TranscodingHints transcoderHints = new TranscodingHints();
@ -275,7 +302,7 @@ public final class ManaSymbols {
shadowY = 2 * Math.round(1f / 16f * resizeToHeight);
resizeToWidth = resizeToWidth - shadowX;
resizeToHeight = resizeToHeight - shadowY;
};
}
if (resizeToWidth > 0) {
transcoderHints.put(ImageTranscoder.KEY_WIDTH, (float) resizeToWidth); //your image width
@ -311,8 +338,6 @@ public final class ManaSymbols {
t.transcode(input, null);
} catch (Exception e) {
throw new IOException("Couldn't convert svg file: " + svgFile + " , reason: " + e.getMessage());
} finally {
cssFile.delete();
}
BufferedImage originImage = imagePointer[0];
@ -432,10 +457,11 @@ public final class ManaSymbols {
// priority: SVG -> GIF
// gif remain for backward compatibility
//boolean fileErrors = false;
int[] iconErrors = new int[2]; // 0 - svg, 1 - gif
AtomicBoolean fileErrors = new AtomicBoolean(false);
Map<String, BufferedImage> sizedSymbols = new ConcurrentHashMap<>();
IntStream.range(0, symbols.length).parallel().forEach(i-> {
IntStream.range(0, symbols.length).parallel().forEach(i -> {
String symbol = symbols[i];
BufferedImage image = null;
File file;
@ -448,7 +474,8 @@ public final class ManaSymbols {
// gif
if (image == null) {
//LOGGER.info("SVG symbol can't be load: " + file.getPath());
iconErrors[0] += 1; // svg fail
file = getSymbolFileNameAsGIF(symbol, size);
if (file.exists()) {
@ -460,11 +487,27 @@ public final class ManaSymbols {
if (image != null) {
sizedSymbols.put(symbol, image);
} else {
iconErrors[1] += 1; // gif fail
fileErrors.set(true);
LOGGER.warn("SVG or GIF symbol can't be load: " + symbol);
}
});
// total errors
String errorInfo = "";
if (iconErrors[0] > 0) {
errorInfo += "SVG fails - " + iconErrors[0];
}
if (iconErrors[1] > 0) {
if (!errorInfo.isEmpty()) {
errorInfo += ", ";
}
errorInfo += "GIF fails - " + iconErrors[1];
}
if (!errorInfo.isEmpty()) {
LOGGER.warn("Symbols can't be load for size " + size + ": " + errorInfo);
}
manaImages.put(size, sizedSymbols);
return !fileErrors.get();
}
@ -563,8 +606,8 @@ public final class ManaSymbols {
public static void draw(Graphics g, String manaCost, int x, int y, int symbolWidth, Color symbolsTextColor, int symbolMarginX) {
if (!manaImages.containsKey(symbolWidth)) {
loadSymbolImages(symbolWidth);
}
}
// TODO: replace with jlabel render (look at table rendere)?
/*
@ -614,7 +657,7 @@ public final class ManaSymbols {
return;
}
manaCost = manaCost.replace("\\", "");
manaCost = manaCost.replace("\\", "");
manaCost = UI.getDisplayManaCost(manaCost);
StringTokenizer tok = new StringTokenizer(manaCost, " ");
while (tok.hasMoreTokens()) {
@ -739,7 +782,7 @@ public final class ManaSymbols {
replaced = REPLACE_SYMBOLS_PATTERN.matcher(replaced).replaceAll(
"<img src='" + filePathToUrl(htmlImagesPath) + "$1$2" + ".png' alt='$1$2' width="
+ symbolSize + " height=" + symbolSize + '>');
+ symbolSize + " height=" + symbolSize + '>');
// ignore data restore
replaced = replaced

View file

@ -158,6 +158,7 @@ public class DownloadGui extends JPanel {
b.addActionListener(e -> {
switch(this.job.getState()) {
case NEW:
case PREPARING:
case WORKING:
this.job.setState(State.ABORTED);
}

View file

@ -23,16 +23,16 @@ import org.mage.plugins.card.utils.CardImageUtils;
* The class DownloadJob.
*
* @version V0.0 25.08.2010
* @author Clemens Koza
* @author Clemens Koza, JayDi85
*/
public class DownloadJob extends AbstractLaternaBean {
public enum State {
NEW, WORKING, FINISHED, ABORTED
NEW, PREPARING, WORKING, FINISHED, ABORTED
}
private final String name;
private final Source source;
private Source source;
private final Destination destination;
private final Property<State> state = properties.property("state", State.NEW);
private final Property<String> message = properties.property("message");
@ -98,6 +98,36 @@ public class DownloadJob extends AbstractLaternaBean {
this.message.setValue(message);
}
/**
* Inner prepare cycle from new to working
*/
public void doPrepareAndStartWork() {
if (this.state.getValue() != State.NEW) {
setError("Can't call prepare at this point.");
return;
}
this.state.setValue(State.PREPARING);
try {
onPreparing();
} catch (Exception e) {
setError("Prepare error: " + e.getMessage(), e);
return;
}
// change to working state on good prepare call
this.state.setValue(State.WORKING);
}
/**
* Prepare code to override in custom download tasks (it's calls before work start)
*/
public void onPreparing() throws Exception {
return;
}
/**
* Sets the job's message.
*
@ -131,6 +161,10 @@ public class DownloadJob extends AbstractLaternaBean {
return source;
}
public void setSource(Source source) {
this.source = source;
}
public Destination getDestination() {
return destination;
}

View file

@ -60,6 +60,7 @@ public class Downloader extends AbstractLaternaBean implements Disposable {
for (DownloadJob j : jobs) {
switch (j.getState()) {
case NEW:
case PREPARING:
case WORKING:
j.setState(State.ABORTED);
}
@ -82,8 +83,11 @@ public class Downloader extends AbstractLaternaBean implements Disposable {
}
public void add(DownloadJob job) {
if (job.getState() == State.PREPARING) {
throw new IllegalArgumentException("Job already preparing");
}
if (job.getState() == State.WORKING) {
throw new IllegalArgumentException("Job already running");
throw new IllegalArgumentException("Job already working");
}
if (job.getState() == State.FINISHED) {
throw new IllegalArgumentException("Job already finished");
@ -106,13 +110,22 @@ public class Downloader extends AbstractLaternaBean implements Disposable {
@Override
public void onMessage(DownloadJob job) {
//the job won't be processed by multiple threads
// start to work
// the job won't be processed by multiple threads
synchronized (job) {
if (job.getState() != State.NEW) {
return;
}
job.setState(State.WORKING);
job.doPrepareAndStartWork();
if (job.getState() != State.WORKING) {
return;
}
}
// download and save data
try {
Source src = job.getSource();
Destination dst = job.getDestination();

View file

@ -8,7 +8,6 @@ import java.io.IOException;
import java.util.HashMap;
/**
*
* @author spjspj
*/
public enum AltMtgOnlTokensImageSource implements CardImageSource {
@ -60,7 +59,7 @@ public enum AltMtgOnlTokensImageSource implements CardImageSource {
}
@Override
public String generateURL(CardDownloadData card) throws Exception {
public CardImageUrls generateURL(CardDownloadData card) throws Exception {
return null;
}
@ -122,7 +121,7 @@ public enum AltMtgOnlTokensImageSource implements CardImageSource {
}
@Override
public String generateTokenUrl(CardDownloadData card) throws IOException {
public CardImageUrls generateTokenUrl(CardDownloadData card) throws IOException {
if (copyUrlToImage == null) {
setupLinks();
}
@ -139,12 +138,12 @@ public enum AltMtgOnlTokensImageSource implements CardImageSource {
}
return -1;
}
@Override
public boolean isTokenSource() {
return true;
}
@Override
public void doPause(String httpImageUrl) {
}

View file

@ -9,9 +9,9 @@ import org.mage.plugins.card.images.CardDownloadData;
*/
public interface CardImageSource {
String generateURL(CardDownloadData card) throws Exception;
CardImageUrls generateURL(CardDownloadData card) throws Exception;
String generateTokenUrl(CardDownloadData card) throws Exception;
CardImageUrls generateTokenUrl(CardDownloadData card) throws Exception;
String getNextHttpImageUrl();

View file

@ -0,0 +1,59 @@
package org.mage.plugins.card.dl.sources;
import java.util.ArrayList;
import java.util.List;
/**
* @author JayDi85
*/
public class CardImageUrls {
public String baseUrl;
public List<String> alternativeUrls;
public CardImageUrls() {
this.baseUrl = null;
this.alternativeUrls = new ArrayList<>();
}
public CardImageUrls(String baseUrl) {
this(baseUrl, null);
}
public CardImageUrls(String baseUrl, String alternativeUrl) {
this();
this.baseUrl = baseUrl;
if (alternativeUrl != null && !alternativeUrl.isEmpty()) {
this.alternativeUrls.add(alternativeUrl);
}
}
public List<String> getDownloadList() {
List<String> downloadUrls = new ArrayList<>();
if (this.baseUrl != null && !this.baseUrl.isEmpty()) {
downloadUrls.add(this.baseUrl);
}
// no needs in base url duplicate
if (this.alternativeUrls != null) {
for (String url : this.alternativeUrls) {
if (!url.equals(this.baseUrl)) {
downloadUrls.add(url);
}
}
}
return downloadUrls;
}
public void addAlternativeUrl(String url) {
if (url != null && !url.isEmpty()) {
this.alternativeUrls.add(url);
} else {
throw new IllegalArgumentException();
}
}
}

View file

@ -0,0 +1,255 @@
package org.mage.plugins.card.dl.sources;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.JOptionPane;
import mage.cards.Sets;
import org.mage.plugins.card.images.CardDownloadData;
/**
*
* @author spjspj
*/
public enum CopyPasteImageSource implements CardImageSource {
instance;
private Set<String> supportedSets = new LinkedHashSet<String>();
private Set<String> missingCards = new LinkedHashSet<String>();
HashMap<String, String> singleLinks = null;
boolean loadedFromDialog = false;
boolean viewMissingCards = true;
HashMap<String, Integer> singleLinksDone = null;
private static int maxTimes = 2;
@Override
public String getSourceName() {
return "";
}
@Override
public float getAverageSize() {
return 260.7f;
}
@Override
public String getNextHttpImageUrl() {
if (singleLinks == null) {
setupLinks();
}
for (String key : singleLinksDone.keySet()) {
if (singleLinksDone.get(key) < maxTimes) {
singleLinksDone.put(key, maxTimes);
return key;
}
}
if (maxTimes < 2) {
maxTimes++;
}
for (String key : singleLinksDone.keySet()) {
if (singleLinksDone.get(key) < maxTimes) {
singleLinksDone.put(key, maxTimes);
return key;
}
}
return null;
}
@Override
public String getFileForHttpImage(String httpImageUrl) {
String copy = httpImageUrl;
if (copy != null) {
return singleLinks.get(copy);
}
return null;
}
@Override
public CardImageUrls generateURL(CardDownloadData card) throws Exception {
if (singleLinks == null) {
setupLinks();
}
String url = singleLinks.get(card.getSet() + "/" + card.getName());
if (url != null && url.length() > 0) {
return new CardImageUrls(url);
}
url = singleLinks.get(card.getSet() + "/" + card.getName() + "." + card.getCollectorId());
if (url != null && url.length() > 0) {
return new CardImageUrls(url);
}
return null;
}
int ls_size_mc = 0;
int ls_size_ss = 0;
int ls_size_sl = 0;
int num_nos = 0;
private boolean isDifferent() {
boolean isdiff = false;
if (ls_size_mc != missingCards.size()) {
ls_size_mc = missingCards.size();
isdiff = true;
}
if (ls_size_ss != supportedSets.size()) {
ls_size_ss = supportedSets.size();
isdiff = true;
}
if (ls_size_sl != singleLinks.size()) {
ls_size_sl = singleLinks.size();
isdiff = true;
}
num_nos++;
if (num_nos > 2) {
num_nos = 0;
isdiff = true;
}
return isdiff;
}
private void setupLinks() {
if (singleLinks != null && loadedFromDialog) {
if (!viewMissingCards) {
if (isDifferent() && JOptionPane.showConfirmDialog(null,
"View your missing cards and reset the list of card images to download again?",
"View missing cards (found " + missingCards.size() + ") / Reset URLs to download ", JOptionPane.YES_NO_OPTION)
== JOptionPane.YES_OPTION) {
viewMissingCards = true;
singleLinks.clear();
loadedFromDialog = false;
supportedSets.clear();
} else {
return;
}
}
if (!(viewMissingCards && missingCards.size() > 0)) {
return;
}
}
singleLinks = new HashMap<>();
loadedFromDialog = false;
final CopyPasteImageSourceDialog dialog = new CopyPasteImageSourceDialog();
dialog.pack();
int count = 0;
if (viewMissingCards && missingCards.size() > 0 && singleLinks.size() == 0) {
viewMissingCards = false;
String displayMissingCardsStr = "Up to the first 20 cards are:\n";
String missingCardsStr = "";
if (this.missingCards != null) {
for (String card : this.missingCards) {
if (count < 20) {
displayMissingCardsStr = displayMissingCardsStr + card + "\n";
}
missingCardsStr = missingCardsStr + card + "\n";
count++;
}
}
StringSelection stringSelection = new StringSelection(missingCardsStr);
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.setContents(stringSelection, null);
if (isDifferent() && JOptionPane.showConfirmDialog(null,
displayMissingCardsStr + "\n\nReset the list again?\n(NB: The full list has been copied to the clipboard)",
"Your missing cards (found " + missingCards.size() + "): ", JOptionPane.YES_NO_OPTION)
== JOptionPane.YES_OPTION) {
viewMissingCards = true;
singleLinks.clear();
loadedFromDialog = false;
supportedSets.clear();
} else {
return;
}
}
dialog.setVisible(true);
String[] lines = dialog.getPastedData().split(System.getProperty("line.separator"));
for (String line : lines) {
// Break into >> "\1", "\2"
Pattern regex = Pattern.compile("\\s*\"(.*?)/(.*?)\"\\s*,\\s*\"(.*?)\"");
Matcher regexMatcher = regex.matcher(line);
while (regexMatcher.find()) {
String setCode = regexMatcher.group(1);
String cardName = regexMatcher.group(2);
String imageURL = regexMatcher.group(3);
supportedSets.add(setCode);
singleLinks.put(setCode + "/" + cardName, imageURL);
isDifferent();
}
}
loadedFromDialog = true;
if (lines.length == 0) {
loadedFromDialog = false;
viewMissingCards = true;
}
}
@Override
public CardImageUrls generateTokenUrl(CardDownloadData card) throws IOException {
try {
return generateURL(card);
} catch (Exception ex) {
}
return null;
}
@Override
public int getTotalImages() {
if (singleLinks == null) {
setupLinks();
}
if (singleLinks != null) {
return singleLinks.size();
}
return -1;
}
@Override
public boolean isTokenSource() {
return false;
}
@Override
public ArrayList<String> getSupportedSets() {
setupLinks();
ArrayList<String> supportedSetsCopy = new ArrayList<>();
if (supportedSets.size() == 0) {
for (String setCode : Sets.getInstance().keySet()) {
supportedSets.add(setCode);
}
}
supportedSetsCopy.addAll(supportedSets);
return supportedSetsCopy;
}
@Override
public void doPause(String httpImageUrl) {
}
@Override
public boolean isImageProvided(String setCode, String cardName) {
missingCards.add(setCode + "/" + cardName);
if (singleLinks != null) {
return singleLinks.containsKey(setCode + "/" + cardName) || singleLinks.containsKey(setCode + "/" + cardName + "-a");
}
return false;
}
@Override
public boolean isSetSupportedComplete(String setCode) {
return false;
}
}

View file

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.mage.plugins.card.dl.sources.CopyPasteImageSourceDialog">
<grid id="cbd77" binding="contentPane" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="10" left="10" bottom="10" right="10"/>
<constraints>
<xy x="48" y="54" width="540" height="500"/>
</constraints>
<properties>
<minimumSize width="540" height="450"/>
</properties>
<border type="none"/>
<children>
<grid id="94766" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="1" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<hspacer id="98af6">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
</hspacer>
<grid id="9538f" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="true" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<component id="e7465" class="javax.swing.JButton" binding="buttonOK">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Import"/>
</properties>
</component>
<component id="5723f" class="javax.swing.JButton" binding="buttonCancel">
<constraints>
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Cancel"/>
</properties>
</component>
</children>
</grid>
</children>
</grid>
<grid id="e3588" layout-manager="FormLayout">
<rowspec value="center:d:grow"/>
<colspec value="fill:d:noGrow"/>
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<component id="f8bac" class="javax.swing.JEditorPane" binding="txtDeckList">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="6" anchor="0" fill="3" indent="0" use-parent-layout="false">
<preferred-size width="150" height="50"/>
</grid>
<forms defaultalign-horz="false" defaultalign-vert="false"/>
</constraints>
<properties>
<minimumSize width="250" height="400"/>
<preferredSize width="550" height="400"/>
</properties>
</component>
</children>
</grid>
</children>
</grid>
</form>

View file

@ -0,0 +1,182 @@
package org.mage.plugins.card.dl.sources;
import mage.util.StreamUtils;
import java.awt.*;
import java.awt.event.*;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Set;
import javax.swing.*;
public class CopyPasteImageSourceDialog extends JDialog {
private JPanel contentPane;
private JButton buttonOK;
private JButton buttonCancel;
private JEditorPane txtDeckList;
private String tmpPath;
public CopyPasteImageSourceDialog() {
initComponents();
setContentPane(contentPane);
setModal(true);
getRootPane().setDefaultButton(buttonOK);
buttonOK.addActionListener(e -> onOK());
buttonCancel.addActionListener(e -> onCancel());
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
onCancel();
}
});
// Close on "ESC"
contentPane.registerKeyboardAction(e -> onCancel(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
}
private void onOK() {
BufferedWriter bw = null;
try {
File temp = File.createTempFile("import_images_from_url", ".txt");
bw = new BufferedWriter(new FileWriter(temp));
bw.write(txtDeckList.getText());
tmpPath = temp.getPath();
} catch (IOException e) {
e.printStackTrace();
} finally {
StreamUtils.closeQuietly(bw);
}
dispose();
}
private void onCancel() {
dispose();
}
public String getTmpPath() {
return tmpPath;
}
private void initComponents() {
contentPane = new JPanel();
JPanel panel1 = new JPanel();
JPanel panel2 = new JPanel();
buttonOK = new JButton();
buttonCancel = new JButton();
JPanel panel3 = new JPanel();
txtDeckList = new JEditorPane();
{
contentPane.setMinimumSize(new Dimension(540, 450));
contentPane.setBorder(new javax.swing.border.CompoundBorder(
new javax.swing.border.TitledBorder(new javax.swing.border.EmptyBorder(0, 0, 0, 0),
"Download Images from Copy/Pasted Text", javax.swing.border.TitledBorder.CENTER,
javax.swing.border.TitledBorder.TOP, new java.awt.Font("Dialog", java.awt.Font.PLAIN, 12),
java.awt.Color.BLACK), contentPane.getBorder()));
contentPane.addPropertyChangeListener(e -> {
if ("border".equals(e.getPropertyName())) {
throw new RuntimeException();
}
});
contentPane.addPropertyChangeListener(e -> {
if ("border".equals(e.getPropertyName())) {
throw new RuntimeException();
}
});
contentPane.setLayout(new GridBagLayout());
((GridBagLayout) contentPane.getLayout()).columnWidths = new int[]{0, 0};
((GridBagLayout) contentPane.getLayout()).rowHeights = new int[]{0, 0, 0};
((GridBagLayout) contentPane.getLayout()).columnWeights = new double[]{0.01, 1.0E-4};
((GridBagLayout) contentPane.getLayout()).rowWeights = new double[]{0.01, 0.0, 1.0E-4};
{
panel1.setLayout(new GridBagLayout());
((GridBagLayout) panel1.getLayout()).columnWidths = new int[]{0, 0, 0};
((GridBagLayout) panel1.getLayout()).rowHeights = new int[]{0, 0};
((GridBagLayout) panel1.getLayout()).columnWeights = new double[]{0.0, 0.01, 1.0E-4};
((GridBagLayout) panel1.getLayout()).rowWeights = new double[]{0.01, 1.0E-4};
{
panel2.setLayout(new GridBagLayout());
((GridBagLayout) panel2.getLayout()).columnWidths = new int[]{0, 4, 0, 0};
((GridBagLayout) panel2.getLayout()).rowHeights = new int[]{0, 0};
((GridBagLayout) panel2.getLayout()).columnWeights = new double[]{0.01, 0.0, 0.01, 1.0E-4};
((GridBagLayout) panel2.getLayout()).rowWeights = new double[]{0.0, 1.0E-4};
//---- buttonOK ----
buttonOK.setText("Download from URLs");
panel2.add(buttonOK, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
new Insets(0, 0, 0, 0), 0, 0));
//---- buttonCancel ----
buttonCancel.setText("Cancel");
panel2.add(buttonCancel, new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
new Insets(0, 0, 0, 0), 0, 0));
}
panel1.add(panel2, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(0, 0, 0, 0), 0, 0));
}
contentPane.add(panel1, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(0, 0, 0, 0), 0, 0));
{
panel3.setLayout(new GridBagLayout());
((GridBagLayout) panel3.getLayout()).columnWidths = new int[]{0, 0};
((GridBagLayout) panel3.getLayout()).rowHeights = new int[]{0, 0};
((GridBagLayout) panel3.getLayout()).columnWeights = new double[]{0.0, 1.0E-4};
((GridBagLayout) panel3.getLayout()).rowWeights = new double[]{1.0, 1.0E-4};
txtDeckList.setMinimumSize(new Dimension(250, 400));
txtDeckList.setPreferredSize(new Dimension(550, 400));
txtDeckList.setText("// Example follows. \nNB: **DELETE ALL TEXT AND GO SELECT THIS SOURCE AGAIN TO SEE THE NAMES CARDS YOU'RE MISSING IMAGES FOR!!!***\n\"SWS/Might of the Wild\", \"http://i.imgur.com/eNXOdxp.jpg\"\n\"PTC/Wolf of Devil's Breach\", \"https://img.scryfall.com/cards/large/en/psoi/192s.jpg\"\n\nExpected columns: Name of Card (Set Trigraph\\Name), URL of image\n\n\n");
JScrollPane txtScrollableDeckList = new JScrollPane(txtDeckList);
panel3.add(txtScrollableDeckList, new GridBagConstraints(0, 0, 1, 1, 1.0, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(0, 0, 0, 0), 0, 0));
}
contentPane.add(panel3, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(0, 0, 5, 0), 0, 0));
}
}
Set<String> missingCards = null;
public void addMissingCards(Set<String> missingCards) {
this.missingCards = missingCards;
String missingCardsStr = "";
boolean found = false;
if (this.missingCards != null) {
for (String card : this.missingCards) {
found = true;
missingCardsStr = missingCardsStr + card + "\n";
}
}
if (found == false) {
missingCardsStr = "\n\nNote: Leave blank to see your missing card names!\n";
}
txtDeckList.setText(txtDeckList.getText() + "\n\nYour missing card images are:\n" + missingCardsStr);
}
public String getPastedData() {
return txtDeckList.getText();
}
}

View file

@ -63,16 +63,16 @@ public class GathererSets implements Iterable<DownloadJob> {
"POR", "P02", "PTK",
"ARC", "DD3EVG",
"W16", "W17",
//"APAC" -- gatherer do not have that set, scrly have PALP
//"APAC" -- gatherer do not have that set, scryfall has PALP
//"ARENA" -- is't many set with different codes, not one
"CLASH", "CP", "DD3GVL", "DPA", "EURO", "FNMP", "GPX", "GRC", "GUR", "H17", "JR", "MBP", "MGDC", "MLP", "MPRP", "MPS-AKH", "PTC", "S00", "S99", "SUS", "SWS", "UGIN", "UGL", "V10", "V17", "WMCQ", // need to fix
"H09", "PD2", "PD3", "UNH", "CM1", "E02", "V11", "A25", "UST", "IMA", "DD2", "EVG", "DDC", "DDE", "DDD", "DDT", "8EB", "9EB", "CHR" // ok
"H09", "PD2", "PD3", "UNH", "CM1", "V11", "A25", "UST", "IMA", "DD2", "EVG", "DDC", "DDE", "DDD", "8EB", "9EB", "CHR" // ok
// current testing
};
private static final String[] symbolsBasicWithMyth = {"M10", "M11", "M12", "M13", "M14", "M15", "ORI",
"DDF", "DDG", "DDH", "DDI", "DDJ", "DDK", "DDL", "DDM", "DDN",
"DD3DVD", "DD3JVC", "DDO", "DDP", "DDQ", "DDR", "DDS", "DDT",
"DD3DVD", "DD3JVC", "DDO", "DDP", "DDQ", "DDR", "DDS", "DDT", "DDU",
"ALA", "CON", "ARB",
"ZEN", "WWK", "ROE",
"SOM", "MBS", "NPH",
@ -90,8 +90,9 @@ public class GathererSets implements Iterable<DownloadJob> {
"KLD", "AER",
"AKH", "HOU",
"XLN", "C17",
"RIX", "DOM", "M19", // not released
"E01"
"RIX", "DOM", "M19",
"E01", "CM2", "E02",
"GS1", "BBD", "C18"
};
private static final String[] symbolsOnlyMyth = {
@ -176,7 +177,7 @@ public class GathererSets implements Iterable<DownloadJob> {
CheckResult res = setsToDownload.get(searchCode);
if (res != null) {
logger.error(String.format("Symbols: founded duplicated code: %s", searchCode));
logger.error(String.format("Symbols: found duplicate code: %s", searchCode));
} else {
res = new CheckResult(searchCode, foundedExp, haveCommon, haveUncommon, haveRare, haveMyth);
setsToDownload.put(searchCode, res);
@ -189,7 +190,7 @@ public class GathererSets implements Iterable<DownloadJob> {
}
// checks for founded sets only
// to early to download
// too early to download
if (!canDownloadTask) {
Calendar c = Calendar.getInstance();
c.setTime(foundedExp.getReleaseDate());

View file

@ -8,11 +8,11 @@ import java.util.LinkedHashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import org.apache.log4j.Logger;
import org.mage.plugins.card.images.CardDownloadData;
/**
*
* @author spjspj
*/
public enum GrabbagImageSource implements CardImageSource {
@ -48,7 +48,7 @@ public enum GrabbagImageSource implements CardImageSource {
}
@Override
public String generateURL(CardDownloadData card) throws Exception {
public CardImageUrls generateURL(CardDownloadData card) throws Exception {
if (singleLinks == null) {
setupLinks();
}
@ -63,7 +63,7 @@ public enum GrabbagImageSource implements CardImageSource {
}
if (url != null) {
return getSourceName(card, url) + url;
return new CardImageUrls(getSourceName(card, url) + url);
}
return null;
}
@ -357,10 +357,81 @@ public enum GrabbagImageSource implements CardImageSource {
singleLinks.put("SWS/Yoda, Jedi Master", "6arN1Hl.png");
singleLinks.put("SWS/Y-Wing", "aQQ5zwA.jpg");
singleLinks.put("SWS/Zam Wesell", "ToG0C1r.jpg");
singleLinks.put("SWS/Astromech Droid", "v0TpHMh.jpg");
singleLinks.put("SWS/Buried Ruin", "QkmIWYg.png");
singleLinks.put("SWS/Flame Trooper", "RkY7KFJ.jpg");
singleLinks.put("SWS/Force Stasis", "FavLrcY.jpg");
singleLinks.put("SWS/Salvage Trader", "qGwk7Bn.jpg");
singleLinks.put("SWS/Outer Rim Gang", "kEjKQGy.png");
singleLinks.put("SWS/Rathtar", "CYhHRqF.png");
singleLinks.put("SWS/Riot Trooper", "PusvaQB.jpg");
singleLinks.put("SWS/Sins of the Father", "32YHTPB.jpg");
singleLinks.put("SWS/Upsilon-class Shuttle", "Le3F3oW.jpg");
singleLinks.put("SWS/Finn", "TU2LI2q.jpg");
singleLinks.put("SWS/General Hux", "UpWfcV6.png");
singleLinks.put("SWS/Poe Dameron", "v8i21dn.png");
singleLinks.put("SWS/Rey", "7n5ZZFA.png");
singleLinks.put("SWS/Kylo Ren", "fFzDMTz.png");
singleLinks.put("SWS/TIE Striker", "6b5GDUQ.jpg");
singleLinks.put("SWS/Bludgeoning Pain", "ap5k3Wl.jpg");
singleLinks.put("SWS/Force Protection", "GrOQLHO.jpg");
singleLinks.put("SWS/Gerrera's Revolutionary", "FQFE1Jt.jpg");
singleLinks.put("SWS/Thermal Detonator", "gTPLM83.jpg");
singleLinks.put("SWS/Hammerhead Corvette", "IlhOAGv.jpg");
singleLinks.put("SWS/U-Wing", "FmoRCmG.jpg");
singleLinks.put("SWS/Bor Gullet", "jXafYHX.jpg");
singleLinks.put("SWS/Imperial Hovertank", "6X1wL4d.jpg");
singleLinks.put("SWS/Occupation", "h4mmkA5.jpg");
singleLinks.put("SWS/Resistance", "lbNhA59.jpg");
singleLinks.put("SWS/Jyn Erso and Cassian Andor", "o0SCGiJ.jpg");
singleLinks.put("SWS/Chirrut Imwe", "wgtXfUF.jpg");
singleLinks.put("SWS/Director Krennic", "52PGsH5.jpg");
singleLinks.put("SWS/Vader's Command", "7Lql6UT.jpg");
singleLinks.put("SWS/Delay Tactic", "ubmzD1m.jpg");
singleLinks.put("SWS/Resistance Bomber", "Sudfkd7.jpg");
singleLinks.put("SWS/Mouse Droid", "oO0p8QE.jpg");
singleLinks.put("SWS/First Order Dreadnought", "80pO9Cc.jpg");
singleLinks.put("SWS/TIE Silencer", "7yeYIjX.jpg");
singleLinks.put("SWS/Canto Bight Enforcer", "VKPQVsn.jpg");
singleLinks.put("SWS/Cantonica Casino", "7LiSvy6.jpg");
singleLinks.put("SWS/Fathier", "0oKquQp.jpg");
singleLinks.put("SWS/Code Slice", "7uNASji.jpg");
singleLinks.put("SWS/Captain Phasma", "LWujx1B.jpg");
singleLinks.put("SWS/Force Telepathy", "e90hswX.jpg");
singleLinks.put("SWS/Praetorian Trooper", "pjS1wyS.jpg");
singleLinks.put("SWS/Supreme Leader Snoke", "eewWiKE.jpg");
singleLinks.put("SWS/Sai Tok", "FVn29tT.jpg");
singleLinks.put("SWS/Porg Nest", "8DnNZKc.jpg");
singleLinks.put("SWS/Inspire", "7lIXhtd.jpg");
singleLinks.put("SWS/Force Projection", "5EfOwyn.jpg");
singleLinks.put("SWS/Luke Skywalker, the Last Jedi", "WMmQcyD.jpg");
singleLinks.put("SWS/Vulptex", "30WeCkw.jpg");
singleLinks.put("SWS/Glorious Charge", "yJwvKzk.jpg");
singleLinks.put("SWS/Plains-520b", "Fx59r9J.jpg");
singleLinks.put("SWS/Island-520a", "jIPpWp5.jpg");
singleLinks.put("SWS/Conscription", "An01yAe.jpg");
singleLinks.put("SWS/Afterburn", "2ydqSvT.jpg");
singleLinks.put("SWS/Corellian Gunship", "mZdDQWH.jpg");
singleLinks.put("SWS/Despair", "TLTddMI.jpg");
singleLinks.put("SWS/Dryden Vos", "6LbtUzN.jpg");
singleLinks.put("SWS/Droid Uprising", "aWuoxho.jpg");
singleLinks.put("SWS/Gamble", "Hwzr60O.jpg");
singleLinks.put("SWS/Han Solo, Scrumrat", "Hqj39dG.jpg");
singleLinks.put("SWS/Mud Trooper", "af8JaDy.jpg");
singleLinks.put("SWS/Enfys Nest", "pstVfQg.jpg");
singleLinks.put("SWS/Kalevan Star Yacht", "nHmSizp.jpg");
singleLinks.put("SWS/Maelstrom Blockade", "sUYT0pc.jpg");
singleLinks.put("SWS/Range Trooper", "kXGvTkE.jpg");
singleLinks.put("SWS/Tobias Beckett", "hzm6ilE.jpg");
singleLinks.put("SWS/Underground Forum", "FH2pRfU.jpg");
singleLinks.put("SWS/Chewbacca, the Beast", "Zb5TitZ.jpg");
// Emblems
singleLinks.put("SWS/Emblem Obi-Wan Kenobi", "Qyc10aT.png");
singleLinks.put("SWS/Aurra Sing", "BLWbVJC.png");
singleLinks.put("SWS/Yoda", "zH0sYxg.png");
singleLinks.put("SWS/Emblem Luke Skywalker", "kHELZDJ.jpg");
// Tokens
singleLinks.put("SWS/Ewok", "N2MvJyr.png");
singleLinks.put("SWS/B-Wing", "oH62AUD.png");
@ -372,10 +443,12 @@ public enum GrabbagImageSource implements CardImageSource {
singleLinks.put("SWS/Royal Guard", "9tqE8vL.png");
singleLinks.put("SWS/Tusken Raider", "gPMiSmP.png");
singleLinks.put("SWS/Droid", "4PRrWFF.png");
singleLinks.put("SWS/Trooper 2", "tcxvGOn.jpg");
singleLinks.put("SWS/Porg", "HBjt1A3.jpg");
}
@Override
public String generateTokenUrl(CardDownloadData card) throws IOException {
public CardImageUrls generateTokenUrl(CardDownloadData card) throws IOException {
try {
return generateURL(card);
} catch (Exception ex) {

View file

@ -6,12 +6,12 @@ import java.util.LinkedHashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import mage.client.dialog.PreferencesDialog;
import org.mage.plugins.card.images.CardDownloadData;
import org.mage.plugins.card.utils.CardImageUtils;
/**
*
* @author North
*/
public enum MagicCardsImageSource implements CardImageSource {
@ -202,13 +202,15 @@ public enum MagicCardsImageSource implements CardImageSource {
add("C17");
add("XLN");
add("DDT");
add("DDU");
add("IMA");
add("E02");
add("V17");
add("UST");
// add("RIX");
// add("A25");
// add("DOM");
add("RIX");
add("A25");
add("DOM");
// add("CM2");
// add("M19");
}
};
@ -263,7 +265,8 @@ public enum MagicCardsImageSource implements CardImageSource {
put("DDQ", "duel-decks-blessed-vs-cursed");
put("DDR", "duel-decks-nissa-vs-ob-nixilis");
put("DDS", "duel-decks-mind-vs-might");
put("DDS", "duel-decks-merfolk-vs-goblin");
put("DDT", "duel-decks-merfolk-vs-goblin");
put("DDU", "duel-decks-elves-vs-inventors");
put("DGM", "dragons-maze");
put("DKA", "dark-ascension");
put("DRB", "from-the-vault-dragons");
@ -339,6 +342,7 @@ public enum MagicCardsImageSource implements CardImageSource {
put("WWK", "worldwake");
put("ZEN", "zendikar");
}
private static final long serialVersionUID = 1L;
};
@ -358,7 +362,7 @@ public enum MagicCardsImageSource implements CardImageSource {
}
@Override
public String generateURL(CardDownloadData card) throws Exception {
public CardImageUrls generateURL(CardDownloadData card) throws Exception {
String collectorId = card.getCollectorId();
String cardSet = card.getSet();
if (collectorId == null || cardSet == null) {
@ -386,11 +390,11 @@ public enum MagicCardsImageSource implements CardImageSource {
}
url.append(".jpg");
return url.toString();
return new CardImageUrls(url.toString());
}
@Override
public String generateTokenUrl(CardDownloadData card) {
public CardImageUrls generateTokenUrl(CardDownloadData card) {
String name = card.getName();
// add type to name if it's not 0
if (card.getType() > 0) {
@ -403,7 +407,7 @@ public enum MagicCardsImageSource implements CardImageSource {
} else {
set += '-' + card.getSet();
}
return "http://magiccards.info/extras/token/" + set + '/' + name + ".jpg";
return new CardImageUrls("http://magiccards.info/extras/token/" + set + '/' + name + ".jpg");
}
@Override

View file

@ -8,10 +8,10 @@ import java.util.LinkedHashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.mage.plugins.card.images.CardDownloadData;
/**
*
* @author Pete Rossi
*/
public enum MagidexImageSource implements CardImageSource {
@ -189,7 +189,6 @@ public enum MagidexImageSource implements CardImageSource {
supportedSets.add("CN2");
supportedSets.add("DDR");
supportedSets.add("KLD");
supportedSets.add("MPS");
// supportedSets.add("PZ2"); // Treasure Chests
supportedSets.add("C16");
supportedSets.add("PCA");
@ -208,11 +207,15 @@ public enum MagidexImageSource implements CardImageSource {
supportedSets.add("IMA");
supportedSets.add("E02");
supportedSets.add("V17");
// supportedSets.add("UST");
// supportedSets.add("RIX");
// supportedSets.add("A25");
// supportedSets.add("DOM");
// supportedSets.add("M19");
supportedSets.add("UST");
supportedSets.add("DDU");
supportedSets.add("RIX");
supportedSets.add("A25");
supportedSets.add("DOM");
supportedSets.add("CM2");
supportedSets.add("M19");
//supportedSets.add("BBD");
//supportedSets.add("C18");
}
@Override
@ -231,7 +234,7 @@ public enum MagidexImageSource implements CardImageSource {
}
@Override
public String generateURL(CardDownloadData card) throws Exception {
public CardImageUrls generateURL(CardDownloadData card) throws Exception {
String cardDownloadName = card.getDownloadName().toLowerCase(Locale.ENGLISH);
String cardSet = card.getSet();
@ -245,7 +248,7 @@ public enum MagidexImageSource implements CardImageSource {
// This will properly escape the url
URI uri = new URI("http", "magidex.com", "/extstatic/card/" + formatSetName(cardSet) + '/' + cardDownloadName + ".jpg", null, null);
return uri.toASCIIString();
return new CardImageUrls(uri.toASCIIString());
}
private String formatSetName(String setName) {
@ -262,7 +265,7 @@ public enum MagidexImageSource implements CardImageSource {
};
@Override
public String generateTokenUrl(CardDownloadData card) {
public CardImageUrls generateTokenUrl(CardDownloadData card) {
return null;
}

View file

@ -2,14 +2,12 @@
package org.mage.plugins.card.dl.sources;
import java.util.Locale;
import org.mage.plugins.card.images.CardDownloadData;
/**
* Site was shutdown by wizards Feb. 2015
*
*
*
*
* @author LevelX2
*/
public enum MtgImageSource implements CardImageSource {
@ -32,7 +30,7 @@ public enum MtgImageSource implements CardImageSource {
}
@Override
public String generateURL(CardDownloadData card) throws Exception {
public CardImageUrls generateURL(CardDownloadData card) throws Exception {
String collectorId = card.getCollectorId();
String cardSet = card.getSet();
if (collectorId == null || cardSet == null) {
@ -59,11 +57,11 @@ public enum MtgImageSource implements CardImageSource {
}
url.append(".jpg");
return url.toString();
return new CardImageUrls(url.toString());
}
@Override
public String generateTokenUrl(CardDownloadData card) {
public CardImageUrls generateTokenUrl(CardDownloadData card) {
return null;
}

View file

@ -3,11 +3,11 @@ package org.mage.plugins.card.dl.sources;
import java.io.IOException;
import java.util.HashMap;
import org.apache.log4j.Logger;
import org.mage.plugins.card.images.CardDownloadData;
/**
*
* @author spjspj
*/
public enum MtgOnlTokensImageSource implements CardImageSource {
@ -59,7 +59,7 @@ public enum MtgOnlTokensImageSource implements CardImageSource {
}
@Override
public String generateURL(CardDownloadData card) throws Exception {
public CardImageUrls generateURL(CardDownloadData card) throws Exception {
return null;
}
@ -324,7 +324,7 @@ public enum MtgOnlTokensImageSource implements CardImageSource {
}
@Override
public String generateTokenUrl(CardDownloadData card) throws IOException {
public CardImageUrls generateTokenUrl(CardDownloadData card) throws IOException {
if (copyUrlToImage == null) {
setupLinks();
}

View file

@ -1,4 +1,3 @@
package org.mage.plugins.card.dl.sources;
import java.io.BufferedReader;
@ -28,7 +27,6 @@ import org.jsoup.select.Elements;
import org.mage.plugins.card.images.CardDownloadData;
/**
*
* @author LevelX2
*/
public enum MythicspoilerComSource implements CardImageSource {
@ -232,6 +230,9 @@ public enum MythicspoilerComSource implements CardImageSource {
supportedSets.add("RIX");
supportedSets.add("DOM");
supportedSets.add("BBD");
supportedSets.add("M19");
// supportedSets.add("C18");
// supportedSets.add("CM2");
sets = new LinkedHashMap<>();
setsAliases = new HashMap<>();
@ -390,7 +391,7 @@ public enum MythicspoilerComSource implements CardImageSource {
}
@Override
public String generateURL(CardDownloadData card) throws Exception {
public CardImageUrls generateURL(CardDownloadData card) throws Exception {
String collectorId = card.getCollectorId();
String cardSet = card.getSet();
if (collectorId == null || cardSet == null) {
@ -409,11 +410,11 @@ public enum MythicspoilerComSource implements CardImageSource {
.replaceAll(",", "")
.replaceAll("/", "");
String link = setLinks.get(searchName);
return link;
return new CardImageUrls(link);
}
@Override
public String generateTokenUrl(CardDownloadData card
public CardImageUrls generateTokenUrl(CardDownloadData card
) {
return null;
}

View file

@ -6,19 +6,33 @@ import java.util.LinkedHashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import mage.client.dialog.PreferencesDialog;
import org.mage.plugins.card.images.CardDownloadData;
/**
* @author Quercitron, JayDi85
*
*/
public enum ScryfallImageSource implements CardImageSource {
instance;
private final Set<String> supportedSets;
private final Map<String, String> languageAliases;
ScryfallImageSource() {
// https://scryfall.com/docs/api/languages
languageAliases = new HashMap<>();
languageAliases.put("en", "en");
languageAliases.put("es", "es");
languageAliases.put("jp", "ja");
languageAliases.put("it", "it");
languageAliases.put("fr", "fr");
languageAliases.put("cn", "zhs"); // Simplified Chinese
languageAliases.put("de", "de");
languageAliases.put("ko", "ko");
languageAliases.put("pt", "pt");
languageAliases.put("ru", "ru");
supportedSets = new LinkedHashSet<>();
// supportedSets.add("PTC"); //
supportedSets.add("LEA");
@ -205,40 +219,62 @@ public enum ScryfallImageSource implements CardImageSource {
supportedSets.add("E02");
supportedSets.add("V17");
supportedSets.add("UST");
supportedSets.add("DDU");
supportedSets.add("RIX");
supportedSets.add("WMCQ");
supportedSets.add("PPRO");
supportedSets.add("A25");
supportedSets.add("DOM");
supportedSets.add("BBD");
// supportedSets.add("M19");
supportedSets.add("C18");
supportedSets.add("CM2");
supportedSets.add("M19");
supportedSets.add("GS1");
}
@Override
public String generateURL(CardDownloadData card) throws Exception {
public CardImageUrls generateURL(CardDownloadData card) throws Exception {
String preferredLanguage = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_PREF_LANGUAGE, "en");
String defaultCode = "en";
String localizedCode = languageAliases.getOrDefault(preferredLanguage, defaultCode);
// loc example: https://api.scryfall.com/cards/xln/121/ru?format=image
// TODO: do not use API at all? It's can help with scryfall request limits (1 request instead 2)
String baseUrl = null;
String alternativeUrl = null;
// special card number like "103a" already compatible
if (card.isCollectorIdWithStr()) {
return "https://img.scryfall.com/cards/large/en/" + formatSetName(card.getSet()) + "/"
if (baseUrl == null && card.isCollectorIdWithStr()) {
baseUrl = "https://img.scryfall.com/cards/large/" + localizedCode + "/" + formatSetName(card.getSet()) + "/"
+ card.getCollectorId() + ".jpg";
alternativeUrl = "https://img.scryfall.com/cards/large/" + defaultCode + "/" + formatSetName(card.getSet()) + "/"
+ card.getCollectorId() + ".jpg";
}
// double faced cards do not supporte by API (need direct link for img)
// double faced cards do not supports by API (need direct link for img)
// example: https://img.scryfall.com/cards/large/en/xln/173b.jpg
if (card.isTwoFacedCard()) {
return "https://img.scryfall.com/cards/large/en/" + formatSetName(card.getSet()) + "/"
if (baseUrl == null && card.isTwoFacedCard()) {
baseUrl = "https://img.scryfall.com/cards/large/" + localizedCode + "/" + formatSetName(card.getSet()) + "/"
+ card.getCollectorId() + (card.isSecondSide() ? "b" : "a") + ".jpg";
alternativeUrl = "https://img.scryfall.com/cards/large/" + defaultCode + "/" + formatSetName(card.getSet()) + "/"
+ card.getCollectorId() + (card.isSecondSide() ? "b" : "a") + ".jpg";
}
// basic cards by api call (redirect to img link)
// example: https://api.scryfall.com/cards/xln/121?format=image
return "https://api.scryfall.com/cards/" + formatSetName(card.getSet()) + "/"
+ card.getCollectorId() + "?format=image";
// example: https://api.scryfall.com/cards/xln/121/en?format=image
if (baseUrl == null) {
baseUrl = "https://api.scryfall.com/cards/" + formatSetName(card.getSet()) + "/"
+ card.getCollectorId() + "/" + localizedCode + "?format=image";
alternativeUrl = "https://api.scryfall.com/cards/" + formatSetName(card.getSet()) + "/"
+ card.getCollectorId() + "/" + defaultCode + "?format=image";
}
return new CardImageUrls(baseUrl, alternativeUrl);
}
@Override
public String generateTokenUrl(CardDownloadData card) throws Exception {
public CardImageUrls generateTokenUrl(CardDownloadData card) throws Exception {
return null;
}

View file

@ -9,8 +9,13 @@ import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import mage.MageException;
import mage.util.StreamUtils;
import org.jsoup.select.Elements;
import org.mage.plugins.card.dl.DownloadJob;
import org.mage.plugins.card.utils.CardImageUtils;
import javax.swing.text.Document;
import static org.mage.card.arcane.ManaSymbols.getSymbolFileNameAsSVG;
import static org.mage.plugins.card.utils.CardImageUtils.getImagesDir;
@ -18,14 +23,14 @@ import static org.mage.plugins.card.utils.CardImageUtils.getImagesDir;
// TODO: add force to download symbols (rewrite exist files)
/**
*
* @author jaydi85@gmail.com
*
* @author JayDi85
*/
public class ScryfallSymbolsSource implements Iterable<DownloadJob> {
static final String SOURCE_URL = "https://assets.scryfall.com/assets/scryfall.css"; // search css-file on https://scryfall.com/docs/api/colors
//static final String SOURCE_URL = "https://assets.scryfall.com/assets/scryfall.css"; // old version with direct css-file on https://scryfall.com/docs/api/colors
static final String CSS_SOURCE_URL = "https://scryfall.com/docs/api/colors";
static final String CSS_SOURCE_SELECTOR = "link[rel=stylesheet]"; // <link rel="stylesheet" media="all" href="https://assets.scryfall.com/assets/scryfall-8cdaa786c4c86d5c49317e3e0fed72a0e409666753d3d3e8c906f33a188e19ed.css">
static final String STATE_PROP_NAME = "state";
static final String DOWNLOAD_TEMP_FILE = getImagesDir() + File.separator + "temp" + File.separator + "scryfall-symbols-source.txt";
@ -55,21 +60,21 @@ public class ScryfallSymbolsSource implements Iterable<DownloadJob> {
return jobs.iterator();
}
private void parseData(String sourcePath){
private void parseData(String sourcePath) {
String sourceData = "";
try {
sourceData = new String(Files.readAllBytes(Paths.get(sourcePath)));
}catch (IOException e) {
} catch (IOException e) {
LOGGER.error("Can't open file to parse data: " + sourcePath + " , reason: " + e.getMessage());
}
// gen symbols list
ArrayList<String> allMageSymbols = new ArrayList<>();
for(int i = 0; i < SYMBOLS_LIST.length; i++){
for (int i = 0; i < SYMBOLS_LIST.length; i++) {
allMageSymbols.add(SYMBOLS_LIST[i]);
}
for(Integer i = SYMBOLS_NUMBER_START; i <= SYMBOLS_NUMBER_END; i++){
for (Integer i = SYMBOLS_NUMBER_START; i <= SYMBOLS_NUMBER_END; i++) {
allMageSymbols.add(String.valueOf(SYMBOLS_NUMBER_START + i));
}
@ -88,23 +93,22 @@ public class ScryfallSymbolsSource implements Iterable<DownloadJob> {
// dirs maker
File dir = getSymbolFileNameAsSVG("W").getParentFile();
if(!dir.exists()){
if (!dir.exists()) {
dir.mkdirs();
}
// decode and save data (only if not exist)
for(String needCode: allMageSymbols){
for (String needCode : allMageSymbols) {
String searchCode = needCode.replace("/", "");
if(!foundedData.containsKey(searchCode))
{
if (!foundedData.containsKey(searchCode)) {
LOGGER.warn("Can't found symbol code from scryfall: " + searchCode);
continue;
}
File destFile = getSymbolFileNameAsSVG(searchCode);
if (destFile.exists() && (destFile.length() > 0)){
if (destFile.exists() && (destFile.length() > 0)) {
continue;
}
FileOutputStream stream = null;
@ -118,7 +122,7 @@ public class ScryfallSymbolsSource implements Iterable<DownloadJob> {
stream.write(fileData);
LOGGER.info("New svg symbol downloaded: " + needCode);
} catch (Exception e) {
} catch (Exception e) {
LOGGER.error("Can't decode svg icon and save to file: " + destFile.getPath() + ", reason: " + e.getMessage());
} finally {
StreamUtils.closeQuietly(stream);
@ -127,23 +131,26 @@ public class ScryfallSymbolsSource implements Iterable<DownloadJob> {
}
private class ScryfallSymbolsDownloadJob extends DownloadJob{
private class ScryfallSymbolsDownloadJob extends DownloadJob {
private String cssUrl = ""; // need to find url from colors page https://scryfall.com/docs/api/colors
// listener for data parse after download complete
private class ScryDownloadOnFinishedListener implements PropertyChangeListener {
private class ScryfallDownloadOnFinishedListener implements PropertyChangeListener {
private String downloadedFile;
public ScryDownloadOnFinishedListener(String ADestFile){
public ScryfallDownloadOnFinishedListener(String ADestFile) {
this.downloadedFile = ADestFile;
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (!evt.getPropertyName().equals(STATE_PROP_NAME)){
if (!evt.getPropertyName().equals(STATE_PROP_NAME)) {
throw new IllegalArgumentException("Unknown download property " + evt.getPropertyName());
}
if (evt.getNewValue() != State.FINISHED){
if (evt.getNewValue() != State.FINISHED) {
return;
}
@ -152,16 +159,34 @@ public class ScryfallSymbolsSource implements Iterable<DownloadJob> {
}
}
@Override
public void onPreparing() throws Exception {
this.cssUrl = "";
org.jsoup.nodes.Document doc = CardImageUtils.downloadHtmlDocument(CSS_SOURCE_URL);
org.jsoup.select.Elements cssList = doc.select(CSS_SOURCE_SELECTOR);
if (cssList.size() == 1) {
this.cssUrl = cssList.first().attr("href").toString();
}
if (this.cssUrl.isEmpty()) {
throw new IllegalStateException("Can't find stylesheet url from scryfall colors page.");
} else {
this.setSource(fromURL(this.cssUrl));
}
}
private String destFile = "";
public ScryfallSymbolsDownloadJob() {
super("Scryfall symbols source", fromURL(SOURCE_URL), toFile(DOWNLOAD_TEMP_FILE));
// download init
super("Scryfall symbols source", fromURL(""), toFile(DOWNLOAD_TEMP_FILE)); // url setup on preparing stage
this.destFile = DOWNLOAD_TEMP_FILE;
this.addPropertyChangeListener(STATE_PROP_NAME, new ScryDownloadOnFinishedListener(this.destFile));
this.addPropertyChangeListener(STATE_PROP_NAME, new ScryfallDownloadOnFinishedListener(this.destFile));
// clear dest file (always download new data)
File file = new File(this.destFile);
if (file.exists()){
if (file.exists()) {
file.delete();
}
}

View file

@ -16,6 +16,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import mage.constants.SubType;
import org.apache.log4j.Logger;
import org.mage.plugins.card.images.CardDownloadData;
@ -23,7 +24,6 @@ import org.mage.plugins.card.images.DownloadPictures;
import org.mage.plugins.card.utils.CardImageUtils;
/**
*
* @author Quercitron
*/
public enum TokensMtgImageSource implements CardImageSource {
@ -58,7 +58,7 @@ public enum TokensMtgImageSource implements CardImageSource {
}
@Override
public String generateURL(CardDownloadData card) throws Exception {
public CardImageUrls generateURL(CardDownloadData card) throws Exception {
return null;
}
@ -80,7 +80,7 @@ public enum TokensMtgImageSource implements CardImageSource {
}
@Override
public String generateTokenUrl(CardDownloadData card) throws IOException {
public CardImageUrls generateTokenUrl(CardDownloadData card) throws IOException {
String name = card.getName();
String set = card.getSet();
int type = card.getType();
@ -125,7 +125,7 @@ public enum TokensMtgImageSource implements CardImageSource {
String url = "http://tokens.mtg.onl/tokens/" + tokenData.getExpansionSetCode().trim() + '_'
+ tokenData.getNumber().trim() + '-' + tokenData.getName().trim() + ".jpg";
url = url.replace(' ', '-');
return url;
return new CardImageUrls(url);
}
@Override
@ -248,7 +248,7 @@ public enum TokensMtgImageSource implements CardImageSource {
List<TokenData> newTokensData = new ArrayList<>();
try (InputStreamReader inputReader = new InputStreamReader(inputStream, "Cp1252");
BufferedReader reader = new BufferedReader(inputReader)) {
BufferedReader reader = new BufferedReader(inputReader)) {
// we have to specify encoding to read special comma
reader.readLine(); // skip header

View file

@ -1,13 +1,6 @@
package org.mage.plugins.card.dl.sources;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
@ -19,21 +12,17 @@ import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.prefs.Preferences;
import mage.cards.Sets;
import mage.cards.repository.CardCriteria;
import mage.cards.repository.CardInfo;
import mage.cards.repository.CardRepository;
import mage.client.MageFrame;
import mage.client.dialog.PreferencesDialog;
import mage.remote.Connection;
import mage.remote.Connection.ProxyType;
import org.apache.log4j.Logger;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.mage.plugins.card.images.CardDownloadData;
import org.mage.plugins.card.utils.CardImageUtils;
/**
* @author North
@ -231,13 +220,14 @@ public enum WizardCardsImageSource implements CardImageSource {
supportedSets.add("DDS");
supportedSets.add("W17");
supportedSets.add("AKH");
supportedSets.add("MPS");
supportedSets.add("CMA");
supportedSets.add("CM2"); // Commander Anthology, Vol. II
supportedSets.add("E01");
supportedSets.add("HOU");
supportedSets.add("C17");
supportedSets.add("XLN");
supportedSets.add("DDT"); // Duel Decks: Merfolk vs. Goblins
supportedSets.add("DDU"); // Duel Decks: Elves vs. Inventors
supportedSets.add("IMA"); // Iconic Msters
supportedSets.add("E02"); // Explorers of Ixalan
supportedSets.add("V17"); // From the Vault: Transform
@ -245,7 +235,12 @@ public enum WizardCardsImageSource implements CardImageSource {
supportedSets.add("RIX"); // Rivals of Ixalan
supportedSets.add("A25"); // Masters 25
supportedSets.add("DOM"); // Dominaria
// supportedSets.add("M19"); // Core 2019
supportedSets.add("BBD"); // Battlebond
supportedSets.add("GS1"); // Global Series: Jiang Yanggu and Mu Yanling
supportedSets.add("M19"); // Core 2019
supportedSets.add("C18"); // Commander 2018
// supportedSets.add("GRN"); // Guilds of Ravnica
// supportedSets.add("RNA"); // Ravnica Allegiance
sets = new HashMap<>();
setsAliases = new HashMap<>();
@ -282,6 +277,7 @@ public enum WizardCardsImageSource implements CardImageSource {
setsAliases.put("C16", "Commander 2016");
setsAliases.put("C17", "Commander 2017");
setsAliases.put("CMA", "Commander Anthology");
setsAliases.put("CM2", "Commander Anthology 2018");
setsAliases.put("CHK", "Champions of Kamigawa");
setsAliases.put("CHR", "Chronicles");
setsAliases.put("CMD", "Magic: The Gathering-Commander");
@ -312,6 +308,7 @@ public enum WizardCardsImageSource implements CardImageSource {
setsAliases.put("DDR", "Duel Decks: Nissa vs. Ob Nixilis");
setsAliases.put("DDS", "Duel Decks: Mind vs. Might");
setsAliases.put("DDT", "Duel Decks: Merfolk vs. Goblins");
setsAliases.put("DDU", "Duel Decks: Elves vs. Inventors");
setsAliases.put("DGM", "Dragon's Maze");
setsAliases.put("DIS", "Dissension");
setsAliases.put("DKA", "Dark Ascension");
@ -458,7 +455,7 @@ public enum WizardCardsImageSource implements CardImageSource {
}
@Override
public String generateURL(CardDownloadData card) throws Exception {
public CardImageUrls generateURL(CardDownloadData card) throws Exception {
String collectorId = card.getCollectorId();
String cardSet = card.getSet();
if (collectorId == null || cardSet == null) {
@ -491,7 +488,7 @@ public enum WizardCardsImageSource implements CardImageSource {
List<String> l = new ArrayList<>(setLinks.values());
if (l.size() >= number) {
link = l.get(number - 1);
} else {;
} else {
link = l.get(number - 21);
if (link != null) {
link = link.replace(Integer.toString(number - 20), (Integer.toString(number - 20) + 'a'));
@ -504,8 +501,12 @@ public enum WizardCardsImageSource implements CardImageSource {
if (link != null && !link.startsWith("http://")) {
link = "http://gatherer.wizards.com" + link;
}
return link;
if (link != null) {
return new CardImageUrls(link);
} else {
return null;
}
}
private Map<String, String> getSetLinks(String cardSet) {
@ -516,7 +517,7 @@ public enum WizardCardsImageSource implements CardImageSource {
if (setNames == null) {
setNames = Sets.getInstance().get(cardSet).getName();
}
String preferedLanguage = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_PREF_LANGUAGE, "en");
String preferredLanguage = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_PREF_LANGUAGE, "en");
for (String setName : setNames.split("\\^")) {
// String URLSetName = URLEncoder.encode(setName, "UTF-8");
String URLSetName = setName.replaceAll(" ", "%20");
@ -526,7 +527,7 @@ public enum WizardCardsImageSource implements CardImageSource {
while (page < 999) {
String searchUrl = "http://gatherer.wizards.com/Pages/Search/Default.aspx?sort=cn+&page=" + page + "&action=advanced&output=spoiler&method=visual&set=+%5B%22" + URLSetName + "%22%5D";
logger.debug("URL: " + searchUrl);
Document doc = getDocument(searchUrl);
Document doc = CardImageUtils.downloadHtmlDocument(searchUrl);
Elements cardsImages = doc.select("img[src^=../../Handlers/]");
if (cardsImages.isEmpty()) {
break;
@ -554,8 +555,8 @@ public enum WizardCardsImageSource implements CardImageSource {
cardName = cardName.substring(0, pos1);
}
}
Integer preferedMultiverseId = getLocalizedMultiverseId(preferedLanguage, multiverseId);
setLinks.put(cardName.toLowerCase(Locale.ENGLISH) + numberChar, generateLink(preferedMultiverseId));
Integer preferredMultiverseId = getLocalizedMultiverseId(preferredLanguage, multiverseId);
setLinks.put(cardName.toLowerCase(Locale.ENGLISH) + numberChar, generateLink(preferredMultiverseId));
}
}
}
@ -578,33 +579,6 @@ public enum WizardCardsImageSource implements CardImageSource {
return setLinks;
}
private Document getDocument(String urlString) throws NumberFormatException, IOException {
Preferences prefs = MageFrame.getPreferences();
Connection.ProxyType proxyType = Connection.ProxyType.valueByText(prefs.get("proxyType", "None"));
Document doc;
if (proxyType == ProxyType.NONE) {
doc = Jsoup.connect(urlString).timeout(60 * 1000).get();
} else {
String proxyServer = prefs.get("proxyAddress", "");
int proxyPort = Integer.parseInt(prefs.get("proxyPort", "0"));
URL url = new URL(urlString);
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyServer, proxyPort));
HttpURLConnection uc = (HttpURLConnection) url.openConnection(proxy);
uc.setConnectTimeout(10000);
uc.setReadTimeout(60000);
uc.connect();
String line;
StringBuffer tmp = new StringBuffer();
BufferedReader in = new BufferedReader(new InputStreamReader(uc.getInputStream()));
while ((line = in.readLine()) != null) {
tmp.append(line);
}
doc = Jsoup.parse(String.valueOf(tmp));
}
return doc;
}
private void getLandVariations(LinkedHashMap<String, String> setLinks, String cardSet, int multiverseId, String cardName) throws IOException, NumberFormatException {
CardCriteria criteria = new CardCriteria();
criteria.nameExact(cardName);
@ -612,7 +586,7 @@ public enum WizardCardsImageSource implements CardImageSource {
List<CardInfo> cards = CardRepository.instance.findCards(criteria);
String urlLandDocument = "http://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=" + multiverseId;
Document landDoc = getDocument(urlLandDocument);
Document landDoc = CardImageUtils.downloadHtmlDocument(urlLandDocument);
Elements variations = landDoc.select("a.variationlink");
if (!variations.isEmpty()) {
if (variations.size() > cards.size()) {
@ -643,12 +617,12 @@ public enum WizardCardsImageSource implements CardImageSource {
return "/Handlers/Image.ashx?multiverseid=" + landMultiverseId + "&type=card";
}
private int getLocalizedMultiverseId(String preferedLanguage, Integer multiverseId) throws IOException {
if (preferedLanguage.equals("en")) {
private int getLocalizedMultiverseId(String preferredLanguage, Integer multiverseId) throws IOException {
if (preferredLanguage.equals("en")) {
return multiverseId;
}
String languageName = languageAliases.get(preferedLanguage);
String languageName = languageAliases.get(preferredLanguage);
HashMap<String, Integer> localizedLanguageIds = getlocalizedMultiverseIds(multiverseId);
if (localizedLanguageIds.containsKey(languageName)) {
return localizedLanguageIds.get(languageName);
@ -659,7 +633,7 @@ public enum WizardCardsImageSource implements CardImageSource {
private HashMap<String, Integer> getlocalizedMultiverseIds(Integer englishMultiverseId) throws IOException {
String cardLanguagesUrl = "http://gatherer.wizards.com/Pages/Card/Languages.aspx?multiverseid=" + englishMultiverseId;
Document cardLanguagesDoc = getDocument(cardLanguagesUrl);
Document cardLanguagesDoc = CardImageUtils.downloadHtmlDocument(cardLanguagesUrl);
Elements languageTableRows = cardLanguagesDoc.select("tr.cardItem");
HashMap<String, Integer> localizedIds = new HashMap<>();
if (!languageTableRows.isEmpty()) {
@ -699,7 +673,7 @@ public enum WizardCardsImageSource implements CardImageSource {
}
@Override
public String generateTokenUrl(CardDownloadData card) {
public CardImageUrls generateTokenUrl(CardDownloadData card) {
return null;
}
@ -708,24 +682,24 @@ public enum WizardCardsImageSource implements CardImageSource {
return 60.0f;
}
// private final class GetImageLinkTask implements Runnable {
// private final class GetImageLinkTask implements Runnable {
//
// private int multiverseId;
// private String cardName;
// private String preferedLanguage;
// private String preferredLanguage;
// private LinkedHashMap setLinks;
//
// public GetImageLinkTask(int multiverseId, String cardName, String preferedLanguage, LinkedHashMap setLinks) {
// public GetImageLinkTask(int multiverseId, String cardName, String preferredLanguage, LinkedHashMap setLinks) {
// try {
// this.multiverseId = multiverseId;
// this.cardName = cardName;
// this.preferedLanguage = preferedLanguage;
// this.preferredLanguage = preferredLanguage;
// this.setLinks = setLinks;
// } catch (Exception ex) {
// logger.error(ex.getMessage());
// logger.error("multiverseId: " + multiverseId);
// logger.error("cardName: " + cardName);
// logger.error("preferedLanguage: " + preferedLanguage);
// logger.error("preferredLanguage: " + preferredLanguage);
// logger.error("setLinks: " + setLinks.toString());
// }
// }
@ -736,8 +710,8 @@ public enum WizardCardsImageSource implements CardImageSource {
// if (cardName.equals("Forest") || cardName.equals("Swamp") || cardName.equals("Mountain") || cardName.equals("Island") || cardName.equals("Plains")) {
// setLinks.putAll(getLandVariations(multiverseId, cardName));
// } else {
// Integer preferedMultiverseId = getLocalizedMultiverseId(preferedLanguage, multiverseId);
// setLinks.put(cardName.toLowerCase(Locale.ENGLISH), generateLink(preferedMultiverseId));
// Integer preferredMultiverseId = getLocalizedMultiverseId(preferredLanguage, multiverseId);
// setLinks.put(cardName.toLowerCase(Locale.ENGLISH), generateLink(preferredMultiverseId));
// }
// } catch (IOException | NumberFormatException ex) {
// logger.error("Exception when parsing the wizards page: " + ex.getMessage());

View file

@ -15,6 +15,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import javax.swing.*;
import mage.cards.ExpansionSet;
import mage.cards.Sets;
import mage.cards.repository.CardCriteria;
@ -33,6 +34,7 @@ import org.apache.log4j.Logger;
import org.mage.plugins.card.dl.sources.*;
import org.mage.plugins.card.properties.SettingsManager;
import org.mage.plugins.card.utils.CardImageUtils;
import static org.mage.plugins.card.utils.CardImageUtils.getImagesDir;
public class DownloadPictures extends DefaultBoundedRangeModel implements Runnable {
@ -42,9 +44,9 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
private static final Logger logger = Logger.getLogger(DownloadPictures.class);
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";
public static final String ALL_IMAGES = "- ALL images from selected source (CAN BE VERY SLOW)";
public static final String ALL_STANDARD_IMAGES = "- Only images from STANDARD sets";
public static final String ALL_TOKENS = "- Only token images from selected source";
private JDialog dialog;
private final JProgressBar bar;
@ -76,14 +78,15 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
private Proxy p = Proxy.NO_PROXY;
enum DownloadSources {
WIZARDS("wizards.com", WizardCardsImageSource.instance),
MYTHICSPOILER("mythicspoiler.com", MythicspoilerComSource.instance),
TOKENS("tokens.mtg.onl", TokensMtgImageSource.instance),
WIZARDS("1. wizards.com - low quality CARDS, multi-language, can be SLOW", WizardCardsImageSource.instance),
TOKENS("2. tokens.mtg.onl - high quality TOKENS", TokensMtgImageSource.instance),
SCRYFALL("3. scryfall.com - high quality CARDS, multi-language", ScryfallImageSource.instance),
MAGIDEX("4. magidex.com - high quality CARDS", MagidexImageSource.instance),
GRAB_BAG("5. GrabBag - STAR WARS cards and tokens", GrabbagImageSource.instance),
MYTHICSPOILER("6. mythicspoiler.com", MythicspoilerComSource.instance),
ALTERNATIVE("7. alternative.mtg.onl", AltMtgOnlTokensImageSource.instance),
COPYPASTE("8. Copy and Paste Image URLs", CopyPasteImageSource.instance);
// MTG_ONL("mtg.onl", MtgOnlTokensImageSource.instance), Not working correctly yet
ALTERNATIVE("alternative.mtg.onl", AltMtgOnlTokensImageSource.instance),
GRAB_BAG("GrabBag", GrabbagImageSource.instance),
MAGIDEX("magidex.com", MagidexImageSource.instance),
SCRYFALL("scryfall.com", ScryfallImageSource.instance);
// MAGICCARDS("magiccards.info", MagicCardsImageSource.instance)
private final String text;
@ -485,7 +488,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
}
try (InputStreamReader input = new InputStreamReader(in);
BufferedReader reader = new BufferedReader(input)) {
BufferedReader reader = new BufferedReader(input)) {
String line = reader.readLine();
while (line != null) {
@ -597,25 +600,25 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
logger.debug("Downloading image: " + card.getName() + " (" + card.getSet() + ')');
String url;
CardImageUrls urls;
if (ignoreUrls.contains(card.getSet()) || card.isToken()) {
if (!"0".equals(card.getCollectorId())) {
continue;
}
url = cardImageSource.generateTokenUrl(card);
urls = cardImageSource.generateTokenUrl(card);
} else {
url = cardImageSource.generateURL(card);
urls = cardImageSource.generateURL(card);
}
if (url == null) {
if (urls == null) {
String imageRef = cardImageSource.getNextHttpImageUrl();
String fileName = cardImageSource.getFileForHttpImage(imageRef);
if (imageRef != null && fileName != null) {
imageRef = cardImageSource.getSourceName() + imageRef;
try {
URL imageUrl = new URL(imageRef);
card.setToken(cardImageSource.isTokenSource());
Runnable task = new DownloadTask(card, imageUrl, fileName, cardImageSource.getTotalImages());
Runnable task = new DownloadTask(card, imageRef, fileName, cardImageSource.getTotalImages());
executor.execute(task);
} catch (Exception ex) {
}
@ -626,7 +629,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
}
}
} else {
Runnable task = new DownloadTask(card, new URL(url), cardsToDownload.size());
Runnable task = new DownloadTask(card, urls, cardsToDownload.size());
executor.execute(task);
}
@ -662,22 +665,26 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
private final class DownloadTask implements Runnable {
private final CardDownloadData card;
private final URL url;
private final CardImageUrls urls;
private final int count;
private final String actualFilename;
private final boolean useSpecifiedPaths;
DownloadTask(CardDownloadData card, URL url, int count) {
DownloadTask(CardDownloadData card, String baseUrl, int count) {
this(card, new CardImageUrls(baseUrl, null), count);
}
DownloadTask(CardDownloadData card, CardImageUrls urls, int count) {
this.card = card;
this.url = url;
this.urls = urls;
this.count = count;
this.actualFilename = "";
useSpecifiedPaths = false;
}
DownloadTask(CardDownloadData card, URL url, String actualFilename, int count) {
DownloadTask(CardDownloadData card, String baseUrl, String actualFilename, int count) {
this.card = card;
this.url = url;
this.urls = new CardImageUrls(baseUrl, null);
this.count = count;
this.actualFilename = actualFilename;
useSpecifiedPaths = true;
@ -751,14 +758,55 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
}
}
cardImageSource.doPause(url.getPath());
URLConnection httpConn = url.openConnection(p);
httpConn.setRequestProperty("User-Agent", "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.4; en-US; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2");
httpConn.connect();
int responseCode = ((HttpURLConnection) httpConn).getResponseCode();
// can download images from many alternative urls
List<String> downloadUrls;
if (this.urls != null) {
downloadUrls = this.urls.getDownloadList();
} else {
downloadUrls = new ArrayList<>();
}
if (responseCode == 200) {
// download OK
boolean isDownloadOK = false;
URLConnection httpConn = null;
List<String> errorsList = new ArrayList<>();
for (String currentUrl : downloadUrls) {
URL url = new URL(currentUrl);
// on download cancel need to stop
if (cancel) {
return;
}
// download
cardImageSource.doPause(url.getPath());
httpConn = url.openConnection(p);
httpConn.setRequestProperty("User-Agent", "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.4; en-US; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2");
httpConn.connect();
int responseCode = ((HttpURLConnection) httpConn).getResponseCode();
// check result
if (responseCode != 200) {
// show errors only on full fail (all urls were not work)
errorsList.add("Image download for " + card.getName()
+ (!card.getDownloadName().equals(card.getName()) ? " downloadname: " + card.getDownloadName() : "")
+ " (" + card.getSet() + ") failed - responseCode: " + responseCode + " url: " + url.toString());
if (logger.isDebugEnabled()) {
// Shows the returned html from the request to the web server
logger.debug("Returned HTML ERROR:\n" + convertStreamToString(((HttpURLConnection) httpConn).getErrorStream()));
}
// go to next try
continue;
} else {
// all fine
isDownloadOK = true;
break;
}
}
// can save result
if (isDownloadOK & httpConn != null) {
// save data to temp
OutputStream out = null;
OutputStream tfileout = null;
@ -792,8 +840,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
}
out.write(buf, 0, len);
}
}
finally {
} finally {
StreamUtils.closeQuietly(in);
StreamUtils.closeQuietly(out);
StreamUtils.closeQuietly(tfileout);
@ -815,15 +862,9 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab
}
} else {
// download ERROR
logger.warn("Image download for " + card.getName()
+ (!card.getDownloadName().equals(card.getName()) ? " downloadname: " + card.getDownloadName() : "")
+ " (" + card.getSet() + ") failed - responseCode: " + responseCode + " url: " + url.toString()
);
if (logger.isDebugEnabled()) {
// Shows the returned html from the request to the web server
logger.debug("Returned HTML ERROR:\n" + convertStreamToString(((HttpURLConnection) httpConn).getErrorStream()));
// download errors
for (String err : errorsList) {
logger.warn(err);
}
}

View file

@ -1,11 +1,17 @@
package org.mage.plugins.card.utils;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.util.HashMap;
import java.util.Locale;
import java.util.prefs.Preferences;
import mage.client.MageFrame;
import mage.client.constants.Constants;
import mage.client.dialog.PreferencesDialog;
@ -13,6 +19,8 @@ import mage.remote.Connection;
import mage.remote.Connection.ProxyType;
import net.java.truevfs.access.TFile;
import org.apache.log4j.Logger;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.mage.plugins.card.images.CardDownloadData;
import org.mage.plugins.card.properties.SettingsManager;
@ -22,7 +30,6 @@ public final class CardImageUtils {
private static final Logger log = Logger.getLogger(CardImageUtils.class);
/**
*
* @param card
* @return String if image exists, else null
*/
@ -54,7 +61,6 @@ public final class CardImageUtils {
}
/**
*
* @param card
* @return String regardless of whether image exists
*/
@ -280,4 +286,31 @@ public final class CardImageUtils {
}
return null;
}
public static Document downloadHtmlDocument(String urlString) throws NumberFormatException, IOException {
Preferences prefs = MageFrame.getPreferences();
Connection.ProxyType proxyType = Connection.ProxyType.valueByText(prefs.get("proxyType", "None"));
Document doc;
if (proxyType == ProxyType.NONE) {
doc = Jsoup.connect(urlString).timeout(60 * 1000).get();
} else {
String proxyServer = prefs.get("proxyAddress", "");
int proxyPort = Integer.parseInt(prefs.get("proxyPort", "0"));
URL url = new URL(urlString);
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyServer, proxyPort));
HttpURLConnection uc = (HttpURLConnection) url.openConnection(proxy);
uc.setConnectTimeout(10000);
uc.setReadTimeout(60000);
uc.connect();
String line;
StringBuffer tmp = new StringBuffer();
BufferedReader in = new BufferedReader(new InputStreamReader(uc.getInputStream()));
while ((line = in.readLine()) != null) {
tmp.append(line);
}
doc = Jsoup.parse(String.valueOf(tmp));
}
return doc;
}
}

View file

@ -357,6 +357,7 @@
|Generate|TOK:C17|Rat|||DeathtouchRatToken|
|Generate|TOK:C17|Vampire|||EdgarMarkovToken|
|Generate|TOK:C17|Zombie||
|Generate|TOK:C18|Myr|||BrudicladTelchorMyrToken|
|Generate|TOK:CHK|Dragon Spirit|||TatsumaDragonToken|
|Generate|TOK:CHK|Elemental|||SeedGuardianToken|
|Generate|TOK:CHK|Illusion|||MelokuTheCloudedMirrorToken|

View file

@ -73,6 +73,6 @@ dd3evg=ddaevg
dd3gvl=ddagvl
dd3jvc=ddajvc
# Remove setname as soon as the images can be downloaded
ignore.urls=TOK,M19,H17
ignore.urls=TOK,H17
# sets ordered by release time (newest goes first)
token.lookup.order=M19,A25,DOM,E02,RIX,UST,XLN,IMA,H17,C17,V17,E01,DDT,CMA,HOU,MM3,DDS,AKH,DD3DVD,DD3EVG,DD3GVL,DD3JVC,H09,AER,PCA,C16,V16,MPS,KLD,DDR,CN2,EMN,EMA,SOI,DDQ,CP,CMA,ARENA,SUS,APAC,EURO,UGIN,C15,OGW,EXP,DDP,BFZ,DRB,V09,V10,V11,V12,V13,V14,V15,TPR,MPRP,DD3,DDO,ORI,MM2,PTC,DTK,FRF,KTK,M15,VMA,CNS,JOU,BNG,THS,DDL,M14,MMA,DGM,GTC,RTR,M13,AVR,DDI,DKA,ISD,M12,NPH,MBS,SOM,M11,ROE,DDE,WWK,ZEN,M10,GVL,ARB,DVD,CFX,JVC,ALA,EVE,SHM,EVG,MOR,LRW,10E,CLS,CHK,GRC
token.lookup.order=C18,M19,A25,DOM,E02,RIX,UST,XLN,IMA,H17,C17,V17,E01,DDT,CMA,HOU,MM3,DDS,AKH,DD3DVD,DD3EVG,DD3GVL,DD3JVC,H09,AER,PCA,C16,V16,MPS,KLD,DDR,CN2,EMN,EMA,SOI,DDQ,CP,CMA,ARENA,SUS,APAC,EURO,UGIN,C15,OGW,EXP,DDP,BFZ,DRB,V09,V10,V11,V12,V13,V14,V15,TPR,MPRP,DD3,DDO,ORI,MM2,PTC,DTK,FRF,KTK,M15,VMA,CNS,JOU,BNG,THS,DDL,M14,MMA,DGM,GTC,RTR,M13,AVR,DDI,DKA,ISD,M12,NPH,MBS,SOM,M11,ROE,DDE,WWK,ZEN,M10,GVL,ARB,DVD,CFX,JVC,ALA,EVE,SHM,EVG,MOR,LRW,10E,CLS,CHK,GRC

View file

@ -4,11 +4,11 @@ import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import org.mage.plugins.card.dl.sources.CardImageSource;
import org.mage.plugins.card.dl.sources.CardImageUrls;
import org.mage.plugins.card.dl.sources.TokensMtgImageSource;
import org.mage.plugins.card.images.CardDownloadData;
/**
*
* @author Quercitron
*/
@Ignore
@ -18,15 +18,16 @@ public class TokensMtgImageSourceTest {
public void generateTokenUrlTest() throws Exception {
CardImageSource imageSource = TokensMtgImageSource.instance;
String url = imageSource.generateTokenUrl(new CardDownloadData("Thopter", "ORI", "0", false, 1, "ORI", ""));
Assert.assertEquals("http://tokens.mtg.onl/tokens/ORI_010-Thopter.jpg", url);
CardImageUrls url = imageSource.generateTokenUrl(new CardDownloadData("Thopter", "ORI", "0", false, 1, "ORI", ""));
Assert.assertEquals("http://tokens.mtg.onl/tokens/ORI_010-Thopter.jpg", url.baseUrl);
url = imageSource.generateTokenUrl(new CardDownloadData("Thopter", "ORI", "0", false, 2, "ORI", ""));
Assert.assertEquals("http://tokens.mtg.onl/tokens/ORI_011-Thopter.jpg", url);
Assert.assertEquals("http://tokens.mtg.onl/tokens/ORI_011-Thopter.jpg", url.baseUrl);
url = imageSource.generateTokenUrl(new CardDownloadData("Ashaya, the Awoken World", "ORI", "0", false, 0, "ORI", ""));
Assert.assertEquals("http://tokens.mtg.onl/tokens/ORI_007-Ashaya,-the-Awoken-World.jpg", url);
Assert.assertEquals("http://tokens.mtg.onl/tokens/ORI_007-Ashaya,-the-Awoken-World.jpg", url.baseUrl);
url = imageSource.generateTokenUrl(new CardDownloadData("Emblem Gideon, Ally of Zendikar", "BFZ", "0", false, 0, null, ""));
Assert.assertEquals("http://tokens.mtg.onl/tokens/BFZ_012-Gideon-Emblem.jpg", url);
Assert.assertEquals("http://tokens.mtg.onl/tokens/BFZ_012-Gideon-Emblem.jpg", url.baseUrl);
}
}

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.30</version>
<version>1.4.31</version>
</parent>
<artifactId>mage-common</artifactId>

View file

@ -1,4 +1,3 @@
package mage.utils;
import java.io.Serializable;
@ -14,8 +13,8 @@ public class MageVersion implements Serializable, Comparable<MageVersion> {
*/
public final static int MAGE_VERSION_MAJOR = 1;
public final static int MAGE_VERSION_MINOR = 4;
public final static int MAGE_VERSION_PATCH = 30;
public final static String MAGE_VERSION_MINOR_PATCH = "V2";
public final static int MAGE_VERSION_PATCH = 31;
public final static String MAGE_VERSION_MINOR_PATCH = "V1";
public final static String MAGE_VERSION_INFO = "";
private final int major;

View file

@ -73,7 +73,7 @@ public class CardsView extends LinkedHashMap<UUID, CardView> {
case BATTLEFIELD:
sourceObject = game.getPermanent(ability.getSourceId());
if (sourceObject == null) {
sourceObject = (Permanent) game.getLastKnownInformation(ability.getSourceId(), Zone.BATTLEFIELD);
sourceObject = game.getLastKnownInformation(ability.getSourceId(), Zone.BATTLEFIELD);
}
isPermanent = true;
break;

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-plugins</artifactId>
<version>1.4.30</version>
<version>1.4.31</version>
</parent>
<artifactId>mage-counter-plugin</artifactId>

View file

@ -41,6 +41,7 @@ public class CounterPluginImpl implements CounterPlugin {
File data = new File(PLUGIN_DATA_FOLDER_PATH + File.separator + DATA_STORAGE_FILE);
if (!data.exists()) {
try {
data.getParentFile().mkdirs();
data.createNewFile();
} catch (IOException e) {
log.error(e.getMessage(), e);

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.30</version>
<version>1.4.31</version>
</parent>
<artifactId>mage-plugins</artifactId>

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.30</version>
<version>1.4.31</version>
</parent>
<groupId>org.mage</groupId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.30</version>
<version>1.4.31</version>
</parent>
<artifactId>mage-deck-constructed</artifactId>

View file

@ -1,4 +1,3 @@
package mage.deck;
import java.util.HashMap;
@ -15,6 +14,73 @@ import mage.constants.SetType;
*/
public class AusHighlander extends Constructed {
public static final Map<String, Integer> pointMap = new HashMap();
static {
pointMap.put("Ancestral Recall", 4);
pointMap.put("Black Lotus", 4);
pointMap.put("Time Vault", 4);
pointMap.put("Demonic Tutor", 3);
pointMap.put("Imperial Seal", 3);
pointMap.put("Mox Emerald", 3);
pointMap.put("Mox Jet", 3);
pointMap.put("Mox Pearl", 3);
pointMap.put("Mox Ruby", 3);
pointMap.put("Mox Sapphire", 3);
pointMap.put("Sol Ring", 3);
pointMap.put("Time Walk", 3);
pointMap.put("Tinker", 3);
pointMap.put("Vampiric Tutor", 3);
pointMap.put("Yawgmoths Will", 3);
pointMap.put("Channel", 2);
pointMap.put("Dig Through Time", 2);
pointMap.put("Library of Alexandria", 2);
pointMap.put("Mana Crypt", 2);
pointMap.put("Mystical Tutor", 2);
pointMap.put("Protean Hulk", 2);
pointMap.put("Skullclamp", 2);
pointMap.put("Strip Mine", 2);
pointMap.put("Tolarian Academy", 2);
pointMap.put("Treasure Cruise", 2);
pointMap.put("Back to Basics", 1);
pointMap.put("Balance", 1);
pointMap.put("Birthing Pod", 1);
pointMap.put("Crop Rotation", 1);
pointMap.put("Dark Petition", 1);
pointMap.put("Enlightened Tutor", 1);
pointMap.put("Fastbond", 1);
pointMap.put("Force of Will", 1);
pointMap.put("Gifts Ungiven", 1);
pointMap.put("Green Suns Zenith", 1);
pointMap.put("Hermit Druid", 1);
pointMap.put("Intuition", 1);
pointMap.put("Jace, the Mind Sculptor", 1);
pointMap.put("Karakas", 1);
pointMap.put("Lim-Duls Vault", 1);
pointMap.put("Mana Drain", 1);
pointMap.put("Mana Vault", 1);
pointMap.put("Memory Jar", 1);
pointMap.put("Merchant Scroll", 1);
pointMap.put("Mind Twist", 1);
pointMap.put("Mishras Workshop", 1);
pointMap.put("Natural Order", 1);
pointMap.put("Oath of Druids", 1);
pointMap.put("Personal Tutor", 1);
pointMap.put("Senseis Divining Top", 1);
pointMap.put("Snapcaster Mage", 1);
pointMap.put("Stoneforge Mystic", 1);
pointMap.put("Survival of the Fittest", 1);
pointMap.put("Tainted Pact", 1);
pointMap.put("Time Spiral", 1);
pointMap.put("Timetwister", 1);
pointMap.put("True-Name Nemesis", 1);
pointMap.put("Umezawas Jitte", 1);
pointMap.put("Wasteland", 1);
pointMap.put("Wheel of Fortune", 1);
pointMap.put("Worldly Tutor", 1);
pointMap.put("Yawgmoths Bargain", 1);
}
public AusHighlander() {
this("Australian Highlander");
for (ExpansionSet set : Sets.getInstance().values()) {
@ -82,79 +148,9 @@ public class AusHighlander extends Constructed {
int totalPoints = 0;
for (Map.Entry<String, Integer> entry : counts.entrySet()) {
String cn = entry.getKey();
if (cn.equals("Ancestral Recall")
|| cn.equals("Black Lotus")
|| cn.equals("Time Vault")) {
totalPoints += 4;
invalid.put(cn, "4 points");
}
if (cn.equals("Demonic Tutor")
|| cn.equals("Imperial Seal")
|| cn.equals("Mox Emerald")
|| cn.equals("Mox Jet")
|| cn.equals("Mox Pearl")
|| cn.equals("Mox Ruby")
|| cn.equals("Sol Ring")
|| cn.equals("Time Walk")
|| cn.equals("Tinker")
|| cn.equals("Vampiric Tutor")
|| cn.equals("Yawgmoth's Will")
|| cn.equals("Mox Sapphire")) {
totalPoints += 3;
invalid.put(cn, "3 points");
}
if (cn.equals("Channel")
|| cn.equals("Dig Through Time")
|| cn.equals("Library of Alexandria")
|| cn.equals("Mana Crypt")
|| cn.equals("Mystical Tutor")
|| cn.equals("Protean Hulk")
|| cn.equals("Skullclamp")
|| cn.equals("Strip Mine")
|| cn.equals("Tolarian Academy")
|| cn.equals("Treasure Cruise")) {
totalPoints += 2;
invalid.put(cn, "2 points");
}
if (cn.equals("Back to Basics")
|| cn.equals("Balance")
|| cn.equals("Birthing Pod")
|| cn.equals("Crop Rotation")
|| cn.equals("Dark Petition")
|| cn.equals("Enlightened Tutor")
|| cn.equals("Fastbond")
|| cn.equals("Force of Will")
|| cn.equals("Gifts Ungiven")
|| cn.equals("Green Sun's Zenith")
|| cn.equals("Hermit Druid")
|| cn.equals("Intuition")
|| cn.equals("Jace, the Mind Sculptor")
|| cn.equals("Karakas")
|| cn.equals("Lim-Dul's Vault")
|| cn.equals("Mana Drain")
|| cn.equals("Mana Vault")
|| cn.equals("Memory Jar")
|| cn.equals("Merchant Scroll")
|| cn.equals("Mind Twist")
|| cn.equals("Mishra's Workshop")
|| cn.equals("Natural Order")
|| cn.equals("Oath of Druids")
|| cn.equals("Personal Tutor")
|| cn.equals("Sensei's Divining Top")
|| cn.equals("Snapcaster Mage")
|| cn.equals("Stoneforge Mystic")
|| cn.equals("Survival of the Fittest")
|| cn.equals("Tainted Pact")
|| cn.equals("Time Spiral")
|| cn.equals("Timetwister")
|| cn.equals("True-Name Nemesis")
|| cn.equals("Umezawa's Jitte")
|| cn.equals("Wasteland")
|| cn.equals("Wheel of Fortune")
|| cn.equals("Yawgmoth's Bargain")
|| cn.equals("Worldly Tutor")) {
totalPoints += 1;
invalid.put(cn, "1 point");
if (pointMap.containsKey(cn)) {
totalPoints += pointMap.get(cn);
invalid.put(entry.getKey(), " " + pointMap.get(cn) + " point " + cn);
}
}
if (totalPoints > 7) {

View file

@ -1,14 +1,10 @@
package mage.deck;
import java.util.*;
import mage.abilities.common.CanBeYourCommanderAbility;
import mage.cards.Card;
import mage.cards.ExpansionSet;
import mage.cards.Sets;
import mage.cards.decks.Constructed;
import mage.cards.decks.Deck;
import mage.constants.SetType;
import mage.filter.FilterMana;
/**
@ -23,41 +19,11 @@ public class Brawl extends Constructed {
super("Brawl");
// Copy of standard sets
GregorianCalendar current = new GregorianCalendar();
List<ExpansionSet> sets = new ArrayList(Sets.getInstance().values());
Collections.sort(sets, new Comparator<ExpansionSet>() {
@Override
public int compare(final ExpansionSet lhs, ExpansionSet rhs) {
return lhs.getReleaseDate().after(rhs.getReleaseDate()) ? -1 : 1;
}
});
int blocksAdded = 0;
int blocksToAdd = 3;
for (Iterator<ExpansionSet> iter = sets.iterator(); iter.hasNext() && blocksAdded < blocksToAdd;) {
ExpansionSet set = iter.next();
if (set.getSetType() == SetType.CORE || set.getSetType() == SetType.EXPANSION || set.getSetType() == SetType.SUPPLEMENTAL_STANDARD_LEGAL) { // Still adding core sets because of Magic Origins
setCodes.addAll(Standard.makeLegalSets());
setCodes.add(set.getCode());
if (set.getReleaseDate().before(current.getTime()) // This stops spoiled sets from counting as "new" blocks
&& set.getParentSet() == null
&& set.getSetType() == SetType.EXPANSION) {
if (blocksAdded == 0 && !isFallBlock(set)) { // if the most current block is no fall block, 4 blocks are added
blocksToAdd++;
}
blocksAdded++;
}
}
}
banned.add("Baral, Chief of Compliance");
banned.add("Smuggler's Copter");
banned.add("Sorcerers' Spyglass");
}
private static boolean isFallBlock(ExpansionSet set) {
Calendar cal = Calendar.getInstance();
cal.setTime(set.getReleaseDate());
// Sets from fall block are normally released in September and January
return cal.get(Calendar.MONTH) > 7 || cal.get(Calendar.MONTH) < 2;
banned.add("Sorcerous Spyglass");
}
public Brawl(String name) {

View file

@ -1,4 +1,3 @@
package mage.deck;
import java.util.HashMap;
@ -15,6 +14,53 @@ import mage.constants.SetType;
*/
public class CanadianHighlander extends Constructed {
public static final Map<String, Integer> pointMap = new HashMap();
static {
pointMap.put("Ancestral Recall", 7);
pointMap.put("Balance", 1);
pointMap.put("Birthing Pod", 3);
pointMap.put("Black Lotus", 7);
pointMap.put("Demonic Tutor", 4);
pointMap.put("Dig Through Time", 1);
pointMap.put("Enlightened Tutor", 1);
pointMap.put("Fastbond", 1);
pointMap.put("Flash", 7);
pointMap.put("Gifts Ungiven", 2);
pointMap.put("Hermit Druid", 1);
pointMap.put("Imperial Seal", 1);
pointMap.put("Intuition", 1);
pointMap.put("Library of Alexandria", 1);
pointMap.put("Mana Crypt", 2);
pointMap.put("Mana Drain", 1);
pointMap.put("Mana Vault", 1);
pointMap.put("Merchant Scroll", 1);
pointMap.put("Mind Twist", 1);
pointMap.put("Mox Emerald", 3);
pointMap.put("Mox Jet", 3);
pointMap.put("Mox Pearl", 3);
pointMap.put("Mox Ruby", 3);
pointMap.put("Mox Sapphire", 3);
pointMap.put("Mystical Tutor", 2);
pointMap.put("Natural Order", 4);
pointMap.put("Personal Tutor", 1);
pointMap.put("Protean Hulk", 3);
pointMap.put("Sol Ring", 3);
pointMap.put("Stoneforge Mystic", 1);
pointMap.put("Strip Mine", 2);
pointMap.put("Summoner's Pact", 2);
pointMap.put("Survival of the Fittest", 2);
pointMap.put("Time Vault", 6);
pointMap.put("Time Walk", 6);
pointMap.put("Tinker", 4);
pointMap.put("Tolarian Academy", 1);
pointMap.put("Transmute Artifact", 1);
pointMap.put("Treasure Cruise", 1);
pointMap.put("True-Name Nemesis", 1);
pointMap.put("Umezawa's Jitte", 2);
pointMap.put("Vampiric Tutor", 3);
}
public CanadianHighlander() {
this("Canadian Highlander");
for (ExpansionSet set : Sets.getInstance().values()) {
@ -54,74 +100,13 @@ public class CanadianHighlander extends Constructed {
}
}
int allowedPoints = 10 * (int) Math.floor(deck.getCards().size() / 100.0);
int allowedPoints = 10;
int totalPoints = 0;
for (Map.Entry<String, Integer> entry : counts.entrySet()) {
String cn = entry.getKey();
if (cn.equals("Balance")
|| cn.equals("Dig Through Time")
|| cn.equals("Doomsday")
|| cn.equals("Enlightened Tutor")
|| cn.equals("Fastbond")
|| cn.equals("Intuition")
|| cn.equals("Library of Alexandria")
|| cn.equals("Mana Vault")
|| cn.equals("Merchant Scroll")
|| cn.equals("Mind Twist")
|| cn.equals("Personal Tutor")
|| cn.equals("Stoneforge Mystic")
|| cn.equals("Tainted Pact")
|| cn.equals("Tolarian Academy")
|| cn.equals("Transmute Artifact")
|| cn.equals("Treasure Cruise")
|| cn.equals("True-Name Nemesis")
|| cn.equals("Worldly Tutor")) {
totalPoints += 1;
invalid.put(entry.getKey(), " 1 point " + cn);
}
if (cn.equals("Gifts Ungiven")
|| cn.equals("Hermit Druid")
|| cn.equals("Imperial Seal")
|| cn.equals("Mana Crypt")
|| cn.equals("Mystical Tutor")
|| cn.equals("Strip Mine")
|| cn.equals("Summoner's Pact")
|| cn.equals("Survival of the Fittest")
|| cn.equals("Umezawa's Jitte")) {
totalPoints += 2;
invalid.put(entry.getKey(), " 2 points " + cn);
}
if (cn.equals("Birthing Pod")
|| cn.equals("Mox Emerald")
|| cn.equals("Mox Jet")
|| cn.equals("Mox Pearl")
|| cn.equals("Mox Ruby")
|| cn.equals("Mox Sapphire")
|| cn.equals("Protean Hulk")
|| cn.equals("Sol Ring")
|| cn.equals("Vampiric Tutor")) {
totalPoints += 3;
invalid.put(entry.getKey(), " 3 points " + cn);
}
if (cn.equals("Demonic Tutor")
|| cn.equals("Tinker")) {
totalPoints += 4;
invalid.put(entry.getKey(), " 4 points " + cn);
}
if (cn.equals("Natural Order")
|| cn.equals("Time Walk")) {
totalPoints += 5;
invalid.put(entry.getKey(), " 5 points " + cn);
}
if (cn.equals("Ancestral Recall")
|| cn.equals("Time Vault")) {
totalPoints += 6;
invalid.put(entry.getKey(), " 6 points " + cn);
}
if (cn.equals("Black Lotus")
|| cn.equals("Flash")) {
totalPoints += 7;
invalid.put(entry.getKey(), " 7 points " + cn);
if (pointMap.containsKey(cn)) {
totalPoints += pointMap.get(cn);
invalid.put(entry.getKey(), " " + pointMap.get(cn) + " point " + cn);
}
}
if (totalPoints > allowedPoints) {

View file

@ -1,4 +1,3 @@
package mage.deck;
import java.util.*;
@ -23,6 +22,7 @@ import mage.filter.FilterMana;
public class Commander extends Constructed {
protected List<String> bannedCommander = new ArrayList<>();
protected boolean partnerAllowed = true;
public Commander() {
this("Commander");
@ -105,6 +105,9 @@ public class Commander extends Constructed {
}
if (deck.getSideboard().size() < 1 || deck.getSideboard().size() > 2) {
if ((deck.getSideboard().size() > 1 && !partnerAllowed)) {
invalid.put("Commander", "You may only have one commander");
}
invalid.put("Commander", "Sideboard must contain only the commander(s)");
valid = false;
} else {

View file

@ -20,7 +20,6 @@ public class FreeformCommander extends Constructed {
protected List<String> bannedCommander = new ArrayList<>();
private static final Map<String, Integer> pdAllowed = new HashMap<>();
private static boolean setupAllowed = false;
public FreeformCommander() {
this("Freeform Commander");
@ -43,7 +42,6 @@ public class FreeformCommander extends Constructed {
valid = false;
}
List<String> basicLandNames = new ArrayList<>(Arrays.asList("Forest", "Island", "Mountain", "Swamp", "Plains", "Wastes"));
Map<String, Integer> counts = new HashMap<>();
countCards(counts, deck.getCards());
countCards(counts, deck.getSideboard());

View file

@ -1,4 +1,3 @@
package mage.deck;
import mage.cards.ExpansionSet;
@ -32,6 +31,7 @@ public class Legacy extends Constructed {
banned.add("Chaos Orb");
banned.add("Contract from Below");
banned.add("Darkpact");
banned.add("Deathrite Shaman");
banned.add("Demonic Attorney");
banned.add("Demonic Consultation");
banned.add("Demonic Tutor");
@ -42,6 +42,7 @@ public class Legacy extends Constructed {
banned.add("Fastbond");
banned.add("Flash");
banned.add("Frantic Search");
banned.add("Gitaxian Probe");
banned.add("Goblin Recruiter");
banned.add("Gush");
banned.add("Hermit Druid");

View file

@ -1,4 +1,3 @@
package mage.deck;
/**
@ -9,70 +8,49 @@ public class MTGO1v1Commander extends Commander {
public MTGO1v1Commander() {
super("MTGO 1v1 Commander");
partnerAllowed = false;
banned.add("Ancestral Recall");
banned.add("Ancient Tomb");
banned.add("Back to Basics");
banned.add("Balance");
banned.add("Baral, Chief of Compliance");
banned.add("Black Lotus");
banned.add("Braids, Cabal Minion");
banned.add("Brainstorm");
banned.add("Channel");
banned.add("Chrome Mox");
banned.add("Derevi, Empyrial Tactician");
banned.add("Demonic Tutor");
banned.add("Dig Through Time");
banned.add("Doomsday");
banned.add("Edgar Markov");
banned.add("Edric, Spymaster of Trest");
banned.add("Emrakul, the Aeons Torn");
banned.add("Enlightened Tutor");
banned.add("Entomb");
banned.add("Erayo, Soratami Ascendant");
banned.add("Fastbond");
banned.add("Food Chain");
banned.add("Gaea's Cradle");
banned.add("Gifts Ungiven");
banned.add("Hermit Druid");
banned.add("Humility");
banned.add("Imperial Seal");
banned.add("Karakas");
banned.add("Library of Alexandria");
banned.add("Mana Crypt");
banned.add("Mana Drain");
banned.add("Mana Vault");
banned.add("Mind Twist");
banned.add("Moat");
banned.add("Mox Diamond");
banned.add("Mox Emerald");
banned.add("Mox Jet");
banned.add("Mox Pearl");
banned.add("Mox Ruby");
banned.add("Mox Sapphire");
banned.add("Mystical Tutor");
banned.add("Natural Order");
banned.add("Necropotence");
banned.add("Oath of Druids");
banned.add("Ponder");
banned.add("Preordain");
banned.add("Rofellos, Llanowar Emissary");
banned.add("Strip Mine");
banned.add("Sensei's Divining Top");
banned.add("Serra Ascendant");
banned.add("Sol Ring");
banned.add("Strip Mine");
banned.add("Survival of the Fittest");
banned.add("Sylvan Library");
banned.add("Sylvan Tutor");
banned.add("The Tabernacle at Pendrell Vale");
banned.add("Time Vault");
banned.add("Time Walk");
banned.add("Tinker");
banned.add("Tolarian Academy");
banned.add("Treachery");
banned.add("Treasure Cruise");
banned.add("Vial Smasher the Fierce");
banned.add("Vampiric Tutor");
banned.add("Winter Orb");
banned.add("Wordly Tutor");
banned.add("Yamgmoth's Bargain");
banned.add("Zur the Enchanter");
}
}

View file

@ -1,12 +1,11 @@
package mage.deck;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.List;
import mage.cards.ExpansionSet;
import mage.cards.Sets;
@ -21,31 +20,9 @@ public class Standard extends Constructed {
public Standard() {
super("Constructed - Standard");
GregorianCalendar current = new GregorianCalendar();
List<ExpansionSet> sets = new ArrayList(Sets.getInstance().values());
Collections.sort(sets, new Comparator<ExpansionSet>() {
@Override
public int compare(final ExpansionSet lhs, ExpansionSet rhs) {
return lhs.getReleaseDate().after(rhs.getReleaseDate()) ? -1 : 1;
}
});
int blocksAdded = 0;
int blocksToAdd = 3;
for (Iterator<ExpansionSet> iter = sets.iterator(); iter.hasNext() && blocksAdded < blocksToAdd;) {
ExpansionSet set = iter.next();
if (set.getSetType() == SetType.CORE || set.getSetType() == SetType.EXPANSION || set.getSetType() == SetType.SUPPLEMENTAL_STANDARD_LEGAL) { // Still adding core sets because of Magic Origins
setCodes.add(set.getCode());
if (set.getReleaseDate().before(current.getTime()) // This stops spoiled sets from counting as "new" blocks
&& set.getParentSet() == null
&& set.getSetType() == SetType.EXPANSION) {
if (blocksAdded == 0 && !isFallBlock(set)) { // if the most current block is no fall block, 4 blocks are added
blocksToAdd++;
}
blocksAdded++;
}
}
}
setCodes.addAll(makeLegalSets());
banned.add("Attune with Aether"); // since 2018-01-15
banned.add("Aetherworks Marvel");
banned.add("Felidar Guardian");
@ -55,10 +32,49 @@ public class Standard extends Constructed {
banned.add("Smuggler's Copter");
}
private static boolean isFallBlock(ExpansionSet set) {
private static boolean isFallSet(ExpansionSet set) {
Calendar cal = Calendar.getInstance();
cal.setTime(set.getReleaseDate());
// Sets from fall block are normally released in September and January
return cal.get(Calendar.MONTH) > 7 || cal.get(Calendar.MONTH) < 2;
// Fall sets are normally released during or after September
return set.getSetType() == SetType.EXPANSION
&& (cal.get(Calendar.MONTH) > 7);
}
public static List<String> makeLegalSets() {
List<String> codes = new ArrayList();
GregorianCalendar current = new GregorianCalendar();
List<ExpansionSet> sets = new ArrayList(Sets.getInstance().values());
Collections.sort(sets, new Comparator<ExpansionSet>() {
@Override
public int compare(final ExpansionSet lhs, ExpansionSet rhs) {
return lhs.getReleaseDate().after(rhs.getReleaseDate()) ? -1 : 1;
}
});
int fallSetsAdded = 0;
Date earliestDate = null;
// Get the second most recent fall set that's been released.
for (ExpansionSet set : sets) {
if (set.getReleaseDate().after(current.getTime())) {
continue;
}
if (isFallSet(set)) {
fallSetsAdded++;
if (fallSetsAdded == 2) {
earliestDate = set.getReleaseDate();
break;
}
}
}
// Get all sets released on or after the second most recent fall set's release
for (ExpansionSet set : sets) {
if ((set.getSetType() == SetType.CORE
|| set.getSetType() == SetType.EXPANSION
|| set.getSetType() == SetType.SUPPLEMENTAL_STANDARD_LEGAL)
&& !set.getReleaseDate().before(earliestDate)) {
// && !set.getReleaseDate().after(current.getTime()))) {
codes.add(set.getCode());
}
}
return codes;
}
}

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.30</version>
<version>1.4.31</version>
</parent>
<artifactId>mage-deck-limited</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.30</version>
<version>1.4.31</version>
</parent>
<artifactId>mage-game-brawlduel</artifactId>

View file

@ -16,7 +16,7 @@ public class BrawlDuelMatch extends MatchImpl {
@Override
public void startGame() throws GameException {
int startLife = 20;
int startLife = 25;
boolean alsoHand = true;
BrawlDuel game = new BrawlDuel(options.getAttackOption(), options.getRange(), options.getFreeMulligans(), startLife);
game.setCheckCommanderDamage(false);

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.30</version>
<version>1.4.31</version>
</parent>
<artifactId>mage-game-brawlfreeforall</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.30</version>
<version>1.4.31</version>
</parent>
<artifactId>mage-game-canadianhighlanderduel</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.30</version>
<version>1.4.31</version>
</parent>
<artifactId>mage-game-commanderduel</artifactId>

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.30</version>
<version>1.4.31</version>
</parent>
<artifactId>mage-game-commanderfreeforall</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.30</version>
<version>1.4.31</version>
</parent>
<artifactId>mage-game-freeforall</artifactId>

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.30</version>
<version>1.4.31</version>
</parent>
<artifactId>mage-game-freeformcommanderfreeforall</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.30</version>
<version>1.4.31</version>
</parent>
<artifactId>mage-game-momirduel</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.30</version>
<version>1.4.31</version>
</parent>
<artifactId>mage-game-momirfreeforall</artifactId>

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.30</version>
<version>1.4.31</version>
</parent>
<artifactId>mage-game-pennydreadfulcommanderfreeforall</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.30</version>
<version>1.4.31</version>
</parent>
<artifactId>mage-game-tinyleadersduel</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.30</version>
<version>1.4.31</version>
</parent>
<artifactId>mage-game-twoplayerduel</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.30</version>
<version>1.4.31</version>
</parent>
<artifactId>mage-player-ai-draftbot</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.30</version>
<version>1.4.31</version>
</parent>
<artifactId>mage-player-ai-ma</artifactId>

View file

@ -136,7 +136,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
sb.setLength(0);
sb.append("-> Permanents: [");
for (Permanent permanent : game.getBattlefield().getAllPermanents()) {
if (permanent.getOwnerId().equals(player.getId())) {
if (permanent.isOwnedBy(player.getId())) {
sb.append(permanent.getName());
if (permanent.isTapped()) {
sb.append("(tapped)");
@ -254,7 +254,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
} else if (stepFinished) {
logger.debug("Step finished");
int testScore = GameStateEvaluator2.evaluate(playerId, game);
if (game.getActivePlayerId().equals(playerId)) {
if (game.isActivePlayer(playerId)) {
if (testScore < currentScore) {
// if score at end of step is worse than original score don't check further
//logger.debug("Add Action -- abandoning check, no immediate benefit");

View file

@ -54,7 +54,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 {
pass(game);
return false;
case PRECOMBAT_MAIN:
if (game.getActivePlayerId().equals(playerId)) {
if (game.isActivePlayer(playerId)) {
printOutState(game);
if (actions.isEmpty()) {
logger.info("Sim Calculate pre combat actions ----------------------------------------------------- ");

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.30</version>
<version>1.4.31</version>
</parent>
<artifactId>mage-player-ai</artifactId>

View file

@ -987,7 +987,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
private boolean priorityPlay(Game game) {
UUID opponentId = game.getOpponents(playerId).iterator().next();
if (game.getActivePlayerId().equals(playerId)) {
if (game.isActivePlayer(playerId)) {
if (game.isMainPhase() && game.getStack().isEmpty()) {
playLand(game);
}

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.30</version>
<version>1.4.31</version>
</parent>
<artifactId>mage-player-ai-mcts</artifactId>

View file

@ -348,7 +348,7 @@ public class ComputerPlayerMCTS extends ComputerPlayer implements Player {
thinkTime = maxThinkTime / 2;
}
}
else if (game.getActivePlayerId().equals(playerId) && (curStep == PhaseStep.PRECOMBAT_MAIN || curStep == PhaseStep.POSTCOMBAT_MAIN) && game.getStack().isEmpty()) {
else if (game.isActivePlayer(playerId) && (curStep == PhaseStep.PRECOMBAT_MAIN || curStep == PhaseStep.POSTCOMBAT_MAIN) && game.getStack().isEmpty()) {
if (nodeSizeRatio < THINK_MIN_RATIO) {
thinkTime = maxThinkTime;
}

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.30</version>
<version>1.4.31</version>
</parent>
<artifactId>mage-player-aiminimax</artifactId>

View file

@ -50,7 +50,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player {
pass(game);
return false;
case PRECOMBAT_MAIN:
if (game.getActivePlayerId().equals(playerId)) {
if (game.isActivePlayer(playerId)) {
if (actions.isEmpty()) {
calculatePreCombatActions(game);
}
@ -64,7 +64,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player {
pass(game);
return false;
case DECLARE_ATTACKERS:
if (!game.getActivePlayerId().equals(playerId)) {
if (!game.isActivePlayer(playerId)) {
if (actions.isEmpty()) {
calculatePreCombatActions(game);
}
@ -81,7 +81,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player {
pass(game);
return false;
case POSTCOMBAT_MAIN:
if (game.getActivePlayerId().equals(playerId)) {
if (game.isActivePlayer(playerId)) {
if (actions.isEmpty()) {
calculatePostCombatActions(game);
}
@ -184,7 +184,7 @@ public class ComputerPlayer3 extends ComputerPlayer2 implements Player {
else if (stepFinished) {
logger.debug(indent(node.depth) + "step finished");
int testScore = GameStateEvaluator.evaluate(playerId, game);
if (game.getActivePlayerId().equals(playerId)) {
if (game.isActivePlayer(playerId)) {
if (testScore < currentScore) {
// if score at end of step is worse than original score don't check further
logger.debug(indent(node.depth) + "simulating -- abandoning check, no immediate benefit");

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.30</version>
<version>1.4.31</version>
</parent>
<artifactId>mage-player-human</artifactId>

View file

@ -341,8 +341,18 @@ public class HumanPlayer extends PlayerImpl {
replacementEffectChoice.getChoices().clear();
replacementEffectChoice.setKeyChoices(rEffects);
// Check if there are different ones
int differentChoices = 0;
String lastChoice = "";
for (String value : replacementEffectChoice.getKeyChoices().values()) {
if (!lastChoice.equalsIgnoreCase(value)) {
lastChoice = value;
differentChoices++;
}
}
while (!abort) {
while (!abort && differentChoices > 1) {
updateGameStatePriority("chooseEffect", game);
prepareForResponse(game);
if (!isExecutingMacro()) {
@ -1943,7 +1953,7 @@ public class HumanPlayer extends PlayerImpl {
if (userData.confirmEmptyManaPool()
&& game.getStack().isEmpty() && getManaPool().count() > 0) {
String activePlayerText;
if (game.getActivePlayerId().equals(playerId)) {
if (game.isActivePlayer(playerId)) {
activePlayerText = "Your turn";
} else {
activePlayerText = game.getPlayer(game.getActivePlayerId()).getName() + "'s turn";

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.30</version>
<version>1.4.31</version>
</parent>
<artifactId>mage-tournament-boosterdraft</artifactId>

View file

@ -0,0 +1,555 @@
package mage.tournament.cubes;
import mage.game.draft.DraftCube;
/**
*
* @author TheELk801
*/
public class VintageCubeJune2018 extends DraftCube {
public VintageCubeJune2018() {
super("MTGO Vintage Cube June 2018");
cubeCards.add(new DraftCube.CardIdentity("Abbot of Keral Keep", ""));
cubeCards.add(new DraftCube.CardIdentity("Abrade", ""));
cubeCards.add(new DraftCube.CardIdentity("Abrupt Decay", ""));
cubeCards.add(new DraftCube.CardIdentity("Academy Ruins", ""));
cubeCards.add(new DraftCube.CardIdentity("Acidic Slime", ""));
cubeCards.add(new DraftCube.CardIdentity("Adanto Vanguard", ""));
cubeCards.add(new DraftCube.CardIdentity("Ajani Vengeant", ""));
cubeCards.add(new DraftCube.CardIdentity("Ancestral Recall", ""));
cubeCards.add(new DraftCube.CardIdentity("Ancestral Vision", ""));
cubeCards.add(new DraftCube.CardIdentity("Ancient Grudge", ""));
cubeCards.add(new DraftCube.CardIdentity("Ancient Stirrings", ""));
cubeCards.add(new DraftCube.CardIdentity("Ancient Tomb", ""));
cubeCards.add(new DraftCube.CardIdentity("Angel of Invention", ""));
cubeCards.add(new DraftCube.CardIdentity("Angel of Sanctions", ""));
cubeCards.add(new DraftCube.CardIdentity("Angel of Serenity", ""));
cubeCards.add(new DraftCube.CardIdentity("Anguished Unmaking", ""));
cubeCards.add(new DraftCube.CardIdentity("Animate Dead", ""));
cubeCards.add(new DraftCube.CardIdentity("Arbor Elf", ""));
cubeCards.add(new DraftCube.CardIdentity("Archangel of Thune", ""));
cubeCards.add(new DraftCube.CardIdentity("Arguel's Blood Fast", ""));
cubeCards.add(new DraftCube.CardIdentity("Arid Mesa", ""));
cubeCards.add(new DraftCube.CardIdentity("Armageddon", ""));
cubeCards.add(new DraftCube.CardIdentity("Ashiok, Nightmare Weaver", ""));
cubeCards.add(new DraftCube.CardIdentity("Augur of Bolas", ""));
cubeCards.add(new DraftCube.CardIdentity("Avacyn's Pilgrim", ""));
cubeCards.add(new DraftCube.CardIdentity("Avalanche Riders", ""));
cubeCards.add(new DraftCube.CardIdentity("Avenger of Zendikar", ""));
cubeCards.add(new DraftCube.CardIdentity("Awakening Zone", ""));
cubeCards.add(new DraftCube.CardIdentity("Azorius Signet", ""));
cubeCards.add(new DraftCube.CardIdentity("Badlands", ""));
cubeCards.add(new DraftCube.CardIdentity("Balance", ""));
cubeCards.add(new DraftCube.CardIdentity("Baleful Strix", ""));
cubeCards.add(new DraftCube.CardIdentity("Baneslayer Angel", ""));
cubeCards.add(new DraftCube.CardIdentity("Banisher Priest", ""));
cubeCards.add(new DraftCube.CardIdentity("Banishing Light", ""));
cubeCards.add(new DraftCube.CardIdentity("Basalt Monolith", ""));
cubeCards.add(new DraftCube.CardIdentity("Batterskull", ""));
cubeCards.add(new DraftCube.CardIdentity("Bayou", ""));
cubeCards.add(new DraftCube.CardIdentity("Bazaar of Baghdad", ""));
cubeCards.add(new DraftCube.CardIdentity("Beast Within", ""));
cubeCards.add(new DraftCube.CardIdentity("Benalish Marshal", ""));
cubeCards.add(new DraftCube.CardIdentity("Birds of Paradise", ""));
cubeCards.add(new DraftCube.CardIdentity("Bitterblossom", ""));
cubeCards.add(new DraftCube.CardIdentity("Black Lotus", ""));
cubeCards.add(new DraftCube.CardIdentity("Blackcleave Cliffs", ""));
cubeCards.add(new DraftCube.CardIdentity("Blade Splicer", ""));
cubeCards.add(new DraftCube.CardIdentity("Blightsteel Colossus", ""));
cubeCards.add(new DraftCube.CardIdentity("Blink of an Eye", ""));
cubeCards.add(new DraftCube.CardIdentity("Blood Crypt", ""));
cubeCards.add(new DraftCube.CardIdentity("Bloodbraid Elf", ""));
cubeCards.add(new DraftCube.CardIdentity("Bloodstained Mire", ""));
cubeCards.add(new DraftCube.CardIdentity("Blooming Marsh", ""));
cubeCards.add(new DraftCube.CardIdentity("Bone Shredder", ""));
cubeCards.add(new DraftCube.CardIdentity("Bonfire of the Damned", ""));
cubeCards.add(new DraftCube.CardIdentity("Boros Signet", ""));
cubeCards.add(new DraftCube.CardIdentity("Botanical Sanctum", ""));
cubeCards.add(new DraftCube.CardIdentity("Braids, Cabal Minion", ""));
cubeCards.add(new DraftCube.CardIdentity("Brain Freeze", ""));
cubeCards.add(new DraftCube.CardIdentity("Brain Maggot", ""));
cubeCards.add(new DraftCube.CardIdentity("Brainstorm", ""));
cubeCards.add(new DraftCube.CardIdentity("Breeding Pool", ""));
cubeCards.add(new DraftCube.CardIdentity("Bribery", ""));
cubeCards.add(new DraftCube.CardIdentity("Brimaz, King of Oreskos", ""));
cubeCards.add(new DraftCube.CardIdentity("Bring to Light", ""));
cubeCards.add(new DraftCube.CardIdentity("Buried Alive", ""));
cubeCards.add(new DraftCube.CardIdentity("Burning of Xinye", ""));
cubeCards.add(new DraftCube.CardIdentity("Burst Lightning", ""));
cubeCards.add(new DraftCube.CardIdentity("Cabal Ritual", ""));
cubeCards.add(new DraftCube.CardIdentity("Cast Down", ""));
cubeCards.add(new DraftCube.CardIdentity("Cast Out", ""));
cubeCards.add(new DraftCube.CardIdentity("Celestial Colonnade", ""));
cubeCards.add(new DraftCube.CardIdentity("Chain Lightning", ""));
cubeCards.add(new DraftCube.CardIdentity("Chandra, Flamecaller", ""));
cubeCards.add(new DraftCube.CardIdentity("Chandra, Pyromaster", ""));
cubeCards.add(new DraftCube.CardIdentity("Chandra, Torch of Defiance", ""));
cubeCards.add(new DraftCube.CardIdentity("Channel", ""));
cubeCards.add(new DraftCube.CardIdentity("Char", ""));
cubeCards.add(new DraftCube.CardIdentity("Chart a Course", ""));
cubeCards.add(new DraftCube.CardIdentity("Chrome Mox", ""));
cubeCards.add(new DraftCube.CardIdentity("Coalition Relic", ""));
cubeCards.add(new DraftCube.CardIdentity("Coercive Portal", ""));
cubeCards.add(new DraftCube.CardIdentity("Commit // Memory", ""));
cubeCards.add(new DraftCube.CardIdentity("Compulsive Research", ""));
cubeCards.add(new DraftCube.CardIdentity("Concealed Courtyard", ""));
cubeCards.add(new DraftCube.CardIdentity("Consecrated Sphinx", ""));
cubeCards.add(new DraftCube.CardIdentity("Control Magic", ""));
cubeCards.add(new DraftCube.CardIdentity("Copperline Gorge", ""));
cubeCards.add(new DraftCube.CardIdentity("Corpse Dance", ""));
cubeCards.add(new DraftCube.CardIdentity("Council's Judgment", ""));
cubeCards.add(new DraftCube.CardIdentity("Counterspell", ""));
cubeCards.add(new DraftCube.CardIdentity("Courser of Kruphix", ""));
cubeCards.add(new DraftCube.CardIdentity("Craterhoof Behemoth", ""));
cubeCards.add(new DraftCube.CardIdentity("Creeping Tar Pit", ""));
cubeCards.add(new DraftCube.CardIdentity("Crucible of Worlds", ""));
cubeCards.add(new DraftCube.CardIdentity("Cryptic Command", ""));
cubeCards.add(new DraftCube.CardIdentity("Dack Fayden", ""));
cubeCards.add(new DraftCube.CardIdentity("Damnation", ""));
cubeCards.add(new DraftCube.CardIdentity("Daretti, Scrap Savant", ""));
cubeCards.add(new DraftCube.CardIdentity("Dark Confidant", ""));
cubeCards.add(new DraftCube.CardIdentity("Dark Petition", ""));
cubeCards.add(new DraftCube.CardIdentity("Dark Ritual", ""));
cubeCards.add(new DraftCube.CardIdentity("Darkslick Shores", ""));
cubeCards.add(new DraftCube.CardIdentity("Day of Judgment", ""));
cubeCards.add(new DraftCube.CardIdentity("Daze", ""));
cubeCards.add(new DraftCube.CardIdentity("Deathrite Shaman", ""));
cubeCards.add(new DraftCube.CardIdentity("Deceiver Exarch", ""));
cubeCards.add(new DraftCube.CardIdentity("Declaration in Stone", ""));
cubeCards.add(new DraftCube.CardIdentity("Delver of Secrets", ""));
cubeCards.add(new DraftCube.CardIdentity("Demonic Tutor", ""));
cubeCards.add(new DraftCube.CardIdentity("Demonlord Belzenlok", ""));
cubeCards.add(new DraftCube.CardIdentity("Den Protector", ""));
cubeCards.add(new DraftCube.CardIdentity("Deranged Hermit", ""));
cubeCards.add(new DraftCube.CardIdentity("Desperate Ritual", ""));
cubeCards.add(new DraftCube.CardIdentity("Dig Through Time", ""));
cubeCards.add(new DraftCube.CardIdentity("Dimir Signet", ""));
cubeCards.add(new DraftCube.CardIdentity("Dire Fleet Daredevil", ""));
cubeCards.add(new DraftCube.CardIdentity("Disenchant", ""));
cubeCards.add(new DraftCube.CardIdentity("Dismember", ""));
cubeCards.add(new DraftCube.CardIdentity("Dissenter's Deliverance", ""));
cubeCards.add(new DraftCube.CardIdentity("Dragonlord Atarka", ""));
cubeCards.add(new DraftCube.CardIdentity("Dragonlord Dromoka", ""));
cubeCards.add(new DraftCube.CardIdentity("Dragonlord Ojutai", ""));
cubeCards.add(new DraftCube.CardIdentity("Dreadbore", ""));
cubeCards.add(new DraftCube.CardIdentity("Dualcaster Mage", ""));
cubeCards.add(new DraftCube.CardIdentity("Duplicant", ""));
cubeCards.add(new DraftCube.CardIdentity("Duress", ""));
cubeCards.add(new DraftCube.CardIdentity("Edric, Spymaster of Trest", ""));
cubeCards.add(new DraftCube.CardIdentity("Eidolon of the Great Revel", ""));
cubeCards.add(new DraftCube.CardIdentity("Electrolyze", ""));
cubeCards.add(new DraftCube.CardIdentity("Elesh Norn, Grand Cenobite", ""));
cubeCards.add(new DraftCube.CardIdentity("Elspeth, Knight-Errant", ""));
cubeCards.add(new DraftCube.CardIdentity("Elspeth, Sun's Champion", ""));
cubeCards.add(new DraftCube.CardIdentity("Elves of Deep Shadow", ""));
cubeCards.add(new DraftCube.CardIdentity("Elvish Mystic", ""));
cubeCards.add(new DraftCube.CardIdentity("Emeria Angel", ""));
cubeCards.add(new DraftCube.CardIdentity("Empty the Warrens", ""));
cubeCards.add(new DraftCube.CardIdentity("Emrakul, the Aeons Torn", ""));
cubeCards.add(new DraftCube.CardIdentity("Emrakul, the Promised End", ""));
cubeCards.add(new DraftCube.CardIdentity("Enlightened Tutor", ""));
cubeCards.add(new DraftCube.CardIdentity("Entomb", ""));
cubeCards.add(new DraftCube.CardIdentity("Eternal Witness", ""));
cubeCards.add(new DraftCube.CardIdentity("Eureka", ""));
cubeCards.add(new DraftCube.CardIdentity("Everflowing Chalice", ""));
cubeCards.add(new DraftCube.CardIdentity("Exhume", ""));
cubeCards.add(new DraftCube.CardIdentity("Exquisite Firecraft", ""));
cubeCards.add(new DraftCube.CardIdentity("Fact or Fiction", ""));
cubeCards.add(new DraftCube.CardIdentity("Faithless Looting", ""));
cubeCards.add(new DraftCube.CardIdentity("Falkenrath Gorger", ""));
cubeCards.add(new DraftCube.CardIdentity("Fastbond", ""));
cubeCards.add(new DraftCube.CardIdentity("Fatal Push", ""));
cubeCards.add(new DraftCube.CardIdentity("Fauna Shaman", ""));
cubeCards.add(new DraftCube.CardIdentity("Field of Ruin", ""));
cubeCards.add(new DraftCube.CardIdentity("Fiend Hunter", ""));
cubeCards.add(new DraftCube.CardIdentity("Fiery Confluence", ""));
cubeCards.add(new DraftCube.CardIdentity("Figure of Destiny", ""));
cubeCards.add(new DraftCube.CardIdentity("Fire // Ice", ""));
cubeCards.add(new DraftCube.CardIdentity("Fireblast", ""));
cubeCards.add(new DraftCube.CardIdentity("Firebolt", ""));
cubeCards.add(new DraftCube.CardIdentity("Firedrinker Satyr", ""));
cubeCards.add(new DraftCube.CardIdentity("Flametongue Kavu", ""));
cubeCards.add(new DraftCube.CardIdentity("Flickerwisp", ""));
cubeCards.add(new DraftCube.CardIdentity("Flooded Strand", ""));
cubeCards.add(new DraftCube.CardIdentity("Force Spike", ""));
cubeCards.add(new DraftCube.CardIdentity("Force of Will", ""));
cubeCards.add(new DraftCube.CardIdentity("Frantic Search", ""));
cubeCards.add(new DraftCube.CardIdentity("Freyalise, Llanowar's Fury", ""));
cubeCards.add(new DraftCube.CardIdentity("Frost Titan", ""));
cubeCards.add(new DraftCube.CardIdentity("Fyndhorn Elves", ""));
cubeCards.add(new DraftCube.CardIdentity("Gaea's Cradle", ""));
cubeCards.add(new DraftCube.CardIdentity("Garruk Relentless", ""));
cubeCards.add(new DraftCube.CardIdentity("Garruk Wildspeaker", ""));
cubeCards.add(new DraftCube.CardIdentity("Garruk, Primal Hunter", ""));
cubeCards.add(new DraftCube.CardIdentity("Geist of Saint Traft", ""));
cubeCards.add(new DraftCube.CardIdentity("Genesis Wave", ""));
cubeCards.add(new DraftCube.CardIdentity("Gideon Jura", ""));
cubeCards.add(new DraftCube.CardIdentity("Gideon of the Trials", ""));
cubeCards.add(new DraftCube.CardIdentity("Gideon, Ally of Zendikar", ""));
cubeCards.add(new DraftCube.CardIdentity("Gifts Ungiven", ""));
cubeCards.add(new DraftCube.CardIdentity("Gilded Lotus", ""));
cubeCards.add(new DraftCube.CardIdentity("Gitaxian Probe", ""));
cubeCards.add(new DraftCube.CardIdentity("Glen Elendra Archmage", ""));
cubeCards.add(new DraftCube.CardIdentity("Glorybringer", ""));
cubeCards.add(new DraftCube.CardIdentity("Go for the Throat", ""));
cubeCards.add(new DraftCube.CardIdentity("Goblin Chainwhirler", ""));
cubeCards.add(new DraftCube.CardIdentity("Goblin Dark-Dwellers", ""));
cubeCards.add(new DraftCube.CardIdentity("Goblin Guide", ""));
cubeCards.add(new DraftCube.CardIdentity("Goblin Welder", ""));
cubeCards.add(new DraftCube.CardIdentity("Godless Shrine", ""));
cubeCards.add(new DraftCube.CardIdentity("Golgari Signet", ""));
cubeCards.add(new DraftCube.CardIdentity("Gonti, Lord of Luxury", ""));
cubeCards.add(new DraftCube.CardIdentity("Grave Titan", ""));
cubeCards.add(new DraftCube.CardIdentity("Green Sun's Zenith", ""));
cubeCards.add(new DraftCube.CardIdentity("Grim Lavamancer", ""));
cubeCards.add(new DraftCube.CardIdentity("Grim Monolith", ""));
cubeCards.add(new DraftCube.CardIdentity("Grim Tutor", ""));
cubeCards.add(new DraftCube.CardIdentity("Griselbrand", ""));
cubeCards.add(new DraftCube.CardIdentity("Gruul Signet", ""));
cubeCards.add(new DraftCube.CardIdentity("Gush", ""));
cubeCards.add(new DraftCube.CardIdentity("Hallowed Fountain", ""));
cubeCards.add(new DraftCube.CardIdentity("Hangarback Walker", ""));
cubeCards.add(new DraftCube.CardIdentity("Harmonize", ""));
cubeCards.add(new DraftCube.CardIdentity("Hazoret the Fervent", ""));
cubeCards.add(new DraftCube.CardIdentity("Heartbeat of Spring", ""));
cubeCards.add(new DraftCube.CardIdentity("Hellrider", ""));
cubeCards.add(new DraftCube.CardIdentity("Hero of Bladehold", ""));
cubeCards.add(new DraftCube.CardIdentity("Hero's Downfall", ""));
cubeCards.add(new DraftCube.CardIdentity("High Tide", ""));
cubeCards.add(new DraftCube.CardIdentity("Hissing Quagmire", ""));
cubeCards.add(new DraftCube.CardIdentity("History of Benalia", ""));
cubeCards.add(new DraftCube.CardIdentity("Honor of the Pure", ""));
cubeCards.add(new DraftCube.CardIdentity("Hostage Taker", ""));
cubeCards.add(new DraftCube.CardIdentity("Huntmaster of the Fells", ""));
cubeCards.add(new DraftCube.CardIdentity("Hymn to Tourach", ""));
cubeCards.add(new DraftCube.CardIdentity("Hypnotic Specter", ""));
cubeCards.add(new DraftCube.CardIdentity("Imperial Recruiter", ""));
cubeCards.add(new DraftCube.CardIdentity("Imperial Seal", ""));
cubeCards.add(new DraftCube.CardIdentity("Impulse", ""));
cubeCards.add(new DraftCube.CardIdentity("Incinerate", ""));
cubeCards.add(new DraftCube.CardIdentity("Inferno Titan", ""));
cubeCards.add(new DraftCube.CardIdentity("Inkwell Leviathan", ""));
cubeCards.add(new DraftCube.CardIdentity("Inquisition of Kozilek", ""));
cubeCards.add(new DraftCube.CardIdentity("Inspiring Vantage", ""));
cubeCards.add(new DraftCube.CardIdentity("Iona, Shield of Emeria", ""));
cubeCards.add(new DraftCube.CardIdentity("Izzet Charm", ""));
cubeCards.add(new DraftCube.CardIdentity("Izzet Signet", ""));
cubeCards.add(new DraftCube.CardIdentity("Jace Beleren", ""));
cubeCards.add(new DraftCube.CardIdentity("Jace, Architect of Thought", ""));
cubeCards.add(new DraftCube.CardIdentity("Jace, Vryn's Prodigy", ""));
cubeCards.add(new DraftCube.CardIdentity("Jace, the Mind Sculptor", ""));
cubeCards.add(new DraftCube.CardIdentity("Jackal Pup", ""));
cubeCards.add(new DraftCube.CardIdentity("Jadelight Ranger", ""));
cubeCards.add(new DraftCube.CardIdentity("Jhoira, Weatherlight Captain", ""));
cubeCards.add(new DraftCube.CardIdentity("Joraga Treespeaker", ""));
cubeCards.add(new DraftCube.CardIdentity("Karakas", ""));
cubeCards.add(new DraftCube.CardIdentity("Karn Liberated", ""));
cubeCards.add(new DraftCube.CardIdentity("Karn, Scion of Urza", ""));
cubeCards.add(new DraftCube.CardIdentity("Kiki-Jiki, Mirror Breaker", ""));
cubeCards.add(new DraftCube.CardIdentity("Kitchen Finks", ""));
cubeCards.add(new DraftCube.CardIdentity("Kitesail Freebooter", ""));
cubeCards.add(new DraftCube.CardIdentity("Knight of the White Orchi", ""));
cubeCards.add(new DraftCube.CardIdentity("Kolaghan's Command", ""));
cubeCards.add(new DraftCube.CardIdentity("Koth of the Hammer", ""));
cubeCards.add(new DraftCube.CardIdentity("Kozilek, Butcher of Truth", ""));
cubeCards.add(new DraftCube.CardIdentity("Kuldotha Forgemaster", ""));
cubeCards.add(new DraftCube.CardIdentity("Kytheon, Hero of Akros", ""));
cubeCards.add(new DraftCube.CardIdentity("Land Tax", ""));
cubeCards.add(new DraftCube.CardIdentity("Lavaclaw Reaches", ""));
cubeCards.add(new DraftCube.CardIdentity("Legion's Landing", ""));
cubeCards.add(new DraftCube.CardIdentity("Leonin Relic-Warder", ""));
cubeCards.add(new DraftCube.CardIdentity("Leovold, Emissary of Trest", ""));
cubeCards.add(new DraftCube.CardIdentity("Leyline of Sanctity", ""));
cubeCards.add(new DraftCube.CardIdentity("Library of Alexandria", ""));
cubeCards.add(new DraftCube.CardIdentity("Lightning Bolt", ""));
cubeCards.add(new DraftCube.CardIdentity("Lightning Greaves", ""));
cubeCards.add(new DraftCube.CardIdentity("Lightning Helix", ""));
cubeCards.add(new DraftCube.CardIdentity("Lightning Strike", ""));
cubeCards.add(new DraftCube.CardIdentity("Liliana of the Veil", ""));
cubeCards.add(new DraftCube.CardIdentity("Liliana, Death's Majesty", ""));
cubeCards.add(new DraftCube.CardIdentity("Lingering Souls", ""));
cubeCards.add(new DraftCube.CardIdentity("Linvala, Keeper of Silence", ""));
cubeCards.add(new DraftCube.CardIdentity("Lion's Eye Diamond", ""));
cubeCards.add(new DraftCube.CardIdentity("Living Death", ""));
cubeCards.add(new DraftCube.CardIdentity("Llanowar Elves", ""));
cubeCards.add(new DraftCube.CardIdentity("Lodestone Golem", ""));
cubeCards.add(new DraftCube.CardIdentity("Looter il-Kor", ""));
cubeCards.add(new DraftCube.CardIdentity("Lotus Bloom", ""));
cubeCards.add(new DraftCube.CardIdentity("Lotus Cobra", ""));
cubeCards.add(new DraftCube.CardIdentity("Lotus Petal", ""));
cubeCards.add(new DraftCube.CardIdentity("Lumbering Falls", ""));
cubeCards.add(new DraftCube.CardIdentity("Lyra Dawnbringer", ""));
cubeCards.add(new DraftCube.CardIdentity("Maelstrom Pulse", ""));
cubeCards.add(new DraftCube.CardIdentity("Magma Jet", ""));
cubeCards.add(new DraftCube.CardIdentity("Magus of the Moon", ""));
cubeCards.add(new DraftCube.CardIdentity("Makeshift Mannequin", ""));
cubeCards.add(new DraftCube.CardIdentity("Mana Confluence", ""));
cubeCards.add(new DraftCube.CardIdentity("Mana Crypt", ""));
cubeCards.add(new DraftCube.CardIdentity("Mana Drain", ""));
cubeCards.add(new DraftCube.CardIdentity("Mana Flare", ""));
cubeCards.add(new DraftCube.CardIdentity("Mana Leak", ""));
cubeCards.add(new DraftCube.CardIdentity("Mana Tithe", ""));
cubeCards.add(new DraftCube.CardIdentity("Mana Vault", ""));
cubeCards.add(new DraftCube.CardIdentity("Manglehorn", ""));
cubeCards.add(new DraftCube.CardIdentity("Manic Vandal", ""));
cubeCards.add(new DraftCube.CardIdentity("Marsh Flats", ""));
cubeCards.add(new DraftCube.CardIdentity("Massacre Wurm", ""));
cubeCards.add(new DraftCube.CardIdentity("Master of the Wild Hunt", ""));
cubeCards.add(new DraftCube.CardIdentity("Maze of Ith", ""));
cubeCards.add(new DraftCube.CardIdentity("Memory Jar", ""));
cubeCards.add(new DraftCube.CardIdentity("Mesmeric Fiend", ""));
cubeCards.add(new DraftCube.CardIdentity("Metalworker", ""));
cubeCards.add(new DraftCube.CardIdentity("Mind Twist", ""));
cubeCards.add(new DraftCube.CardIdentity("Mind's Desire", ""));
cubeCards.add(new DraftCube.CardIdentity("Mindslaver", ""));
cubeCards.add(new DraftCube.CardIdentity("Mirari's Wake", ""));
cubeCards.add(new DraftCube.CardIdentity("Mirran Crusader", ""));
cubeCards.add(new DraftCube.CardIdentity("Mishra's Factory", ""));
cubeCards.add(new DraftCube.CardIdentity("Mishra's Workshop", ""));
cubeCards.add(new DraftCube.CardIdentity("Misty Rainforest", ""));
cubeCards.add(new DraftCube.CardIdentity("Mizzium Mortars", ""));
cubeCards.add(new DraftCube.CardIdentity("Moat", ""));
cubeCards.add(new DraftCube.CardIdentity("Monastery Mentor", ""));
cubeCards.add(new DraftCube.CardIdentity("Monastery Swiftspear", ""));
cubeCards.add(new DraftCube.CardIdentity("Mother of Runes", ""));
cubeCards.add(new DraftCube.CardIdentity("Mox Diamond", ""));
cubeCards.add(new DraftCube.CardIdentity("Mox Emerald", ""));
cubeCards.add(new DraftCube.CardIdentity("Mox Jet", ""));
cubeCards.add(new DraftCube.CardIdentity("Mox Pearl", ""));
cubeCards.add(new DraftCube.CardIdentity("Mox Ruby", ""));
cubeCards.add(new DraftCube.CardIdentity("Mox Sapphire", ""));
cubeCards.add(new DraftCube.CardIdentity("Mulldrifter", ""));
cubeCards.add(new DraftCube.CardIdentity("Murderous Cut", ""));
cubeCards.add(new DraftCube.CardIdentity("Mutavault", ""));
cubeCards.add(new DraftCube.CardIdentity("Myr Battlesphere", ""));
cubeCards.add(new DraftCube.CardIdentity("Mystic Confluence", ""));
cubeCards.add(new DraftCube.CardIdentity("Mystic Snake", ""));
cubeCards.add(new DraftCube.CardIdentity("Mystical Tutor", ""));
cubeCards.add(new DraftCube.CardIdentity("Nahiri, the Harbinger", ""));
cubeCards.add(new DraftCube.CardIdentity("Natural Order", ""));
cubeCards.add(new DraftCube.CardIdentity("Nature's Claim", ""));
cubeCards.add(new DraftCube.CardIdentity("Necromancy", ""));
cubeCards.add(new DraftCube.CardIdentity("Necropotence", ""));
cubeCards.add(new DraftCube.CardIdentity("Needle Spires", ""));
cubeCards.add(new DraftCube.CardIdentity("Nekrataal", ""));
cubeCards.add(new DraftCube.CardIdentity("Nevinyrral's Disk", ""));
cubeCards.add(new DraftCube.CardIdentity("Nezumi Graverobber", ""));
cubeCards.add(new DraftCube.CardIdentity("Nezumi Shortfang", ""));
cubeCards.add(new DraftCube.CardIdentity("Nicol Bolas, Planeswalker", ""));
cubeCards.add(new DraftCube.CardIdentity("Nissa, Worldwaker", ""));
cubeCards.add(new DraftCube.CardIdentity("Noble Hierarch", ""));
cubeCards.add(new DraftCube.CardIdentity("Noxious Gearhulk", ""));
cubeCards.add(new DraftCube.CardIdentity("Nykthos, Shrine to Nyx", ""));
cubeCards.add(new DraftCube.CardIdentity("Oath of Druids", ""));
cubeCards.add(new DraftCube.CardIdentity("Oath of Nissa", ""));
cubeCards.add(new DraftCube.CardIdentity("Oblivion Ring", ""));
cubeCards.add(new DraftCube.CardIdentity("Olivia Voldaren", ""));
cubeCards.add(new DraftCube.CardIdentity("Oona's Prowler", ""));
cubeCards.add(new DraftCube.CardIdentity("Ophiomancer", ""));
cubeCards.add(new DraftCube.CardIdentity("Opposition", ""));
cubeCards.add(new DraftCube.CardIdentity("Oracle of Mul Daya", ""));
cubeCards.add(new DraftCube.CardIdentity("Orzhov Signet", ""));
cubeCards.add(new DraftCube.CardIdentity("Overgrown Tomb", ""));
cubeCards.add(new DraftCube.CardIdentity("Pack Rat", ""));
cubeCards.add(new DraftCube.CardIdentity("Painful Truths", ""));
cubeCards.add(new DraftCube.CardIdentity("Palinchron", ""));
cubeCards.add(new DraftCube.CardIdentity("Parallax Wave", ""));
cubeCards.add(new DraftCube.CardIdentity("Path to Exile", ""));
cubeCards.add(new DraftCube.CardIdentity("Pentad Prism", ""));
cubeCards.add(new DraftCube.CardIdentity("Pernicious Deed", ""));
cubeCards.add(new DraftCube.CardIdentity("Pestermite", ""));
cubeCards.add(new DraftCube.CardIdentity("Phantasmal Image", ""));
cubeCards.add(new DraftCube.CardIdentity("Phyrexian Metamorph", ""));
cubeCards.add(new DraftCube.CardIdentity("Phyrexian Revoker", ""));
cubeCards.add(new DraftCube.CardIdentity("Plateau", ""));
cubeCards.add(new DraftCube.CardIdentity("Polluted Delta", ""));
cubeCards.add(new DraftCube.CardIdentity("Polukranos, World Eater", ""));
cubeCards.add(new DraftCube.CardIdentity("Ponder", ""));
cubeCards.add(new DraftCube.CardIdentity("Porcelain Legionnaire", ""));
cubeCards.add(new DraftCube.CardIdentity("Preordain", ""));
cubeCards.add(new DraftCube.CardIdentity("Primal Command", ""));
cubeCards.add(new DraftCube.CardIdentity("Primeval Titan", ""));
cubeCards.add(new DraftCube.CardIdentity("Progenitus", ""));
cubeCards.add(new DraftCube.CardIdentity("Putrid Imp", ""));
cubeCards.add(new DraftCube.CardIdentity("Pyretic Ritual", ""));
cubeCards.add(new DraftCube.CardIdentity("Qasali Pridemage", ""));
cubeCards.add(new DraftCube.CardIdentity("Raging Ravine", ""));
cubeCards.add(new DraftCube.CardIdentity("Rakdos Signet", ""));
cubeCards.add(new DraftCube.CardIdentity("Rakdos's Return", ""));
cubeCards.add(new DraftCube.CardIdentity("Ravages of War", ""));
cubeCards.add(new DraftCube.CardIdentity("Ravenous Chupacabra", ""));
cubeCards.add(new DraftCube.CardIdentity("Razorverge Thicket", ""));
cubeCards.add(new DraftCube.CardIdentity("Reanimate", ""));
cubeCards.add(new DraftCube.CardIdentity("Reclamation Sage", ""));
cubeCards.add(new DraftCube.CardIdentity("Recruiter of the Guard", ""));
cubeCards.add(new DraftCube.CardIdentity("Recurring Nightmare", ""));
cubeCards.add(new DraftCube.CardIdentity("Regrowth", ""));
cubeCards.add(new DraftCube.CardIdentity("Rekindling Phoenix", ""));
cubeCards.add(new DraftCube.CardIdentity("Remand", ""));
cubeCards.add(new DraftCube.CardIdentity("Repeal", ""));
cubeCards.add(new DraftCube.CardIdentity("Restoration Angel", ""));
cubeCards.add(new DraftCube.CardIdentity("Reveillark", ""));
cubeCards.add(new DraftCube.CardIdentity("Rift Bolt", ""));
cubeCards.add(new DraftCube.CardIdentity("Riftwing Cloudskate", ""));
cubeCards.add(new DraftCube.CardIdentity("Rishadan Port", ""));
cubeCards.add(new DraftCube.CardIdentity("Rishkar, Peema Renegade", ""));
cubeCards.add(new DraftCube.CardIdentity("Rite of Flame", ""));
cubeCards.add(new DraftCube.CardIdentity("Rofellos, Llanowar Emissary", ""));
cubeCards.add(new DraftCube.CardIdentity("Sacred Foundry", ""));
cubeCards.add(new DraftCube.CardIdentity("Sakura-Tribe Elder", ""));
cubeCards.add(new DraftCube.CardIdentity("Savannah", ""));
cubeCards.add(new DraftCube.CardIdentity("Scalding Tarn", ""));
cubeCards.add(new DraftCube.CardIdentity("Scavenging Ooze", ""));
cubeCards.add(new DraftCube.CardIdentity("Scrubland", ""));
cubeCards.add(new DraftCube.CardIdentity("Seachrome Coast", ""));
cubeCards.add(new DraftCube.CardIdentity("Search for Azcanta", ""));
cubeCards.add(new DraftCube.CardIdentity("Search for Tomorrow", ""));
cubeCards.add(new DraftCube.CardIdentity("Searing Spear", ""));
cubeCards.add(new DraftCube.CardIdentity("Seething Song", ""));
cubeCards.add(new DraftCube.CardIdentity("Selesnya Signet", ""));
cubeCards.add(new DraftCube.CardIdentity("Selfless Spirit", ""));
cubeCards.add(new DraftCube.CardIdentity("Sensei's Divining Top", ""));
cubeCards.add(new DraftCube.CardIdentity("Shallow Grave", ""));
cubeCards.add(new DraftCube.CardIdentity("Shambling Vent", ""));
cubeCards.add(new DraftCube.CardIdentity("Shardless Agent", ""));
cubeCards.add(new DraftCube.CardIdentity("Shelldock Isle", ""));
cubeCards.add(new DraftCube.CardIdentity("Sheoldred, Whispering One", ""));
cubeCards.add(new DraftCube.CardIdentity("Show and Tell", ""));
cubeCards.add(new DraftCube.CardIdentity("Shriekmaw", ""));
cubeCards.add(new DraftCube.CardIdentity("Shrine of Burning Rage", ""));
cubeCards.add(new DraftCube.CardIdentity("Siege-Gang Commander", ""));
cubeCards.add(new DraftCube.CardIdentity("Silverblade Paladin", ""));
cubeCards.add(new DraftCube.CardIdentity("Simic Signet", ""));
cubeCards.add(new DraftCube.CardIdentity("Skullclamp", ""));
cubeCards.add(new DraftCube.CardIdentity("Skymarcher Aspirant", ""));
cubeCards.add(new DraftCube.CardIdentity("Smokestack", ""));
cubeCards.add(new DraftCube.CardIdentity("Smuggler's Copter", ""));
cubeCards.add(new DraftCube.CardIdentity("Snapcaster Mage", ""));
cubeCards.add(new DraftCube.CardIdentity("Sneak Attack", ""));
cubeCards.add(new DraftCube.CardIdentity("Sol Ring", ""));
cubeCards.add(new DraftCube.CardIdentity("Solemn Simulacrum", ""));
cubeCards.add(new DraftCube.CardIdentity("Song of the Dryads", ""));
cubeCards.add(new DraftCube.CardIdentity("Sorcerous Spyglass", ""));
cubeCards.add(new DraftCube.CardIdentity("Soulfire Grand Master", ""));
cubeCards.add(new DraftCube.CardIdentity("Sower of Temptation", ""));
cubeCards.add(new DraftCube.CardIdentity("Spear of Heliod", ""));
cubeCards.add(new DraftCube.CardIdentity("Spectral Procession", ""));
cubeCards.add(new DraftCube.CardIdentity("Spell Pierce", ""));
cubeCards.add(new DraftCube.CardIdentity("Spellskite", ""));
cubeCards.add(new DraftCube.CardIdentity("Sphinx of the Steel Wind", ""));
cubeCards.add(new DraftCube.CardIdentity("Sphinx's Revelation", ""));
cubeCards.add(new DraftCube.CardIdentity("Spirebluff Canal", ""));
cubeCards.add(new DraftCube.CardIdentity("Splinter Twin", ""));
cubeCards.add(new DraftCube.CardIdentity("Steam Vents", ""));
cubeCards.add(new DraftCube.CardIdentity("Stirring Wildwood", ""));
cubeCards.add(new DraftCube.CardIdentity("Stomping Ground", ""));
cubeCards.add(new DraftCube.CardIdentity("Stoneforge Mystic", ""));
cubeCards.add(new DraftCube.CardIdentity("Stormbreath Dragon", ""));
cubeCards.add(new DraftCube.CardIdentity("Strip Mine", ""));
cubeCards.add(new DraftCube.CardIdentity("Student of Warfare", ""));
cubeCards.add(new DraftCube.CardIdentity("Sulfuric Vortex", ""));
cubeCards.add(new DraftCube.CardIdentity("Sun Titan", ""));
cubeCards.add(new DraftCube.CardIdentity("Sundering Titan", ""));
cubeCards.add(new DraftCube.CardIdentity("Supreme Verdict", ""));
cubeCards.add(new DraftCube.CardIdentity("Survival of the Fittest", ""));
cubeCards.add(new DraftCube.CardIdentity("Sweltering Suns", ""));
cubeCards.add(new DraftCube.CardIdentity("Sword of Body and Mind", ""));
cubeCards.add(new DraftCube.CardIdentity("Sword of Feast and Famine", ""));
cubeCards.add(new DraftCube.CardIdentity("Sword of Fire and Ice", ""));
cubeCards.add(new DraftCube.CardIdentity("Sword of Light and Shadow", ""));
cubeCards.add(new DraftCube.CardIdentity("Sword of War and Peace", ""));
cubeCards.add(new DraftCube.CardIdentity("Swords to Plowshares", ""));
cubeCards.add(new DraftCube.CardIdentity("Sylvan Caryatid", ""));
cubeCards.add(new DraftCube.CardIdentity("Sylvan Library", ""));
cubeCards.add(new DraftCube.CardIdentity("Taiga", ""));
cubeCards.add(new DraftCube.CardIdentity("Tamiyo, the Moon Sage", ""));
cubeCards.add(new DraftCube.CardIdentity("Tangle Wire", ""));
cubeCards.add(new DraftCube.CardIdentity("Tarmogoyf", ""));
cubeCards.add(new DraftCube.CardIdentity("Tasigur, the Golden Fang", ""));
cubeCards.add(new DraftCube.CardIdentity("Teferi, Hero of Dominaria", ""));
cubeCards.add(new DraftCube.CardIdentity("Temple Garden", ""));
cubeCards.add(new DraftCube.CardIdentity("Tendrils of Agony", ""));
cubeCards.add(new DraftCube.CardIdentity("Terastodon", ""));
cubeCards.add(new DraftCube.CardIdentity("Terminate", ""));
cubeCards.add(new DraftCube.CardIdentity("Tezzeret the Seeker", ""));
cubeCards.add(new DraftCube.CardIdentity("Tezzeret, Agent of Bolas", ""));
cubeCards.add(new DraftCube.CardIdentity("Thalia, Guardian of Thraben", ""));
cubeCards.add(new DraftCube.CardIdentity("The Abyss", ""));
cubeCards.add(new DraftCube.CardIdentity("The Scarab God", ""));
cubeCards.add(new DraftCube.CardIdentity("Thing in the Ice", ""));
cubeCards.add(new DraftCube.CardIdentity("Thirst for Knowledge", ""));
cubeCards.add(new DraftCube.CardIdentity("Thoughtseize", ""));
cubeCards.add(new DraftCube.CardIdentity("Thragtusk", ""));
cubeCards.add(new DraftCube.CardIdentity("Thran Dynamo", ""));
cubeCards.add(new DraftCube.CardIdentity("Thrashing Brontodon", ""));
cubeCards.add(new DraftCube.CardIdentity("Through the Breach", ""));
cubeCards.add(new DraftCube.CardIdentity("Thrun, the Last Troll", ""));
cubeCards.add(new DraftCube.CardIdentity("Thundermaw Hellkite", ""));
cubeCards.add(new DraftCube.CardIdentity("Tidehollow Sculler", ""));
cubeCards.add(new DraftCube.CardIdentity("Time Spiral", ""));
cubeCards.add(new DraftCube.CardIdentity("Time Walk", ""));
cubeCards.add(new DraftCube.CardIdentity("Timely Reinforcements", ""));
cubeCards.add(new DraftCube.CardIdentity("Timetwister", ""));
cubeCards.add(new DraftCube.CardIdentity("Tinker", ""));
cubeCards.add(new DraftCube.CardIdentity("Tolarian Academy", ""));
cubeCards.add(new DraftCube.CardIdentity("Tooth and Nail", ""));
cubeCards.add(new DraftCube.CardIdentity("Torrential Gearhulk", ""));
cubeCards.add(new DraftCube.CardIdentity("Toxic Deluge", ""));
cubeCards.add(new DraftCube.CardIdentity("Treachery", ""));
cubeCards.add(new DraftCube.CardIdentity("Treasure Cruise", ""));
cubeCards.add(new DraftCube.CardIdentity("Trinket Mage", ""));
cubeCards.add(new DraftCube.CardIdentity("Tropical Island", ""));
cubeCards.add(new DraftCube.CardIdentity("True-Name Nemesis", ""));
cubeCards.add(new DraftCube.CardIdentity("Trygon Predator", ""));
cubeCards.add(new DraftCube.CardIdentity("Tundra", ""));
cubeCards.add(new DraftCube.CardIdentity("Turnabout", ""));
cubeCards.add(new DraftCube.CardIdentity("Ugin, the Spirit Dragon", ""));
cubeCards.add(new DraftCube.CardIdentity("Ulamog, the Ceaseless Hunger", ""));
cubeCards.add(new DraftCube.CardIdentity("Ulamog, the Infinite Gyre", ""));
cubeCards.add(new DraftCube.CardIdentity("Ultimate Price", ""));
cubeCards.add(new DraftCube.CardIdentity("Umezawa's Jitte", ""));
cubeCards.add(new DraftCube.CardIdentity("Unburial Rites", ""));
cubeCards.add(new DraftCube.CardIdentity("Underground Sea", ""));
cubeCards.add(new DraftCube.CardIdentity("Unexpectedly Absent", ""));
cubeCards.add(new DraftCube.CardIdentity("Upheaval", ""));
cubeCards.add(new DraftCube.CardIdentity("Urborg, Tomb of Yawgmoth", ""));
cubeCards.add(new DraftCube.CardIdentity("Vampire Nighthawk", ""));
cubeCards.add(new DraftCube.CardIdentity("Vampiric Tutor", ""));
cubeCards.add(new DraftCube.CardIdentity("Vedalken Shackles", ""));
cubeCards.add(new DraftCube.CardIdentity("Vendilion Clique", ""));
cubeCards.add(new DraftCube.CardIdentity("Venser, Shaper Savant", ""));
cubeCards.add(new DraftCube.CardIdentity("Verdant Catacombs", ""));
cubeCards.add(new DraftCube.CardIdentity("Verdurous Gearhulk", ""));
cubeCards.add(new DraftCube.CardIdentity("Vindicate", ""));
cubeCards.add(new DraftCube.CardIdentity("Voice of Resurgence", ""));
cubeCards.add(new DraftCube.CardIdentity("Volcanic Island", ""));
cubeCards.add(new DraftCube.CardIdentity("Vraska's Contempt", ""));
cubeCards.add(new DraftCube.CardIdentity("Vraska, Relic Seeker", ""));
cubeCards.add(new DraftCube.CardIdentity("Walking Ballista", ""));
cubeCards.add(new DraftCube.CardIdentity("Wall of Blossoms", ""));
cubeCards.add(new DraftCube.CardIdentity("Wall of Omens", ""));
cubeCards.add(new DraftCube.CardIdentity("Wall of Roots", ""));
cubeCards.add(new DraftCube.CardIdentity("Wandering Fumarole", ""));
cubeCards.add(new DraftCube.CardIdentity("Wasteland", ""));
cubeCards.add(new DraftCube.CardIdentity("Watery Grave", ""));
cubeCards.add(new DraftCube.CardIdentity("Wear // Tear", ""));
cubeCards.add(new DraftCube.CardIdentity("Wheel of Fortune", ""));
cubeCards.add(new DraftCube.CardIdentity("Wildfire", ""));
cubeCards.add(new DraftCube.CardIdentity("Windswept Heath", ""));
cubeCards.add(new DraftCube.CardIdentity("Winter Orb", ""));
cubeCards.add(new DraftCube.CardIdentity("Wooded Foothills", ""));
cubeCards.add(new DraftCube.CardIdentity("Woodfall Primus", ""));
cubeCards.add(new DraftCube.CardIdentity("Worn Powerstone", ""));
cubeCards.add(new DraftCube.CardIdentity("Wrath of God", ""));
cubeCards.add(new DraftCube.CardIdentity("Wurmcoil Engine", ""));
cubeCards.add(new DraftCube.CardIdentity("Xenagos, the Reveler", ""));
cubeCards.add(new DraftCube.CardIdentity("Yavimaya Elder", ""));
cubeCards.add(new DraftCube.CardIdentity("Yawgmoth's Bargain", ""));
cubeCards.add(new DraftCube.CardIdentity("Yawgmoth's Will", ""));
cubeCards.add(new DraftCube.CardIdentity("Young Pyromancer", ""));
cubeCards.add(new DraftCube.CardIdentity("Zealous Conscripts", ""));
cubeCards.add(new DraftCube.CardIdentity("Zurgo Bellstriker", ""));
}
}

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.30</version>
<version>1.4.31</version>
</parent>
<artifactId>mage-tournament-constructed</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.30</version>
<version>1.4.31</version>
</parent>
<artifactId>mage-tournament-sealed</artifactId>

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.30</version>
<version>1.4.31</version>
</parent>
<artifactId>mage-server-plugins</artifactId>

View file

@ -133,6 +133,7 @@
<draftCube name="MTGO Vintage Cube November 2016" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCubeNovember2016"/>
<draftCube name="MTGO Vintage Cube June 2017" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCubeJune2017"/>
<draftCube name="MTGO Vintage Cube December 2017" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCubeDecember2017"/>
<draftCube name="MTGO Vintage Cube June 2018" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeJune2018"/>
<draftCube name="The Peasant's Toolbox" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.PeasantsToolboxCube"/>
<draftCube name="www.MTGCube.com" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.MTGCube"/>
<draftCube name="Cube From Deck" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.CubeFromDeck"/>

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.30</version>
<version>1.4.31</version>
</parent>
<artifactId>mage-server</artifactId>

View file

@ -127,6 +127,7 @@
<draftCube name="MTGO Vintage Cube November 2016" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeNovember2016"/>
<draftCube name="MTGO Vintage Cube June 2017" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeJune2017"/>
<draftCube name="MTGO Vintage Cube December 2017" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeDecember2017"/>
<draftCube name="MTGO Vintage Cube June 2018" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeJune2018"/>
<draftCube name="The Peasant's Toolbox" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.PeasantsToolboxCube"/>
<draftCube name="www.MTGCube.com" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.MTGCube"/>
<draftCube name="Cube From Deck" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.CubeFromDeck"/>

View file

@ -1,4 +1,3 @@
package mage.server.game;
import java.io.*;
@ -1149,7 +1148,7 @@ public class GameController implements GameCallback {
sb.append(state.getTurnMods());
sb.append("<br>getTurnNum: ");
sb.append(state.getTurnNum());
sb.append("<br>Using plane chase?:" + state.isPlaneChase());
if (state.isPlaneChase()) {
Plane currentPlane = state.getCurrentPlane();
@ -1157,7 +1156,7 @@ public class GameController implements GameCallback {
sb.append("<br>Current plane:" + currentPlane.getName());
}
}
sb.append("<br>Future Timeout:");
if (futureTimeout != null) {
sb.append("Cancelled?=");
@ -1188,8 +1187,13 @@ public class GameController implements GameCallback {
sb.append("<br>Active player is: ");
sb.append(game.getPlayer(state.getActivePlayerId()).getName());
PassAbility pass = new PassAbility();
if (game.getPlayer(state.getActivePlayerId()).hasLeft()) {
Player p = game.getPlayer(state.getActivePlayerId());
if (p != null) {
p.concede(game);
}
Phase currentPhase = game.getPhase();
if (currentPhase != null) {
currentPhase.getStep().skipStep(game, state.getActivePlayerId());
@ -1204,6 +1208,10 @@ public class GameController implements GameCallback {
sb.append("<br>getChoosingPlayerId: ");
if (state.getChoosingPlayerId() != null) {
if (game.getPlayer(state.getChoosingPlayerId()).hasLeft()) {
Player p = game.getPlayer(state.getChoosingPlayerId());
if (p != null) {
p.concede(game);
}
Phase currentPhase = game.getPhase();
if (currentPhase != null && !fixedAlready) {
currentPhase.getStep().endStep(game, state.getActivePlayerId());
@ -1218,7 +1226,11 @@ public class GameController implements GameCallback {
sb.append("<br><font color=orange>Player with Priority is: ");
if (state.getPriorityPlayerId() != null) {
if (game.getPlayer(state.getPriorityPlayerId()).hasLeft()) {
if (game.getPlayer(state.getPriorityPlayerId()).hasLeft()) {
Player p = game.getPlayer(state.getPriorityPlayerId());
if (p != null) {
p.concede(game);
}
Phase currentPhase = game.getPhase();
if (currentPhase != null && !fixedAlready) {
currentPhase.getStep().skipStep(game, state.getActivePlayerId());
@ -1228,7 +1240,7 @@ public class GameController implements GameCallback {
}
sb.append(game.getPlayer(state.getPriorityPlayerId()).getName());
sb.append("</font>");
}
}
sb.append("<br>Future Timeout:");
if (futureTimeout != null) {

View file

@ -40,7 +40,7 @@ public enum TournamentFactory {
Map<String,Integer> setInfo = new LinkedHashMap<>();
for (String setCode: options.getLimitedOptions().getSetCodes()) {
tournament.getSets().add(Sets.findSet(setCode));
int count = setInfo.containsKey(setCode) ? setInfo.get(setCode) : 0;
int count = setInfo.getOrDefault(setCode, 0);
setInfo.put(setCode, count + 1);
}
tournament.getOptions().getLimitedOptions().setNumberBoosters(tournament.getTournamentType().getNumBoosters());

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.30</version>
<version>1.4.31</version>
</parent>
<groupId>org.mage</groupId>

View file

@ -155,7 +155,7 @@ class AbandonedSarcophagusReplacementEffect extends ReplacementEffectImpl {
Card card = game.getCard(event.getTargetId());
if (card != null
&& watcher != null
&& card.getOwnerId().equals(controller.getId())) {
&& card.isOwnedBy(controller.getId())) {
for (Ability ability : card.getAbilities()) {
if (ability instanceof CyclingAbility) {
cardHasCycling = true;
@ -199,7 +199,7 @@ class AbandonedSarcophagusWatcher extends Watcher {
Player controller = game.getPlayer(event.getPlayerId());
if (card != null
&& controller != null
&& card.getOwnerId().equals(controller.getId())) {
&& card.isOwnedBy(controller.getId())) {
Cards c = getCardsCycledThisTurn(event.getPlayerId());
c.add(card);
cycledCardsThisTurn.put(event.getPlayerId(), c);

View file

@ -108,7 +108,7 @@ class AbbotOfKeralKeepCastFromExileEffect extends AsThoughEffectImpl {
@Override
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
return source.getControllerId().equals(affectedControllerId)
return source.isControlledBy(affectedControllerId)
&& objectId.equals(getTargetPointer().getFirst(game, source));
}
}

View file

@ -0,0 +1,43 @@
package mage.cards.a;
import java.util.UUID;
import mage.abilities.common.DiesTriggeredAbility;
import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect;
import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.target.common.TargetCreaturePermanent;
/**
*
* @author TheElk801
*/
public final class AbnormalEndurance extends CardImpl {
public AbnormalEndurance(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}");
// Until end of turn, target creature gets +2/+0 and gains "When this creature dies, return it to the battlefield tapped under its owner's control."
getSpellAbility().addTarget(new TargetCreaturePermanent());
getSpellAbility().addEffect(new BoostTargetEffect(2, 0, Duration.EndOfTurn)
.setText("Until end of turn, target creature gets +2/+0")
);
getSpellAbility().addEffect(new GainAbilityTargetEffect(
new DiesTriggeredAbility(new ReturnSourceFromGraveyardToBattlefieldEffect(true, true), false),
Duration.EndOfTurn,
"and gains \"When this creature dies, return it to the battlefield tapped under its owner's control.\""
));
}
public AbnormalEndurance(final AbnormalEndurance card) {
super(card);
}
@Override
public AbnormalEndurance copy() {
return new AbnormalEndurance(this);
}
}

View file

@ -31,9 +31,9 @@ public final class AbruptDecay extends CardImpl {
public AbruptDecay(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{B}{G}");
// Abrupt Decay can't be countered by spells or abilities.
// Abrupt Decay can't be countered.
Effect effect = new CantBeCounteredSourceEffect();
effect.setText("{this} can't be countered by spells or abilities");
effect.setText("this spell can't be countered");
Ability ability = new SimpleStaticAbility(Zone.STACK, effect);
ability.setRuleAtTheTop(true);
this.addAbility(ability);

View file

@ -5,7 +5,7 @@ import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.condition.common.ControlsCreatureGreatestToughnessCondition;
import mage.abilities.decorator.ConditionalTriggeredAbility;
import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -27,7 +27,7 @@ public final class AbzanBeastmaster extends CardImpl {
this.toughness = new MageInt(1);
// At the beginning of your upkeep, draw a card if you control the creature with the greatest toughness or tied for the greatest toughness.
this.addAbility(new ConditionalTriggeredAbility(
this.addAbility(new ConditionalInterveningIfTriggeredAbility(
new BeginningOfUpkeepTriggeredAbility(new DrawCardSourceControllerEffect(1), TargetController.YOU, false),
ControlsCreatureGreatestToughnessCondition.instance,
"At the beginning of your upkeep, draw a card if you control the creature with the greatest toughness or tied for the greatest toughness."

View file

@ -57,7 +57,7 @@ class AcidicSoilEffect extends OneShotEffect {
if (player != null) {
int amount = 0;
for (Permanent permanent : permanents) {
if (permanent.getControllerId().equals(playerId)) {
if (permanent.isControlledBy(playerId)) {
amount++;
}
}

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