1
0
Fork 0
mirror of https://github.com/correl/mage.git synced 2025-04-04 01:06:04 -09:00

fix conflicts

This commit is contained in:
Ingmar Goudt 2019-12-29 19:28:20 +01:00
commit ce23f6900d
2451 changed files with 84128 additions and 14873 deletions
.gitignore
Mage.Client
Mage.Common
Mage.Plugins
Mage.Counter.Plugin
pom.xml
Mage.Server.Console
pom.xml
src/main/java/mage/server/console
Mage.Server.Plugins/Mage.Deck.Constructed

5
.gitignore vendored
View file

@ -48,6 +48,8 @@ Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/target/
Mage.Server.Plugins/Mage.Game.FreeForAll/target
Mage.Server.Plugins/Mage.Game.MomirDuel/target
Mage.Server.Plugins/Mage.Game.MomirGame/target/
Mage.Server.Plugins/Mage.Game.OathbreakerDuel/target/
Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/target/
Mage.Server.Plugins/Mage.Game.PennyDreadfulCommanderFreeForAll/target
Mage.Server.Plugins/Mage.Game.FreeformCommanderDuel/target/
Mage.Server.Plugins/Mage.Game.FreeformCommanderFreeForAll/target/
@ -150,3 +152,6 @@ mage-bundle
# build-tools config and log files when building client/server with Atom
.build-tools.cson
build-output.log
# Visual Studio Code
.history

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.35</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-client</artifactId>

View file

@ -0,0 +1,88 @@
1 [C19:207] Vraska the Unseen
1 [C19:48] Rayami, First of the Fallen
1 [C19:51] Volrath, the Shapestealer
1 [C19:8] Kadena's Silencer
1 [C19:12] Thought Sponge
1 [C19:21] Thieving Amalgam
1 [C19:31] Apex Altisaur
1 [C19:44] Grismold, the Dreadsower
1 [C19:160] Deathmist Raptor
1 [C19:172] Hooded Hydra
1 [C19:81] Chromeshell Crab
1 [C19:87] Ixidron
1 [C19:89] Kheru Spellsnatcher
1 [C19:96] Stratus Dancer
1 [C19:100] Thousand Winds
1 [C19:101] Vesuvan Shapeshifter
1 [C19:104] Bane of the Living
1 [C19:118] Grim Haruspex
1 [C19:128] Silumgar Assassin
1 [C19:161] Den Protector
1 [C19:179] Seedborn Muse
1 [C19:184] Thelonite Hermit
1 [C19:200] Sagu Mauler
1 [C19:36] Voice of Many
1 [C19:57] Scaretiller
1 [C19:102] Willbender
1 [C19:129] Skinthinner
1 [C19:156] Ainok Survivalist
1 [C19:170] Great Oak Guardian
1 [C19:174] Nantuko Vigilante
1 [C19:177] Sakura-Tribe Elder
1 [C19:194] Icefeather Aven
1 [C19:34] Road of Return
1 [C19:115] Ghastly Conscription
1 [C19:120] Hex
1 [C19:175] Overwhelming Stampede
1 [C19:183] Tempt with Discovery
1 [C19:19] Mire in Misery
1 [C19:98] Tezzeret's Gambit
1 [C19:159] Cultivate
1 [C19:164] Explore
1 [C19:165] Farseek
1 [C19:205] Urban Evolution
1 [C19:11] Sudden Substitution
1 [C19:187] Biomass Mutation
1 [C19:9] Leadership Vacuum
1 [C19:84] Echoing Truth
1 [C19:92] Reality Shift
1 [C19:197] Putrefy
1 [C19:202] Sultai Charm
1 [C19:56] Pendant of Prosperity
1 [C19:58] Scroll of Fate
1 [C19:224] Strionic Resonator
1 [C19:221] Sol Ring
1 [C19:225] Thran Dynamo
1 [C19:17] Gift of Doom
1 [C19:186] Trail of Mystery
1 [C19:189] Bounty of the Luxa
1 [C19:201] Secret Plans
1 [C19:238] Darkwater Catacombs
1 [C19:242] Exotic Orchard
1 [C19:258] Llanowar Wastes
1 [C19:273] Shrine of the Forsaken Gods
1 [C19:278] Sunken Hollow
1 [C19:282] Thespian's Stage
1 [C19:287] Yavimaya Coast
5 [C19:291] Island
3 [C19:294] Swamp
7 [C19:300] Forest
1 [C19:227] Ash Barrens
1 [C19:232] Bojuka Bog
1 [C19:237] Command Tower
1 [C19:239] Dimir Aqueduct
1 [C19:241] Evolving Wilds
1 [C19:244] Foul Orchard
1 [C19:247] Golgari Guildgate
1 [C19:248] Golgari Rot Farm
1 [C19:254] Jungle Hollow
1 [C19:261] Myriad Landscape
1 [C19:264] Opulent Palace
1 [C19:268] Reliquary Tower
1 [C19:274] Simic Growth Chamber
1 [C19:275] Simic Guildgate
1 [C19:280] Temple of the False God
1 [C19:281] Terramorphic Expanse
1 [C19:283] Thornwood Falls
1 [C19:286] Woodland Stream
SB: 1 [C19:45] Kadena, Slinking Sorcerer

View file

@ -0,0 +1,82 @@
1 [C19:124] Ob Nixilis Reignited
1 [C19:39] Chainer, Nightmare Adept
1 [C19:43] Greven, Predator Captain
1 [C19:14] Archfiend of Spite
1 [C19:15] Bone Miser
1 [C19:18] K'rrik, Son of Yawgmoth
1 [C19:22] Anje's Ravager
1 [C19:28] Skyfire Phoenix
1 [C19:30] Wildfire Devils
1 [C19:109] Champion of Stray Souls
1 [C19:114] Geth, Lord of the Vault
1 [C19:130] Soul of Innistrad
1 [C19:103] Asylum Visitor
1 [C19:111] Doomed Necromancer
1 [C19:125] Overseer of the Damned
1 [C19:144] Flayer of the Hatebound
1 [C19:149] Magus of the Wheel
1 [C19:152] Squee, Goblin Nabob
1 [C19:153] Stromkirk Occultist
1 [C19:188] Bloodhall Priest
1 [C19:222] Solemn Simulacrum
1 [C19:57] Scaretiller
1 [C19:106] Big Game Hunter
1 [C19:116] Gorgon Recluse
1 [C19:117] Grave Scrabbler
1 [C19:123] Nightshade Assassin
1 [C19:126] Plaguecrafter
1 [C19:127] Sanitarium Skeleton
1 [C19:218] Meteor Golem
1 [C19:20] Nightmare Unmaking
1 [C19:107] Boneyard Parley
1 [C19:105] Beacon of Unrest
1 [C19:113] From Under the Floorboards
1 [C19:121] In Garruk's Wake
1 [C19:134] Avacyn's Judgment
1 [C19:19] Mire in Misery
1 [C19:26] Hate Mirage
1 [C19:108] Call to the Netherworld
1 [C19:122] Murderous Compulsion
1 [C19:133] Alchemist's Greeting
1 [C19:150] Malevolent Whispers
1 [C19:136] Chaos Warp
1 [C19:110] Dark Withering
1 [C19:142] Fiery Temper
1 [C19:154] Violent Eruption
1 [C19:213] Grimoire of the Dead
1 [C19:216] Key to the City
1 [C19:53] Bloodthirsty Blade
1 [C19:52] Aeon Engine
1 [C19:209] Armillary Sphere
1 [C19:214] Hedron Archive
1 [C19:220] Rakdos Locket
1 [C19:221] Sol Ring
1 [C19:16] Curse of Fool's Wisdom
1 [C19:119] Hedonist's Trove
1 [C19:155] Warstorm Surge
1 [C19:112] Faith of the Devoted
1 [C19:131] The Eldest Reborn
1 [C19:132] Zombie Infestation
1 [C19:59] Sanctum of Eternity
1 [C19:240] Drownyard Temple
1 [C19:242] Exotic Orchard
1 [C19:246] Geier Reach Sanitarium
10 [C19:294] Swamp
10 [C19:297] Mountain
1 [C19:226] Akoum Refuge
1 [C19:227] Ash Barrens
1 [C19:229] Barren Moor
1 [C19:230] Bloodfell Caves
1 [C19:235] Cinder Barrens
1 [C19:237] Command Tower
1 [C19:241] Evolving Wilds
1 [C19:243] Forgotten Cave
1 [C19:259] Memorial to Folly
1 [C19:260] Mortuary Mire
1 [C19:261] Myriad Landscape
1 [C19:266] Rakdos Carnarium
1 [C19:267] Rakdos Guildgate
1 [C19:269] Rix Maadi, Dungeon Palace
1 [C19:281] Terramorphic Expanse
1 [C19:280] Temple of the False God
SB: 1 [C19:37] Anje Falkenrath

View file

@ -0,0 +1,82 @@
1 [C19:198] Ral Zarek
1 [C19:40] Elsha of the Infinite
1 [C19:47] Pramikon, Sky Rampart
1 [C19:7] Thalia's Geistcaller
1 [C19:13] Wall of Stolen Identity
1 [C19:23] Backdraft Hellkite
1 [C19:24] Dockside Extortionist
1 [C19:41] Gerrard, Weatherlight Hero
1 [C19:70] Pristine Angel
1 [C19:76] Sun Titan
1 [C19:82] Clever Impersonator
1 [C19:79] Zetalpa, Primal Dawn
1 [C19:93] River Kelpie
1 [C19:97] Talrand, Sky Summoner
1 [C19:196] Pristine Skywise
1 [C19:1] Cliffside Rescuer
1 [C19:57] Scaretiller
1 [C19:145] Guttersnipe
1 [C19:190] Crackling Drake
1 [C19:211] Burnished Hart
1 [C19:5] Sevinne's Reclamation
1 [C19:10] Mass Diminish
1 [C19:27] Ignite the Future
1 [C19:62] Divine Reckoning
1 [C19:63] Dusk // Dawn
1 [C19:66] Increasing Devotion
1 [C19:75] Storm Herd
1 [C19:138] Devil's Play
1 [C19:83] Deep Analysis
1 [C19:90] Mystic Retrieval
1 [C19:94] Runic Repetition
1 [C19:140] Faithless Looting
1 [C19:151] Rolling Temblor
1 [C19:4] Mandate of Peace
1 [C19:147] Increasing Vengeance
1 [C19:148] Magmaquake
1 [C19:199] Refuse // Cooperate
1 [C19:9] Leadership Vacuum
1 [C19:69] Prismatic Strands
1 [C19:71] Purify the Grave
1 [C19:72] Ray of Distortion
1 [C19:80] Chemister's Insight
1 [C19:85] Fact or Fiction
1 [C19:86] Fervent Denial
1 [C19:91] Oona's Grace
1 [C19:99] Think Twice
1 [C19:137] Desperate Ravings
1 [C19:192] Farm // Market
1 [C19:54] Empowered Autogenerator
1 [C19:53] Bloodthirsty Blade
1 [C19:209] Armillary Sphere
1 [C19:210] Azorius Locket
1 [C19:212] Commander's Sphere
1 [C19:215] Izzet Locket
1 [C19:221] Sol Ring
1 [C19:88] Jace's Sanctum
1 [C19:64] Ghostly Prison
1 [C19:95] Secrets of the Dead
1 [C19:135] Burning Vengeance
1 [C19:242] Exotic Orchard
1 [C19:265] Prairie Stream
9 [C19:288] Plains
8 [C19:291] Island
4 [C19:297] Mountain
1 [C19:227] Ash Barrens
1 [C19:228] Azorius Chancery
1 [C19:233] Boros Garrison
1 [C19:234] Boros Guildgate
1 [C19:237] Command Tower
1 [C19:241] Evolving Wilds
1 [C19:251] Highland Lake
1 [C19:252] Izzet Boilerworks
1 [C19:253] Izzet Guildgate
1 [C19:261] Myriad Landscape
1 [C19:262] Mystic Monastery
1 [C19:276] Stone Quarry
1 [C19:279] Swiftwater Cliffs
1 [C19:280] Temple of the False God
1 [C19:281] Terramorphic Expanse
1 [C19:284] Tranquil Cove
1 [C19:285] Wind-Scarred Crag
SB: 1 [C19:49] Sevinne, the Chronoclasm

View file

@ -0,0 +1,84 @@
1 [C19:167] Garruk, Primal Hunter
1 [C19:38] Atla Palani, Nest Tender
1 [C19:46] Marisi, Breaker of the Coil
1 [C19:3] Doomed Artisan
1 [C19:29] Tectonic Hellion
1 [C19:33] Ohran Frostfang
1 [C19:35] Selesnya Eulogist
1 [C19:50] Tahngarth, First Mate
1 [C19:61] Angel of Sanctions
1 [C19:78] Wingmate Roc
1 [C19:139] Dragonmaster Outcast
1 [C19:141] Feldon of the Third Path
1 [C19:169] Giant Adephage
1 [C19:182] Soul of Zendikar
1 [C19:204] Trostani, Selesnya's Voice
1 [C19:60] Desolation Twin
1 [C19:143] Flamerush Rider
1 [C19:146] Heart-Piercer Manticore
1 [C19:176] Rampaging Baloths
1 [C19:185] Thragtusk
1 [C19:191] Emmara Tandris
1 [C19:208] Wayfaring Temple
1 [C19:1] Cliffside Rescuer
1 [C19:36] Voice of Many
1 [C19:57] Scaretiller
1 [C19:73] Roc Egg
1 [C19:168] Garruk's Packleader
1 [C19:177] Sakura-Tribe Elder
1 [C19:206] Vitu-Ghazi Guildmage
1 [C19:25] Ghired's Belligerence
1 [C19:32] Full Flowering
1 [C19:65] Hour of Reckoning
1 [C19:68] Phyrexian Rebirth
1 [C19:180] Shamanic Revelation
1 [C19:26] Hate Mirage
1 [C19:159] Cultivate
1 [C19:164] Explore
1 [C19:165] Farseek
1 [C19:171] Harmonize
1 [C19:166] Fresh Meat
1 [C19:173] Momentous Fall
1 [C19:178] Second Harvest
1 [C19:74] Rootborn Defenses
1 [C19:77] Trostani's Judgment
1 [C19:157] Beast Within
1 [C19:162] Druid's Deliverance
1 [C19:181] Slice in Twain
1 [C19:195] Naya Charm
1 [C19:203] Sundering Growth
1 [C19:55] Idol of Oblivion
1 [C19:219] Mimic Vat
1 [C19:223] Soul Foundry
1 [C19:217] Lightning Greaves
1 [C19:221] Sol Ring
1 [C19:2] Commander's Insignia
1 [C19:6] Song of the Worldsoul
1 [C19:193] Growing Ranks
1 [C19:67] Intangible Virtue
1 [C19:158] Colossal Majesty
1 [C19:163] Elemental Bond
1 [C19:236] Cinder Glade
1 [C19:242] Exotic Orchard
1 [C19:245] Gargoyle Castle
1 [C19:277] Sungrass Prairie
7 [C19:288] Plains
4 [C19:297] Mountain
8 [C19:300] Forest
1 [C19:227] Ash Barrens
1 [C19:231] Blossoming Sands
1 [C19:233] Boros Garrison
1 [C19:237] Command Tower
1 [C19:241] Evolving Wilds
1 [C19:249] Graypelt Refuge
1 [C19:250] Gruul Turf
1 [C19:255] Jungle Shrine
1 [C19:256] Kazandu Refuge
1 [C19:257] Krosan Verge
1 [C19:261] Myriad Landscape
1 [C19:263] Naya Panorama
1 [C19:270] Rogue's Passage
1 [C19:271] Rugged Highlands
1 [C19:272] Selesnya Sanctuary
1 [C19:281] Terramorphic Expanse
SB: 1 [C19:42] Ghired, Conclave Exile

View file

@ -988,6 +988,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
btnDebug.setFocusable(false);
btnDebug.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
btnDebug.addMouseListener(new java.awt.event.MouseAdapter() {
@Override
public void mouseClicked(java.awt.event.MouseEvent evt) {
btnDebugMouseClicked(evt);
}

View file

@ -517,7 +517,7 @@ public class Card extends MagePermanent implements MouseMotionListener, MouseLis
}
@Override
public void setSelected(boolean selected) {
public void setSelected(boolean isSelected) {
}
@Override

View file

@ -952,13 +952,16 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
searchByTextField = new JTextField();
searchByTextField.setToolTipText("Searches for card names, types, rarity, casting cost and rules text. NB: Mana symbols are written like {W},{U},{C} etc");
searchByTextField.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e) {
reselectBy();
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
}
});

View file

@ -9,6 +9,7 @@ import java.awt.Rectangle;
import java.awt.Stroke;
import java.awt.geom.Rectangle2D;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -16,12 +17,12 @@ import javax.swing.JComponent;
public class ManaBarChart extends JComponent {
HashMap<String, Integer> pips_at_cmcs = new HashMap<String, Integer>();
Map<String, Integer> pips_at_cmcs = new HashMap<String, Integer>();
ManaBarChart() {
}
ManaBarChart(HashMap<String, Integer> pips_at_cmcs) {
ManaBarChart(Map<String, Integer> pips_at_cmcs) {
this.pips_at_cmcs = pips_at_cmcs;
}
@ -35,6 +36,7 @@ public class ManaBarChart extends JComponent {
return preferred;
}
@Override
public void paint(Graphics g) {
drawBar((Graphics2D) g, getBounds());
}

View file

@ -60,6 +60,7 @@ public class ManaPieChart extends JComponent {
return preferred;
}
@Override
public void paint(Graphics g) {
drawPie((Graphics2D) g, getBounds(), slices.toArray(new Slice[slices.size()]));
}

View file

@ -374,6 +374,7 @@ public class ChatPanelBasic extends javax.swing.JPanel {
txtMessage.setName(""); // NOI18N
txtMessage.setPreferredSize(new java.awt.Dimension(6, 70));
txtMessage.addKeyListener(new java.awt.event.KeyAdapter() {
@Override
public void keyTyped(java.awt.event.KeyEvent evt) {
txtMessageKeyTyped(evt);
}

View file

@ -20,39 +20,48 @@ class TranslucentSynthSytle extends SynthStyle {
style = s;
}
@Override
public Object get(SynthContext context, Object key) {
return style.get(context, key);
}
@Override
public boolean getBoolean(SynthContext context, Object key,
boolean defaultValue) {
return style.getBoolean(context, key, defaultValue);
}
@Override
public Color getColor(SynthContext context, ColorType type) {
return style.getColor(context, type);
}
@Override
public Font getFont(SynthContext context) {
return style.getFont(context);
}
@Override
public SynthGraphicsUtils getGraphicsUtils(SynthContext context) {
return style.getGraphicsUtils(context);
}
@Override
public Icon getIcon(SynthContext context, Object key) {
return style.getIcon(context, key);
}
@Override
public Insets getInsets(SynthContext context, Insets insets) {
return style.getInsets(context, insets);
}
@Override
public int getInt(SynthContext context, Object key, int defaultValue) {
return style.getInt(context, key, defaultValue);
}
@Override
public SynthPainter getPainter(final SynthContext context) {
return new SynthPainter() {
public void paintInternalFrameBackground(SynthContext context,
@ -63,19 +72,23 @@ class TranslucentSynthSytle extends SynthStyle {
};
}
@Override
public String getString(SynthContext context, Object key,
String defaultValue) {
return style.getString(context, key, defaultValue);
}
@Override
public void installDefaults(SynthContext context) {
style.installDefaults(context);
}
@Override
public void uninstallDefaults(SynthContext context) {
style.uninstallDefaults(context);
}
@Override
public boolean isOpaque(SynthContext context) {
if (context.getRegion() == Region.INTERNAL_FRAME) {
return false;

View file

@ -60,6 +60,8 @@ public class ShadowLabel extends JLabel {
this.invertColors = invertColors;
}
@Override
public void setText(String text) {
this.text = text;
repaint();

View file

@ -1415,14 +1415,15 @@ class ImportFilter extends FileFilter {
|| ext.equalsIgnoreCase("dek")
|| ext.equalsIgnoreCase("cod")
|| ext.equalsIgnoreCase("o8d")
|| ext.equalsIgnoreCase("draft");
|| ext.equalsIgnoreCase("draft")
|| ext.equalsIgnoreCase("mtga");
}
return false;
}
@Override
public String getDescription() {
return "All formats (*.dec; *.mwDeck; *.txt; *.dek; *.cod; *.o8d; *.draft)";
return "All formats (*.dec; *.mwDeck; *.txt; *.dek; *.cod; *.o8d; *.draft; *.mtga)";
}
}

View file

@ -352,7 +352,7 @@ public class MageBook extends JComponent {
List<Plane> planes = getPlanes(currentPage, currentSet, numTokensEmblems);
int numPlanes = 0;
if (planes != null && planes.size() > 0) {
if (!planes.isEmpty()) {
int size = planes.size();
numPlanes = size;
Rectangle rectangle = new Rectangle();
@ -523,7 +523,7 @@ public class MageBook extends JComponent {
// second run for empty numbers
int countHave = haveNumbers.size();
int countNotHave = 0;
if (cards.size() > 0) {
if (!cards.isEmpty()) {
for (int i = startNumber; i <= endNumber; i++) {
if (!haveNumbers.contains(i)) {
countNotHave++;
@ -593,8 +593,8 @@ public class MageBook extends JComponent {
}
private List<Emblem> getEmblems(int page, String set, int numTokensEmblems) {
ArrayList<CardDownloadData> allEmblems = getTokenCardUrls();
ArrayList<Emblem> emblems = new ArrayList<>();
List<CardDownloadData> allEmblems = getTokenCardUrls();
List<Emblem> emblems = new ArrayList<>();
for (CardDownloadData emblem : allEmblems) {
if (emblem.getSet().equals(set)) {
@ -650,8 +650,8 @@ public class MageBook extends JComponent {
}
private List<Plane> getPlanes(int page, String set, int numTokensEmblems) {
ArrayList<CardDownloadData> allPlanes = getTokenCardUrls();
ArrayList<Plane> planes = new ArrayList<>();
List<CardDownloadData> allPlanes = getTokenCardUrls();
List<Plane> planes = new ArrayList<>();
for (CardDownloadData plane : allPlanes) {
if (plane.getSet().equals(set)) {
@ -695,13 +695,13 @@ public class MageBook extends JComponent {
int totalTokensEmblems = totalTokens + getTotalNumEmblems(set);
int start = 0;
if (!(page * conf.CARDS_PER_PAGE <= totalTokensEmblems && (page + 1) * conf.CARDS_PER_PAGE >= totalTokensEmblems)) {
start = page * conf.CARDS_PER_PAGE - totalTokensEmblems;
start = Math.max(0, page * conf.CARDS_PER_PAGE - totalTokensEmblems);
pageRight.setVisible(true);
}
int end = planes.size();
if ((page + 1) * conf.CARDS_PER_PAGE < totalTokensEmblems + planes.size()) {
end = (page + 1) * conf.CARDS_PER_PAGE - totalTokensEmblems;
end = Math.max(0, (page + 1) * conf.CARDS_PER_PAGE - totalTokensEmblems);
pageRight.setVisible(true);
} else {
pageRight.setVisible(false);

View file

@ -37,6 +37,10 @@ public class AddLandDialog extends MageDialog {
this.setModal(true);
}
private boolean setHaveSnowLands(ExpansionInfo exp) {
return CardRepository.instance.haveSnowLands(exp.getCode());
}
public void showDialog(Deck deck, DeckEditorMode mode) {
this.deck = deck;
SortedSet<String> landSetNames = new TreeSet<>();
@ -45,7 +49,7 @@ public class AddLandDialog extends MageDialog {
// decide from which sets basic lands are taken from
for (String setCode : deck.getExpansionSetCodes()) {
ExpansionInfo expansionInfo = ExpansionRepository.instance.getSetByCode(setCode);
if (expansionInfo != null && expansionInfo.hasBasicLands()) {
if (expansionInfo != null && expansionInfo.hasBasicLands() && !setHaveSnowLands(expansionInfo)) {
defaultSetName = expansionInfo.getName();
break;
}
@ -58,7 +62,7 @@ public class AddLandDialog extends MageDialog {
if (expansionInfo != null) {
List<ExpansionInfo> blockSets = ExpansionRepository.instance.getSetsFromBlock(expansionInfo.getBlockName());
for (ExpansionInfo blockSet : blockSets) {
if (blockSet.hasBasicLands()) {
if (blockSet.hasBasicLands() && !setHaveSnowLands(expansionInfo)) {
defaultSetName = expansionInfo.getName();
break;
}
@ -70,6 +74,10 @@ public class AddLandDialog extends MageDialog {
// if still no set with lands found, add list of all available
List<ExpansionInfo> basicLandSets = ExpansionRepository.instance.getSetsWithBasicLandsByReleaseDate();
for (ExpansionInfo expansionInfo : basicLandSets) {
// snow lands only in free mode
if (mode != DeckEditorMode.FREE_BUILDING && setHaveSnowLands(expansionInfo)) {
continue;
}
landSetNames.add(expansionInfo.getName());
}
if (landSetNames.isEmpty()) {
@ -472,19 +480,32 @@ public class AddLandDialog extends MageDialog {
white += m.getWhite();
}
int total = red + green + black + blue + white;
int redcards = Math.round(land_number * ((float) red / (float) total));
int redcards = 0;
int greencards = 0;
int blackcards = 0;
int bluecards = 0;
int whitecards = 0;
if (total > 0) {
redcards = Math.round(land_number * ((float) red / (float) total));
total -= red;
land_number -= redcards;
int greencards = Math.round(land_number * ((float) green / (float) total));
greencards = Math.round(land_number * ((float) green / (float) total));
total -= green;
land_number -= greencards;
int blackcards = Math.round(land_number * ((float) black / (float) total));
blackcards = Math.round(land_number * ((float) black / (float) total));
total -= black;
land_number -= blackcards;
int bluecards = Math.round(land_number * ((float) blue / (float) total));
bluecards = Math.round(land_number * ((float) blue / (float) total));
total -= blue;
land_number -= bluecards;
int whitecards = land_number;
whitecards = land_number;
}
spnMountain.setValue(redcards);
spnForest.setValue(greencards);
spnSwamp.setValue(blackcards);

View file

@ -422,8 +422,8 @@
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/flags/us.png"/>
</Property>
<Property name="text" type="java.lang.String" value="P"/>
<Property name="toolTipText" type="java.lang.String" value="Connect to mtg.powersofwar.com (USA, use any username without registration)"/>
<Property name="text" type="java.lang.String" value="US"/>
<Property name="toolTipText" type="java.lang.String" value="Connect to us.xmage.today (USA, use any username without registration)"/>
<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

@ -283,8 +283,8 @@ public class ConnectDialog extends MageDialog {
});
btnFindUs.setIcon(new javax.swing.ImageIcon(getClass().getResource("/flags/us.png"))); // NOI18N
btnFindUs.setText("P");
btnFindUs.setToolTipText("Connect to mtg.powersofwar.com (USA, use any username without registration)");
btnFindUs.setText("US");
btnFindUs.setToolTipText("Connect to us.xmage.today (USA, use any username without registration)");
btnFindUs.setActionCommand("connectXmageus");
btnFindUs.setAlignmentY(0.0F);
btnFindUs.setMargin(new java.awt.Insets(2, 2, 2, 2));
@ -765,7 +765,7 @@ public class ConnectDialog extends MageDialog {
}//GEN-LAST:event_btnFind2findPublicServerActionPerformed
private void connectXmageus(java.awt.event.ActionEvent evt) {
String serverAddress = "mtg.powersofwar.com";
String serverAddress = "us.xmage.today";
this.txtServer.setText(serverAddress);
this.txtPort.setText("17171");
// Update userName and password according to the chosen server.
@ -774,7 +774,7 @@ public class ConnectDialog extends MageDialog {
}
private void connectBeta(java.awt.event.ActionEvent evt) {
String serverAddress = "xmage.today";
String serverAddress = "beta.xmage.today";
this.txtServer.setText(serverAddress);
this.txtPort.setText("17171");
// Update userName and password according to the chosen server.

View file

@ -359,7 +359,7 @@
<Component class="javax.swing.JLabel" name="lbTimeLimit">
<Properties>
<Property name="text" type="java.lang.String" value="Time Limit:"/>
<Property name="toolTipText" type="java.lang.String" value="The active time a player may use to finish the match. If his or her time runs out, the player looses the current game."/>
<Property name="toolTipText" type="java.lang.String" value="The active time a player may use to finish the match. If their time runs out, the player looses the current game."/>
</Properties>
</Component>
<Component class="javax.swing.JComboBox" name="cbTimeLimit">

View file

@ -187,7 +187,7 @@ public class NewTableDialog extends MageDialog {
lbDeckType.setText("Deck Type:");
lbTimeLimit.setText("Time Limit:");
lbTimeLimit.setToolTipText("The active time a player may use to finish the match. If his or her time runs out, the player looses the current game.");
lbTimeLimit.setToolTipText("The active time a player may use to finish the match. If their time runs out, the player looses the current game.");
lblGameType.setText("Game Type:");
@ -637,6 +637,7 @@ public class NewTableDialog extends MageDialog {
case "Variant Magic - Commander":
case "Variant Magic - Duel Commander":
case "Variant Magic - MTGO 1v1 Commander":
case "Variant Magic - Centurion Commander":
case "Variant Magic - Penny Dreadful Commander":
if (!options.getGameType().startsWith("Commander")) {
JOptionPane.showMessageDialog(MageFrame.getDesktop(), "Deck type Commander needs also a Commander game type", "Error", JOptionPane.ERROR_MESSAGE);
@ -668,6 +669,12 @@ public class NewTableDialog extends MageDialog {
return false;
}
break;
case "Variant Magic - Oathbreaker":
if (!options.getGameType().startsWith("Oathbreaker")) {
JOptionPane.showMessageDialog(MageFrame.getDesktop(), "Deck type Oathbreaker needs also a Oathbreaker game type", "Error", JOptionPane.ERROR_MESSAGE);
return false;
}
break;
}
// game => deck
@ -677,6 +684,7 @@ public class NewTableDialog extends MageDialog {
if (!options.getDeckType().equals("Variant Magic - Commander")
&& !options.getDeckType().equals("Variant Magic - Duel Commander")
&& !options.getDeckType().equals("Variant Magic - MTGO 1v1 Commander")
&& !options.getDeckType().equals("Variant Magic - Centurion Commander")
&& !options.getDeckType().equals("Variant Magic - Freeform Commander")
&& !options.getDeckType().equals("Variant Magic - Penny Dreadful Commander")) {
JOptionPane.showMessageDialog(MageFrame.getDesktop(), "Deck type Commander needs also a Commander game type", "Error", JOptionPane.ERROR_MESSAGE);
@ -704,6 +712,13 @@ public class NewTableDialog extends MageDialog {
return false;
}
break;
case "Oathbreaker Two Player Duel":
case "Oathbreaker Free For All":
if (!options.getDeckType().equals("Variant Magic - Oathbreaker")) {
JOptionPane.showMessageDialog(MageFrame.getDesktop(), "Deck type Oathbreaker needs also a Oathbreaker game type", "Error", JOptionPane.ERROR_MESSAGE);
return false;
}
break;
}
return true;
}

View file

@ -362,7 +362,7 @@
<Component class="javax.swing.JLabel" name="lbTimeLimit">
<Properties>
<Property name="text" type="java.lang.String" value="Time Limit:"/>
<Property name="toolTipText" type="java.lang.String" value="The time a player has for the whole match. If a player runs out of time during a game, he loses the complete match. "/>
<Property name="toolTipText" type="java.lang.String" value="The time a player has for the whole match. If a player runs out of time during a game, they lose the complete match. "/>
</Properties>
<BindingProperties>
<BindingProperty name="labelFor" source="cbTimeLimit" target="lbTimeLimit" targetPath="labelFor" updateStrategy="0" immediately="false"/>
@ -370,13 +370,13 @@
</Component>
<Component class="javax.swing.JComboBox" name="cbTimeLimit">
<Properties>
<Property name="toolTipText" type="java.lang.String" value="The time a player has for the whole match. If a player runs out of time during a game, he loses the complete match. "/>
<Property name="toolTipText" type="java.lang.String" value="The time a player has for the whole match. If a player runs out of time during a game, they lose the complete match. "/>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lbSkillLevel">
<Properties>
<Property name="text" type="java.lang.String" value="Skill Level:"/>
<Property name="toolTipText" type="java.lang.String" value="The time a player has for the whole match. If a player runs out of time during a game, he loses the complete match. "/>
<Property name="toolTipText" type="java.lang.String" value="The time a player has for the whole match. If a player runs out of time during a game, they lose the complete match. "/>
</Properties>
</Component>
<Component class="javax.swing.JComboBox" name="cbSkillLevel">

View file

@ -1,5 +1,10 @@
package mage.client.dialog;
import java.awt.*;
import java.io.File;
import java.util.*;
import java.util.stream.Collectors;
import javax.swing.*;
import mage.cards.decks.Deck;
import mage.cards.decks.DeckFileFilter;
import mage.cards.decks.importer.DeckImporter;
@ -26,13 +31,6 @@ import mage.view.TableView;
import mage.view.TournamentTypeView;
import org.apache.log4j.Logger;
import javax.swing.*;
import java.awt.*;
import java.io.File;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author BetaSteward_at_googlemail.com, JayDi85
*/
@ -41,13 +39,13 @@ public class NewTournamentDialog extends MageDialog {
private static final Logger logger = Logger.getLogger(NewTournamentDialog.class);
private TableView table;
private UUID playerId;
// private UUID playerId;
private UUID roomId;
private String lastSessionId;
private RandomPacksSelectorDialog randomPackSelector;
private JTextArea txtRandomPacks;
private final List<TournamentPlayerPanel> players = new ArrayList<>();
private final List<JPanel> packPanels = new ArrayList<>();
private final java.util.List<TournamentPlayerPanel> players = new ArrayList<>();
private final java.util.List<JPanel> packPanels = new ArrayList<>();
private static final int CONSTRUCTION_TIME_MIN = 6;
private static final int CONSTRUCTION_TIME_MAX = 30;
private boolean isRandom = false;
@ -231,15 +229,15 @@ public class NewTournamentDialog extends MageDialog {
lblName.setText("Name:");
lbTimeLimit.setText("Time Limit:");
lbTimeLimit.setToolTipText("The time a player has for the whole match. If a player runs out of time during a game, he loses the complete match. ");
lbTimeLimit.setToolTipText("The time a player has for the whole match. If a player runs out of time during a game, they lose the complete match. ");
org.jdesktop.beansbinding.Binding binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, cbTimeLimit, org.jdesktop.beansbinding.ObjectProperty.create(), lbTimeLimit, org.jdesktop.beansbinding.BeanProperty.create("labelFor"));
bindingGroup.addBinding(binding);
cbTimeLimit.setToolTipText("The time a player has for the whole match. If a player runs out of time during a game, he loses the complete match. ");
cbTimeLimit.setToolTipText("The time a player has for the whole match. If a player runs out of time during a game, they lose the complete match. ");
lbSkillLevel.setText("Skill Level:");
lbSkillLevel.setToolTipText("The time a player has for the whole match. If a player runs out of time during a game, he loses the complete match. ");
lbSkillLevel.setToolTipText("The time a player has for the whole match. If a player runs out of time during a game, they lose the complete match. ");
cbSkillLevel.setToolTipText("<HTML>This option can be used to make it easier to find matches<br>\nwith opponents of the appropriate skill level.");
@ -709,12 +707,12 @@ public class NewTournamentDialog extends MageDialog {
private void btnCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCancelActionPerformed
this.table = null;
this.playerId = null;
// this.playerId = null;
this.hideDialog();
}//GEN-LAST:event_btnCancelActionPerformed
private void updateNumSeats() {
int numPlayers = (Integer) this.spnNumPlayers.getValue();
// int numPlayers = (Integer) this.spnNumPlayers.getValue();
int numSeats = (Integer) this.spnNumSeats.getValue();
if (numSeats > 2) {
@ -966,11 +964,6 @@ public class NewTournamentDialog extends MageDialog {
}
randomPackSelector.setSelectedPacks(packList);
txtRandomPacks.setText(packNames);
// workaround to apply field's auto-size
this.pack();
this.revalidate();
this.repaint();
}
private void createRandomPacks() {
@ -993,6 +986,7 @@ public class NewTournamentDialog extends MageDialog {
btnSelectRandomPacks.setToolTipText(RandomPacksSelectorDialog.randomDraftDescription);
btnSelectRandomPacks.addActionListener(evt -> showRandomPackSelectorDialog());
pnlRandomPacks.add(btnSelectRandomPacks);
this.pnlRandomPacks.setMinimumSize(new Dimension(784, 150));
}
txtRandomPacks.setText(txtRandomPacks.getText()); // workaround to apply field's auto-size
this.pack();
@ -1154,7 +1148,7 @@ public class NewTournamentDialog extends MageDialog {
int packNumber = 0;
for (String pack : packsArray) {
packNumber++;
if (this.packPanels.size() >= packNumber - 1) {
if (!packPanels.isEmpty() && this.packPanels.size() >= packNumber - 1) {
JPanel panel = packPanels.get(packNumber - 1);
JComboBox comboBox = findComboInComponent(panel);

View file

@ -36,12 +36,17 @@
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="pnlSelect" min="-2" pref="241" max="-2" attributes="0"/>
<EmptySpace pref="300" max="32767" attributes="0"/>
<Component id="pnlApply" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="pnlSelect" min="-2" pref="196" max="-2" attributes="0"/>
<EmptySpace pref="402" max="32767" attributes="0"/>
<Component id="pnlApply" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnApply" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="pnlPacks" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
@ -49,11 +54,13 @@
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="pnlPacks" min="-2" pref="372" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="pnlPacks" min="-2" pref="362" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="pnlApply" min="-2" pref="32" max="-2" attributes="0"/>
<Component id="pnlSelect" min="-2" pref="32" max="-2" attributes="0"/>
<Component id="btnApply" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
</Group>
@ -64,8 +71,8 @@
<Container class="java.awt.Panel" name="pnlPacks">
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridLayout">
<Property name="columns" type="int" value="12"/>
<Property name="rows" type="int" value="11"/>
<Property name="columns" type="int" value="13"/>
<Property name="rows" type="int" value="12"/>
</Layout>
</Container>
<Container class="javax.swing.JPanel" name="pnlSelect">
@ -94,7 +101,7 @@
<Container class="javax.swing.JPanel" name="pnlApply">
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout"/>
<SubComponents>
</Container>
<Component class="javax.swing.JButton" name="btnApply">
<Properties>
<Property name="text" type="java.lang.String" value="Apply"/>
@ -105,6 +112,4 @@
</Events>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>

View file

@ -58,15 +58,15 @@ public class RandomPacksSelectorDialog extends javax.swing.JDialog {
this.setModal(true);
}
public void setSelectedPacks(ArrayList<String> packs){
if (!boxesCreated){
public void setSelectedPacks(ArrayList<String> packs) {
if (!boxesCreated) {
createCheckboxes();
}
for (Component pack : pnlPacks.getComponents()) {
JCheckBox thePack = (JCheckBox) pack;
if (packs.contains(thePack.getText())) {
thePack.setSelected(true);
} else{
} else {
thePack.setSelected(false);
}
}
@ -74,9 +74,9 @@ public class RandomPacksSelectorDialog extends javax.swing.JDialog {
public ArrayList<String> getSelectedPacks() {
ArrayList<String> returnVal = new ArrayList<>();
for (Component pack: pnlPacks.getComponents()){
for (Component pack : pnlPacks.getComponents()) {
JCheckBox thePack = (JCheckBox) pack;
if (thePack.isSelected()){
if (thePack.isSelected()) {
returnVal.add(thePack.getText());
}
}
@ -100,7 +100,6 @@ public class RandomPacksSelectorDialog extends javax.swing.JDialog {
}
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
@ -118,7 +117,7 @@ public class RandomPacksSelectorDialog extends javax.swing.JDialog {
btnApply = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
setTitle(title);
setTitle("Random Booster Draft Packs Selector");
setModal(true);
setModalExclusionType(java.awt.Dialog.ModalExclusionType.APPLICATION_EXCLUDE);
setPreferredSize(new java.awt.Dimension(600, 450));
@ -129,50 +128,63 @@ public class RandomPacksSelectorDialog extends javax.swing.JDialog {
}
});
pnlPacks.setLayout(new java.awt.GridLayout(11, 12));
pnlPacks.setLayout(new java.awt.GridLayout(12, 13));
pnlSelect.setLayout(new javax.swing.BoxLayout(pnlSelect, javax.swing.BoxLayout.LINE_AXIS));
btnNone.setText("Select none");
btnNone.setActionCommand("none");
btnNone.addActionListener(evt -> btnNoneActionPerformed(evt));
btnNone.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnNoneActionPerformed(evt);
}
});
pnlSelect.add(btnNone);
btnAll.setText("Select all");
btnAll.addActionListener(evt -> btnAllActionPerformed(evt));
btnAll.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnAllActionPerformed(evt);
}
});
pnlSelect.add(btnAll);
pnlApply.setLayout(new javax.swing.BoxLayout(pnlApply, javax.swing.BoxLayout.LINE_AXIS));
btnApply.setText("Apply");
if (isRandomDraft) {
btnApply.setToolTipText("At least 2 packs must be selected");
} else if (isRichManDraft) {
btnApply.setToolTipText("At least 1 pack must be selected");
btnApply.setToolTipText("At least two packs must be selected");
btnApply.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnApplyActionPerformed(evt);
}
btnApply.addActionListener(evt -> btnApplyActionPerformed(evt));
pnlApply.add(btnApply);
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(pnlSelect, javax.swing.GroupLayout.PREFERRED_SIZE, 241, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 300, Short.MAX_VALUE)
.addComponent(pnlApply, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(pnlPacks, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(pnlSelect, javax.swing.GroupLayout.PREFERRED_SIZE, 196, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 402, Short.MAX_VALUE)
.addComponent(pnlApply, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnApply))
.addComponent(pnlPacks, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(pnlPacks, javax.swing.GroupLayout.PREFERRED_SIZE, 372, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap()
.addComponent(pnlPacks, javax.swing.GroupLayout.PREFERRED_SIZE, 362, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(pnlApply, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(pnlSelect, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(pnlSelect, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(btnApply))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
@ -198,7 +210,7 @@ public class RandomPacksSelectorDialog extends javax.swing.JDialog {
public void doApply() {
if (getSelectedPacks().size() < 2 && isRandomDraft) {
JOptionPane.showMessageDialog(this, "At least 2 sets must be selected", "Error", JOptionPane.ERROR_MESSAGE);
} else if (getSelectedPacks().size() < 1 && isRichManDraft) {
} else if (getSelectedPacks().isEmpty() && isRichManDraft) {
JOptionPane.showMessageDialog(this, "At least 1 set must be selected", "Error", JOptionPane.ERROR_MESSAGE);
} else {
this.setVisible(false);

View file

@ -22,7 +22,7 @@ import mage.game.command.emblems.AjaniAdversaryOfTyrantsEmblem;
import mage.game.command.planes.AkoumPlane;
import mage.game.match.MatchType;
import mage.game.mulligan.Mulligan;
import mage.game.mulligan.VancouverMulligan;
import mage.game.mulligan.MulliganType;
import mage.game.permanent.PermanentCard;
import mage.players.Player;
import mage.players.StubPlayer;
@ -113,7 +113,7 @@ public class TestCardRenderDialog extends MageDialog {
cardsPanel.cleanUp();
cardsPanel.setCustomRenderMode(comboRenderMode.getSelectedIndex());
Game game = new TestGame(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, new VancouverMulligan(0), 20);
Game game = new TestGame(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 20);
Player player = new StubPlayer("player1", RangeOfInfluence.ALL);
Deck deck = new Deck();
game.addPlayer(player, deck);

View file

@ -606,10 +606,13 @@ public final class GamePanel extends javax.swing.JPanel {
}
public synchronized void updateGame(GameView game) {
updateGame(game, null);
updateGame(game, false, null, null);
}
public synchronized void updateGame(GameView game, Map<String, Serializable> options) {
public synchronized void updateGame(GameView game, boolean showPlayable, Map<String, Serializable> options, Set<UUID> targets) {
prepareSelectableView(game, showPlayable, options, targets);
if (playerId == null && game.getWatchedHands() == null) {
this.handContainer.setVisible(false);
} else {
@ -622,14 +625,6 @@ public final class GamePanel extends javax.swing.JPanel {
}
if (playerId != null) {
handCards.put(YOUR_HAND, game.getHand());
// Mark playable
if (game.getCanPlayInHand() != null) {
for (CardView card : handCards.get(YOUR_HAND).values()) {
if (game.getCanPlayInHand().contains(card.getId())) {
card.setPlayable(true);
}
}
}
// Get opponents hand cards if available (only possible for players)
if (game.getOpponentHands() != null) {
for (Map.Entry<String, SimpleCardsView> hand : game.getOpponentHands().entrySet()) {
@ -719,7 +714,7 @@ public final class GamePanel extends javax.swing.JPanel {
}
}
}
players.get(player.getPlayerId()).update(player);
players.get(player.getPlayerId()).update(game, player, targets);
if (player.getPlayerId().equals(playerId)) {
skipButtons.updateFromPlayer(player);
}
@ -1183,25 +1178,23 @@ public final class GamePanel extends javax.swing.JPanel {
}
public void ask(String question, GameView gameView, int messageId, Map<String, Serializable> options) {
updateGame(gameView);
updateGame(gameView, false, options, null);
this.feedbackPanel.getFeedback(FeedbackMode.QUESTION, question, false, options, messageId, true, gameView.getPhase());
}
private void prepareSelectableView(GameView gameView, Map<String, Serializable> options, Set<UUID> targets) {
// make cards/perm selectable
// highlighting chosen
// code calls after each selects or updates, no needs in switch off cards
private void prepareSelectableView(GameView gameView, boolean showPlayable, Map<String, Serializable> options, Set<UUID> targets) {
// make cards/perm selectable/chooseable/playable
// playable must be used for ask dialog only (priority and mana pay)
Zone needZone = Zone.ALL;
if (options.containsKey("targetZone")) {
if (options != null && options.containsKey("targetZone")) {
needZone = (Zone) options.get("targetZone");
}
List<UUID> needChoosen = null;
if (options.containsKey("chosen")) {
List<UUID> needChoosen;
if (options != null && options.containsKey("chosen")) {
needChoosen = (List<UUID>) options.get("chosen");
}
if (needChoosen == null) {
} else {
needChoosen = new ArrayList<>();
}
@ -1212,7 +1205,14 @@ public final class GamePanel extends javax.swing.JPanel {
needSelectable = new HashSet<>();
}
if (needChoosen.size() == 0 && needSelectable.size() == 0) {
Map<UUID, Integer> needPlayable;
if (showPlayable && gameView.getCanPlayObjects() != null) {
needPlayable = gameView.getCanPlayObjects();
} else {
needPlayable = new HashMap<>();
}
if (needChoosen.isEmpty() && needSelectable.isEmpty() && needPlayable.isEmpty()) {
return;
}
@ -1225,6 +1225,10 @@ public final class GamePanel extends javax.swing.JPanel {
if (needChoosen.contains(card.getId())) {
card.setSelected(true);
}
if (needPlayable.containsKey(card.getId())) {
card.setPlayable(true);
card.setPlayableAmount(needPlayable.get(card.getId()));
}
}
}
@ -1237,6 +1241,7 @@ public final class GamePanel extends javax.swing.JPanel {
if (needChoosen.contains(card.getKey())) {
card.getValue().setSelected(true);
}
// play from stack unsupported
}
}
@ -1250,6 +1255,10 @@ public final class GamePanel extends javax.swing.JPanel {
if (needChoosen.contains(perm.getKey())) {
perm.getValue().setSelected(true);
}
if (needPlayable.containsKey(perm.getKey())) {
perm.getValue().setPlayable(true);
perm.getValue().setPlayableAmount(needPlayable.get(perm.getKey()));
}
}
}
}
@ -1264,6 +1273,10 @@ public final class GamePanel extends javax.swing.JPanel {
if (needChoosen.contains(card.getKey())) {
card.getValue().setSelected(true);
}
if (needPlayable.containsKey(card.getKey())) {
card.getValue().setPlayable(true);
card.getValue().setPlayableAmount(needPlayable.get(card.getKey()));
}
}
}
}
@ -1278,6 +1291,28 @@ public final class GamePanel extends javax.swing.JPanel {
if (needChoosen.contains(card.getKey())) {
card.getValue().setSelected(true);
}
if (needPlayable.containsKey(card.getKey())) {
card.getValue().setPlayable(true);
card.getValue().setPlayableAmount(needPlayable.get(card.getKey()));
}
}
}
}
// command
if (needZone == Zone.COMMAND || needZone == Zone.ALL) {
for (PlayerView player : gameView.getPlayers()) {
for (CommandObjectView com : player.getCommandObjectList()) {
if (needSelectable.contains(com.getId())) {
com.setChoosable(true);
}
if (needChoosen.contains(com.getId())) {
com.setSelected(true);
}
if (needPlayable.containsKey(com.getId())) {
com.setPlayable(true);
com.setPlayableAmount(needPlayable.get(com.getId()));
}
}
}
}
@ -1291,6 +1326,20 @@ public final class GamePanel extends javax.swing.JPanel {
if (needChoosen.contains(card.getKey())) {
card.getValue().setSelected(true);
}
if (needPlayable.containsKey(card.getKey())) {
card.getValue().setPlayable(true);
card.getValue().setPlayableAmount(needPlayable.get(card.getKey()));
}
}
}
// looked at
for (LookedAtView look : gameView.getLookedAt()) {
for (Map.Entry<UUID, SimpleCardView> card : look.getCards().entrySet()) {
if (needPlayable.containsKey(card.getKey())) {
card.getValue().setPlayable(true);
card.getValue().setPlayableAmount(needPlayable.get(card.getKey()));
}
}
}
}
@ -1315,10 +1364,8 @@ public final class GamePanel extends javax.swing.JPanel {
switch (needType) {
case PICK_ABILITY:
popupMenuType = PopUpMenuType.TRIGGER_ORDER;
prepareSelectableView(gameView, options, targets);
break;
case PICK_TARGET:
prepareSelectableView(gameView, options, targets);
break;
default:
logger.warn("Unknown query type in pick target: " + needType + " in " + message);
@ -1327,7 +1374,8 @@ public final class GamePanel extends javax.swing.JPanel {
}
}
updateGame(gameView);
updateGame(gameView, false, options, targets);
Map<String, Serializable> options0 = options == null ? new HashMap<>() : options;
ShowCardsDialog dialog = null;
if (cardView != null && !cardView.isEmpty()) {
@ -1359,7 +1407,8 @@ public final class GamePanel extends javax.swing.JPanel {
PreferencesDialog.getCachedValue(KEY_USE_FIRST_MANA_ABILITY, "false").equals("true"),
false);
updateGame(gameView, options);
updateGame(gameView, true, options, null);
boolean controllingPlayer = false;
for (PlayerView playerView : gameView.getPlayers()) {
if (playerView.getPlayerId().equals(playerId)) {
@ -1393,13 +1442,13 @@ public final class GamePanel extends javax.swing.JPanel {
}
public void playMana(String message, GameView gameView, Map<String, Serializable> options, int messageId) {
updateGame(gameView);
updateGame(gameView, true, options, null);
DialogManager.getManager(gameId).fadeOut();
this.feedbackPanel.getFeedback(FeedbackMode.CANCEL, message, gameView.getSpecial(), options, messageId, true, gameView.getPhase());
}
public void playXMana(String message, GameView gameView, int messageId) {
updateGame(gameView);
updateGame(gameView, true, null, null);
DialogManager.getManager(gameId).fadeOut();
this.feedbackPanel.getFeedback(FeedbackMode.CONFIRM, message, gameView.getSpecial(), null, messageId, true, gameView.getPhase());
}

View file

@ -365,7 +365,7 @@ public class HelperPanel extends JPanel {
this.mainPanel.setOpaque(false);
}
if (buttons.size() == 0) {
if (buttons.isEmpty()) {
return;
}

View file

@ -1,42 +1,29 @@
package mage.client.game;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.lang.reflect.Field;
import java.util.UUID;
import javax.swing.BorderFactory;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.MenuSelectionManager;
import javax.swing.event.ChangeListener;
import mage.cards.decks.importer.DeckImporter;
import mage.client.MageFrame;
import mage.client.SessionHandler;
import mage.client.cards.BigCard;
import mage.client.dialog.PreferencesDialog;
import static mage.client.dialog.PreferencesDialog.KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS;
import static mage.client.dialog.PreferencesDialog.KEY_GAME_MANA_AUTOPAYMENT;
import static mage.client.dialog.PreferencesDialog.KEY_GAME_MANA_AUTOPAYMENT_ONLY_ONE;
import static mage.client.dialog.PreferencesDialog.KEY_USE_FIRST_MANA_ABILITY;
import mage.client.util.GUISizeHelper;
import mage.constants.PlayerAction;
import mage.view.GameView;
import mage.view.PlayerView;
import mage.view.UserRequestMessage;
import javax.swing.*;
import javax.swing.GroupLayout.Alignment;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.*;
import java.lang.reflect.Field;
import java.util.Set;
import java.util.UUID;
import static mage.client.dialog.PreferencesDialog.*;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public class PlayAreaPanel extends javax.swing.JPanel {
@ -77,7 +64,7 @@ public class PlayAreaPanel extends javax.swing.JPanel {
popupMenu = new JPopupMenu();
if (options.isPlayer) {
addPopupMenuPlayer(player.getUserData().isAllowRequestShowHandCards());
addPopupMenuPlayer(player.getUserData().isAllowRequestHandToAll());
} else {
addPopupMenuWatcher();
}
@ -85,7 +72,7 @@ public class PlayAreaPanel extends javax.swing.JPanel {
setGUISize();
init(player, bigCard, gameId, priorityTime);
update(player);
update(null, player, null);
}
public void CleanUp() {
@ -331,12 +318,12 @@ public class PlayAreaPanel extends javax.swing.JPanel {
// Request to see hand cards
menuItem.addActionListener(e -> SessionHandler.sendPlayerAction(PlayerAction.REQUEST_PERMISSION_TO_SEE_HAND_CARDS, gameId, playerId));
} else {
allowViewHandCardsMenuItem = new JCheckBoxMenuItem("Allow requests to show from other users", allowRequestToShowHandCards);
allowViewHandCardsMenuItem = new JCheckBoxMenuItem("Allow hand requests from other users", allowRequestToShowHandCards);
allowViewHandCardsMenuItem.setMnemonic(KeyEvent.VK_A);
allowViewHandCardsMenuItem.setToolTipText("If activated watchers or other players can request to see your hand cards. If you grant this to a user, it's valid for the complete match.");
allowViewHandCardsMenuItem.setToolTipText("Watchers or other players can request your hand cards once per game. Re-activate it to allow new requests.");
handCardsMenu.add(allowViewHandCardsMenuItem);
// Requests allowed
// requests allowed (disable -> enable to reset requested list)
allowViewHandCardsMenuItem.addActionListener(e -> {
boolean requestsAllowed = ((JCheckBoxMenuItem) e.getSource()).getState();
PreferencesDialog.setPrefValue(KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS, requestsAllowed);
@ -518,11 +505,11 @@ public class PlayAreaPanel extends javax.swing.JPanel {
}
}
public final void update(PlayerView player) {
this.playerPanel.update(player);
public final void update(GameView game, PlayerView player, Set<UUID> possibleTargets) {
this.playerPanel.update(game, player, possibleTargets);
this.battlefieldPanel.update(player.getBattlefield());
if (this.allowViewHandCardsMenuItem != null) {
this.allowViewHandCardsMenuItem.setSelected(player.getUserData().isAllowRequestShowHandCards());
this.allowViewHandCardsMenuItem.setSelected(player.getUserData().isAllowRequestHandToAll());
}
}

View file

@ -1,34 +1,5 @@
/*
* PlayerPanel.java
*
* Created on Nov 18, 2009, 3:01:31 PM
*/
package mage.client.game;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import javax.swing.BorderFactory;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.SwingConstants;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import mage.cards.decks.importer.DckDeckImporter;
import mage.client.MageFrame;
import mage.client.SessionHandler;
@ -44,26 +15,34 @@ import mage.client.util.gui.countryBox.CountryUtil;
import mage.components.ImagePanel;
import mage.components.ImagePanelStyle;
import mage.constants.CardType;
import static mage.constants.Constants.DEFAULT_AVATAR_ID;
import static mage.constants.Constants.MAX_AVATAR_ID;
import static mage.constants.Constants.MIN_AVATAR_ID;
import mage.constants.ManaType;
import mage.counters.Counter;
import mage.counters.CounterType;
import mage.designations.DesignationType;
import mage.utils.timer.PriorityTimer;
import mage.view.CardView;
import mage.view.ManaPoolView;
import mage.view.PlayerView;
import mage.view.*;
import org.mage.card.arcane.ManaSymbols;
import javax.swing.*;
import javax.swing.GroupLayout.Alignment;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.*;
import static mage.constants.Constants.*;
/**
* Enhanced player pane.
*
* @author nantuko
* @author nantuko, JayDi85
*/
public class PlayerPanelExt extends javax.swing.JPanel {
// TODO: *.form file was lost, panel must be reworks in designer
private UUID playerId;
private UUID gameId;
private PlayerView player;
@ -84,6 +63,10 @@ public class PlayerPanelExt extends javax.swing.JPanel {
private final Color activeBackgroundColor = new Color(200, 255, 200, 200);
private final Color deadBackgroundColor = new Color(131, 94, 83, 200);
private final Color activeValueColor = new Color(244, 9, 47);
private final Font fontValuesZero = this.getFont().deriveFont(Font.PLAIN);
private final Font fontValuesNonZero = this.getFont().deriveFont(Font.BOLD);
private int avatarId = -1;
private String flagName;
private String basicTooltipText;
@ -140,15 +123,44 @@ public class PlayerPanelExt extends javax.swing.JPanel {
}
private void setTextForLabel(JLabel label, int amount, boolean alwaysBlack) {
setTextForLabel(label, amount, alwaysBlack, Color.BLACK);
}
private void setTextForLabel(JLabel label, int amount, boolean alwaysBlack, Color fontColor) {
label.setText(Integer.toString(amount));
if (amount != 0 || alwaysBlack) {
label.setForeground(Color.BLACK);
label.setForeground(fontColor);
label.setFont(fontValuesNonZero);
} else {
label.setForeground(new Color(100, 100, 100));
label.setFont(fontValuesZero);
}
}
public void update(PlayerView player) {
private boolean isCardsPlayable(Collection<CardView> cards, GameView gameView, Set<UUID> possibleTargets) {
if (cards != null) {
// can play
if (gameView != null && gameView.getCanPlayObjects() != null && !gameView.getCanPlayObjects().isEmpty()) {
for (CardView card : cards) {
if (gameView.getCanPlayObjects().containsKey(card.getId())) {
return true;
}
}
}
// can select
if (possibleTargets != null && !possibleTargets.isEmpty()) {
for (CardView card : cards) {
if (possibleTargets.contains(card.getId())) {
return true;
}
}
}
}
return false;
}
public void update(GameView game, PlayerView player, Set<UUID> possibleTargets) {
this.player = player;
int pastLife = player.getLife();
if (playerLives != null) {
@ -220,10 +232,26 @@ public class PlayerPanelExt extends javax.swing.JPanel {
graveLabel.setFont(font);
changedFontGrave = false;
}
setTextForLabel(graveLabel, graveCards, false);
Color graveColor = isCardsPlayable(player.getGraveyard().values(), game, possibleTargets) ? activeValueColor : Color.BLACK;
setTextForLabel(graveLabel, graveCards, false, graveColor);
graveLabel.setToolTipText("Card Types: " + qtyCardTypes(player.getGraveyard()));
Color commandColor = Color.BLACK;
for (CommandObjectView com : player.getCommandObjectList()) {
if (game != null && game.getCanPlayObjects() != null && game.getCanPlayObjects().containsKey(com.getId())) {
commandColor = activeValueColor;
break;
}
if (possibleTargets != null && possibleTargets.contains(com.getId())) {
commandColor = activeValueColor;
break;
}
}
setTextForLabel(commandLabel, player.getCommandObjectList().size(), false, commandColor);
int exileCards = player.getExile().size();
Color excileColor = isCardsPlayable(player.getExile().values(), game, possibleTargets) ? activeValueColor : Color.BLACK;
if (exileCards > 99) {
if (!changedFontExile) {
Font font = exileLabel.getFont();
@ -237,21 +265,21 @@ public class PlayerPanelExt extends javax.swing.JPanel {
exileLabel.setFont(font);
changedFontExile = false;
}
setTextForLabel(exileLabel, exileCards, false);
setTextForLabel(exileLabel, exileCards, false, excileColor);
if (!MageFrame.isLite()) {
int id = player.getUserData().getAvatarId();
if (!(id >= 1000) && (id <= 0 || (id <= MIN_AVATAR_ID && id > MAX_AVATAR_ID))) {
if (!(id > 1000) && (id != 64) && (id < MIN_AVATAR_ID || id > MAX_AVATAR_ID)) {
id = DEFAULT_AVATAR_ID;
}
if (id != avatarId) {
avatarId = id;
String path = "/avatars/" + String.valueOf(avatarId) + ".jpg";
String path = "/avatars/" + avatarId + ".jpg";
if (avatarId == 64) {
path = "/avatars/i64.jpg";
} else if (avatarId >= 1000) {
avatarId = avatarId - 1000;
path = "/avatars/special/" + String.valueOf(avatarId) + ".gif";
path = "/avatars/special/" + avatarId + ".gif";
}
Image image = ImageHelper.getImageFromResources(path);
Rectangle r = new Rectangle(80, 80);
@ -364,15 +392,41 @@ public class PlayerPanelExt extends javax.swing.JPanel {
}
protected void update(ManaPoolView pool) {
setTextForLabel(manaLabels.get("B"), pool.getBlack(), false);
setTextForLabel(manaLabels.get("R"), pool.getRed(), false);
setTextForLabel(manaLabels.get("W"), pool.getWhite(), false);
setTextForLabel(manaLabels.get("G"), pool.getGreen(), false);
setTextForLabel(manaLabels.get("U"), pool.getBlue(), false);
setTextForLabel(manaLabels.get("X"), pool.getColorless(), false);
for (Map.Entry<JLabel, ManaType> mana : manaLabels.entrySet()) {
switch (mana.getValue()) {
case BLACK:
setTextForLabel(mana.getKey(), pool.getBlack(), false, activeValueColor);
break;
case RED:
setTextForLabel(mana.getKey(), pool.getRed(), false, activeValueColor);
break;
case WHITE:
setTextForLabel(mana.getKey(), pool.getWhite(), false, activeValueColor);
break;
case GREEN:
setTextForLabel(mana.getKey(), pool.getGreen(), false, activeValueColor);
break;
case BLUE:
setTextForLabel(mana.getKey(), pool.getBlue(), false, activeValueColor);
break;
case COLORLESS:
setTextForLabel(mana.getKey(), pool.getColorless(), false, activeValueColor);
break;
}
//HoverButton btn = manaButtons.get(mana.getKey());
//mana.getKey().setOpaque(true);
//mana.getKey().setBackground(Color.green);
}
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
panelBackground = new MageRoundPane();
@ -387,6 +441,7 @@ public class PlayerPanelExt extends javax.swing.JPanel {
energyLabel = new JLabel();
experienceLabel = new JLabel();
graveLabel = new JLabel();
commandLabel = new JLabel();
libraryLabel = new JLabel();
setOpaque(false);
@ -482,6 +537,7 @@ public class PlayerPanelExt extends javax.swing.JPanel {
cheat.addActionListener(e -> btnCheatActionPerformed(e));
zonesPanel = new JPanel();
//zonesPanel.setBorder(BorderFactory.createLineBorder(Color.red));
zonesPanel.setPreferredSize(new Dimension(100, 60));
zonesPanel.setSize(100, 60);
zonesPanel.setLayout(null);
@ -491,13 +547,17 @@ public class PlayerPanelExt extends javax.swing.JPanel {
r = new Rectangle(21, 21);
resized = ImageHelper.getResizedImage(BufferedImageBuilder.bufferImage(image, BufferedImage.TYPE_INT_ARGB), r);
commandZone = new HoverButton(null, resized, resized, resized, r);
commandZone.setToolTipText("Command Zone (Commander and Emblems)");
commandZone.setToolTipText("Command Zone (Commanders, Emblems and Planes)");
commandZone.setOpaque(false);
commandZone.setObserver(() -> btnCommandZoneActionPerformed(null));
commandZone.setBounds(5, 0, 21, 21);
commandZone.setBounds(3, 0, 21, 21);
zonesPanel.add(commandZone);
cheat.setBounds(28, 0, 25, 21);
commandLabel.setToolTipText("Command zone");
commandLabel.setBounds(25, 0, 21, 21);
zonesPanel.add(commandLabel);
cheat.setBounds(40, 2, 25, 21);
zonesPanel.add(cheat);
energyExperiencePanel = new JPanel();
@ -533,72 +593,99 @@ public class PlayerPanelExt extends javax.swing.JPanel {
btnPlayer.addActionListener(e -> SessionHandler.sendPlayerUUID(gameId, playerId));
// Add mana symbols
// TODO: replace "button + label" to label on rework
/*
MouseAdapter manaMouseAdapter = new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent evt) {
JLabel label = (JLabel) evt.getSource();
if (manaLabels.containsKey(label)) {
btnManaActionPerformed(manaLabels.get(label));
}
}
};
JLabel manaCountLabelW = new JLabel();
manaCountLabelW.setToolTipText("White mana");
setTextForLabel(manaCountLabelW, 0, false);
manaLabels.put("W", manaCountLabelW);
manaCountLabelW.setIcon(new ImageIcon(ManaSymbols.getSizedManaSymbol("W", 15)));
manaCountLabelW.addMouseListener(manaMouseAdapter);
manaLabels.put(manaCountLabelW, ManaType.WHITE);l
//*/
///*
JLabel manaCountLabelW = new JLabel();
manaCountLabelW.setToolTipText("White mana");
setTextForLabel(manaCountLabelW, 0, false);
manaLabels.put(manaCountLabelW, ManaType.WHITE);
r = new Rectangle(15, 15);
BufferedImage imageManaW = ManaSymbols.getSizedManaSymbol("W", 15);
HoverButton btnWhiteMana = new HoverButton(null, imageManaW, imageManaW, imageManaW, r);
btnWhiteMana.setToolTipText("White mana");
btnWhiteMana.setOpaque(false);
btnWhiteMana.setObserver(() -> btnManaActionPerformed(ManaType.WHITE));
manaButtons.put(manaCountLabelW, btnWhiteMana);
//*/
JLabel manaCountLabelU = new JLabel();
manaCountLabelU.setToolTipText("Blue mana");
setTextForLabel(manaCountLabelU, 0, false);
manaLabels.put("U", manaCountLabelU);
manaLabels.put(manaCountLabelU, ManaType.BLUE);
r = new Rectangle(15, 15);
BufferedImage imageManaU = ManaSymbols.getSizedManaSymbol("U", 15);
HoverButton btnBlueMana = new HoverButton(null, imageManaU, imageManaU, imageManaU, r);
btnBlueMana.setToolTipText("Blue mana");
btnBlueMana.setOpaque(false);
btnBlueMana.setObserver(() -> btnManaActionPerformed(ManaType.BLUE));
manaButtons.put(manaCountLabelU, btnBlueMana);
JLabel manaCountLabelB = new JLabel();
manaCountLabelB.setToolTipText("Black mana");
setTextForLabel(manaCountLabelB, 0, false);
manaLabels.put("B", manaCountLabelB);
manaLabels.put(manaCountLabelB, ManaType.BLACK);
r = new Rectangle(15, 15);
BufferedImage imageManaB = ManaSymbols.getSizedManaSymbol("B", 15);
HoverButton btnBlackMana = new HoverButton(null, imageManaB, imageManaB, imageManaB, r);
btnBlackMana.setToolTipText("Black mana");
btnBlackMana.setOpaque(false);
btnBlackMana.setObserver(() -> btnManaActionPerformed(ManaType.BLACK));
manaButtons.put(manaCountLabelB, btnBlackMana);
JLabel manaCountLabelR = new JLabel();
manaCountLabelR.setToolTipText("Red mana");
setTextForLabel(manaCountLabelR, 0, false);
manaLabels.put("R", manaCountLabelR);
manaLabels.put(manaCountLabelR, ManaType.RED);
r = new Rectangle(15, 15);
BufferedImage imageManaR = ManaSymbols.getSizedManaSymbol("R", 15);
HoverButton btnRedMana = new HoverButton(null, imageManaR, imageManaR, imageManaR, r);
btnRedMana.setToolTipText("Red mana");
btnRedMana.setOpaque(false);
btnRedMana.setObserver(() -> btnManaActionPerformed(ManaType.RED));
manaButtons.put(manaCountLabelR, btnRedMana);
JLabel manaCountLabelG = new JLabel();
manaCountLabelG.setToolTipText("Green mana");
setTextForLabel(manaCountLabelG, 0, false);
manaLabels.put("G", manaCountLabelG);
manaLabels.put(manaCountLabelG, ManaType.GREEN);
r = new Rectangle(15, 15);
BufferedImage imageManaG = ManaSymbols.getSizedManaSymbol("G", 15);
HoverButton btnGreenMana = new HoverButton(null, imageManaG, imageManaG, imageManaG, r);
btnGreenMana.setToolTipText("Green mana");
btnGreenMana.setOpaque(false);
btnGreenMana.setObserver(() -> btnManaActionPerformed(ManaType.GREEN));
manaButtons.put(manaCountLabelG, btnGreenMana);
JLabel manaCountLabelX = new JLabel();
manaCountLabelX.setToolTipText("Colorless mana");
setTextForLabel(manaCountLabelX, 0, false);
manaLabels.put("X", manaCountLabelX);
manaLabels.put(manaCountLabelX, ManaType.COLORLESS);
r = new Rectangle(15, 15);
BufferedImage imageManaX = ManaSymbols.getSizedManaSymbol("C", 15);
HoverButton btnColorlessMana = new HoverButton(null, imageManaX, imageManaX, imageManaX, r);
btnColorlessMana.setToolTipText("Colorless mana");
btnColorlessMana.setOpaque(false);
btnColorlessMana.setObserver(() -> btnManaActionPerformed(ManaType.COLORLESS));
manaButtons.put(manaCountLabelX, btnColorlessMana);
GroupLayout gl_panelBackground = new GroupLayout(panelBackground);
gl_panelBackground.setHorizontalGroup(
@ -674,9 +761,6 @@ public class PlayerPanelExt extends javax.swing.JPanel {
.addGroup(gl_panelBackground.createSequentialGroup()
.addGap(40)
.addComponent(experienceLabel, GroupLayout.PREFERRED_SIZE, 25, GroupLayout.PREFERRED_SIZE))
/*.addGroup(gl_panelBackground.createSequentialGroup()
.addGap(18)
.addComponent(cheat, GroupLayout.PREFERRED_SIZE, 25, GroupLayout.PREFERRED_SIZE))*/
.addGroup(gl_panelBackground.createSequentialGroup()
.addGap(18)
.addComponent(exileZone, GroupLayout.PREFERRED_SIZE, 25, GroupLayout.PREFERRED_SIZE)
@ -776,9 +860,6 @@ public class PlayerPanelExt extends javax.swing.JPanel {
.addGap(31)
.addComponent(manaCountLabelG, GroupLayout.PREFERRED_SIZE, 30, GroupLayout.PREFERRED_SIZE))
.addComponent(experienceLabel, GroupLayout.PREFERRED_SIZE, 20, GroupLayout.PREFERRED_SIZE)
/*.addGroup(gl_panelBackground.createSequentialGroup()
.addGap(76)
.addComponent(cheat, GroupLayout.PREFERRED_SIZE, 21, GroupLayout.PREFERRED_SIZE))*/
.addGroup(gl_panelBackground.createSequentialGroup()
.addGap(76)
.addComponent(exileZone, GroupLayout.PREFERRED_SIZE, 21, GroupLayout.PREFERRED_SIZE)
@ -812,7 +893,7 @@ public class PlayerPanelExt extends javax.swing.JPanel {
);
setLayout(groupLayout);
}
}// </editor-fold>//GEN-END:initComponents
protected void sizePlayerPanel(boolean smallMode) {
if (smallMode) {
@ -850,7 +931,7 @@ public class PlayerPanelExt extends javax.swing.JPanel {
DialogManager.getManager(gameId).showExileDialog(player.getExile(), bigCard, gameId);
}
private void btnCheatActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCheatActionPerformed
private void btnCheatActionPerformed(java.awt.event.ActionEvent evt) {
DckDeckImporter deckImporter = new DckDeckImporter();
SessionHandler.cheat(gameId, playerId, deckImporter.importDeck("cheat.dck"));
}
@ -875,6 +956,7 @@ public class PlayerPanelExt extends javax.swing.JPanel {
}
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private HoverButton avatar;
private JButton btnPlayer;
private ImagePanel life;
@ -895,16 +977,20 @@ public class PlayerPanelExt extends javax.swing.JPanel {
private JLabel energyLabel;
private JLabel experienceLabel;
private JLabel graveLabel;
private JLabel commandLabel;
private JLabel exileLabel;
private boolean changedFontLibrary;
private boolean changedFontLife;
private boolean changedFontGrave;
private boolean changedFontExile;
private JPanel zonesPanel;
private JPanel energyExperiencePanel;
private HoverButton exileZone;
private HoverButton commandZone;
// End of variables declaration//GEN-END:variables
private boolean changedFontLibrary;
private boolean changedFontLife;
private boolean changedFontGrave;
private boolean changedFontExile;
private final Map<JLabel, ManaType> manaLabels = new HashMap<>();
private final Map<JLabel, HoverButton> manaButtons = new HashMap<>();
private final Map<String, JLabel> manaLabels = new HashMap<>();
}

View file

@ -274,7 +274,7 @@ public class CallbackClientImpl implements CallbackClient {
if (panel != null) {
appendJsonEvent("GAME_UPDATE", callback.getObjectId(), callback.getData());
panel.updateGame((GameView) callback.getData());
panel.updateGame((GameView) callback.getData(), true, null, null); // update after undo
}
break;
}

View file

@ -47,7 +47,7 @@
<Component id="btnQuickStartDuel" min="-2" max="-2" attributes="0"/>
<Component id="btnQuickStartCommander" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace pref="734" max="32767" attributes="0"/>
<EmptySpace pref="667" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -290,7 +290,7 @@
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnRatedbtnFilterActionPerformed"/>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnFilterActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JToggleButton" name="btnUnrated">
@ -307,7 +307,7 @@
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnUnratedbtnFilterActionPerformed"/>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnFilterActionPerformed"/>
</Events>
</Component>
</SubComponents>
@ -366,6 +366,20 @@
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnFilterActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JToggleButton" name="btnFormatPioneer">
<Properties>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" value="Pioneer"/>
<Property name="toolTipText" type="java.lang.String" value="Pioneer format."/>
<Property name="focusPainted" type="boolean" value="false"/>
<Property name="focusable" type="boolean" value="false"/>
<Property name="requestFocusEnabled" type="boolean" value="false"/>
<Property name="verifyInputWhenFocusTarget" type="boolean" value="false"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnFilterActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JToggleButton" name="btnFormatLegacy">
<Properties>
@ -396,7 +410,7 @@
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnFormatVintageActionPerformed"/>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnFilterActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JToggleButton" name="btnFormatPremodern">
@ -412,7 +426,7 @@
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnFormatPremodernActionPerformed"/>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnFilterActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JToolBar$Separator" name="jSeparator3">
@ -433,6 +447,22 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnFilterActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JToggleButton" name="btnFormatOathbreaker">
<Properties>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" value="Oathbreaker"/>
<Property name="toolTipText" type="java.lang.String" value="Oathbreaker format."/>
<Property name="focusPainted" type="boolean" value="false"/>
<Property name="focusable" type="boolean" value="false"/>
<Property name="horizontalTextPosition" type="int" value="0"/>
<Property name="requestFocusEnabled" type="boolean" value="false"/>
<Property name="verifyInputWhenFocusTarget" type="boolean" value="false"/>
<Property name="verticalTextPosition" type="int" value="3"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnFilterActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JToggleButton" name="btnFormatTinyLeader">
<Properties>
<Property name="selected" type="boolean" value="true"/>

View file

@ -329,11 +329,11 @@ public class TablesPanel extends javax.swing.JPanel {
chatPanelMain.getUserChatPanel().setBorder(null);
chatPanelMain.getUserChatPanel().setChatType(ChatPanelBasic.ChatType.TABLES);
// 4. BUTTONS
// 4. BUTTONS (add new buttons to the end of the list -- if not then users lost their filter settings)
filterButtons = new JToggleButton[]{btnStateWaiting, btnStateActive, btnStateFinished,
btnTypeMatch, btnTypeTourneyConstructed, btnTypeTourneyLimited,
btnFormatBlock, btnFormatStandard, btnFormatModern, btnFormatLegacy, btnFormatVintage, btnFormatPremodern, btnFormatCommander, btnFormatTinyLeader, btnFormatLimited, btnFormatOther,
btnSkillBeginner, btnSkillCasual, btnSkillSerious, btnRated, btnUnrated, btnOpen, btnPassword};
btnSkillBeginner, btnSkillCasual, btnSkillSerious, btnRated, btnUnrated, btnOpen, btnPassword, btnFormatOathbreaker, btnFormatPioneer};
JComponent[] components = new JComponent[]{chatPanelMain, jSplitPane1, jScrollPaneTablesActive, jScrollPaneTablesFinished, jPanelTop, jPanelTables};
for (JComponent component : components) {
@ -802,6 +802,9 @@ public class TablesPanel extends javax.swing.JPanel {
if (btnFormatModern.isSelected()) {
formatFilterList.add(RowFilter.regexFilter("^Constructed - Modern", TablesTableModel.COLUMN_DECK_TYPE));
}
if (btnFormatPioneer.isSelected()) {
formatFilterList.add(RowFilter.regexFilter("^Constructed - Pioneer", TablesTableModel.COLUMN_DECK_TYPE));
}
if (btnFormatLegacy.isSelected()) {
formatFilterList.add(RowFilter.regexFilter("^Constructed - Legacy", TablesTableModel.COLUMN_DECK_TYPE));
}
@ -812,11 +815,14 @@ public class TablesPanel extends javax.swing.JPanel {
formatFilterList.add(RowFilter.regexFilter("^Constructed - Premodern", TablesTableModel.COLUMN_DECK_TYPE));
}
if (btnFormatCommander.isSelected()) {
formatFilterList.add(RowFilter.regexFilter("^Commander|^Duel Commander|^Penny Dreadful Commander|^Freeform Commander|^MTGO 1v1 Commander|^Duel Brawl|^Brawl", TablesTableModel.COLUMN_DECK_TYPE));
formatFilterList.add(RowFilter.regexFilter("^Commander|^Duel Commander|^Centurion Commander|^Penny Dreadful Commander|^Freeform Commander|^MTGO 1v1 Commander|^Duel Brawl|^Brawl", TablesTableModel.COLUMN_DECK_TYPE));
}
if (btnFormatTinyLeader.isSelected()) {
formatFilterList.add(RowFilter.regexFilter("^Tiny", TablesTableModel.COLUMN_DECK_TYPE));
}
if (btnFormatOathbreaker.isSelected()) {
formatFilterList.add(RowFilter.regexFilter("^Oathbreaker", TablesTableModel.COLUMN_DECK_TYPE));
}
if (btnFormatLimited.isSelected()) {
formatFilterList.add(RowFilter.regexFilter("^Limited", TablesTableModel.COLUMN_DECK_TYPE));
}
@ -962,11 +968,13 @@ public class TablesPanel extends javax.swing.JPanel {
btnFormatBlock = new javax.swing.JToggleButton();
btnFormatStandard = new javax.swing.JToggleButton();
btnFormatModern = new javax.swing.JToggleButton();
btnFormatPioneer = new javax.swing.JToggleButton();
btnFormatLegacy = new javax.swing.JToggleButton();
btnFormatVintage = new javax.swing.JToggleButton();
btnFormatPremodern = new javax.swing.JToggleButton();
jSeparator3 = new javax.swing.JToolBar.Separator();
btnFormatCommander = new javax.swing.JToggleButton();
btnFormatOathbreaker = new javax.swing.JToggleButton();
btnFormatTinyLeader = new javax.swing.JToggleButton();
jSeparator2 = new javax.swing.JToolBar.Separator();
btnFormatLimited = new javax.swing.JToggleButton();
@ -1180,7 +1188,7 @@ public class TablesPanel extends javax.swing.JPanel {
btnRated.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
btnRated.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnRatedbtnFilterActionPerformed(evt);
btnFilterActionPerformed(evt);
}
});
filterBar1.add(btnRated);
@ -1197,7 +1205,7 @@ public class TablesPanel extends javax.swing.JPanel {
btnUnrated.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
btnUnrated.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnUnratedbtnFilterActionPerformed(evt);
btnFilterActionPerformed(evt);
}
});
filterBar1.add(btnUnrated);
@ -1252,6 +1260,20 @@ public class TablesPanel extends javax.swing.JPanel {
});
filterBar2.add(btnFormatModern);
btnFormatPioneer.setSelected(true);
btnFormatPioneer.setText("Pioneer");
btnFormatPioneer.setToolTipText("Pioneer format.");
btnFormatPioneer.setFocusPainted(false);
btnFormatPioneer.setFocusable(false);
btnFormatPioneer.setRequestFocusEnabled(false);
btnFormatPioneer.setVerifyInputWhenFocusTarget(false);
btnFormatPioneer.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnFilterActionPerformed(evt);
}
});
filterBar2.add(btnFormatPioneer);
btnFormatLegacy.setSelected(true);
btnFormatLegacy.setText("Legacy");
btnFormatLegacy.setToolTipText("Legacy format.");
@ -1279,7 +1301,7 @@ public class TablesPanel extends javax.swing.JPanel {
btnFormatVintage.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
btnFormatVintage.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnFormatVintageActionPerformed(evt);
btnFilterActionPerformed(evt);
}
});
filterBar2.add(btnFormatVintage);
@ -1295,7 +1317,7 @@ public class TablesPanel extends javax.swing.JPanel {
btnFormatPremodern.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
btnFormatPremodern.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnFormatPremodernActionPerformed(evt);
btnFilterActionPerformed(evt);
}
});
filterBar2.add(btnFormatPremodern);
@ -1317,6 +1339,22 @@ public class TablesPanel extends javax.swing.JPanel {
});
filterBar2.add(btnFormatCommander);
btnFormatOathbreaker.setSelected(true);
btnFormatOathbreaker.setText("Oathbreaker");
btnFormatOathbreaker.setToolTipText("Oathbreaker format.");
btnFormatOathbreaker.setFocusPainted(false);
btnFormatOathbreaker.setFocusable(false);
btnFormatOathbreaker.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
btnFormatOathbreaker.setRequestFocusEnabled(false);
btnFormatOathbreaker.setVerifyInputWhenFocusTarget(false);
btnFormatOathbreaker.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
btnFormatOathbreaker.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnFilterActionPerformed(evt);
}
});
filterBar2.add(btnFormatOathbreaker);
btnFormatTinyLeader.setSelected(true);
btnFormatTinyLeader.setText("Tiny Leader");
btnFormatTinyLeader.setToolTipText("Tiny Leader format.");
@ -1432,7 +1470,7 @@ public class TablesPanel extends javax.swing.JPanel {
.addGroup(jPanelTopLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(btnQuickStartDuel)
.addComponent(btnQuickStartCommander))
.addContainerGap(734, Short.MAX_VALUE))
.addContainerGap(667, Short.MAX_VALUE))
);
jPanelTopLayout.setVerticalGroup(
jPanelTopLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -1631,22 +1669,6 @@ public class TablesPanel extends javax.swing.JPanel {
this.startUpdateTasks(true);
}//GEN-LAST:event_btnStateFinishedActionPerformed
private void btnRatedbtnFilterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRatedbtnFilterActionPerformed
setTableFilter();
}//GEN-LAST:event_btnRatedbtnFilterActionPerformed
private void btnUnratedbtnFilterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnUnratedbtnFilterActionPerformed
setTableFilter();
}//GEN-LAST:event_btnUnratedbtnFilterActionPerformed
private void btnFormatPremodernActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnFormatPremodernActionPerformed
setTableFilter();
}//GEN-LAST:event_btnFormatPremodernActionPerformed
private void btnFormatVintageActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnFormatVintageActionPerformed
setTableFilter();
}//GEN-LAST:event_btnFormatVintageActionPerformed
private void buttonWhatsNewActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonWhatsNewActionPerformed
MageFrame.getInstance().showWhatsNewDialog(true);
}//GEN-LAST:event_buttonWhatsNewActionPerformed
@ -1666,6 +1688,8 @@ public class TablesPanel extends javax.swing.JPanel {
private javax.swing.JToggleButton btnFormatLegacy;
private javax.swing.JToggleButton btnFormatLimited;
private javax.swing.JToggleButton btnFormatModern;
private javax.swing.JToggleButton btnFormatPioneer;
private javax.swing.JToggleButton btnFormatOathbreaker;
private javax.swing.JToggleButton btnFormatOther;
private javax.swing.JToggleButton btnFormatPremodern;
private javax.swing.JToggleButton btnFormatStandard;

View file

@ -38,6 +38,8 @@ public class CombatDialog extends MageDialog {
JPanel contentPane = new JPanel() {
private static final long serialVersionUID = -8283955788355547309L;
@Override
public void paintComponent(Graphics g) {
g.setColor(new Color(50, 50, 50, 100));
g.fillRect(0, 0, getWidth(), getHeight());

View file

@ -1,15 +1,14 @@
package mage.client.util;
import java.util.List;
import java.util.Map;
import mage.cards.Card;
import mage.cards.repository.CardInfo;
import mage.cards.repository.CardRepository;
import mage.view.*;
import java.util.List;
import java.util.Map;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public final class CardsViewUtil {
@ -21,7 +20,7 @@ public final class CardsViewUtil {
CardInfo cardInfo = CardRepository.instance.findCard(simple.getExpansionSetCode(), simple.getCardNumber());
Card card = cardInfo != null ? cardInfo.getMockCard() : null;
if (card != null) {
cards.put(simple.getId(), new CardView(card, simple.getId()));
cards.put(simple.getId(), new CardView(card, simple));
}
}
@ -40,7 +39,7 @@ public final class CardsViewUtil {
loadedCards.put(key, card);
}
if (card != null) {
cards.put(simple.getId(), new CardView(card, simple.getId()));
cards.put(simple.getId(), new CardView(card, simple));
}
}
@ -55,8 +54,7 @@ public final class CardsViewUtil {
CardView cardView = new CardView((EmblemView) commandObject);
cards.put(commandObject.getId(), cardView);
} else if (commandObject instanceof PlaneView) {
CardView cardView = null;
cardView = new CardView((PlaneView) commandObject);
CardView cardView = new CardView((PlaneView) commandObject);
cards.put(commandObject.getId(), cardView);
} else if (commandObject instanceof CommanderView) {
cards.put(commandObject.getId(), (CommanderView) commandObject);

View file

@ -119,6 +119,8 @@ public class MusicPlayer {
}
@Override
public void run() {
try {
TimeUnit.MILLISECONDS.sleep(100);
@ -146,6 +148,8 @@ public class MusicPlayer {
final byte[] tempBuffer = new byte[320];
@Override
public void run() {
try {
sourceDataLine.flush();

View file

@ -32,6 +32,8 @@ public class Arrow extends JPanel {
setOpacity(0.6f);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
float ex = endX - startX;

View file

@ -112,10 +112,11 @@ public class ArrowBuilder {
* Removes all arrows from the screen.
*/
public void removeAllArrows(UUID gameId) {
synchronized (map) {
if (map.containsKey(gameId)) {
Map<Type, List<Arrow>> innerMap = map.get(gameId);
JPanel p = getArrowsPanel(gameId);
synchronized (map) {
if (p != null && p.getComponentCount() > 0) {
p.removeAll();
p.revalidate();

View file

@ -194,7 +194,7 @@ public class CountryComboBox extends JComboBox {
{"Portugal", "pt"},
{"Puerto Rico", "pr"},
{"Qatar", "qa"},
{"Réunion", "re"},
{"Reunion", "re"},
{"Romania", "ro"},
{"Russian Federation", "ru"},
{"Rwanda", "rw"},
@ -228,7 +228,7 @@ public class CountryComboBox extends JComboBox {
{"Sweden", "se"},
{"Switzerland", "ch"},
{"Syrian Arab Republic", "sy"},
{"Taiwan, Province of China", "tw"},
{"Taiwan", "tw"},
{"Tajikistan", "tj"},
{"Tanzania, United Republic of", "tz"},
{"Thailand", "th"},

View file

@ -20,6 +20,7 @@ public final class ConstructedFormats {
public static final String STANDARD = "- Standard";
public static final String EXTENDED = "- Extended";
public static final String FRONTIER = "- Frontier";
public static final String PIONEER = "- Pioneer";
public static final String MODERN = "- Modern";
public static final String VINTAGE_LEGACY = "- Vintage / Legacy";
public static final String JOKE = "- Joke Sets";
@ -27,9 +28,10 @@ public final class ConstructedFormats {
public static final Standard STANDARD_CARDS = new Standard();
// Attention -Month is 0 Based so Feb = 1 for example. //
private static final Date extendedDate = new GregorianCalendar(2009, 7, 20).getTime();
private static final Date frontierDate = new GregorianCalendar(2014, 6, 17).getTime();
private static final Date modernDate = new GregorianCalendar(2003, 6, 20).getTime();
private static final Date extendedDate = new GregorianCalendar(2009, Calendar.AUGUST, 20).getTime();
private static final Date frontierDate = new GregorianCalendar(2014, Calendar.JULY, 17).getTime();
private static final Date pioneerDate = new GregorianCalendar(2012, Calendar.NOVEMBER, 5).getTime();
private static final Date modernDate = new GregorianCalendar(2003, Calendar.JULY, 20).getTime();
// for all sets just return empty list
private static final List<String> all = new ArrayList<>();
@ -82,6 +84,7 @@ public final class ConstructedFormats {
underlyingSetCodesPerFormat.put(STANDARD, new ArrayList<>());
underlyingSetCodesPerFormat.put(EXTENDED, new ArrayList<>());
underlyingSetCodesPerFormat.put(FRONTIER, new ArrayList<>());
underlyingSetCodesPerFormat.put(PIONEER, new ArrayList<>());
underlyingSetCodesPerFormat.put(MODERN, new ArrayList<>());
underlyingSetCodesPerFormat.put(VINTAGE_LEGACY, new ArrayList<>());
underlyingSetCodesPerFormat.put(JOKE, new ArrayList<>());
@ -134,6 +137,11 @@ public final class ConstructedFormats {
underlyingSetCodesPerFormat.get(FRONTIER).add(set.getCode());
}
// frontier
if (set.getType().isStandardLegal() && set.getReleaseDate().after(pioneerDate)) {
underlyingSetCodesPerFormat.get(PIONEER).add(set.getCode());
}
// modern
if (set.getType().isModernLegal() && set.getReleaseDate().after(modernDate)) {
underlyingSetCodesPerFormat.get(MODERN).add(set.getCode());
@ -251,6 +259,7 @@ public final class ConstructedFormats {
formats.add(0, JOKE);
formats.add(0, VINTAGE_LEGACY);
formats.add(0, MODERN);
formats.add(0, PIONEER);
formats.add(0, FRONTIER);
formats.add(0, EXTENDED);
formats.add(0, STANDARD);

View file

@ -0,0 +1,19 @@
package org.mage.plugins.card.dl;
import java.net.Proxy;
/**
* @author JayDi85
*/
public interface DownloadServiceInfo {
Proxy getProxy();
boolean isNeedCancel();
void incErrorCount();
void updateMessage(String text);
void showDownloadControls(boolean needToShow);
}

View file

@ -1,10 +1,12 @@
package org.mage.plugins.card.dl.sources;
import org.apache.log4j.Logger;
import org.mage.plugins.card.dl.DownloadServiceInfo;
import org.mage.plugins.card.images.CardDownloadData;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
/**
* @author spjspj
@ -57,6 +59,11 @@ public enum AltMtgOnlTokensImageSource implements CardImageSource {
return null;
}
@Override
public boolean prepareDownloadList(DownloadServiceInfo downloadServiceInfo, List<CardDownloadData> downloadList) {
return true;
}
@Override
public CardImageUrls generateCardUrl(CardDownloadData card) throws Exception {
return null;

View file

@ -1,9 +1,11 @@
package org.mage.plugins.card.dl.sources;
import mage.client.util.CardLanguage;
import org.mage.plugins.card.dl.DownloadServiceInfo;
import org.mage.plugins.card.images.CardDownloadData;
import java.util.ArrayList;
import java.util.List;
/**
* @author North, JayDi85
@ -14,6 +16,8 @@ public interface CardImageSource {
CardImageUrls generateTokenUrl(CardDownloadData card) throws Exception;
boolean prepareDownloadList(DownloadServiceInfo downloadServiceInfo, List<CardDownloadData> downloadList);
String getNextHttpImageUrl();
String getFileForHttpImage(String httpImageUrl);

View file

@ -1,6 +1,7 @@
package org.mage.plugins.card.dl.sources;
import mage.cards.Sets;
import org.mage.plugins.card.dl.DownloadServiceInfo;
import org.mage.plugins.card.images.CardDownloadData;
import javax.swing.*;
@ -8,10 +9,8 @@ import java.awt.*;
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.List;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -73,6 +72,11 @@ public enum CopyPasteImageSource implements CardImageSource {
return null;
}
@Override
public boolean prepareDownloadList(DownloadServiceInfo downloadServiceInfo, List<CardDownloadData> downloadList) {
return true;
}
@Override
public CardImageUrls generateCardUrl(CardDownloadData card) throws Exception {
if (singleLinks == null) {
@ -141,7 +145,7 @@ public enum CopyPasteImageSource implements CardImageSource {
final CopyPasteImageSourceDialog dialog = new CopyPasteImageSourceDialog();
dialog.pack();
int count = 0;
if (viewMissingCards && missingCards.size() > 0 && singleLinks.size() == 0) {
if (viewMissingCards && !missingCards.isEmpty() && singleLinks.isEmpty()) {
viewMissingCards = false;
String displayMissingCardsStr = "Up to the first 20 cards are:\n";
String missingCardsStr = "";
@ -224,7 +228,7 @@ public enum CopyPasteImageSource implements CardImageSource {
public ArrayList<String> getSupportedSets() {
setupLinks();
ArrayList<String> supportedSetsCopy = new ArrayList<>();
if (supportedSets.size() == 0) {
if (supportedSets.isEmpty()) {
for (String setCode : Sets.getInstance().keySet()) {
supportedSets.add(setCode);
}

View file

@ -6,12 +6,14 @@ import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import mage.cards.ExpansionSet;
import mage.cards.Sets;
import mage.client.constants.Constants;
import mage.constants.Rarity;
import org.apache.log4j.Logger;
import org.mage.plugins.card.dl.DownloadJob;
import static org.mage.plugins.card.dl.DownloadJob.fromURL;
import static org.mage.plugins.card.dl.DownloadJob.toFile;
import static org.mage.plugins.card.utils.CardImageUtils.getImagesDir;
@ -27,12 +29,12 @@ public class GathererSets implements Iterable<DownloadJob> {
boolean haveRare;
boolean haveMyth;
private CheckResult(String ACode, ExpansionSet ASet, boolean AHaveCommon, boolean AHaveUncommon, boolean AHhaveRare, boolean AHaveMyth) {
private CheckResult(String ACode, ExpansionSet ASet, boolean AHaveCommon, boolean AHaveUncommon, boolean AHaveRare, boolean AHaveMyth) {
code = ACode;
set = ASet;
haveCommon = AHaveCommon;
haveUncommon = AHaveUncommon;
haveRare = AHhaveRare;
haveRare = AHaveRare;
haveMyth = AHaveMyth;
}
}
@ -63,10 +65,11 @@ public class GathererSets implements Iterable<DownloadJob> {
"POR", "P02", "PTK",
"ARC", "DD3EVG",
"W16", "W17",
//"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", "V11", "A25", "UST", "IMA", "DD2", "EVG", "DDC", "DDE", "DDD", "8EB", "9EB", "CHR" // ok
// "APAC" -- gatherer do not have that set, scryfall has PALP
// "ARENA" -- is't many set with different codes, not one
// "ATH" -- has cards from many sets, symbol does not exist on gatherer
// "CLASH", "CP", "DPA", "EURO", "FNMP", "GPX", "GRC", "GUR", "H17", "JR", "MBP", "MGDC", "MLP", "MPRP", "PTC", "SUS", "SWS", "WMCQ", // need to fix
"H09", "PD2", "PD3", "UNH", "CM1", "V11", "A25", "UST", "IMA", "DD2", "EVG", "DDC", "DDE", "DDD", "8EB", "9EB", "CHR", "G18", "DD3GVL", "S00", "S99", "UGL" // ok
// current testing
};
@ -84,7 +87,7 @@ public class GathererSets implements Iterable<DownloadJob> {
"THS", "BNG", "JOU",
"CNS", "CN2",
"VMA", "TPR",
"KTK", "FRF", "DTK",
"KTK", "FRF", "UGIN", "DTK",
"BFZ", "OGW",
"SOI", "EMN",
"KLD", "AER",
@ -92,14 +95,19 @@ public class GathererSets implements Iterable<DownloadJob> {
"XLN", "C17",
"RIX", "DOM", "M19",
"E01", "CM2", "E02",
"GS1", "BBD", "C18"
"GS1", "BBD", "C18",
"GNT", "UMA", "GRN",
"RNA", "WAR", "MH1",
"M20"
// "HHO", "ANA" -- do not exist on gatherer
};
private static final String[] symbolsOnlyMyth = {
"DRB", "V09", "V12", "V13", "V14", "V15", "V16", "EXP"
"DRB", "V09", "V10", "V12", "V13", "V14", "V15", "V16", "V17", "EXP", "MEDM"
// "HTR" does not exist
};
private static final String[] symbolsOnlySpecial = {
"MPS"
"MPS", "MPS-AKH"
};
private static final HashMap<String, String> codeReplacements = new HashMap<>();
@ -116,8 +124,10 @@ public class GathererSets implements Iterable<DownloadJob> {
codeReplacements.put("ARN", "AN");
codeReplacements.put("ATQ", "AQ");
codeReplacements.put("CMA", "CM1");
codeReplacements.put("CHR", "CH");
codeReplacements.put("DD3DVD", "DD3_DVD");
codeReplacements.put("DD3EVG", "DD3_EVG");
codeReplacements.put("DD3GVL", "DD3_GVL");
codeReplacements.put("DD3JVC", "DD3_JVC");
codeReplacements.put("DRK", "DK");
codeReplacements.put("EXO", "EX");
@ -128,7 +138,9 @@ public class GathererSets implements Iterable<DownloadJob> {
codeReplacements.put("LEA", "1E");
codeReplacements.put("LEB", "2E");
codeReplacements.put("LEG", "LE");
codeReplacements.put("MEDM", "MPS_WAR");
codeReplacements.put("MPS", "MPS_KLD");
codeReplacements.put("MPS-AKH", "MPS_AKH");
codeReplacements.put("MIR", "MI");
codeReplacements.put("MMQ", "MM");
codeReplacements.put("NEM", "NE");
@ -138,16 +150,19 @@ public class GathererSets implements Iterable<DownloadJob> {
codeReplacements.put("POR", "PO");
codeReplacements.put("P02", "P2");
codeReplacements.put("PTK", "PK");
codeReplacements.put("S00", "P4");
codeReplacements.put("S99", "P3");
codeReplacements.put("STH", "ST");
codeReplacements.put("TMP", "TE");
codeReplacements.put("UDS", "CG");
codeReplacements.put("UGIN", "FRF_UGIN");
codeReplacements.put("UGL", "UG");
codeReplacements.put("ULG", "GU");
codeReplacements.put("USG", "UZ");
codeReplacements.put("VIS", "VI");
codeReplacements.put("WTH", "WL");
codeReplacements.put("8EB", "8ED"); // inner xmage set for 8th edition
codeReplacements.put("9EB", "8ED"); // inner xmage set for 9th edition
codeReplacements.put("CHR", "CH");
}
public GathererSets() {
@ -223,16 +238,16 @@ public class GathererSets implements Iterable<DownloadJob> {
// 2. missing rarity icon:
// WARNING, need too much time (60+ secs), only for debug mode
///*
if ((set.getCardsByRarity(Rarity.COMMON).size() > 0) && !res.haveCommon) {
if (!set.getCardsByRarity(Rarity.COMMON).isEmpty() && !res.haveCommon) {
logger.error(String.format("Symbols: set have common cards, but don't download icon: %s (%s)", set.getCode(), set.getName()));
}
if ((set.getCardsByRarity(Rarity.UNCOMMON).size() > 0) && !res.haveUncommon) {
if (!set.getCardsByRarity(Rarity.UNCOMMON).isEmpty() && !res.haveUncommon) {
logger.error(String.format("Symbols: set have uncommon cards, but don't download icon: %s (%s)", set.getCode(), set.getName()));
}
if ((set.getCardsByRarity(Rarity.RARE).size() > 0) && !res.haveRare) {
if (!set.getCardsByRarity(Rarity.RARE).isEmpty() && !res.haveRare) {
logger.error(String.format("Symbols: set have rare cards, but don't download icon: %s (%s)", set.getCode(), set.getName()));
}
if ((set.getCardsByRarity(Rarity.MYTHIC).size() > 0) && !res.haveMyth) {
if (!set.getCardsByRarity(Rarity.MYTHIC).isEmpty() && !res.haveMyth) {
logger.error(String.format("Symbols: set have mythic cards, but don't download icon: %s (%s)", set.getCode(), set.getName()));
}
//*/
@ -332,7 +347,7 @@ public class GathererSets implements Iterable<DownloadJob> {
if (codeReplacements.containsKey(set)) {
set = codeReplacements.get(set);
}
String url = "http://gatherer.wizards.com/Handlers/Image.ashx?type=symbol&set=" + set + "&size=small&rarity=" + urlRarity;
String url = "https://gatherer.wizards.com/Handlers/Image.ashx?type=symbol&set=" + set + "&size=small&rarity=" + urlRarity;
return new DownloadJob(set + '-' + rarity, fromURL(url), toFile(dst));
}
}

View file

@ -23,11 +23,11 @@ import static org.mage.plugins.card.utils.CardImageUtils.getImagesDir;
*/
public class GathererSymbols implements Iterable<DownloadJob> {
//TODO chaos and planeswalker symbol
//chaos: http://gatherer.wizards.com/Images/Symbols/chaos.gif
//chaos: https://gatherer.wizards.com/Images/Symbols/chaos.gif
private static File outDir;
private static final String urlFmt = "http://gatherer.wizards.com/handlers/image.ashx?size=%1$s&name=%2$s&type=symbol";
private static final String urlFmt = "https://gatherer.wizards.com/handlers/image.ashx?size=%1$s&name=%2$s&type=symbol";
private static final String[] sizes = {"small", "medium", "large"};

View file

@ -1,13 +1,11 @@
package org.mage.plugins.card.dl.sources;
import org.apache.log4j.Logger;
import org.mage.plugins.card.dl.DownloadServiceInfo;
import org.mage.plugins.card.images.CardDownloadData;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
@ -46,6 +44,11 @@ public enum GrabbagImageSource implements CardImageSource {
return null;
}
@Override
public boolean prepareDownloadList(DownloadServiceInfo downloadServiceInfo, List<CardDownloadData> downloadList) {
return true;
}
@Override
public CardImageUrls generateCardUrl(CardDownloadData card) throws Exception {
if (singleLinks == null) {
@ -290,7 +293,7 @@ public enum GrabbagImageSource implements CardImageSource {
singleLinks.put("SWS/Senator Bail Organa", "BRkUuYU.jpg");
singleLinks.put("SWS/Senator Lott Dod", "yYQtXZo.jpg");
singleLinks.put("SWS/Senator Onaconda Farr", "oPez77z.png");
singleLinks.put("SWS/Senator Padmé Amidala", "287deD9.jpg");
singleLinks.put("SWS/Senator Padme Amidala", "287deD9.jpg");
singleLinks.put("SWS/Senator Passel Argente", "51qpnaE.jpg");
singleLinks.put("SWS/Shaak Herd", "PtnZD0I.jpg");
singleLinks.put("SWS/Shadow Trooper", "09NAiGa.jpg");

View file

@ -1,5 +1,6 @@
package org.mage.plugins.card.dl.sources;
import org.mage.plugins.card.dl.DownloadServiceInfo;
import org.mage.plugins.card.images.CardDownloadData;
import java.net.URI;
@ -227,6 +228,11 @@ public enum MagidexImageSource implements CardImageSource {
return null;
}
@Override
public boolean prepareDownloadList(DownloadServiceInfo downloadServiceInfo, List<CardDownloadData> downloadList) {
return true;
}
@Override
public CardImageUrls generateCardUrl(CardDownloadData card) throws Exception {
String cardDownloadName = card.getDownloadName().toLowerCase(Locale.ENGLISH);

View file

@ -1,7 +1,9 @@
package org.mage.plugins.card.dl.sources;
import org.mage.plugins.card.dl.DownloadServiceInfo;
import org.mage.plugins.card.images.CardDownloadData;
import java.util.List;
import java.util.Locale;
/**
@ -28,6 +30,11 @@ public enum MtgImageSource implements CardImageSource {
return null;
}
@Override
public boolean prepareDownloadList(DownloadServiceInfo downloadServiceInfo, List<CardDownloadData> downloadList) {
return true;
}
@Override
public CardImageUrls generateCardUrl(CardDownloadData card) throws Exception {
String collectorId = card.getCollectorId();

View file

@ -1,10 +1,12 @@
package org.mage.plugins.card.dl.sources;
import org.apache.log4j.Logger;
import org.mage.plugins.card.dl.DownloadServiceInfo;
import org.mage.plugins.card.images.CardDownloadData;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
/**
* @author spjspj
@ -57,6 +59,11 @@ public enum MtgOnlTokensImageSource implements CardImageSource {
return null;
}
@Override
public boolean prepareDownloadList(DownloadServiceInfo downloadServiceInfo, List<CardDownloadData> downloadList) {
return true;
}
@Override
public CardImageUrls generateCardUrl(CardDownloadData card) throws Exception {
return null;

View file

@ -7,6 +7,7 @@ import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.mage.plugins.card.dl.DownloadServiceInfo;
import org.mage.plugins.card.images.CardDownloadData;
import java.io.BufferedReader;
@ -381,6 +382,11 @@ public enum MythicspoilerComSource implements CardImageSource {
return pageLinks;
}
@Override
public boolean prepareDownloadList(DownloadServiceInfo downloadServiceInfo, List<CardDownloadData> downloadList) {
return true;
}
@Override
public CardImageUrls generateCardUrl(CardDownloadData card) throws Exception {
String collectorId = card.getCollectorId();

View file

@ -1,12 +1,24 @@
package org.mage.plugins.card.dl.sources;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import mage.cards.ExpansionSet;
import mage.cards.Sets;
import mage.client.util.CardLanguage;
import org.apache.log4j.Logger;
import org.mage.plugins.card.dl.DownloadServiceInfo;
import org.mage.plugins.card.images.CardDownloadData;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.*;
/**
* @author JayDi85
@ -15,8 +27,11 @@ public enum ScryfallImageSource implements CardImageSource {
instance;
private static final Logger logger = Logger.getLogger(ScryfallImageSource.class);
private final Map<CardLanguage, String> languageAliases;
private CardLanguage currentLanguage = CardLanguage.ENGLISH; // working language
private Map<CardDownloadData, String> preparedUrls = new HashMap<>();
ScryfallImageSource() {
// LANGUAGES
@ -36,6 +51,11 @@ public enum ScryfallImageSource implements CardImageSource {
}
private CardImageUrls innerGenerateURL(CardDownloadData card, boolean isToken) {
String prepared = preparedUrls.getOrDefault(card, null);
if (prepared != null) {
return new CardImageUrls(prepared, null);
}
String defaultCode = CardLanguage.ENGLISH.getCode();
String localizedCode = languageAliases.getOrDefault(this.getCurrentLanguage(), defaultCode);
// loc example: https://api.scryfall.com/cards/xln/121/ru?format=image
@ -62,29 +82,40 @@ public enum ScryfallImageSource implements CardImageSource {
alternativeUrl = null;
}
// special card number like "103a" and "U123" already compatible
if (baseUrl == null && card.isCollectorIdWithStr()) {
// WARNING, after 2018 it's not compatible and some new sets have GUID files instead card numbers
// TODO: replace card number links to API calls (need test with lands, alternative images and double faces), replace not working images by direct links
// art variation cards
// ARN and POR use notation
// PLS uses notation
if (baseUrl == null && card.getUsesVariousArt() && card.getSet().matches("ARN|POR|PLS")) {
String scryfallCollectorId = card.getCollectorIdAsInt().toString();
if (card.getCollectorId().startsWith("U") || card.getCollectorIdAsInt() == -1) {
// fix for Ultimate Box Topper (PUMA) and Mythic Edition (MED) -- need to use API
// ignored and go to API call at the end
} else {
baseUrl = "https://img.scryfall.com/cards/large/" + localizedCode + "/" + formatSetName(card.getSet(), isToken) + "/"
+ card.getCollectorId() + ".jpg";
alternativeUrl = "https://img.scryfall.com/cards/large/" + defaultCode + "/" + formatSetName(card.getSet(), isToken) + "/"
+ card.getCollectorId() + ".jpg";
if (card.getCollectorId().endsWith("b")) {
if (card.getSet().matches("ARN|POR")) {
scryfallCollectorId += "";
} else if (card.getSet().matches("PLS")) {
scryfallCollectorId += "";
}
}
// 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 (baseUrl == null && card.isTwoFacedCard()) {
baseUrl = "https://img.scryfall.com/cards/large/" + localizedCode + "/" + formatSetName(card.getSet(), isToken) + "/"
+ card.getCollectorId() + (card.isSecondSide() ? "b" : "a") + ".jpg";
alternativeUrl = "https://img.scryfall.com/cards/large/" + defaultCode + "/" + formatSetName(card.getSet(), isToken) + "/"
+ card.getCollectorId() + (card.isSecondSide() ? "b" : "a") + ".jpg";
try {
scryfallCollectorId = URLEncoder.encode(scryfallCollectorId, "utf-8");
} catch (UnsupportedEncodingException e) {
// URL failed to encode, this will cause download to miss in certain environments
}
baseUrl = "https://api.scryfall.com/cards/" + formatSetName(card.getSet(), isToken) + "/"
+ scryfallCollectorId + "/" + localizedCode + "?format=image";
alternativeUrl = "https://api.scryfall.com/cards/" + formatSetName(card.getSet(), isToken) + "/"
+ scryfallCollectorId + "/" + defaultCode + "?format=image";
}
// double faced card
// the front face can be downloaded normally
// the back face is prepared beforehand
if (baseUrl == null && card.isTwoFacedCard() && !card.isSecondSide()) {
baseUrl = "https://api.scryfall.com/cards/" + formatSetName(card.getSet(), isToken) + "/"
+ card.getCollectorIdAsInt() + "/" + localizedCode + "?format=image";
alternativeUrl = "https://api.scryfall.com/cards/" + formatSetName(card.getSet(), isToken) + "/"
+ card.getCollectorIdAsInt() + "/" + defaultCode + "?format=image";
}
// basic cards by api call (redirect to img link)
@ -99,6 +130,120 @@ public enum ScryfallImageSource implements CardImageSource {
return new CardImageUrls(baseUrl, alternativeUrl);
}
private String getFaceImageUrl(Proxy proxy, CardDownloadData card, boolean isToken, String localizationCode) throws Exception {
// connect to Scryfall API
final URL cardUrl = new URL("https://api.scryfall.com/cards/" + formatSetName(card.getSet(), isToken) + "/"
+ (card.getCollectorIdAsInt() % 1000) + "/" + localizationCode);
URLConnection request = proxy == null ? cardUrl.openConnection() : cardUrl.openConnection(proxy);
request.connect();
// parse the response and return the image URI from the correct card face
JsonParser jp = new JsonParser();
JsonElement root = jp.parse(new InputStreamReader((InputStream) request.getContent()));
JsonObject jsonCard = root.getAsJsonObject();
if (!jsonCard.has("card_faces")) {
throw new Exception("Couldn't find card_faces in Card JSON.");
}
JsonArray jsonCardFaces = jsonCard.getAsJsonArray("card_faces");
JsonObject jsonCardFace = jsonCardFaces.get(card.isSecondSide() ? 1 : 0).getAsJsonObject();
JsonObject jsonImageUris = jsonCardFace.getAsJsonObject("image_uris");
return jsonImageUris.get("large").getAsString();
}
@Override
public boolean prepareDownloadList(DownloadServiceInfo downloadServiceInfo, List<CardDownloadData> downloadList) {
// prepare download list example (
Proxy proxy = downloadServiceInfo.getProxy();
preparedUrls.clear();
final List<ExpansionSet.SetCardInfo> sixthEditionCards = Sets.findSet("6ED").getSetCardInfo();
for (CardDownloadData card : downloadList) {
// need cancel
if (downloadServiceInfo.isNeedCancel()) {
return false;
}
// prepare the back face URL
if (card.isTwoFacedCard() && card.isSecondSide()) {
final String defaultCode = CardLanguage.ENGLISH.getCode();
final String localizedCode = languageAliases.getOrDefault(this.getCurrentLanguage(), defaultCode);
String url = null;
try {
url = getFaceImageUrl(proxy, card, card.isToken(), localizedCode);
} catch (Exception e) {
logger.warn("Failed to prepare image URL for " + card.getName() + " (" + card.getSet() + ") #" + card.getCollectorId());
downloadServiceInfo.incErrorCount();
continue;
}
preparedUrls.put(card, url);
}
// if a S00 card is in 6ED, it's actually a 6ED card
if (card.getSet().equals("S00") && sixthEditionCards.stream().anyMatch(sixthEditionCard -> sixthEditionCard.getName().equals(card.getName()))) {
// we have direct links for the lands because there are multiple search results
if (card.getUsesVariousArt()) { // lands are the only defined multiple art cards in S00 in XMage
continue;
}
String url = null;
try {
url = searchCard(proxy, "6ED", card.getName());
} catch (Exception e) {
logger.warn("Failed to prepare image URL for " + card.getName() + " (" + card.getSet() + ") #" + card.getCollectorId());
downloadServiceInfo.incErrorCount();
continue;
}
preparedUrls.put(card, url);
}
// if an E01 card number is above 106, it's actually an AKH card
if (card.getSet().equals("E01") && card.getCollectorIdAsInt() > 106) {
String url = null;
try {
url = searchCard(proxy, "AKH", card.getName());
} catch (Exception e) {
logger.warn("Failed to prepare image URL for " + card.getName() + " (" + card.getSet() + ") #" + card.getCollectorId());
downloadServiceInfo.incErrorCount();
continue;
}
preparedUrls.put(card, url);
}
// inc error count to stop on too many errors
// downloadServiceInfo.incErrorCount();
}
return true;
}
private String searchCard(Proxy proxy, String set, String name) throws Exception {
final URL searchUrl = new URL("https://api.scryfall.com/cards/search?q=s:" + URLEncoder.encode(set + " " + name, "UTF-8"));
URLConnection request = proxy == null ? searchUrl.openConnection() : searchUrl.openConnection(proxy);
request.connect();
// parse the response and return the image URI from the correct card face
JsonParser jp = new JsonParser();
JsonElement root = jp.parse(new InputStreamReader((InputStream) request.getContent()));
JsonObject searchResult = root.getAsJsonObject();
if (searchResult.get("total_cards").getAsInt() != 1) {
throw new Exception("Card not found in Scryfall.");
}
JsonObject jsonCard = searchResult.getAsJsonArray("data").get(0).getAsJsonObject();
JsonObject jsonImageUris = jsonCard.getAsJsonObject("image_uris");
return jsonImageUris.get("large").getAsString();
}
@Override
public CardImageUrls generateCardUrl(CardDownloadData card) throws Exception {
return innerGenerateURL(card, false);

View file

@ -23,9 +23,9 @@ public class ScryfallImageSupportCards {
put("EURO", "pelp").
put("GPX", "pgpx").
put("MED", "me1").
put("MEDM", "med").build();
put("MEDM", "med").
put("CELD", "eld"). // scryfall moved ELD and CELD cards in one set, but card numbers are different
build();
private static final Set<String> supportedSets = new ArraySet<String>() {
{
@ -239,12 +239,25 @@ public class ScryfallImageSupportCards {
add("GK2");
add("MH1");
add("WAR");
add("M20");
add("C19");
add("ELD");
add("CELD");
add("THB");
//
add("EURO");
add("GPX");
add("ATH");
add("GRC");
add("ANA");
add("G18");
add("PM20");
add("PS19");
add("SS1");
add("SS2");
add("PPP1");
add("PF19");
add("MPS-AKH");
}
};
@ -266,104 +279,109 @@ public class ScryfallImageSupportCards {
// Duels of the Planeswalkers Promos -- xmage uses one set (DPAP), but scryfall store it by years
// 2009 - https://scryfall.com/sets/pdtp
put("DPAP/Garruk Wildspeaker", "https://img.scryfall.com/cards/large/en/pdtp/1.jpg");
put("DPAP/Garruk Wildspeaker", "https://api.scryfall.com/cards/pdtp/1/en?format=image");
// 2010 - https://scryfall.com/sets/pdp10
put("DPAP/Liliana Vess", "https://img.scryfall.com/cards/large/en/pdp10/1.jpg");
put("DPAP/Nissa Revane", "https://img.scryfall.com/cards/large/en/pdp10/2.jpg");
put("DPAP/Liliana Vess", "https://api.scryfall.com/cards/pdp10/1/en?format=image");
put("DPAP/Nissa Revane", "https://api.scryfall.com/cards/pdp10/2/en?format=image");
// 2011 - https://scryfall.com/sets/pdp11
put("DPAP/Frost Titan", "https://img.scryfall.com/cards/large/en/pdp11/1.jpg");
put("DPAP/Grave Titan", "https://img.scryfall.com/cards/large/en/pdp11/2.jpg");
put("DPAP/Inferno Titan", "https://img.scryfall.com/cards/large/en/pdp11/3.jpg");
put("DPAP/Frost Titan", "https://api.scryfall.com/cards/pdp11/1/en?format=image");
put("DPAP/Grave Titan", "https://api.scryfall.com/cards/pdp11/2/en?format=image");
put("DPAP/Inferno Titan", "https://api.scryfall.com/cards/pdp11/3/en?format=image");
// 2012 - https://scryfall.com/sets/pdp12
put("DPAP/Primordial Hydra", "https://img.scryfall.com/cards/large/en/pdp12/1.jpg");
put("DPAP/Serra Avatar", "https://img.scryfall.com/cards/large/en/pdp12/2.jpg");
put("DPAP/Vampire Nocturnus", "https://img.scryfall.com/cards/large/en/pdp12/3.jpg");
put("DPAP/Primordial Hydra", "https://api.scryfall.com/cards/pdp12/1/en?format=image");
put("DPAP/Serra Avatar", "https://api.scryfall.com/cards/pdp12/2/en?format=image");
put("DPAP/Vampire Nocturnus", "https://api.scryfall.com/cards/pdp12/3/en?format=image");
// 2013 - https://scryfall.com/sets/pdp13
put("DPAP/Bonescythe Sliver", "https://img.scryfall.com/cards/large/en/pdp13/1.jpg");
put("DPAP/Ogre Battledriver", "https://img.scryfall.com/cards/large/en/pdp13/2.jpg");
put("DPAP/Scavenging Ooze", "https://img.scryfall.com/cards/large/en/pdp13/3.jpg");
put("DPAP/Bonescythe Sliver", "https://api.scryfall.com/cards/pdp13/1/en?format=image");
put("DPAP/Ogre Battledriver", "https://api.scryfall.com/cards/pdp13/2/en?format=image");
put("DPAP/Scavenging Ooze", "https://api.scryfall.com/cards/pdp13/3/en?format=image");
// 2014 - https://scryfall.com/sets/pdp14
put("DPAP/Soul of Ravnica", "https://img.scryfall.com/cards/large/en/pdp14/1.jpg");
put("DPAP/Soul of Zendikar", "https://img.scryfall.com/cards/large/en/pdp14/2.jpg");
put("DPAP/Soul of Ravnica", "https://api.scryfall.com/cards/pdp14/1/en?format=image");
put("DPAP/Soul of Zendikar", "https://api.scryfall.com/cards/pdp14/2/en?format=image");
// Gateway Promos -- xmage uses one set (GRC), but scryfall store it by years
// 2006 - https://scryfall.com/sets/pgtw
put("GRC/Fiery Temper", "https://img.scryfall.com/cards/large/en/pgtw/3.jpg");
put("GRC/Icatian Javelineers", "https://img.scryfall.com/cards/large/en/pgtw/2.jpg");
put("GRC/Wood Elves", "https://img.scryfall.com/cards/large/en/pgtw/1.jpg");
put("GRC/Fiery Temper", "https://api.scryfall.com/cards/pgtw/3/en?format=image");
put("GRC/Icatian Javelineers", "https://api.scryfall.com/cards/pgtw/2/en?format=image");
put("GRC/Wood Elves", "https://api.scryfall.com/cards/pgtw/1/en?format=image");
// 2007 - https://scryfall.com/sets/pg07
put("GRC/Boomerang", "https://img.scryfall.com/cards/large/en/pg07/4.jpg");
put("GRC/Calciderm", "https://img.scryfall.com/cards/large/en/pg07/5.jpg");
put("GRC/Dauntless Dourbark", "https://img.scryfall.com/cards/large/en/pg07/12.jpg");
put("GRC/Llanowar Elves", "https://img.scryfall.com/cards/large/en/pg07/9.jpg");
put("GRC/Mind Stone", "https://img.scryfall.com/cards/large/en/pg07/11.jpg");
put("GRC/Mogg Fanatic", "https://img.scryfall.com/cards/large/en/pg07/10.jpg");
put("GRC/Reckless Wurm", "https://img.scryfall.com/cards/large/en/pg07/6.jpg");
put("GRC/Yixlid Jailer", "https://img.scryfall.com/cards/large/en/pg07/7.jpg");
put("GRC/Zoetic Cavern", "https://img.scryfall.com/cards/large/en/pg07/8.jpg");
put("GRC/Boomerang", "https://api.scryfall.com/cards/pg07/4/en?format=image");
put("GRC/Calciderm", "https://api.scryfall.com/cards/pg07/5/en?format=image");
put("GRC/Dauntless Dourbark", "https://api.scryfall.com/cards/pg07/12/en?format=image");
put("GRC/Llanowar Elves", "https://api.scryfall.com/cards/pg07/9/en?format=image");
put("GRC/Mind Stone", "https://api.scryfall.com/cards/pg07/11/en?format=image");
put("GRC/Mogg Fanatic", "https://api.scryfall.com/cards/pg07/10/en?format=image");
put("GRC/Reckless Wurm", "https://api.scryfall.com/cards/pg07/6/en?format=image");
put("GRC/Yixlid Jailer", "https://api.scryfall.com/cards/pg07/7/en?format=image");
put("GRC/Zoetic Cavern", "https://api.scryfall.com/cards/pg07/8/en?format=image");
// 2008a - https://scryfall.com/sets/pg08
put("GRC/Boggart Ram-Gang", "https://img.scryfall.com/cards/large/en/pg08/17.jpg");
put("GRC/Cenn's Tactician", "https://img.scryfall.com/cards/large/en/pg08/14.jpg");
put("GRC/Duergar Hedge-Mage", "https://img.scryfall.com/cards/large/en/pg08/19.jpg");
put("GRC/Gravedigger", "https://img.scryfall.com/cards/large/en/pg08/16.jpg");
put("GRC/Lava Axe", "https://img.scryfall.com/cards/large/en/pg08/13.jpg");
put("GRC/Oona's Blackguard", "https://img.scryfall.com/cards/large/en/pg08/15.jpg");
put("GRC/Selkie Hedge-Mage", "https://img.scryfall.com/cards/large/en/pg08/20.jpg");
put("GRC/Wilt-Leaf Cavaliers", "https://img.scryfall.com/cards/large/en/pg08/18.jpg");
put("GRC/Boggart Ram-Gang", "https://api.scryfall.com/cards/pg08/17/en?format=image");
put("GRC/Cenn's Tactician", "https://api.scryfall.com/cards/pg08/14/en?format=image");
put("GRC/Duergar Hedge-Mage", "https://api.scryfall.com/cards/pg08/19/en?format=image");
put("GRC/Gravedigger", "https://api.scryfall.com/cards/pg08/16/en?format=image");
put("GRC/Lava Axe", "https://api.scryfall.com/cards/pg08/13/en?format=image");
put("GRC/Oona's Blackguard", "https://api.scryfall.com/cards/pg08/15/en?format=image");
put("GRC/Selkie Hedge-Mage", "https://api.scryfall.com/cards/pg08/20/en?format=image");
put("GRC/Wilt-Leaf Cavaliers", "https://api.scryfall.com/cards/pg08/18/en?format=image");
// Wizards Play Network Promos -- xmage uses one set (GRC), but scryfall store it by years
// 2008b - https://scryfall.com/sets/pwpn
put("GRC/Sprouting Thrinax", "https://img.scryfall.com/cards/large/en/pwpn/21.jpg");
put("GRC/Woolly Thoctar", "https://img.scryfall.com/cards/large/en/pwpn/22.jpg");
put("GRC/Sprouting Thrinax", "https://api.scryfall.com/cards/pwpn/21/en?format=image");
put("GRC/Woolly Thoctar", "https://api.scryfall.com/cards/pwpn/22/en?format=image");
// 2009 - https://scryfall.com/sets/pwp09
put("GRC/Hellspark Elemental", "https://img.scryfall.com/cards/large/en/pwp09/25.jpg");
put("GRC/Kor Duelist", "https://img.scryfall.com/cards/large/en/pwp09/32.jpg");
put("GRC/Marisi's Twinclaws", "https://img.scryfall.com/cards/large/en/pwp09/26.jpg");
put("GRC/Mind Control", "https://img.scryfall.com/cards/large/en/pwp09/30.jpg");
put("GRC/Path to Exile", "https://img.scryfall.com/cards/large/en/pwp09/24.jpg");
put("GRC/Rise from the Grave", "https://img.scryfall.com/cards/large/en/pwp09/31.jpg");
put("GRC/Slave of Bolas", "https://img.scryfall.com/cards/large/en/pwp09/27.jpg");
put("GRC/Vampire Nighthawk", "https://img.scryfall.com/cards/large/en/pwp09/33.jpg");
put("GRC/Hellspark Elemental", "https://api.scryfall.com/cards/pwp09/25/en?format=image");
put("GRC/Kor Duelist", "https://api.scryfall.com/cards/pwp09/32/en?format=image");
put("GRC/Marisi's Twinclaws", "https://api.scryfall.com/cards/pwp09/26/en?format=image");
put("GRC/Mind Control", "https://api.scryfall.com/cards/pwp09/30/en?format=image");
put("GRC/Path to Exile", "https://api.scryfall.com/cards/pwp09/24/en?format=image");
put("GRC/Rise from the Grave", "https://api.scryfall.com/cards/pwp09/31/en?format=image");
put("GRC/Slave of Bolas", "https://api.scryfall.com/cards/pwp09/27/en?format=image");
put("GRC/Vampire Nighthawk", "https://api.scryfall.com/cards/pwp09/33/en?format=image");
// 2010 - https://scryfall.com/sets/pwp10
put("GRC/Kor Firewalker", "https://img.scryfall.com/cards/large/en/pwp10/36.jpg");
put("GRC/Leatherback Baloth", "https://img.scryfall.com/cards/large/en/pwp10/37.jpg");
put("GRC/Syphon Mind", "https://img.scryfall.com/cards/large/en/pwp10/40.jpg");
put("GRC/Pathrazer of Ulamog", "https://img.scryfall.com/cards/large/en/pwp10/46.jpg");
put("GRC/Curse of Wizardry", "https://img.scryfall.com/cards/large/en/pwp10/47.jpg");
put("GRC/Fling/50", "https://img.scryfall.com/cards/large/en/pwp10/50.jpg"); // same card but different year
put("GRC/Sylvan Ranger/51", "https://img.scryfall.com/cards/large/en/pwp10/51.jpg"); // same card but different year
put("GRC/Plague Stinger", "https://img.scryfall.com/cards/large/en/pwp10/59.jpg");
put("GRC/Golem's Heart", "https://img.scryfall.com/cards/large/en/pwp10/60.jpg");
put("GRC/Skinrender", "https://img.scryfall.com/cards/large/en/pwp10/63.jpg");
put("GRC/Kor Firewalker", "https://api.scryfall.com/cards/pwp10/36/en?format=image");
put("GRC/Leatherback Baloth", "https://api.scryfall.com/cards/pwp10/37/en?format=image");
put("GRC/Syphon Mind", "https://api.scryfall.com/cards/pwp10/40/en?format=image");
put("GRC/Pathrazer of Ulamog", "https://api.scryfall.com/cards/pwp10/46/en?format=image");
put("GRC/Curse of Wizardry", "https://api.scryfall.com/cards/pwp10/47/en?format=image");
put("GRC/Fling/50", "https://api.scryfall.com/cards/pwp10/50/en?format=image"); // same card but different year
put("GRC/Sylvan Ranger/51", "https://api.scryfall.com/cards/pwp10/51/en?format=image"); // same card but different year
put("GRC/Plague Stinger", "https://api.scryfall.com/cards/pwp10/59/en?format=image");
put("GRC/Golem's Heart", "https://api.scryfall.com/cards/pwp10/60/en?format=image");
put("GRC/Skinrender", "https://api.scryfall.com/cards/pwp10/63/en?format=image");
// 2011 - https://scryfall.com/sets/pwp11
put("GRC/Auramancer", "https://img.scryfall.com/cards/large/en/pwp11/77.jpg");
put("GRC/Bloodcrazed Neonate", "https://img.scryfall.com/cards/large/en/pwp11/83.jpg");
put("GRC/Boneyard Wurm", "https://img.scryfall.com/cards/large/en/pwp11/84.jpg");
put("GRC/Circle of Flame", "https://img.scryfall.com/cards/large/en/pwp11/78.jpg");
put("GRC/Curse of the Bloody Tome", "https://img.scryfall.com/cards/large/en/pwp11/80.jpg");
put("GRC/Fling/69", "https://img.scryfall.com/cards/large/en/pwp11/69.jpg"); // same card but different year
put("GRC/Master's Call", "https://img.scryfall.com/cards/large/en/pwp11/64.jpg");
put("GRC/Maul Splicer", "https://img.scryfall.com/cards/large/en/pwp11/72.jpg");
put("GRC/Plague Myr", "https://img.scryfall.com/cards/large/en/pwp11/65.jpg");
put("GRC/Shrine of Burning Rage", "https://img.scryfall.com/cards/large/en/pwp11/73.jpg");
put("GRC/Signal Pest", "https://img.scryfall.com/cards/large/en/pwp11/66.jpg");
put("GRC/Sylvan Ranger/70", "https://img.scryfall.com/cards/large/en/pwp11/70.jpg"); // same card but different year
put("GRC/Tormented Soul", "https://img.scryfall.com/cards/large/en/pwp11/76.jpg");
put("GRC/Vault Skirge", "https://img.scryfall.com/cards/large/en/pwp11/71.jpg");
put("GRC/Auramancer", "https://api.scryfall.com/cards/pwp11/77/en?format=image");
put("GRC/Bloodcrazed Neonate", "https://api.scryfall.com/cards/pwp11/83/en?format=image");
put("GRC/Boneyard Wurm", "https://api.scryfall.com/cards/pwp11/84/en?format=image");
put("GRC/Circle of Flame", "https://api.scryfall.com/cards/pwp11/78/en?format=image");
put("GRC/Curse of the Bloody Tome", "https://api.scryfall.com/cards/pwp11/80/en?format=image");
put("GRC/Fling/69", "https://api.scryfall.com/cards/pwp11/69/en?format=image"); // same card but different year
put("GRC/Master's Call", "https://api.scryfall.com/cards/pwp11/64/en?format=image");
put("GRC/Maul Splicer", "https://api.scryfall.com/cards/pwp11/72/en?format=image");
put("GRC/Plague Myr", "https://api.scryfall.com/cards/pwp11/65/en?format=image");
put("GRC/Shrine of Burning Rage", "https://api.scryfall.com/cards/pwp11/73/en?format=image");
put("GRC/Signal Pest", "https://api.scryfall.com/cards/pwp11/66/en?format=image");
put("GRC/Sylvan Ranger/70", "https://api.scryfall.com/cards/pwp11/70/en?format=image"); // same card but different year
put("GRC/Tormented Soul", "https://api.scryfall.com/cards/pwp11/76/en?format=image");
put("GRC/Vault Skirge", "https://api.scryfall.com/cards/pwp11/71/en?format=image");
// 2012 - https://scryfall.com/sets/pwp12
put("GRC/Curse of Thirst", "https://img.scryfall.com/cards/large/en/pwp12/81.jpg");
put("GRC/Gather the Townsfolk", "https://img.scryfall.com/cards/large/en/pwp12/79.jpg");
put("GRC/Nearheath Stalker", "https://img.scryfall.com/cards/large/en/pwp12/82.jpg");
put("GRC/Curse of Thirst", "https://api.scryfall.com/cards/pwp12/81/en?format=image");
put("GRC/Gather the Townsfolk", "https://api.scryfall.com/cards/pwp12/79/en?format=image");
put("GRC/Nearheath Stalker", "https://api.scryfall.com/cards/pwp12/82/en?format=image");
// TODO: remove Grand Prix fix after scryfall fix image's link (that's link must be work: https://img.scryfall.com/cards/large/en/pgpx/2016b.jpg )
put("GPX/Sword of Feast and Famine", "https://img.scryfall.com/cards/large/en/pgpx/1%E2%98%85.jpg");
// TODO: remove after scryfall add lands to RNA (that's link must works: https://api.scryfall.com/cards/rna/262/en?format=image)
put("RNA/Plains", "https://api.scryfall.com/cards/grn/260/en?format=image");
put("RNA/Island", "https://api.scryfall.com/cards/grn/261/en?format=image");
put("RNA/Swamp", "https://api.scryfall.com/cards/grn/262/en?format=image");
put("RNA/Mountain", "https://api.scryfall.com/cards/grn/263/en?format=image");
put("RNA/Forest", "https://api.scryfall.com/cards/grn/264/en?format=image");
// Spined Wurm print in Starter 2000 is actually from Magazine Inserts
put("S00/Spined Wurm", "https://api.scryfall.com/cards/pmei/11/en?format=image");
// Most of the other S00 cards are from 6ED
// We'll download lands manually because we have multiple arts and XMage has totally different ID's
put("S00/Forest/49", "https://api.scryfall.com/cards/6ed/347/en?format=image");
put("S00/Forest/50", "https://api.scryfall.com/cards/6ed/348/en?format=image");
put("S00/Island/51", "https://api.scryfall.com/cards/6ed/335/en?format=image");
put("S00/Island/52", "https://api.scryfall.com/cards/6ed/336/en?format=image");
put("S00/Mountain/53", "https://api.scryfall.com/cards/6ed/343/en?format=image");
put("S00/Mountain/54", "https://api.scryfall.com/cards/6ed/344/en?format=image");
put("S00/Plains/55", "https://api.scryfall.com/cards/6ed/331/en?format=image");
put("S00/Plains/56", "https://api.scryfall.com/cards/6ed/332/en?format=image");
put("S00/Swamp/57", "https://api.scryfall.com/cards/6ed/339/en?format=image");
put("S00/Swamp/58", "https://api.scryfall.com/cards/6ed/340/en?format=image");
}
};

View file

@ -49,6 +49,143 @@ public class ScryfallImageSupportTokens {
put("RNA/Treasure", "https://api.scryfall.com/cards/trna/12/en?format=image");
put("RNA/Zombie", "https://api.scryfall.com/cards/trna/3/en?format=image");
//GRN
put("GRN/Angel", "https://api.scryfall.com/cards/tgrn/1/en?format=image");
put("GRN/Bird Illusion", "https://api.scryfall.com/cards/tgrn/3/en?format=image");
put("GRN/Elf Knight", "https://api.scryfall.com/cards/tgrn/6/en?format=image");
put("GRN/Goblin", "https://api.scryfall.com/cards/tgrn/4/en?format=image");
put("GRN/Insect", "https://api.scryfall.com/cards/tgrn/5/en?format=image");
put("GRN/Emblem Ral, Izzet Viceroy", "https://api.scryfall.com/cards/tgrn/7/en?format=image");
put("GRN/Soldier", "https://api.scryfall.com/cards/tgrn/2/en?format=image");
put("GRN/Emblem Vraska, Golgari Queen", "https://api.scryfall.com/cards/tgrn/8/en?format=image");
//DOM
put("DOM/Cleric", "https://api.scryfall.com/cards/tdom/4/en?format=image");
put("DOM/Construct", "https://api.scryfall.com/cards/tdom/14/en?format=image");
put("DOM/Demon", "https://api.scryfall.com/cards/tdom/7/en?format=image");
put("DOM/Elemental", "https://api.scryfall.com/cards/tdom/8/en?format=image");
put("DOM/Goblin", "https://api.scryfall.com/cards/tdom/9/en?format=image");
put("DOM/Emblem Jaya Ballard", "https://api.scryfall.com/cards/tdom/15/en?format=image");
put("DOM/Karox Bladewing", "https://api.scryfall.com/cards/tdom/10/en?format=image");
put("DOM/Knight/1", "https://api.scryfall.com/cards/tdom/1/en?format=image");
put("DOM/Knight/2", "https://api.scryfall.com/cards/tdom/2/en?format=image");
put("DOM/Nightmare Horror", "https://api.scryfall.com/cards/tdom/6/en?format=image");
put("DOM/Saproling/1", "https://api.scryfall.com/cards/tdom/11/en?format=image");
put("DOM/Saproling/2", "https://api.scryfall.com/cards/tdom/12/en?format=image");
put("DOM/Saproling/3", "https://api.scryfall.com/cards/tdom/13/en?format=image");
put("DOM/Soldier", "https://api.scryfall.com/cards/tdom/3/en?format=image");
put("DOM/Emblem Teferi, Hero of Dominaria", "https://api.scryfall.com/cards/tdom/16/en?format=image");
put("DOM/Zombie Knight", "https://api.scryfall.com/cards/tdom/5/en?format=image");
//XLN
put("XLN/Dinosaur", "https://api.scryfall.com/cards/txln/5/en?format=image");
put("XLN/Illusion", "https://api.scryfall.com/cards/txln/2/en?format=image");
put("XLN/Merfolk", "https://api.scryfall.com/cards/txln/3/en?format=image");
put("XLN/Pirate", "https://api.scryfall.com/cards/txln/4/en?format=image");
put("XLN/Plant", "https://api.scryfall.com/cards/txln/6/en?format=image");
put("XLN/Treasure/1", "https://api.scryfall.com/cards/txln/7/en?format=image");
put("XLN/Treasure/2", "https://api.scryfall.com/cards/txln/8/en?format=image");
put("XLN/Treasure/3", "https://api.scryfall.com/cards/txln/9/en?format=image");
put("XLN/Treasure/4", "https://api.scryfall.com/cards/txln/10/en?format=image");
put("XLN/Vampire", "https://api.scryfall.com/cards/txln/1/en?format=image");
//HOU
put("HOU/Horse", "https://api.scryfall.com/cards/thou/10/en?format=image");
put("HOU/Insect", "https://api.scryfall.com/cards/thou/12/en?format=image");
put("HOU/Snake", "https://api.scryfall.com/cards/thou/11/en?format=image");
//AKH
put("AKH/Beast", "https://api.scryfall.com/cards/takh/21/en?format=image");
put("AKH/Cat", "https://api.scryfall.com/cards/takh/16/en?format=image");
put("AKH/Drake", "https://api.scryfall.com/cards/takh/18/en?format=image");
put("AKH/Emblem Gideon", "https://api.scryfall.com/cards/takh/25/en?format=image");
put("AKH/Hippo", "https://api.scryfall.com/cards/takh/22/en?format=image");
put("AKH/Snake", "https://api.scryfall.com/cards/takh/23/en?format=image");
put("AKH/Warrior", "https://api.scryfall.com/cards/takh/17/en?format=image");
put("AKH/Wurm", "https://api.scryfall.com/cards/takh/24/en?format=image");
put("AKH/Zombie", "https://api.scryfall.com/cards/takh/20/en?format=image");
//AER
put("AER/Etherium Cell", "https://api.scryfall.com/cards/taer/3/en?format=image");
put("AER/Gremlin", "https://api.scryfall.com/cards/taer/1/en?format=image");
put("AER/Ragavan", "https://api.scryfall.com/cards/taer/2/en?format=image");
put("AER/Emblem Tezzeret the Schemer", "https://api.scryfall.com/cards/taer/4/en?format=image");
//KLD
put("KLD/Beast", "https://api.scryfall.com/cards/tkld/1/en?format=image");
put("KLD/Emblem Chandra", "https://api.scryfall.com/cards/tkld/10/en?format=image");
put("KLD/Construct/1", "https://api.scryfall.com/cards/tkld/2/en?format=image");
put("KLD/Construct/2", "https://api.scryfall.com/cards/tkld/3/en?format=image");
put("KLD/Emblem Dovin", "https://api.scryfall.com/cards/tkld/12/en?format=image");
put("KLD/Emblem Nissa", "https://api.scryfall.com/cards/tkld/11/en?format=image");
put("KLD/Servo/1", "https://api.scryfall.com/cards/tkld/4/en?format=image");
put("KLD/Servo/2", "https://api.scryfall.com/cards/tkld/5/en?format=image");
put("KLD/Servo/3", "https://api.scryfall.com/cards/tkld/6/en?format=image");
put("KLD/Thopter/1", "https://api.scryfall.com/cards/tkld/7/en?format=image");
put("KLD/Thopter/2", "https://api.scryfall.com/cards/tkld/8/en?format=image");
put("KLD/Thopter/3", "https://api.scryfall.com/cards/tkld/9/en?format=image");
//EMN
put("EMN/Eldrazi Horror", "https://api.scryfall.com/cards/temn/1/en?format=image");
put("EMN/Human", "https://api.scryfall.com/cards/temn/7/en?format=image");
put("EMN/Human Wizard", "https://api.scryfall.com/cards/temn/2/en?format=image");
put("EMN/Emblem Liliana", "https://api.scryfall.com/cards/temn/9/en?format=image");
put("EMN/Spider", "https://api.scryfall.com/cards/temn/8/en?format=image");
put("EMN/Emblem Tamiyo", "https://api.scryfall.com/cards/temn/10/en?format=image");
put("EMN/Zombie/1", "https://api.scryfall.com/cards/temn/3/en?format=image");
put("EMN/Zombie/2", "https://api.scryfall.com/cards/temn/4/en?format=image");
put("EMN/Zombie/3", "https://api.scryfall.com/cards/temn/5/en?format=image");
put("EMN/Zombie/4", "https://api.scryfall.com/cards/temn/6/en?format=image");
//SOI
put("SOI/Angel", "https://api.scryfall.com/cards/tsoi/1/en?format=image");
put("SOI/Emblem Arlinn", "https://api.scryfall.com/cards/tsoi/18/en?format=image");
put("SOI/Clue/1", "https://api.scryfall.com/cards/tsoi/11/en?format=image");
put("SOI/Clue/2", "https://api.scryfall.com/cards/tsoi/12/en?format=image");
put("SOI/Clue/3", "https://api.scryfall.com/cards/tsoi/13/en?format=image");
put("SOI/Clue/4", "https://api.scryfall.com/cards/tsoi/14/en?format=image");
put("SOI/Clue/5", "https://api.scryfall.com/cards/tsoi/15/en?format=image");
put("SOI/Clue/6", "https://api.scryfall.com/cards/tsoi/16/en?format=image");
put("SOI/Devil", "https://api.scryfall.com/cards/tsoi/6/en?format=image");
put("SOI/Human Cleric", "https://api.scryfall.com/cards/tsoi/10/en?format=image");
put("SOI/Human Soldier", "https://api.scryfall.com/cards/tsoi/2/en?format=image");
put("SOI/Insect", "https://api.scryfall.com/cards/tsoi/7/en?format=image");
put("SOI/Emblem Jace", "https://api.scryfall.com/cards/tsoi/17/en?format=image");
put("SOI/Ooze", "https://api.scryfall.com/cards/tsoi/8/en?format=image");
put("SOI/Spirit", "https://api.scryfall.com/cards/tsoi/3/en?format=image");
put("SOI/Vampire Knight", "https://api.scryfall.com/cards/tsoi/4/en?format=image");
put("SOI/Wolf", "https://api.scryfall.com/cards/tsoi/9/en?format=image");
put("SOI/Zombie", "https://api.scryfall.com/cards/tsoi/5/en?format=image");
//OGW
put("OGW/Angel", "https://api.scryfall.com/cards/togw/7/en?format=image");
put("OGW/Eldrazi Scion/1", "https://api.scryfall.com/cards/togw/1/en?format=image");
put("OGW/Eldrazi Scion/2", "https://api.scryfall.com/cards/togw/2/en?format=image");
put("OGW/Eldrazi Scion/3", "https://api.scryfall.com/cards/togw/3/en?format=image");
put("OGW/Eldrazi Scion/4", "https://api.scryfall.com/cards/togw/4/en?format=image");
put("OGW/Eldrazi Scion/5", "https://api.scryfall.com/cards/togw/5/en?format=image");
put("OGW/Eldrazi Scion/6", "https://api.scryfall.com/cards/togw/6/en?format=image");
put("OGW/Elemental/1", "https://api.scryfall.com/cards/togw/10/en?format=image");
put("OGW/Elemental/2", "https://api.scryfall.com/cards/togw/9/en?format=image");
put("OGW/Plant", "https://api.scryfall.com/cards/togw/11/en?format=image");
put("OGW/Zombie", "https://api.scryfall.com/cards/togw/8/en?format=image");
//BFZ
put("BFZ/Dragon", "https://api.scryfall.com/cards/tbfz/8/en?format=image");
put("BFZ/Eldrazi", "https://api.scryfall.com/cards/tbfz/1/en?format=image");
put("BFZ/Eldrazi Scion/1", "https://api.scryfall.com/cards/tbfz/2/en?format=image");
put("BFZ/Eldrazi Scion/2", "https://api.scryfall.com/cards/tbfz/3/en?format=image");
put("BFZ/Eldrazi Scion/3", "https://api.scryfall.com/cards/tbfz/4/en?format=image");
put("BFZ/Elemental/1", "https://api.scryfall.com/cards/tbfz/11/en?format=image");
put("BFZ/Elemental/2", "https://api.scryfall.com/cards/tbfz/9/en?format=image");
put("BFZ/Emblem Gideon", "https://api.scryfall.com/cards/tbfz/12/en?format=image");
put("BFZ/Emblem Kiora", "https://api.scryfall.com/cards/tbfz/14/en?format=image");
put("BFZ/Knight Ally", "https://api.scryfall.com/cards/tbfz/5/en?format=image");
put("BFZ/Kor Ally", "https://api.scryfall.com/cards/tbfz/6/en?format=image");
put("BFZ/Emblem Nixilis", "https://api.scryfall.com/cards/tbfz/13/en?format=image");
put("BFZ/Octopus", "https://api.scryfall.com/cards/tbfz/7/en?format=image");
put("BFZ/Plant", "https://api.scryfall.com/cards/tbfz/10/en?format=image");
// WAR
put("WAR/Angel", "https://api.scryfall.com/cards/twar/2/en?format=image");
put("WAR/Assassin", "https://api.scryfall.com/cards/twar/6/en?format=image");
@ -70,6 +207,133 @@ public class ScryfallImageSupportTokens {
put("WAR/Zombie Warrior", "https://api.scryfall.com/cards/twar/11/en?format=image");
put("WAR/Zombie", "https://api.scryfall.com/cards/twar/7/en?format=image");
// MH1
put("MH1/Angel", "https://api.scryfall.com/cards/tmh1/2/en?format=image");
put("MH1/Bear", "https://api.scryfall.com/cards/tmh1/11/en?format=image");
put("MH1/Bird", "https://api.scryfall.com/cards/tmh1/3/en?format=image");
put("MH1/Construct", "https://api.scryfall.com/cards/tmh1/17/en?format=image");
put("MH1/Elemental/1", "https://api.scryfall.com/cards/tmh1/8/en?format=image");
put("MH1/Elemental/2", "https://api.scryfall.com/cards/tmh1/9/en?format=image");
put("MH1/Elephant", "https://api.scryfall.com/cards/tmh1/12/en?format=image");
put("MH1/Goblin", "https://api.scryfall.com/cards/tmh1/10/en?format=image");
put("MH1/Golem", "https://api.scryfall.com/cards/tmh1/18/en?format=image");
put("MH1/Illusion", "https://api.scryfall.com/cards/tmh1/5/en?format=image");
put("MH1/Marit Lage", "https://api.scryfall.com/cards/tmh1/6/en?format=image");
put("MH1/Myr", "https://api.scryfall.com/cards/tmh1/19/en?format=image");
put("MH1/Rhino", "https://api.scryfall.com/cards/tmh1/13/en?format=image");
put("MH1/Emblem Serra the Benevolent", "https://api.scryfall.com/cards/tmh1/20/en?format=image");
put("MH1/Shapeshifter", "https://api.scryfall.com/cards/tmh1/1/en?format=image");
put("MH1/Soldier", "https://api.scryfall.com/cards/tmh1/4/en?format=image");
put("MH1/Spider", "https://api.scryfall.com/cards/tmh1/14/en?format=image");
put("MH1/Spirit", "https://api.scryfall.com/cards/tmh1/16/en?format=image");
put("MH1/Squirrel", "https://api.scryfall.com/cards/tmh1/15/en?format=image");
put("MH1/Emblem Wrenn and Six", "https://api.scryfall.com/cards/tmh1/21/en?format=image");
put("MH1/Zombie", "https://api.scryfall.com/cards/tmh1/7/en?format=image");
// M19
put("M19/Emblem Ajani, Adversary of Tyrants", "https://api.scryfall.com/cards/tm19/15/en?format=image");
put("M19/Angel", "https://api.scryfall.com/cards/tm19/1/en?format=image");
put("M19/Avatar", "https://api.scryfall.com/cards/tm19/2/en?format=image");
put("M19/Bat", "https://api.scryfall.com/cards/tm19/7/en?format=image");
put("M19/Beast", "https://api.scryfall.com/cards/tm19/12/en?format=image");
put("M19/Cat", "https://api.scryfall.com/cards/tm19/3/en?format=image");
put("M19/Dragon/1", "https://api.scryfall.com/cards/tm19/9/en?format=image");
put("M19/Dragon/2", "https://api.scryfall.com/cards/tm19/10/en?format=image");
put("M19/Elf Warrior", "https://api.scryfall.com/cards/tm19/13/en?format=image");
put("M19/Goblin", "https://api.scryfall.com/cards/tm19/11/en?format=image");
put("M19/Knight", "https://api.scryfall.com/cards/tm19/4/en?format=image");
put("M19/Ox", "https://api.scryfall.com/cards/tm19/5/en?format=image");
put("M19/Soldier", "https://api.scryfall.com/cards/tm19/6/en?format=image");
put("M19/Emblem Tezzeret, Artifice Master", "https://api.scryfall.com/cards/tm19/16/en?format=image");
put("M19/Thopter", "https://api.scryfall.com/cards/tm19/14/en?format=image");
put("M19/Emblem Vivien Reid", "https://api.scryfall.com/cards/tm19/17/en?format=image");
put("M19/Zombie", "https://api.scryfall.com/cards/tm19/8/en?format=image");
// M20
put("M20/Ajani's Pridemate", "https://api.scryfall.com/cards/tm20/1/en?format=image");
put("M20/Emblem Chandra, Awakened Inferno", "https://api.scryfall.com/cards/tm20/11/en?format=image");
put("M20/Demon", "https://api.scryfall.com/cards/tm20/5/en?format=image");
put("M20/Elemental Bird", "https://api.scryfall.com/cards/tm20/4/en?format=image");
put("M20/Elemental", "https://api.scryfall.com/cards/tm20/7/en?format=image");
put("M20/Golem", "https://api.scryfall.com/cards/tm20/9/en?format=image");
put("M20/Emblem Mu Yanling, Sky Dancer", "https://api.scryfall.com/cards/tm20/12/en?format=image");
put("M20/Soldier", "https://api.scryfall.com/cards/tm20/2/en?format=image");
put("M20/Spirit", "https://api.scryfall.com/cards/tm20/3/en?format=image");
put("M20/Treasure", "https://api.scryfall.com/cards/tm20/10/en?format=image");
put("M20/Wolf", "https://api.scryfall.com/cards/tm20/8/en?format=image");
put("M20/Zombie", "https://api.scryfall.com/cards/tm20/6/en?format=image");
// C18
put("C18/Angel", "https://api.scryfall.com/cards/tc18/3/en?format=image");
put("C18/Cat Warrior", "https://api.scryfall.com/cards/tc18/15/en?format=image");
put("C18/Cat", "https://api.scryfall.com/cards/tc18/5/en?format=image");
put("C18/Clue", "https://api.scryfall.com/cards/tc18/19/en?format=image");
put("C18/Construct/1", "https://api.scryfall.com/cards/tc18/20/en?format=image");
put("C18/Construct/2", "https://api.scryfall.com/cards/tc18/21/en?format=image");
put("C18/Dragon Egg", "https://api.scryfall.com/cards/tc18/10/en?format=image");
put("C18/Dragon", "https://api.scryfall.com/cards/tc18/11/en?format=image");
put("C18/Elemental", "https://api.scryfall.com/cards/tc18/16/en?format=image");
put("C18/Horror", "https://api.scryfall.com/cards/tc18/22/en?format=image");
put("C18/Manifest", "https://api.scryfall.com/cards/tc18/1/en?format=image");
put("C18/Mask", "https://api.scryfall.com/cards/tc18/4/en?format=image");
put("C18/Myr", "https://api.scryfall.com/cards/tc18/7/en?format=image");
put("C18/Plant", "https://api.scryfall.com/cards/tc18/17/en?format=image");
put("C18/Servo", "https://api.scryfall.com/cards/tc18/24/en?format=image");
put("C18/Survivor", "https://api.scryfall.com/cards/tc18/12/en?format=image");
put("C18/Thopter/1", "https://api.scryfall.com/cards/tc18/25/en?format=image");
put("C18/Thopter/2", "https://api.scryfall.com/cards/tc18/26/en?format=image");
put("C18/Thopter/3", "https://api.scryfall.com/cards/tc18/8/en?format=image");
put("C18/Worm", "https://api.scryfall.com/cards/tc18/18/en?format=image");
put("C18/Zombie", "https://api.scryfall.com/cards/tc18/9/en?format=image");
//C19
put("C19/Assassin", "https://api.scryfall.com/cards/tc19/9/en?format=image");
put("C19/Beast/1", "https://api.scryfall.com/cards/tc19/13/en?format=image");
put("C19/Beast/2", "https://api.scryfall.com/cards/tc19/14/en?format=image");
put("C19/Bird/1", "https://api.scryfall.com/cards/tc19/2/en?format=image");
put("C19/Bird/2", "https://api.scryfall.com/cards/tc19/1/en?format=image");
put("C19/Centaur", "https://api.scryfall.com/cards/tc19/15/en?format=image");
put("C19/Dragon", "https://api.scryfall.com/cards/tc19/12/en?format=image");
put("C19/Drake", "https://api.scryfall.com/cards/tc19/8/en?format=image");
put("C19/Egg", "https://api.scryfall.com/cards/tc19/16/en?format=image");
put("C19/Eldrazi", "https://api.scryfall.com/cards/tc19/26/en?format=image");
put("C19/Gargoyle", "https://api.scryfall.com/cards/tc19/22/en?format=image");
put("C19/Horror", "https://api.scryfall.com/cards/tc19/23/en?format=image");
put("C19/Human", "https://api.scryfall.com/cards/tc19/3/en?format=image");
put("C19/Emblem Ob Nixilis Reignited", "https://api.scryfall.com/cards/tc19/29/en?format=image");
put("C19/Pegasus", "https://api.scryfall.com/cards/tc19/4/en?format=image");
put("C19/Plant", "https://api.scryfall.com/cards/tc19/17/en?format=image");
put("C19/Rhino", "https://api.scryfall.com/cards/tc19/18/en?format=image");
put("C19/Saproling", "https://api.scryfall.com/cards/tc19/19/en?format=image");
put("C19/Sculpture", "https://api.scryfall.com/cards/tc19/24/en?format=image");
put("C19/Snake", "https://api.scryfall.com/cards/tc19/20/en?format=image");
put("C19/Spirit", "https://api.scryfall.com/cards/tc19/5/en?format=image");
put("C19/Treasure", "https://api.scryfall.com/cards/tc19/25/en?format=image");
put("C19/Wurm", "https://api.scryfall.com/cards/tc19/21/en?format=image");
put("C19/Zombie/1", "https://api.scryfall.com/cards/tc19/11/en?format=image");
put("C19/Zombie/2", "https://api.scryfall.com/cards/tc19/10/en?format=image");
// ELD
put("ELD/Bear", "https://api.scryfall.com/cards/teld/8/en?format=image");
put("ELD/Boar", "https://api.scryfall.com/cards/teld/9/en?format=image");
put("ELD/Dwarf", "https://api.scryfall.com/cards/teld/7/en?format=image");
put("ELD/Faerie", "https://api.scryfall.com/cards/teld/5/en?format=image");
put("ELD/Food/1", "https://api.scryfall.com/cards/teld/15/en?format=image");
put("ELD/Food/2", "https://api.scryfall.com/cards/teld/16/en?format=image");
put("ELD/Food/3", "https://api.scryfall.com/cards/teld/17/en?format=image");
put("ELD/Food/4", "https://api.scryfall.com/cards/teld/18/en?format=image");
put("ELD/Emblem Garruk, Cursed Huntsman", "https://api.scryfall.com/cards/teld/19/en?format=image");
put("ELD/Giant", "https://api.scryfall.com/cards/teld/10/en?format=image");
put("ELD/Goat", "https://api.scryfall.com/cards/teld/1/en?format=image");
put("ELD/Human Cleric", "https://api.scryfall.com/cards/teld/11/en?format=image");
put("ELD/Human Rogue", "https://api.scryfall.com/cards/teld/12/en?format=image");
put("ELD/Human Warrior", "https://api.scryfall.com/cards/teld/13/en?format=image");
put("ELD/Human", "https://api.scryfall.com/cards/teld/2/en?format=image");
put("ELD/Knight", "https://api.scryfall.com/cards/teld/3/en?format=image");
put("ELD/Mouse", "https://api.scryfall.com/cards/teld/4/en?format=image");
put("ELD/Rat", "https://api.scryfall.com/cards/teld/6/en?format=image");
put("ELD/Wolf", "https://api.scryfall.com/cards/teld/14/en?format=image");
// generate supported sets
supportedSets.clear();
for (String cardName : this.keySet()) {

View file

@ -2,6 +2,7 @@ package org.mage.plugins.card.dl.sources;
import mage.constants.SubType;
import org.apache.log4j.Logger;
import org.mage.plugins.card.dl.DownloadServiceInfo;
import org.mage.plugins.card.images.CardDownloadData;
import org.mage.plugins.card.images.DownloadPicturesService;
import org.mage.plugins.card.utils.CardImageUtils;
@ -50,6 +51,11 @@ public enum TokensMtgImageSource implements CardImageSource {
return null;
}
@Override
public boolean prepareDownloadList(DownloadServiceInfo downloadServiceInfo, List<CardDownloadData> downloadList) {
return true;
}
@Override
public CardImageUrls generateCardUrl(CardDownloadData card) throws Exception {
return null;
@ -180,7 +186,7 @@ public enum TokensMtgImageSource implements CardImageSource {
private HashMap<String, List<TokenData>> getTokensData() throws IOException {
synchronized (tokensDataSync) {
if (tokensData == null) {
DownloadPicturesService.getInstance().updateAndViewMessage("Find tokens data...");
DownloadPicturesService.getInstance().updateMessage("Find tokens data...");
tokensData = new HashMap<>();
// get tokens data from resource file
@ -231,10 +237,11 @@ public enum TokensMtgImageSource implements CardImageSource {
}
}
}
DownloadPicturesService.getInstance().updateAndViewMessage("");
DownloadPicturesService.getInstance().updateMessage("");
DownloadPicturesService.getInstance().showDownloadControls(true);
} catch (Exception ex) {
logger.warn("Failed to get tokens description from tokens.mtg.onl", ex);
DownloadPicturesService.getInstance().updateAndViewMessage(ex.getMessage());
DownloadPicturesService.getInstance().updateMessage(ex.getMessage());
}
}
}

View file

@ -9,6 +9,7 @@ import org.apache.log4j.Logger;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.mage.plugins.card.dl.DownloadServiceInfo;
import org.mage.plugins.card.images.CardDownloadData;
import org.mage.plugins.card.utils.CardImageUtils;
@ -451,6 +452,11 @@ public enum WizardCardsImageSource implements CardImageSource {
return null;
}
@Override
public boolean prepareDownloadList(DownloadServiceInfo downloadServiceInfo, List<CardDownloadData> downloadList) {
return true;
}
@Override
public CardImageUrls generateCardUrl(CardDownloadData card) throws Exception {
String collectorId = card.getCollectorId();
@ -495,8 +501,8 @@ public enum WizardCardsImageSource implements CardImageSource {
}
}
}
if (link != null && !link.startsWith("http://")) {
link = "http://gatherer.wizards.com" + link;
if (link != null && !link.startsWith("https://")) {
link = "https://gatherer.wizards.com" + link;
}
if (link != null) {
@ -522,7 +528,7 @@ public enum WizardCardsImageSource implements CardImageSource {
int firstMultiverseIdLastPage = 0;
Pages:
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";
String searchUrl = "https://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 = CardImageUtils.downloadHtmlDocument(searchUrl);
Elements cardsImages = doc.select("img[src^=../../Handlers/]");
@ -582,7 +588,7 @@ public enum WizardCardsImageSource implements CardImageSource {
criteria.setCodes(cardSet);
List<CardInfo> cards = CardRepository.instance.findCards(criteria);
String urlLandDocument = "http://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=" + multiverseId;
String urlLandDocument = "https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=" + multiverseId;
Document landDoc = CardImageUtils.downloadHtmlDocument(urlLandDocument);
Elements variations = landDoc.select("a.variationlink");
if (!variations.isEmpty()) {
@ -629,7 +635,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;
String cardLanguagesUrl = "https://gatherer.wizards.com/Pages/Card/Languages.aspx?multiverseid=" + englishMultiverseId;
Document cardLanguagesDoc = CardImageUtils.downloadHtmlDocument(cardLanguagesUrl);
Elements languageTableRows = cardLanguagesDoc.select("tr.cardItem");
HashMap<String, Integer> localizedIds = new HashMap<>();

View file

@ -16,6 +16,7 @@ import net.java.truevfs.access.TFileOutputStream;
import net.java.truevfs.access.TVFS;
import net.java.truevfs.kernel.spec.FsSyncException;
import org.apache.log4j.Logger;
import org.mage.plugins.card.dl.DownloadServiceInfo;
import org.mage.plugins.card.dl.sources.*;
import org.mage.plugins.card.utils.CardImageUtils;
@ -37,7 +38,7 @@ import static org.mage.plugins.card.utils.CardImageUtils.getImagesDir;
/**
* @author JayDi85
*/
public class DownloadPicturesService extends DefaultBoundedRangeModel implements Runnable {
public class DownloadPicturesService extends DefaultBoundedRangeModel implements DownloadServiceInfo, Runnable {
// don't forget to remove new sets from ignore.urls to download (properties file in resources)
private static DownloadPicturesService instance;
@ -65,7 +66,7 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
private static CardImageSource selectedSource;
private final Object sync = new Object();
private Proxy p = Proxy.NO_PROXY;
private Proxy proxy = Proxy.NO_PROXY;
enum DownloadSources {
WIZARDS("1. wizards.com - low quality CARDS, multi-language, slow download", WizardCardsImageSource.instance),
@ -118,7 +119,7 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
instance.setNeedCancel(true);
}
private boolean getNeedCancel() {
public boolean isNeedCancel() {
return this.needCancel || (this.errorCount > MAX_ERRORS_COUNT_BEFORE_CANCEL);
}
@ -126,8 +127,12 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
this.needCancel = needCancel;
}
private void incErrorCount() {
public void incErrorCount() {
this.errorCount = this.errorCount + 1;
if (this.errorCount == MAX_ERRORS_COUNT_BEFORE_CANCEL + 1) {
logger.warn("Too many errors (> " + MAX_ERRORS_COUNT_BEFORE_CANCEL + ") in images download");
}
}
private void resetErrorCount() {
@ -196,23 +201,24 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
}
public void findMissingCards() {
updateAndViewMessage("Loading...");
updateMessage("Loading...");
this.cardsAll.clear();
this.cardsMissing.clear();
this.cardsDownloadQueue.clear();
updateAndViewMessage("Loading cards list...");
updateMessage("Loading cards list...");
this.cardsAll = Collections.synchronizedList(CardRepository.instance.findCards(new CardCriteria()));
updateAndViewMessage("Finding missing images...");
updateMessage("Finding missing images...");
this.cardsMissing = prepareMissingCards(this.cardsAll, uiDialog.getRedownloadCheckbox().isSelected());
updateAndViewMessage("Finding available sets from selected source...");
updateMessage("Finding available sets from selected source...");
this.uiDialog.getSetsCombo().setModel(new DefaultComboBoxModel<>(getSetsForCurrentImageSource()));
reloadCardsToDownload(this.uiDialog.getSetsCombo().getSelectedItem().toString());
this.uiDialog.showDownloadControls(true);
updateAndViewMessage("");
updateMessage("");
showDownloadControls(true);
}
private void reloadLanguagesForSelectedSource() {
@ -237,13 +243,13 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
}
}
public void updateAndViewMessage(String text) {
public void updateMessage(String text) {
this.uiDialog.setGlobalInfo(text);
// auto-size on empty message (on complete)
if (text.isEmpty()) {
this.uiDialog.showDownloadControls(true);
}
public void showDownloadControls(boolean needToShow) {
// auto-size form on show
this.uiDialog.showDownloadControls(needToShow);
}
private String getSetNameWithYear(ExpansionSet exp) {
@ -433,7 +439,7 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
throw new IllegalStateException("Second side card can't have empty name.");
}
CardInfo secondSideCard = CardRepository.instance.findCard(card.getSecondSideName());
CardInfo secondSideCard = CardRepository.instance.findCardWPreferredSet(card.getSecondSideName(), card.getSetCode(), false);
if (secondSideCard == null) {
throw new IllegalStateException("Can''t find second side card in database: " + card.getSecondSideName());
}
@ -541,9 +547,11 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
CardDownloadData card = new CardDownloadData(params[3], set, "0", false, type, "", "", true, fileName);
card.setTokenClassName(tokenClassName);
list.add(card);
} else {
logger.error("wrong line format in tokens file: " + line);
}
} else {
logger.error("wrong format for image urls: " + line);
logger.error("wrong line data in tokens file: " + line);
}
}
line = reader.readLine();
@ -569,6 +577,7 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
@Override
public void run() {
this.cardIndex = 0;
this.resetErrorCount();
File base = new File(getImagesDir());
if (!base.exists()) {
@ -587,7 +596,7 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
break;
case NONE:
default:
p = Proxy.NO_PROXY;
proxy = Proxy.NO_PROXY;
break;
}
@ -595,21 +604,22 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
try {
String address = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_PROXY_ADDRESS, "");
Integer port = Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_PROXY_PORT, "80"));
p = new Proxy(type, new InetSocketAddress(address, port));
proxy = new Proxy(type, new InetSocketAddress(address, port));
} catch (Exception ex) {
throw new RuntimeException("Gui_DownloadPicturesService : error 1 - " + ex);
}
}
if (p != null) {
update(0, cardsDownloadQueue.size());
if (proxy != null) {
logger.info("Started download of " + cardsDownloadQueue.size() + " images"
+ " from source: " + selectedSource.getSourceName()
+ ", language: " + selectedSource.getCurrentLanguage().getCode());
uiDialog.getProgressBar().setString("Preparing download list...");
if (selectedSource.prepareDownloadList(this, cardsDownloadQueue)) {
update(0, cardsDownloadQueue.size());
int numberOfThreads = Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_THREADS, "10"));
ExecutorService executor = Executors.newFixedThreadPool(numberOfThreads);
for (int i = 0; i < cardsDownloadQueue.size() && !this.getNeedCancel(); i++) {
for (int i = 0; i < cardsDownloadQueue.size() && !this.isNeedCancel(); i++) {
try {
CardDownloadData card = cardsDownloadQueue.get(i);
@ -659,6 +669,7 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
}
}
}
}
try {
TVFS.umount();
@ -671,6 +682,7 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
// stop
reloadCardsToDownload(uiDialog.getSetsCombo().getSelectedItem().toString());
enableDialogButtons();
// reset images cache
ImageCache.clearCache();
@ -707,7 +719,7 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
@Override
public void run() {
if (DownloadPicturesService.getInstance().getNeedCancel()) {
if (DownloadPicturesService.getInstance().isNeedCancel()) {
synchronized (sync) {
update(cardIndex + 1, count);
}
@ -791,14 +803,14 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
URL url = new URL(currentUrl);
// on download cancel need to stop
if (DownloadPicturesService.getInstance().getNeedCancel()) {
if (DownloadPicturesService.getInstance().isNeedCancel()) {
return;
}
// download
selectedSource.doPause(url.getPath());
httpConn = url.openConnection(p);
httpConn = url.openConnection(proxy);
if (httpConn != null) {
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");
@ -838,7 +850,7 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
}
// can save result
if (isDownloadOK & httpConn != null) {
if (isDownloadOK && httpConn != null) {
// save data to temp
try (InputStream in = new BufferedInputStream(httpConn.getInputStream());
OutputStream tfileout = new TFileOutputStream(fileTempImage);
@ -847,7 +859,7 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
int len;
while ((len = in.read(buf)) != -1) {
// user cancelled
if (DownloadPicturesService.getInstance().getNeedCancel()) {
if (DownloadPicturesService.getInstance().isNeedCancel()) {
// stop download, save current state and exit
TFile archive = destFile.getTopLevelArchive();
///* not need to unmout/close - it's auto action
@ -934,14 +946,21 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
// try download again
}
this.uiDialog.getRedownloadCheckbox().setSelected(false);
uiDialog.enableActionControls(true);
uiDialog.getStartButton().setEnabled(true);
enableDialogButtons();
}
}
private static final long serialVersionUID = 1L;
private void enableDialogButtons() {
uiDialog.getRedownloadCheckbox().setSelected(false); // reset re-download button after finished
uiDialog.enableActionControls(true);
uiDialog.getStartButton().setEnabled(true);
}
public Proxy getProxy() {
return proxy;
}
}
class LoadMissingCardDataNew implements Runnable {

View file

@ -54,6 +54,7 @@
|Generate|EMBLEM!:C14|Emblem Nixilis|||ObNixilisOfTheBlackOathEmblem|
|Generate|EMBLEM!:C14|Emblem Teferi|||TeferiTemporalArchmageEmblem|
|Generate|EMBLEM!:C16|Emblem Daretti|||DarettiScrapSavantEmblem|
|Generate|EMBLEM:C19|Ob Nixilis Reignited||Emblem Nixilis|ObNixilisReignitedEmblem|
|Generate|EMBLEM!:CNS|Emblem Dack Fayden||Emblem Dack|DackFaydenEmblem|
|Generate|EMBLEM!:DTK|Emblem Narset|||NarsetTranscendentEmblem|
|Generate|EMBLEM!:EMA|Emblem Dack Fayden||Emblem Dack|DackFaydenEmblem|
@ -62,7 +63,6 @@
|Generate|EMBLEM!:KLD|Emblem Chandra|||ChandraTorchOfDefianceEmblem|
|Generate|EMBLEM!:KLD|Emblem Dovin|||DovinBaanEmblem|
|Generate|EMBLEM!:KLD|Emblem Nissa|||NissaVitalForceEmblem|
|Generate|EMBLEM!:KLD|Emblem Tezzeret|||TezzeretTheSchemerEmblem|
|Generate|EMBLEM!:KTK|Emblem Sarkhan|||SarkhanTheDragonspeakerEmblem|
|Generate|EMBLEM!:KTK|Emblem Sorin|||SorinSolemnVisitorEmblem|
|Generate|EMBLEM!:M15|Emblem Ajani|||AjaniSteadfastEmblem|
@ -88,6 +88,19 @@
|Generate|EMBLEM:RIX|Huatli, Radiant Champion||Emblem Huatli|HuatliRadiantChampionEmblem|
|Generate|EMBLEM:RNA|Domri, Chaos Bringer||Emblem Domri|DomriChaosBringerEmblem|
|Generate|EMBLEM:WAR|Nissa, Who Shakes the World||Emblem Nissa|NissaWhoShakesTheWorldEmblem|
|Generate|EMBLEM:MH1|Serra the Benevolent||Emblem Serra|SerraTheBenevolentEmblem|
|Generate|EMBLEM:MH1|Wrenn and Six||Emblem Wrenn|WrennAndSixEmblem|
|Generate|EMBLEM:M19|Ajani, Adversary of Tyrants||Emblem Ajani|AjaniAdversaryOfTyrantsEmblem|
|Generate|EMBLEM:M19|Tezzeret, Artifice Master||Emblem Tezzeret|TezzeretArtificeMasterEmblem|
|Generate|EMBLEM:M19|Vivien Reid||Emblem Vivien|VivienReidEmblem|
|Generate|EMBLEM:M20|Chandra, Awakened Inferno||Emblem Chandra|ChandraAwakenedInfernoEmblem|
|Generate|EMBLEM:M20|Mu Yanling, Sky Dancer||Emblem Yanling|MuYanlingSkyDancerEmblem|
|Generate|EMBLEM:GRN|Ral, Izzet Viceroy||Emblem Ral|RalIzzetViceroyEmblem|
|Generate|EMBLEM:GRN|Vraska, Golgari Queen||Emblem Vraska|VraskaGolgariQueenEmblem|
|Generate|EMBLEM:DOM|Jaya Ballard||Emblem Jaya Ballard|JayaBallardEmblem|
|Generate|EMBLEM:DOM|Teferi, Hero of Dominaria||Emblem Teferi|TeferiHeroOfDominariaEmblem|
|Generate|EMBLEM:AER|Tezzeret the Schemer||Emblem Tezzeret|TezzeretTheSchemerEmblem|
|Generate|EMBLEM:ELD|Garruk, Cursed Huntsman||Emblem Garruk|GarrukCursedHuntsmanEmblem|
|Generate|PLANE:PCA|Plane - Academy At Tolaria West|||AcademyAtTolariaWestPlane|
|Generate|PLANE:PCA|Plane - Agyrem|||AgyremPlane|
|Generate|PLANE:PCA|Plane - Akoum|||AkoumPlane|
@ -149,32 +162,33 @@
|Generate|TOK:8ED|Rukh||
|Generate|TOK:9ED|Bird|||RukhEggBirdToken|
|Generate|TOK:9ED|Saproling|||SaprolingToken|
|Generate|TOK:AER|Etherium Cell||
|Generate|TOK:AER|Gremlin||
|Generate|TOK:AER|Ragavan||
|Generate|TOK:AKH|Angel of Sanctions||
|Generate|TOK:AKH|Anointer Priest||
|Generate|TOK:AKH|Aven Initiate||
|Generate|TOK:AKH|Aven Wind Guide||
|Generate|TOK:AER|Etherium Cell|||EtheriumCellToken|
|Generate|TOK:AER|Gremlin|||GremlinToken|
|Generate|TOK:AER|Ragavan|||RagavanToken|
|Generate|TOK:AKH|Beast|||BeastToken3|
|Generate|TOK:AKH|Cat|||CatToken2|
|Generate|TOK:AKH|Drake||
|Generate|TOK:AKH|Glyph Keeper||
|Generate|TOK:AKH|Heart-Piercer Manticore||
|Generate|TOK:AKH|Drake|||DrakeToken|
|Generate|TOK:AKH|Hippo|||HippoToken2|
|Generate|TOK:AKH|Honored Hydra||
|Generate|TOK:AKH|Labyrinth Guardian||
|Generate|TOK:AKH|Oketra's Attendant||
|Generate|TOK:AKH|Sacred Cat||
|Generate|TOK:AKH|Snake|||DeathtouchSnakeToken|
|Generate|TOK:AKH|Tah-Crop Skirmisher||
|Generate|TOK:AKH|Temmet, Vizier of Naktamun||
|Generate|TOK:AKH|Trueheart Duelist||
|Generate|TOK:AKH|Unwavering Initiate||
|Generate|TOK:AKH|Vizier of Many Faces||
|Generate|TOK:AKH|Warrior|||WarriorVigilantToken|
|Generate|TOK:AKH|Wurm|||WurmToken3|
|Generate|TOK:AKH|Zombie||
|Generate|TOK:AKH|Zombie|||ZombieToken
#TOK:AKH - some tokens from real cards (see Embalm ability)
#|Generate|TOK:AKH|Angel of Sanctions||
#|Generate|TOK:AKH|Anointer Priest||
#|Generate|TOK:AKH|Aven Initiate||
#|Generate|TOK:AKH|Aven Wind Guide||
#|Generate|TOK:AKH|Glyph Keeper||
#|Generate|TOK:AKH|Heart-Piercer Manticore||
#|Generate|TOK:AKH|Honored Hydra||
#|Generate|TOK:AKH|Labyrinth Guardian||
#|Generate|TOK:AKH|Oketra's Attendant||
#|Generate|TOK:AKH|Sacred Cat||
#|Generate|TOK:AKH|Tah-Crop Skirmisher||
#|Generate|TOK:AKH|Temmet, Vizier of Naktamun||
#|Generate|TOK:AKH|Trueheart Duelist||
#|Generate|TOK:AKH|Unwavering Initiate||
#|Generate|TOK:AKH|Vizier of Many Faces||
|Generate|TOK:ALA|Beast|||GodSireBeastToken|
|Generate|TOK:ALA|Dragon|||DragonToken|
|Generate|TOK:ALA|Goblin|||GoblinTokenWithHaste|
@ -229,7 +243,7 @@
|Generate|TOK:BFZ|Eldrazi Scion|3||EldraziScionToken|
|Generate|TOK:BFZ|Eldrazi|||EldraziToken|
|Generate|TOK:BFZ|Elemental|1||OmnathElementalToken|
|Generate|TOK:BFZ|Elemental|2||ElementalToken|
|Generate|TOK:BFZ|Elemental|2||AkoumStonewakerElementalToken|
|Generate|TOK:BFZ|Knight Ally|||KnightAllyToken|
|Generate|TOK:BFZ|Kor Ally|||KorAllyToken|
|Generate|TOK:BFZ|Octopus|||OctopusToken|
@ -356,13 +370,56 @@
|Generate|TOK:C17|Cat Dragon|||WasitoraCatDragonToken|
|Generate|TOK:C17|Cat Warrior||
|Generate|TOK:C17|Dragon|1||DragonToken|
|Generate|TOK:C17|Dragon|2||UtavaraHellkiteDragonToken|
|Generate|TOK:C17|Dragon|2||UtvaraHellkiteDragonToken|
|Generate|TOK:C17|Eldrazi Spawn||
|Generate|TOK:C17|Gold||
|Generate|TOK:C17|Rat|||DeathtouchRatToken|
|Generate|TOK:C17|Vampire|||EdgarMarkovToken|
|Generate|TOK:C17|Zombie||
|Generate|TOK:C18|Myr|||BrudicladTelchorMyrToken|
|Generate|TOK:C18|Angel|||AngelToken|
|Generate|TOK:C18|Cat|||CatToken|
|Generate|TOK:C18|Cat Warrior|||CatWarriorToken|
|Generate|TOK:C18|Clue|||ClueArtifactToken|
|Generate|TOK:C18|Construct|1||RetrofitterFoundryToken|
|Generate|TOK:C18|Construct|2||StoneTrapIdolToken|
|Generate|TOK:C18|Dragon|||DragonEggDragonToken|
|Generate|TOK:C18|Dragon Egg|||NestingDragonToken|
|Generate|TOK:C18|Elemental|||DokaiWeaverofLifeToken|
|Generate|TOK:C18|Horror|||PhyrexianRebirthHorrorToken|
|Generate|TOK:C18|Mask|||MaskToken|
|Generate|TOK:C18|Plant|||PlantToken|
|Generate|TOK:C18|Servo|||ServoToken|
|Generate|TOK:C18|Survivor|||SurvivorToken|
|Generate|TOK:C18|Thopter|1||ThopterColorlessToken|
|Generate|TOK:C18|Thopter|2||ThopterColorlessToken|
|Generate|TOK:C18|Thopter|3||ThopterColorlessToken|
|Generate|TOK:C18|Worm|||WormHarvestToken|
|Generate|TOK:C18|Zombie|||ZombieToken|
|Generate|TOK:C19|Assassin|||AssassinToken|
|Generate|TOK:C19|Beast|1||BeastToken|
|Generate|TOK:C19|Beast|2||BeastToken2|
|Generate|TOK:C19|Bird|1||RocEggToken|
|Generate|TOK:C19|Bird|2||WingmateRocToken|
|Generate|TOK:C19|Centaur|||CentaurToken|
|Generate|TOK:C19|Dragon|||DragonToken2|
|Generate|TOK:C19|Drake|||DrakeToken|
|Generate|TOK:C19|Egg|||AtlaPalaniToken|
|Generate|TOK:C19|Eldrazi|||EldraziToken|
|Generate|TOK:C19|Gargoyle|||GargoyleToken|
|Generate|TOK:C19|Horror|||PhyrexianRebirthHorrorToken|
|Generate|TOK:C19|Human|||HumanToken|
|Generate|TOK:C19|Pegasus|||PegasusToken|
|Generate|TOK:C19|Plant|||GrismoldPlantToken|
|Generate|TOK:C19|Rhino|||RhinoToken|
|Generate|TOK:C19|Saproling|||SaprolingToken|
|Generate|TOK:C19|Sculpture|||DoomedArtisanToken|
|Generate|TOK:C19|Snake|||SnakeToken|
|Generate|TOK:C19|Spirit|||SpiritToken|
|Generate|TOK:C19|Treasure|||TreasureToken|
|Generate|TOK:C19|Wurm|||WurmToken|
|Generate|TOK:C19|Zombie|1||ZombieToken|
|Generate|TOK:C19|Zombie|2||ZombieToken|
|Generate|TOK:CHK|Dragon Spirit|||TatsumaDragonToken|
|Generate|TOK:CHK|Elemental|||SeedGuardianToken|
|Generate|TOK:CHK|Illusion|||MelokuTheCloudedMirrorToken|
@ -524,16 +581,16 @@
|Generate|TOK:DOM|Construct|||KarnConstructToken|
|Generate|TOK:DOM|Demon|||BelzenlokDemonToken|
|Generate|TOK:DOM|Elemental|||ValdukElementalToken|
|Gererate|TOK:DOM|Goblin||
|Generate|TOK:DOM|Goblin|||GoblinToken|
|Generate|TOK:DOM|Karox Bladewing|||KaroxBladewingDragonToken|
|Generate|TOK:DOM|Knight|1|
|Generate|TOK:DOM|Knight|2|
|Generate|TOK:DOM|Knight|1||KnightToken|
|Generate|TOK:DOM|Knight|2||KnightToken|
|Generate|TOK:DOM|Nightmare Horror|||ChainersTormentNightmareToken|
|Generate|TOK:DOM|Saproling|1|
|Generate|TOK:DOM|Saproling|2|
|Generate|TOK:DOM|Saproling|3|
|Generate|TOK:DOM|Soldier||
|Generate|TOK:DOM|Zombie Knight||
|Generate|TOK:DOM|Saproling|1||SaprolingToken|
|Generate|TOK:DOM|Saproling|2||SaprolingToken|
|Generate|TOK:DOM|Saproling|3||SaprolingToken|
|Generate|TOK:DOM|Soldier|||SoldierToken|
|Generate|TOK:DOM|Zombie Knight|||ZombieKnightToken|
|Generate|TOK:DRB|Saproling|||SaprolingToken|
|Generate|TOK:DST|Beast|||BeastToken|
|Generate|TOK:DST|Elemental|1||WandOfTheElementsFirstToken|
@ -572,15 +629,16 @@
|Generate|TOK:EMA|Wall|||TidalWaveWallToken|
|Generate|TOK:EMA|Wurm|||WurmToken|
|Generate|TOK:EMA|Zombie|||ZombieToken|
|Generate|TOK:EMN|Devil|||DevilToken|
#TOK:EMN - Human Soldier, Spirit, Devil, Insect and Wolf tokens from SOI set
#|Generate|TOK:EMN|Devil|||DevilToken|
#|Generate|TOK:EMN|Human Soldier|||HumanSoldierToken|
#|Generate|TOK:EMN|Insect|||InsectToken|
#|Generate|TOK:EMN|Spirit|||SpiritWhiteToken|
#|Generate|TOK:EMN|Wolf|||WolfToken|
|Generate|TOK:EMN|Eldrazi Horror|||EldraziHorrorToken|
|Generate|TOK:EMN|Human Soldier|||HumanSoldierToken|
|Generate|TOK:EMN|Human Wizard|||HumanWizardToken|
|Generate|TOK:EMN|Human|||RedHumanToken|
|Generate|TOK:EMN|Insect|||InsectToken|
|Generate|TOK:EMN|Spider|||SpiderToken|
|Generate|TOK:EMN|Spirit|||SpiritWhiteToken|
|Generate|TOK:EMN|Wolf|||WolfToken|
|Generate|TOK:EMN|Zombie|1||ZombieToken|
|Generate|TOK:EMN|Zombie|2||ZombieToken|
|Generate|TOK:EMN|Zombie|3||ZombieToken|
@ -650,19 +708,20 @@
|Generate|TOK:HOP|Pentavite|||PentaviteToken|
|Generate|TOK:HOP|Pest|||PestToken|
|Generate|TOK:HOP|Saproling|||SaprolingToken|
|Generate|TOK:HOU|Horse|||CrestedSunmareToken|
|Generate|TOK:HOU|Insect|||TheLocustGodInsectToken|
|Generate|TOK:HOU|Snake|||RhonassLastStandToken|
#TOK:HOU - some tokens from real cards (see Eternalize ability)
#TOK:HOU - Cat, Warrior and Zombie tokens from AKH set
|Generate|TOK:HOU|Adorned Pouncer||||
|Generate|TOK:HOU|Champion of Wits||||
|Generate|TOK:HOU|Dreamstealer||||
|Generate|TOK:HOU|Earthshaker Khenra||||
|Generate|TOK:HOU|Horse|||CrestedSunmareToken|
|Generate|TOK:HOU|Insect|||TheLocustGodInsectToken|
|Generate|TOK:HOU|Proven Combatant||||
|Generate|TOK:HOU|Resilient Khenra||||
|Generate|TOK:HOU|Sinuous Striker||||
|Generate|TOK:HOU|Snake|||RhonassLastStandToken|
|Generate|TOK:HOU|Steadfast Sentinel||||
|Generate|TOK:HOU|Sunscourge Champion||||
|Generate|TOK:HOU|Zombie||
|Generate|TOK:ICE|Caribou|||CaribouToken|
|Generate|TOK:INV|Bird|||OwlToken|
|Generate|TOK:INV|Elephant|||ElephantToken|
@ -1199,6 +1258,12 @@
|Generate|TOK:RNA|Thopter|||ThopterToken|
|Generate|TOK:RNA|Treasure|||TreasureToken|
|Generate|TOK:RNA|Zombie|||ZombieToken|
|Generate|TOK:GRN|Angel|||AngelVigilanceToken|
|Generate|TOK:GRN|Bird Illusion|||BirdIllusionToken|
|Generate|TOK:GRN|Elf Knight|||ElfKnightToken|
|Generate|TOK:GRN|Goblin|||GoblinToken|
|Generate|TOK:GRN|Insect|||IzoniInsectToken|
|Generate|TOK:GRN|Soldier|||SoldierLifelinkToken|
|Generate|TOK:WAR|Angel|||AngelVigilanceToken|
|Generate|TOK:WAR|Assassin|||AssassinToken2|
|Generate|TOK:WAR|Devil|||DevilToken|
@ -1216,10 +1281,64 @@
|Generate|TOK:WAR|Zombie Army|1||ZombieArmyToken|
|Generate|TOK:WAR|Zombie Army|2||ZombieArmyToken|
|Generate|TOK:WAR|Zombie Army|3||ZombieArmyToken|
|Generate|TOK:MH1|Shapeshifter|||ShapeshifterToken|
|Generate|TOK:MH1|Angel|||AngelVigilanceToken|
|Generate|TOK:MH1|Bear|||BearToken|
|Generate|TOK:MH1|Bird|||BirdToken|
|Generate|TOK:MH1|Construct|||KarnConstructToken|
|Generate|TOK:MH1|Elemental|1||YoungPyromancerElementalToken|
|Generate|TOK:MH1|Elemental|2||AkoumStonewakerElementalToken|
|Generate|TOK:MH1|Elephant|||ElephantToken|
|Generate|TOK:MH1|Goblin|||GoblinToken|
|Generate|TOK:MH1|Golem|||GolemToken|
|Generate|TOK:MH1|Illusion|||MelokuTheCloudedMirrorToken|
|Generate|TOK:MH1|Marit Lage|||MaritLageToken|
|Generate|TOK:MH1|Myr|||MyrToken|
|Generate|TOK:MH1|Rhino|||RhinoToken|
|Generate|TOK:MH1|Soldier|||SoldierToken|
|Generate|TOK:MH1|Spider|||SpiderToken|
|Generate|TOK:MH1|Spirit|||WhiteBlackSpiritToken|
|Generate|TOK:MH1|Squirrel|||SquirrelToken|
|Generate|TOK:MH1|Zombie|||ZombieToken|
|Generate|TOK:M19|Angel|||AngelVigilanceToken|
|Generate|TOK:M19|Avatar|||AvatarToken2|
|Generate|TOK:M19|Bat|||BatToken|
|Generate|TOK:M19|Beast|||BeastToken|
|Generate|TOK:M19|Cat|||CatToken2|
|Generate|TOK:M19|Dragon|1||DragonEggDragonToken|
|Generate|TOK:M19|Dragon|2||DragonToken2|
|Generate|TOK:M19|Elf Warrior|||ElfToken|
|Generate|TOK:M19|Goblin|||GoblinToken|
|Generate|TOK:M19|Knight|||KnightToken|
|Generate|TOK:M19|Ox|||OxToken|
|Generate|TOK:M19|Soldier|||SoldierToken|
|Generate|TOK:M19|Thopter|||ThopterColorlessToken|
|Generate|TOK:M19|Zombie|||ZombieToken|
|Generate|TOK:M20|Ajani's Pridemate|||AjanisPridemateToken|
|Generate|TOK:M20|Demon|||DemonToken|
|Generate|TOK:M20|Elemental|||YoungPyromancerElementalToken|
|Generate|TOK:M20|Elemental Bird|||MuYanlingSkyDancerToken|
|Generate|TOK:M20|Golem|||GolemToken|
|Generate|TOK:M20|Soldier|||SoldierToken|
|Generate|TOK:M20|Spirit|||SpiritWhiteToken|
|Generate|TOK:M20|Treasure|||TreasureToken|
|Generate|TOK:M20|Wolf|||WolfToken|
|Generate|TOK:M20|Zombie|||ZombieToken|
|Generate|TOK:ELD|Bear|||BearToken|
|Generate|TOK:ELD|Boar|||WolfsQuarryToken|
|Generate|TOK:ELD|Dwarf|||DwarfToken|
|Generate|TOK:ELD|Faerie|||FaerieToken|
|Generate|TOK:ELD|Food|1||FoodToken|
|Generate|TOK:ELD|Food|2||FoodToken|
|Generate|TOK:ELD|Food|3||FoodToken|
|Generate|TOK:ELD|Food|4||FoodToken|
|Generate|TOK:ELD|Giant|||GiantOpportunityToken|
|Generate|TOK:ELD|Goat|||GoatToken|
|Generate|TOK:ELD|Human|||HumanToken|
|Generate|TOK:ELD|Human Cleric|||OutlawsMerrimentClericToken|
|Generate|TOK:ELD|Human Rogue|||OutlawsMerrimentRogueToken|
|Generate|TOK:ELD|Human Warrior|||OutlawsMerrimentWarriorToken|
|Generate|TOK:ELD|Knight|||KnightToken|
|Generate|TOK:ELD|Mouse|||MouseToken|
|Generate|TOK:ELD|Rat|||RatToken|
|Generate|TOK:ELD|Wolf|||GarrukCursedHuntsmanToken|

View file

@ -655,7 +655,7 @@ Elemental, 008, G, 2|2, -, Creature - Elemental, Marco Nelor, -
Elf Warrior, 009, G, 1|1, -, Creature - Elf Warrior, William O'Connor, -
Thopter, 010, -, 1|1, -, Artifact Creature - Thopter, Adam Paquette, Flying
Thopter, 011, -, 1|1, -, Artifact Creature - Thopter, Svetlin Velinov, Flying
Jace Emblem, 012, -, -, -, Emblem - Jace, Jaime Jones, Whenever you cast a spell<6C> target opponent puts the top five cards of his or her library into his or her graveyard.
Jace Emblem, 012, -, -, -, Emblem - Jace, Jaime Jones, Whenever you cast a spell<6C> target opponent puts the top five cards of their library into their graveyard.
Liliana Emblem, 013, -, -, -, Emblem - Liliana, Karla Ortiz, Whenever a creature dies<65> return it to the battlefield under your control at the beginning of the next end step.
Chandra Emblem, 014, -, -, -, Emblem - Chandra, Eric Deschamps, At the beginning of your upkeep<65> this emblem deals 3 damage to you.
@ -743,7 +743,7 @@ Clue, 013, -, -, -, Artifact - Clue, Zezhou Chen, {2} Sacrifice this Artifact
Clue, 014, -, -, -, Artifact - Clue, Cliff Childs, {2} Sacrifice this Artifact: Draw a card.
Clue, 015, -, -, -, Artifact - Clue, James Paick, {2} Sacrifice this Artifact: Draw a card.
Clue, 016, -, -, -, Artifact - Clue, Franz Vohwinkel, {2} Sacrifice this Artifact: Draw a card.
Jace Emblem, 017, -, -, -, Emblem - Jace, Tyler Jacobson, Whenever an opponent casts his or her first spell each turn<72> counter that spell.
Jace Emblem, 017, -, -, -, Emblem - Jace, Tyler Jacobson, Whenever an opponent casts their first spell each turn<72> counter that spell.
Arlinn Emblem, 018, -, -, -, Emblem - Arlinn, Winona Nelson, Creatures you control have haste and '{T}: This creature deals damage equal to its power to any target.'

Can't render this file because it contains an unexpected character in line 549 and column 140.

View file

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

View file

@ -56,6 +56,8 @@ public class ImagePanel extends JPanel {
super.add(component, constraints);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);

View file

@ -1,5 +1,12 @@
package mage.remote;
import java.io.*;
import java.lang.reflect.UndeclaredThrowableException;
import java.net.*;
import java.util.*;
import java.util.concurrent.CancellationException;
import java.util.concurrent.TimeUnit;
import javax.swing.*;
import mage.MageException;
import mage.cards.decks.DeckCardLists;
import mage.cards.repository.CardInfo;
@ -28,14 +35,6 @@ import org.jboss.remoting.transport.bisocket.Bisocket;
import org.jboss.remoting.transport.socket.SocketWrapper;
import org.jboss.remoting.transporter.TransporterClient;
import javax.swing.*;
import java.io.*;
import java.lang.reflect.UndeclaredThrowableException;
import java.net.*;
import java.util.*;
import java.util.concurrent.CancellationException;
import java.util.concurrent.TimeUnit;
/**
* @author BetaSteward_at_googlemail.com, JayDi85
*/
@ -502,7 +501,7 @@ public class SessionImpl implements Session {
/**
* @param askForReconnect - true = connection was lost because of error and
* ask the user if he want to try to reconnect
* ask the user if they want to try to reconnect
*/
@Override
public synchronized void disconnect(boolean askForReconnect) {
@ -557,8 +556,21 @@ public class SessionImpl implements Session {
@Override
public void handleCallback(Callback callback) throws HandleCallbackException {
//logger.info("callback handler");
try {
// Object object = callback.getCallbackObject();
// if (((ClientCallback) object).getMethod().equals(ClientCallbackMethod.GAME_TARGET)) {
// Object data = ((ClientCallback) object).getData();
// if (data instanceof GameClientMessage) {
// GameClientMessage message = (GameClientMessage) ((ClientCallback) object).getData();
// logger.info("Client Session Event->" + ((ClientCallback) object).getMethod() + " (id:" + ((ClientCallback) object).getMessageId() + ") " + message.getMessage()
// );
// }
// }
client.processCallback((ClientCallback) callback.getCallbackObject());
} catch (Exception ex) {
logger.error("handleCallback error", ex);
}
}
}

View file

@ -11,11 +11,11 @@ public class MageVersion implements Serializable, Comparable<MageVersion> {
public static final int MAGE_VERSION_MAJOR = 1;
public static final int MAGE_VERSION_MINOR = 4;
public static final int MAGE_VERSION_PATCH = 35;
public static final int MAGE_VERSION_PATCH = 41;
public static final String MAGE_EDITION_INFO = ""; // set "-beta" for 1.4.32-betaV0
public static final String MAGE_VERSION_MINOR_PATCH = "V5"; // default
public static final String MAGE_VERSION_MINOR_PATCH = "V1"; // default
// strict mode
private static final boolean MAGE_VERSION_MINOR_PATCH_MUST_BE_SAME = true; // set true on uncompatible github changes, set false after new major release (after MAGE_VERSION_PATCH changes)
private static final boolean MAGE_VERSION_MINOR_PATCH_MUST_BE_SAME = false; // set true on uncompatible github changes, set false after new major release (after MAGE_VERSION_PATCH changes)
public static final boolean MAGE_VERSION_SHOW_BUILD_TIME = true;
private final int major;

View file

@ -50,9 +50,9 @@ public class CardView extends SimpleCardView {
@Expose
protected String loyalty = "";
protected String startingLoyalty;
protected EnumSet<CardType> cardTypes;
protected Set<CardType> cardTypes;
protected SubTypeList subTypes;
protected EnumSet<SuperType> superTypes;
protected Set<SuperType> superTypes;
protected ObjectColor color;
protected ObjectColor frameColor;
protected FrameStyle frameStyle;
@ -104,9 +104,6 @@ public class CardView extends SimpleCardView {
protected boolean rotate;
protected boolean hideInfo; // controls if the tooltip window is shown (eg. controlled face down morph card)
protected boolean isPlayable;
protected boolean isChoosable;
protected boolean selected;
protected boolean canAttack;
protected boolean canBlock;
protected boolean inViewerOnly;
@ -117,9 +114,13 @@ public class CardView extends SimpleCardView {
this(card, null, false);
}
public CardView(Card card, UUID cardId) {
public CardView(Card card, SimpleCardView simpleCardView) {
this(card, null, false);
this.id = cardId;
this.id = simpleCardView.getId();
this.isPlayable = simpleCardView.isPlayable;
this.isChoosable = simpleCardView.isChoosable;
this.isSelected = simpleCardView.isSelected;
}
public CardView(Card card, Game game, UUID cardId) {
@ -128,10 +129,12 @@ public class CardView extends SimpleCardView {
}
public CardView(CardView cardView) {
super(cardView.id, cardView.expansionSetCode, cardView.cardNumber, cardView.usesVariousArt, cardView.tokenSetCode, cardView.gameObject, cardView.tokenDescriptor);
super(cardView);
this.originalCard = cardView.originalCard;
// generetate new ID
this.id = UUID.randomUUID();
this.parentId = cardView.parentId;
this.name = cardView.name;
this.displayName = cardView.displayName;
@ -198,9 +201,6 @@ public class CardView extends SimpleCardView {
this.rotate = cardView.rotate;
this.hideInfo = cardView.hideInfo;
this.isPlayable = cardView.isPlayable;
this.isChoosable = cardView.isChoosable;
this.selected = cardView.selected;
this.canAttack = cardView.canAttack;
this.canBlock = cardView.canBlock;
this.inViewerOnly = cardView.inViewerOnly;
@ -468,8 +468,6 @@ public class CardView extends SimpleCardView {
// Get starting loyalty
this.startingLoyalty = "" + card.getStartingLoyalty();
}
public CardView(MageObject object) {
@ -731,7 +729,7 @@ public class CardView extends SimpleCardView {
return subTypes;
}
public EnumSet<SuperType> getSuperTypes() {
public Set<SuperType> getSuperTypes() {
return superTypes;
}
@ -964,30 +962,6 @@ public class CardView extends SimpleCardView {
return hideInfo;
}
public boolean isPlayable() {
return isPlayable;
}
public void setPlayable(boolean isPlayable) {
this.isPlayable = isPlayable;
}
public boolean isChoosable() {
return isChoosable;
}
public void setChoosable(boolean isChoosable) {
this.isChoosable = isChoosable;
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
public boolean isCanAttack() {
return canAttack;
}

View file

@ -1,11 +1,5 @@
package mage.view;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.effects.Effect;
@ -20,8 +14,9 @@ import mage.game.permanent.PermanentToken;
import mage.target.targetpointer.TargetPointer;
import mage.util.GameLog;
import java.util.*;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public class CardsView extends LinkedHashMap<UUID, CardView> {
@ -91,11 +86,11 @@ public class CardsView extends LinkedHashMap<UUID, CardView> {
// throw new IllegalArgumentException("Source card for emblem not found.");
// }
abilityView = new AbilityView(ability, sourceObject.getName(), new CardView(new EmblemView((Emblem) sourceObject)));
abilityView.setName(((Emblem) sourceObject).getName());
abilityView.setName(sourceObject.getName());
// abilityView.setExpansionSetCode(sourceCard.getExpansionSetCode());
} else if (sourceObject instanceof Plane) {
abilityView = new AbilityView(ability, sourceObject.getName(), new CardView(new PlaneView((Plane) sourceObject)));
abilityView.setName(((Plane) sourceObject).getName());
abilityView.setName(sourceObject.getName());
}
break;
}
@ -131,7 +126,10 @@ public class CardsView extends LinkedHashMap<UUID, CardView> {
if ((mageObject instanceof Card) && ((Card) mageObject).isFaceDown(game)) {
continue;
}
names.add(GameLog.getColoredObjectIdNameForTooltip(mageObject));
String newName = GameLog.getColoredObjectIdNameForTooltip(mageObject);
if (!names.contains(newName)) {
names.add(newName);
}
}
}
if (!names.isEmpty()) {

View file

@ -1,21 +1,18 @@
package mage.view;
import java.io.Serializable;
import java.util.List;
import java.util.UUID;
/**
*
* @author Plopman
*/
public interface CommandObjectView extends Serializable {
public String getExpansionSetCode();
public interface CommandObjectView extends SelectableObjectView {
public String getName();
String getExpansionSetCode();
public UUID getId();
String getName();
public List<String> getRules();
UUID getId();
List<String> getRules();
}

View file

@ -1,10 +1,11 @@
package mage.view;
import mage.cards.Card;
import mage.game.command.Emblem;
import java.io.Serializable;
import java.util.List;
import java.util.UUID;
import mage.cards.Card;
import mage.game.command.Emblem;
/**
* @author noxx
@ -15,24 +16,25 @@ public class EmblemView implements CommandObjectView, Serializable {
protected String name;
protected String expansionSetCode;
protected List<String> rules;
protected boolean isPlayable = false;
protected int playableAmount = 0;
public EmblemView(Emblem emblem, Card sourceCard) {
id = emblem.getId();
name = "Emblem " + sourceCard.getName();
this.id = emblem.getId();
this.name = "Emblem " + sourceCard.getName();
if (emblem.getExpansionSetCodeForImage() == null) {
expansionSetCode = sourceCard.getExpansionSetCode();
this.expansionSetCode = sourceCard.getExpansionSetCode();
} else {
expansionSetCode = emblem.getExpansionSetCodeForImage();
this.expansionSetCode = emblem.getExpansionSetCodeForImage();
}
rules = emblem.getAbilities().getRules(sourceCard.getName());
this.rules = emblem.getAbilities().getRules(sourceCard.getName());
}
public EmblemView(Emblem emblem) {
id = emblem.getId();
name = emblem.getName();
expansionSetCode = emblem.getExpansionSetCodeForImage();
rules = emblem.getAbilities().getRules(emblem.getName());
this.id = emblem.getId();
this.name = emblem.getName();
this.expansionSetCode = emblem.getExpansionSetCodeForImage();
this.rules = emblem.getAbilities().getRules(emblem.getName());
}
@Override
@ -54,4 +56,47 @@ public class EmblemView implements CommandObjectView, Serializable {
public List<String> getRules() {
return rules;
}
@Override
public boolean isPlayable() {
return isPlayable;
}
@Override
public void setPlayable(boolean isPlayable) {
this.isPlayable = isPlayable;
}
@Override
public void setPlayableAmount(int playableAmount) {
this.playableAmount = playableAmount;
}
@Override
public int getPlayableAmount() {
return playableAmount;
}
@Override
public boolean isChoosable() {
// unsupported
return false;
}
@Override
public void setChoosable(boolean isChoosable) {
// unsupported
}
@Override
public boolean isSelected() {
// unsupported
return false;
}
@Override
public void setSelected(boolean isSelected) {
// unsupported
}
}

View file

@ -26,7 +26,10 @@ import mage.watchers.common.CastSpellLastTurnWatcher;
import org.apache.log4j.Logger;
import java.io.Serializable;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
* @author BetaSteward_at_googlemail.com
@ -39,7 +42,7 @@ public class GameView implements Serializable {
private final int priorityTime;
private final List<PlayerView> players = new ArrayList<>();
private CardsView hand;
private Set<UUID> canPlayInHand;
private Map<UUID, Integer> canPlayObjects;
private Map<String, SimpleCardsView> opponentHands;
private Map<String, SimpleCardsView> watchedHands;
private final CardsView stack = new CardsView();
@ -300,12 +303,12 @@ public class GameView implements Serializable {
return isPlayer;
}
public Set<UUID> getCanPlayInHand() {
return canPlayInHand;
public Map<UUID, Integer> getCanPlayObjects() {
return canPlayObjects;
}
public void setCanPlayInHand(Set<UUID> canPlayInHand) {
this.canPlayInHand = canPlayInHand;
public void setCanPlayObjects(Map<UUID, Integer> canPlayObjects) {
this.canPlayObjects = canPlayObjects;
}
public int getSpellsCastCurrentTurn() {

View file

@ -111,8 +111,8 @@ public class PermanentView extends CardView {
this.rules.add("A manifested creature card can be turned face up any time for it's mana cost."
+ " A face-down card can also be turned face up for its morph cost.");
} else if (permanent.isMorphed()) {
this.rules.add("If the controller has priority, he or she may turn this permanent face up."
+ " This is a special action; it doesn't use the stack. To do this he or she pays the morph costs,"
this.rules.add("If the controller has priority, they may turn this permanent face up."
+ " This is a special action; it doesn't use the stack. To do this they pay the morph costs,"
+ " then turns this permanent face up.");
}
}

View file

@ -1,10 +1,11 @@
package mage.view;
import mage.cards.Card;
import mage.game.command.Plane;
import java.io.Serializable;
import java.util.List;
import java.util.UUID;
import mage.cards.Card;
import mage.game.command.Plane;
/**
* @author spjspj
@ -16,23 +17,25 @@ public class PlaneView implements CommandObjectView, Serializable {
protected String expansionSetCode;
protected List<String> rules;
public PlaneView(Plane plane, Card sourceCard) {
id = plane.getId();
name = "Plane " + sourceCard.getName();
if (plane.getExpansionSetCodeForImage() == null) {
expansionSetCode = sourceCard.getExpansionSetCode();
} else {
expansionSetCode = plane.getExpansionSetCodeForImage();
}
protected boolean isPlayable = false;
protected int playableAmount = 0;
rules = plane.getAbilities().getRules(sourceCard.getName());
public PlaneView(Plane plane, Card sourceCard) {
this.id = plane.getId();
this.name = "Plane " + sourceCard.getName();
if (plane.getExpansionSetCodeForImage() == null) {
this.expansionSetCode = sourceCard.getExpansionSetCode();
} else {
this.expansionSetCode = plane.getExpansionSetCodeForImage();
}
this.rules = plane.getAbilities().getRules(sourceCard.getName());
}
public PlaneView(Plane plane) {
id = plane.getId();
name = plane.getName();
expansionSetCode = plane.getExpansionSetCodeForImage();
rules = plane.getAbilities().getRules(plane.getName());
this.id = plane.getId();
this.name = plane.getName();
this.expansionSetCode = plane.getExpansionSetCodeForImage();
this.rules = plane.getAbilities().getRules(plane.getName());
}
@Override
@ -54,4 +57,46 @@ public class PlaneView implements CommandObjectView, Serializable {
public List<String> getRules() {
return rules;
}
@Override
public boolean isPlayable() {
return isPlayable;
}
@Override
public void setPlayable(boolean isPlayable) {
this.isPlayable = isPlayable;
}
@Override
public void setPlayableAmount(int playableAmount) {
this.playableAmount = playableAmount;
}
@Override
public int getPlayableAmount() {
return playableAmount;
}
@Override
public boolean isChoosable() {
// unsupported
return false;
}
@Override
public void setChoosable(boolean isChoosable) {
// unsupported
}
@Override
public boolean isSelected() {
// unsupported
return false;
}
@Override
public void setSelected(boolean isSelected) {
// unsupported
}
}

View file

@ -0,0 +1,23 @@
package mage.view;
/**
* @author JayDi85
*/
public interface SelectableObjectView {
boolean isPlayable();
void setPlayable(boolean isPlayable);
void setPlayableAmount(int playableAmount);
int getPlayableAmount();
boolean isChoosable();
void setChoosable(boolean isChoosable);
boolean isSelected();
void setSelected(boolean isSelected);
}

View file

@ -1,5 +1,3 @@
package mage.view;
import com.google.gson.annotations.Expose;
@ -8,10 +6,9 @@ import java.io.Serializable;
import java.util.UUID;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public class SimpleCardView implements Serializable {
public class SimpleCardView implements Serializable, SelectableObjectView {
@Expose
protected UUID id;
protected String expansionSetCode;
@ -21,9 +18,30 @@ public class SimpleCardView implements Serializable {
protected boolean usesVariousArt;
protected boolean gameObject;
protected boolean isPlayable;
protected boolean isChoosable;
protected boolean isSelected;
protected int playableAmount; // playable abilities count on object
public SimpleCardView(final SimpleCardView view) {
this.id = view.id;
this.expansionSetCode = view.expansionSetCode;
this.tokenSetCode = view.tokenSetCode;
this.tokenDescriptor = view.tokenDescriptor;
this.cardNumber = view.cardNumber;
this.usesVariousArt = view.usesVariousArt;
this.gameObject = view.gameObject;
this.isPlayable = view.isPlayable;
this.isChoosable = view.isChoosable;
this.isSelected = view.isSelected;
this.playableAmount = view.playableAmount;
}
public SimpleCardView(UUID id, String expansionSetCode, String cardNumber, boolean usesVariousArt, String tokenSetCode, String tokenDescriptor) {
this(id, expansionSetCode, cardNumber, usesVariousArt, tokenSetCode, false, tokenDescriptor);
}
public SimpleCardView(UUID id, String expansionSetCode, String cardNumber, boolean usesVariousArt, String tokenSetCode, boolean isGameObject, String tokenDescriptor) {
this.id = id;
this.expansionSetCode = expansionSetCode;
@ -61,4 +79,44 @@ public class SimpleCardView implements Serializable {
public boolean isGameObject() {
return gameObject;
}
@Override
public boolean isPlayable() {
return isPlayable;
}
@Override
public void setPlayable(boolean isPlayable) {
this.isPlayable = isPlayable;
}
@Override
public void setPlayableAmount(int playableAmount) {
this.playableAmount = playableAmount;
}
@Override
public int getPlayableAmount() {
return playableAmount;
}
@Override
public boolean isChoosable() {
return isChoosable;
}
@Override
public void setChoosable(boolean isChoosable) {
this.isChoosable = isChoosable;
}
@Override
public boolean isSelected() {
return isSelected;
}
@Override
public void setSelected(boolean isSelected) {
this.isSelected = isSelected;
}
}

View file

@ -1,9 +1,5 @@
package mage.view;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Mode;
import mage.abilities.Modes;
@ -18,8 +14,11 @@ import mage.target.targetpointer.FixedTarget;
import mage.target.targetpointer.TargetPointer;
import mage.util.GameLog;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public class StackAbilityView extends CardView {
@ -94,7 +93,10 @@ public class StackAbilityView extends CardView {
if ((mageObject instanceof Card) && ((Card) mageObject).isFaceDown(game)) {
continue;
}
names.add(GameLog.getColoredObjectIdNameForTooltip(mageObject));
String newName = GameLog.getColoredObjectIdNameForTooltip(mageObject);
if (!names.contains(newName)) {
names.add(newName);
}
}
}

View file

@ -135,6 +135,7 @@ public class TableView implements Serializable {
switch (table.getState()) {
case WAITING:
stateText.append(" (").append(table.getTournament().getPlayers().size()).append('/').append(table.getNumberOfSeats()).append(')');
break;
case READY_TO_START:
case STARTING:
infoText.append(" Time: ").append(table.getTournament().getOptions().getMatchOptions().getMatchTimeLimit().toString());
@ -153,6 +154,7 @@ public class TableView implements Serializable {
if (draft != null) {
stateText.append(' ').append(draft.getBoosterNum()).append('/').append(draft.getCardNum() - 1);
}
break;
default:
}
this.additionalInfo = infoText.toString();

View file

@ -1,9 +1,10 @@
package mage.view;
import java.io.Serializable;
import mage.players.net.UserData;
import mage.players.net.UserSkipPrioritySteps;
import java.io.Serializable;
/**
* Transfer object for {@link mage.players.net.UserData}
*
@ -14,7 +15,6 @@ public class UserDataView implements Serializable {
protected int avatarId;
protected int userGroup;
protected boolean showAbilityPickerForced;
protected boolean allowRequestShowHandCards;
protected boolean confirmEmptyManaPool;
protected UserSkipPrioritySteps userSkipPrioritySteps;
String flagName;
@ -32,7 +32,6 @@ public class UserDataView implements Serializable {
boolean confirmEmptyManaPool, UserSkipPrioritySteps userSkipPrioritySteps, String flagName, boolean askMoveToGraveOrder) {
this.avatarId = avatarId;
this.showAbilityPickerForced = showAbilityPickerForced;
this.allowRequestShowHandCards = allowRequestShowHandCards;
this.userSkipPrioritySteps = userSkipPrioritySteps;
this.confirmEmptyManaPool = confirmEmptyManaPool;
this.flagName = flagName;
@ -43,7 +42,6 @@ public class UserDataView implements Serializable {
public UserDataView(UserData userData) {
this.avatarId = userData.getAvatarId();
this.userGroup = userData.getGroupId();
this.allowRequestShowHandCards = userData.isAllowRequestShowHandCards();
this.showAbilityPickerForced = userData.isShowAbilityPickerForced();
this.userSkipPrioritySteps = userData.getUserSkipPrioritySteps();
this.confirmEmptyManaPool = userData.confirmEmptyManaPool();
@ -59,10 +57,6 @@ public class UserDataView implements Serializable {
return showAbilityPickerForced;
}
public boolean allowRequestShowHandCards() {
return allowRequestShowHandCards;
}
public UserSkipPrioritySteps getUserSkipPrioritySteps() {
return userSkipPrioritySteps;
}

View file

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

View file

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

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.35</version>
<version>1.4.41</version>
</parent>
<artifactId>mage.server.console</artifactId>

View file

@ -1,31 +1,26 @@
package mage.server.console;
import mage.remote.Session;
import mage.view.TableView;
import mage.view.UserView;
import org.apache.log4j.Logger;
/*
* ConsolePanel.java
*
* Created on 14-May-2011, 6:08:48 PM
*/
package mage.server.console;
import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableRowSorter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import javax.swing.*;
import static javax.swing.JTable.AUTO_RESIZE_NEXT_COLUMN;
import static javax.swing.JTable.AUTO_RESIZE_OFF;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableRowSorter;
import mage.remote.Session;
import mage.view.TableView;
import mage.view.UserView;
import org.apache.log4j.Logger;
import static javax.swing.JTable.AUTO_RESIZE_NEXT_COLUMN;
import static javax.swing.JTable.AUTO_RESIZE_OFF;
/**
/**
* @author BetaSteward_at_googlemail.com
*/
public class ConsolePanel extends javax.swing.JPanel {
public class ConsolePanel extends javax.swing.JPanel {
private static final Logger logger = Logger.getLogger(ConsolePanel.class);
@ -404,9 +399,9 @@ public class ConsolePanel extends javax.swing.JPanel {
private javax.swing.JTable tblTables;
private javax.swing.JTable tblUsers;
// End of variables declaration//GEN-END:variables
}
}
class TableUserModel extends AbstractTableModel {
class TableUserModel extends AbstractTableModel {
public static final int POS_USER_NAME = 0;
public static final int POS_HOST = 1;
@ -487,9 +482,9 @@ class TableUserModel extends AbstractTableModel {
return false;
}
}
}
class TableTableModel extends AbstractTableModel {
class TableTableModel extends AbstractTableModel {
private final String[] columnNames = new String[]{"Table Name", "Owner", "Game Type", "Deck Type", "Status"};
private TableView[] tables = new TableView[0];
@ -553,15 +548,12 @@ class TableTableModel extends AbstractTableModel {
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
if (columnIndex != 5) {
return false;
}
return true;
return columnIndex == 5;
}
}
}
class UpdateUsersTask extends SwingWorker<Void, List<UserView>> {
class UpdateUsersTask extends SwingWorker<Void, List<UserView>> {
private final Session session;
private final ConsolePanel panel;
@ -589,44 +581,35 @@ class UpdateUsersTask extends SwingWorker<Void, List<UserView>> {
users = users2;
}
if (previousUsers == null || checkUserListChanged(users)) {
logger.debug("Need to update the user list");
checkUserListChanged(users);
this.publish(users);
previousUsers = users;
}
Thread.sleep(2000);
}
return null;
}
private boolean checkUserListChanged(List<UserView> usersToCheck) {
private void checkUserListChanged(List<UserView> usersToCheck) {
if (previousUsers == null || usersToCheck == null) {
return true;
}
if (previousUsers.size() != usersToCheck.size()) {
// new user appeared
return true;
return;
}
for (UserView u1 : previousUsers) {
for (UserView u2 : usersToCheck) {
if (u1.getUserName().equals(u2.getUserName())) {
String s = u1.getUserName() + ',' + u1.getHost();
if (peopleIps.get(s) == null) {
logger.warn("Found new user: " + u1.getUserName() + ',' + u1.getHost());
peopleIps.put(s, "1");
}
s = u2.getUserName() + ',' + u2.getHost();
}
for (UserView u1 : usersToCheck) {
String s = u1.getUserName() + ',' + u1.getHost();
if (peopleIps.get(s) == null) {
logger.warn("Found new user: " + u1.getUserName() + ',' + u1.getHost());
peopleIps.put(s, "1");
}
break;
}
}
}
// seems nothing has been changed
return true;
}
@Override
protected void process(List<List<UserView>> view) {
@ -648,9 +631,9 @@ class UpdateUsersTask extends SwingWorker<Void, List<UserView>> {
} catch (CancellationException ex) {
}
}
}
}
class UpdateTablesTask extends SwingWorker<Void, Collection<TableView>> {
class UpdateTablesTask extends SwingWorker<Void, Collection<TableView>> {
private final Session session;
private final UUID roomId;
@ -700,4 +683,4 @@ class UpdateTablesTask extends SwingWorker<Void, Collection<TableView>> {
} catch (CancellationException ex) {
}
}
}
}

View file

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

View file

@ -12,7 +12,7 @@ public class AmonkhetBlock extends Constructed {
public AmonkhetBlock() {
super("Constructed - Amonkhet Block");
setCodes.add("AKH");
setCodes.add("HOU");
setCodes.add(mage.sets.Amonkhet.getInstance().getCode());
setCodes.add(mage.sets.HourOfDevastation.getInstance().getCode());
}
}

View file

@ -29,7 +29,6 @@ public class AusHighlander extends Constructed {
pointMap.put("Sol Ring", 3);
pointMap.put("Time Walk", 3);
pointMap.put("Vampiric Tutor", 3);
pointMap.put("Yawgmoth's Will", 3);
pointMap.put("Channel", 2);
pointMap.put("Dig Through Time", 2);
pointMap.put("Library of Alexandria", 2);
@ -37,17 +36,20 @@ public class AusHighlander extends Constructed {
pointMap.put("Mind Twist", 2);
pointMap.put("Mystical Tutor", 2);
pointMap.put("Protean Hulk", 2);
pointMap.put("Strip Mine", 2);
pointMap.put("Tinker", 2);
pointMap.put("Tolarian Academy", 2);
pointMap.put("Treasure Cruise", 2);
pointMap.put("True-Name Nemesis", 2);
pointMap.put("Balance", 1);
pointMap.put("Birthing Pod", 1);
pointMap.put("Crop Rotation", 1);
pointMap.put("Dark Petition", 1);
pointMap.put("Doomsday", 1);
pointMap.put("Enlightened Tutor", 1);
pointMap.put("Fastbond", 1);
pointMap.put("Flash", 1);
pointMap.put("Force of Will", 1);
pointMap.put("Gifts Ungiven", 1);
pointMap.put("Green Sun's Zenith", 1);
pointMap.put("Hermit Druid", 1);
pointMap.put("Intuition", 1);
@ -57,25 +59,25 @@ public class AusHighlander extends Constructed {
pointMap.put("Lim-Dul's Vault", 1);
pointMap.put("Mana Drain", 1);
pointMap.put("Mana Vault", 1);
pointMap.put("Memory Jar", 1);
pointMap.put("Merchant Scroll", 1);
pointMap.put("Mishra's Workshop", 1);
pointMap.put("Natural Order", 1);
pointMap.put("Oath of Druids", 1);
pointMap.put("Personal Tutor", 1);
pointMap.put("Scheming Symmetry", 1);
pointMap.put("Sensei's Divining Top", 1);
pointMap.put("Skullclamp", 1);
pointMap.put("Snapcaster Mage", 1);
pointMap.put("Stoneforge Mystic", 1);
pointMap.put("Strip Mine", 1);
pointMap.put("Survival of the Fittest", 1);
pointMap.put("Tainted Pact", 1);
pointMap.put("Tendrils of Agony", 1);
pointMap.put("Time Spiral", 1);
pointMap.put("Timetwister", 1);
pointMap.put("True-Name Nemesis", 1);
pointMap.put("Umezawa's Jitte", 1);
pointMap.put("Wasteland", 1);
pointMap.put("Yawgmoth's Bargain", 1);
pointMap.put("Yawgmoth's Will", 1);
}
public AusHighlander() {
@ -133,14 +135,7 @@ public class AusHighlander extends Constructed {
Map<String, Integer> counts = new HashMap<>();
countCards(counts, deck.getCards());
countCards(counts, deck.getSideboard());
for (Map.Entry<String, Integer> entry : counts.entrySet()) {
if (entry.getValue() > 1) {
if (!basicLandNames.contains(entry.getKey()) && !anyNumberCardsAllowed.contains(entry.getKey())) {
invalid.put(entry.getKey(), "Too many: " + entry.getValue());
valid = false;
}
}
}
valid = checkCounts(1, counts) && valid;
int totalPoints = 0;
for (Map.Entry<String, Integer> entry : counts.entrySet()) {

View file

@ -12,7 +12,7 @@ public class BattleForZendikarBlock extends Constructed {
public BattleForZendikarBlock() {
super("Constructed - Battle for Zendikar Block");
setCodes.add("BFZ");
setCodes.add("OGW");
setCodes.add(mage.sets.BattleForZendikar.getInstance().getCode());
setCodes.add(mage.sets.OathOfTheGatewatch.getInstance().getCode());
}
}

View file

@ -5,6 +5,7 @@ import mage.cards.Card;
import mage.cards.decks.Constructed;
import mage.cards.decks.Deck;
import mage.filter.FilterMana;
import mage.util.ManaUtil;
import java.util.*;
@ -21,8 +22,7 @@ public class Brawl extends Constructed {
// Copy of standard sets
setCodes.addAll(Standard.makeLegalSets());
banned.add("Baral, Chief of Compliance");
banned.add("Smuggler's Copter");
banned.add("Oko, Thief of Crowns");
banned.add("Sorcerous Spyglass");
}
@ -48,14 +48,7 @@ public class Brawl extends Constructed {
Map<String, Integer> counts = new HashMap<>();
countCards(counts, deck.getCards());
countCards(counts, deck.getSideboard());
for (Map.Entry<String, Integer> entry : counts.entrySet()) {
if (entry.getValue() > 1) {
if (!basicLandNames.contains(entry.getKey()) && !anyNumberCardsAllowed.contains(entry.getKey())) {
invalid.put(entry.getKey(), "Too many: " + entry.getValue());
valid = false;
}
}
}
valid = checkCounts(1, counts) && valid;
for (String bannedCard : banned) {
if (counts.containsKey(bannedCard)) {
@ -78,25 +71,7 @@ public class Brawl extends Constructed {
invalid.put("Brawl", "Invalid Commander (" + commander.getName() + ')');
valid = false;
}
FilterMana commanderColor = commander.getColorIdentity();
if (commanderColor.isWhite()) {
colorIdentity.setWhite(true);
}
if (commanderColor.isBlue()) {
colorIdentity.setBlue(true);
}
if (commanderColor.isBlack()) {
colorIdentity.setBlack(true);
}
if (commanderColor.isRed()) {
colorIdentity.setRed(true);
}
if (commanderColor.isGreen()) {
colorIdentity.setGreen(true);
}
if (commanderColor.isColorless()) {
colorIdentity.setColorless(true);
}
ManaUtil.collectColorIdentity(colorIdentity, commander.getColorIdentity());
}
}
Set<String> basicsInDeck = new HashSet<>();
@ -108,7 +83,7 @@ public class Brawl extends Constructed {
}
}
for (Card card : deck.getCards()) {
if (!cardHasValidColor(colorIdentity, card)
if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())
&& !(colorIdentity.isColorless()
&& basicsInDeck.size() == 1
&& basicsInDeck.contains(card.getName()))) {
@ -135,13 +110,4 @@ public class Brawl extends Constructed {
return valid;
}
public boolean cardHasValidColor(FilterMana commander, Card card) {
FilterMana cardColor = card.getColorIdentity();
return !(cardColor.isBlack() && !commander.isBlack()
|| cardColor.isBlue() && !commander.isBlue()
|| cardColor.isGreen() && !commander.isGreen()
|| cardColor.isRed() && !commander.isRed()
|| cardColor.isWhite() && !commander.isWhite());
}
}

View file

@ -13,23 +13,23 @@ import java.util.Map;
*/
public class CanadianHighlander extends Constructed {
public static final Map<String, Integer> pointMap = new HashMap<>();
private static final Map<String, Integer> pointMap = new HashMap<>();
static {
pointMap.put("Ancestral Recall", 7);
pointMap.put("Balance", 1);
pointMap.put("Birthing Pod", 2);
pointMap.put("Black Lotus", 7);
pointMap.put("Demonic Tutor", 3);
pointMap.put("Crop Rotation", 1);
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("Flash", 6);
pointMap.put("Gifts Ungiven", 2);
pointMap.put("Imperial Seal", 1);
pointMap.put("Intuition", 1);
pointMap.put("Library of Alexandria", 1);
pointMap.put("Mana Crypt", 3);
pointMap.put("Mana Crypt", 4);
pointMap.put("Mana Drain", 1);
pointMap.put("Mana Vault", 1);
pointMap.put("Merchant Scroll", 1);
@ -42,7 +42,7 @@ public class CanadianHighlander extends Constructed {
pointMap.put("Mystical Tutor", 2);
pointMap.put("Natural Order", 4);
pointMap.put("Protean Hulk", 3);
pointMap.put("Sol Ring", 3);
pointMap.put("Sol Ring", 4);
pointMap.put("Spellseeker", 1);
pointMap.put("Stoneforge Mystic", 1);
pointMap.put("Strip Mine", 2);
@ -56,7 +56,7 @@ public class CanadianHighlander extends Constructed {
pointMap.put("Treasure Cruise", 1);
pointMap.put("True-Name Nemesis", 1);
pointMap.put("Umezawa's Jitte", 2);
pointMap.put("Vampiric Tutor", 3);
pointMap.put("Vampiric Tutor", 2);
}
public CanadianHighlander() {
@ -89,14 +89,7 @@ public class CanadianHighlander extends Constructed {
Map<String, Integer> counts = new HashMap<>();
countCards(counts, deck.getCards());
countCards(counts, deck.getSideboard());
for (Map.Entry<String, Integer> entry : counts.entrySet()) {
if (entry.getValue() > 1) {
if (!basicLandNames.contains(entry.getKey()) && !anyNumberCardsAllowed.contains(entry.getKey())) {
invalid.put(entry.getKey(), "Too many: " + entry.getValue());
valid = false;
}
}
}
valid = checkCounts(1, counts) && valid;
int allowedPoints = 10;
int totalPoints = 0;

View file

@ -0,0 +1,86 @@
package mage.deck;
/**
*
* @author andreacosta
*/
public class CenturionCommander extends Commander {
public CenturionCommander() {
super("Centurion Commander");
banned.add("Ancestral Recall");
banned.add("Ancient Tomb");
banned.add("Back to Basic");
banned.add("Balance");
banned.add("Bazaar of Baghdad");
banned.add("Black Lotus");
banned.add("Cataclysm");
banned.add("Channel");
banned.add("Chaos Orb");
banned.add("Chrome Mox");
banned.add("Demonic Tutor");
banned.add("Dig Through Time");
banned.add("Emrakul, the Aeons Torn");
banned.add("Emrakul, the Promised End");
banned.add("Entomb");
banned.add("Erayo, Soratami Ascendant");
banned.add("Falling Star");
banned.add("Fastbond");
banned.add("Food Chain");
banned.add("Gaeas Cradle");
banned.add("Gifts Ungiven");
banned.add("Grim Monolith");
banned.add("Grindstone");
banned.add("Hermit Druid");
banned.add("High Tide");
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("Mishras Workshop");
banned.add("Mind Twist");
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("Protean Hulk");
banned.add("Senseis Diving Top");
banned.add("Serra Ascendant");
banned.add("Sharazad");
banned.add("Survival of the Fittest");
banned.add("Sol Ring");
banned.add("Strip Mine");
banned.add("The Tabernacle at Pendrell Vale");
banned.add("Time Vault");
banned.add("Time Walk");
banned.add("Tinker");
banned.add("Tolarian Academy");
banned.add("Treasure Cruise");
banned.add("Vampiric Tutor");
banned.add("Vanishing");
banned.add("Winter Orb");
banned.add("Yawgmoths Bargain");
bannedCommander.add("Baral, Chief of Compliance");
bannedCommander.add("Derevi, Empyrial Tactician");
bannedCommander.add("Edgar Markov");
bannedCommander.add("Kess, Dissident Mage");
bannedCommander.add("Rofellos, Llanowar Emissary");
bannedPartner.add("Rowan Kenrith");
bannedPartner.add("Tymna the Weaver");
bannedPartner.add("Will Kenrith");
bannedPartner.add("Vial Smasher The Fierce");
}
}

View file

@ -12,6 +12,7 @@ import mage.cards.Sets;
import mage.cards.decks.Constructed;
import mage.cards.decks.Deck;
import mage.filter.FilterMana;
import mage.util.ManaUtil;
import java.util.*;
@ -20,7 +21,8 @@ import java.util.*;
*/
public class Commander extends Constructed {
protected List<String> bannedCommander = new ArrayList<>();
protected final List<String> bannedCommander = new ArrayList<>();
protected final List<String> bannedPartner = new ArrayList<>();
protected boolean partnerAllowed = true;
public Commander() {
@ -42,6 +44,7 @@ public class Commander extends Constructed {
banned.add("Fastbond");
banned.add("Gifts Ungiven");
banned.add("Griselbrand");
banned.add("Iona, Shield of Emeria");
banned.add("Karakas");
banned.add("Leovold, Emissary of Trest");
banned.add("Library of Alexandria");
@ -51,8 +54,8 @@ public class Commander extends Constructed {
banned.add("Mox Pearl");
banned.add("Mox Ruby");
banned.add("Mox Sapphire");
banned.add("Painter's Servant");
banned.add("Panoptic Mirror");
banned.add("Paradox Engine");
banned.add("Primeval Titan");
banned.add("Prophet of Kruphix");
banned.add("Recurring Nightmare");
@ -97,14 +100,7 @@ public class Commander extends Constructed {
Map<String, Integer> counts = new HashMap<>();
countCards(counts, deck.getCards());
countCards(counts, deck.getSideboard());
for (Map.Entry<String, Integer> entry : counts.entrySet()) {
if (entry.getValue() > 1) {
if (!basicLandNames.contains(entry.getKey()) && !anyNumberCardsAllowed.contains(entry.getKey())) {
invalid.put(entry.getKey(), "Too many: " + entry.getValue());
valid = false;
}
}
}
valid = checkCounts(1, counts) && valid;
for (String bannedCard : banned) {
if (counts.containsKey(bannedCard)) {
@ -113,7 +109,7 @@ public class Commander extends Constructed {
}
}
if (deck.getSideboard().size() < 1 || deck.getSideboard().size() > 2) {
if (deck.getSideboard().isEmpty() || deck.getSideboard().size() > 2) {
if ((deck.getSideboard().size() > 1 && !partnerAllowed)) {
invalid.put("Commander", "You may only have one commander");
}
@ -134,40 +130,36 @@ public class Commander extends Constructed {
invalid.put("Commander", "Commander invalid (" + commander.getName() + ')');
valid = false;
}
if (deck.getSideboard().size() == 2 && !commander.getAbilities().contains(PartnerAbility.getInstance())) {
boolean partnersWith = false;
for (Ability ability : commander.getAbilities()) {
if (ability instanceof PartnerWithAbility
&& commanderNames.contains(((PartnerWithAbility) ability).getPartnerName())) {
partnersWith = true;
break;
}
if (deck.getSideboard().size() == 2) {
if (commander.getAbilities().contains(PartnerAbility.getInstance())) {
if (bannedPartner.contains(commander.getName())) {
invalid.put("Commander", "Partner banned (" + commander.getName() + ')');
valid = false;
}
} else {
boolean partnersWith = commander.getAbilities()
.stream()
.filter(PartnerWithAbility.class::isInstance)
.map(PartnerWithAbility.class::cast)
.map(PartnerWithAbility::getPartnerName)
.anyMatch(commanderNames::contains);
if (!partnersWith) {
invalid.put("Commander", "Commander without Partner (" + commander.getName() + ')');
valid = false;
}
}
FilterMana commanderColor = commander.getColorIdentity();
if (commanderColor.isWhite()) {
colorIdentity.setWhite(true);
}
if (commanderColor.isBlue()) {
colorIdentity.setBlue(true);
}
if (commanderColor.isBlack()) {
colorIdentity.setBlack(true);
}
if (commanderColor.isRed()) {
colorIdentity.setRed(true);
}
if (commanderColor.isGreen()) {
colorIdentity.setGreen(true);
ManaUtil.collectColorIdentity(colorIdentity, commander.getColorIdentity());
}
}
// no needs in cards check on wrong commanders
if (!valid) {
return false;
}
for (Card card : deck.getCards()) {
if (!cardHasValidColor(colorIdentity, card)) {
if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) {
invalid.put(card.getName(), "Invalid color (" + colorIdentity.toString() + ')');
valid = false;
}
@ -191,15 +183,6 @@ public class Commander extends Constructed {
return valid;
}
public boolean cardHasValidColor(FilterMana commander, Card card) {
FilterMana cardColor = card.getColorIdentity();
return !(cardColor.isBlack() && !commander.isBlack()
|| cardColor.isBlue() && !commander.isBlue()
|| cardColor.isGreen() && !commander.isGreen()
|| cardColor.isRed() && !commander.isRed()
|| cardColor.isWhite() && !commander.isWhite());
}
@Override
public int getEdhPowerLevel(Deck deck) {
if (deck == null) {

View file

@ -47,6 +47,7 @@ public class DuelCommander extends Commander {
banned.add("Polymorph");
banned.add("Price of Progress");
banned.add("Protean Hulk");
banned.add("Scapeshift");
banned.add("Sensei's Divining Top");
banned.add("Shahrazad");
banned.add("Sol Ring");
@ -55,25 +56,30 @@ public class DuelCommander extends Commander {
banned.add("The Tabernacle at Pendrell Vale");
banned.add("Time Vault");
banned.add("Time Walk");
banned.add("Timetwister");
banned.add("Tinker");
banned.add("Tolarian Academy");
banned.add("Treasure Cruise");
banned.add("Vampiric Tutor");
bannedCommander.add("Arahbo, Roar of the World");
bannedCommander.add("Breya, Etherium Shaper");
bannedCommander.add("Bruse Tarl, Boorish Herder");
bannedCommander.add("Derevi, Empyrial Tactician");
bannedCommander.add("Edgar Markov");
bannedCommander.add("Edric, Spymaster of Trest");
bannedCommander.add("Erayo, Soratami Ascendant");
bannedCommander.add("Emry, Lurker of the Loch");
bannedCommander.add("Geist of Saint Traft");
bannedCommander.add("Jace, Vryn's Prodigy");
bannedCommander.add("Marath, Will of the Wild");
bannedCommander.add("Najeela, the Blade-Blossom");
bannedCommander.add("Oloro, Ageless Ascetic");
bannedCommander.add("Rofellos, Llanowar Emissary");
bannedCommander.add("Tasigur, the Golden Fang");
bannedCommander.add("Teferi, Temporal Archmage");
bannedCommander.add("Urza, Lord High Artificer");
bannedCommander.add("Vial Smasher the Fierce");
bannedCommander.add("Zur the Enchanter");
bannedCommander.add("Yuriko, the Tigers Shadow");
bannedCommander.add("Zurgo Bellstriker");
}

View file

@ -9,6 +9,7 @@ import mage.cards.Sets;
import mage.cards.decks.Constructed;
import mage.cards.decks.Deck;
import mage.filter.FilterMana;
import mage.util.ManaUtil;
import java.util.*;
@ -58,18 +59,9 @@ public class FreeformCommander extends Constructed {
countCards(counts, deck.getCards());
countCards(counts, deck.getSideboard());
for (Map.Entry<String, Integer> entry : counts.entrySet()) {
if (entry.getValue() > 1) {
if (!basicLandNames.contains(entry.getKey()) && !anyNumberCardsAllowed.contains(entry.getKey())) {
invalid.put(entry.getKey(), "Too many: " + entry.getValue());
valid = false;
}
}
}
valid = checkCounts(1, counts) && valid;
generateFreeformHash();
if (deck.getSideboard().size() < 1 || deck.getSideboard().size() > 2) {
if (deck.getSideboard().isEmpty() || deck.getSideboard().size() > 2) {
invalid.put("Commander", "Sideboard must contain only the commander(s)");
valid = false;
} else {
@ -97,27 +89,17 @@ public class FreeformCommander extends Constructed {
valid = false;
}
}
FilterMana commanderColor = commander.getColorIdentity();
if (commanderColor.isWhite()) {
colorIdentity.setWhite(true);
}
if (commanderColor.isBlue()) {
colorIdentity.setBlue(true);
}
if (commanderColor.isBlack()) {
colorIdentity.setBlack(true);
}
if (commanderColor.isRed()) {
colorIdentity.setRed(true);
}
if (commanderColor.isGreen()) {
colorIdentity.setGreen(true);
}
ManaUtil.collectColorIdentity(colorIdentity, commander.getColorIdentity());
}
}
// no needs in cards check on wrong commanders
if (!valid) {
return false;
}
for (Card card : deck.getCards()) {
if (!cardHasValidColor(colorIdentity, card)) {
if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) {
invalid.put(card.getName(), "Invalid color (" + colorIdentity.toString() + ')');
valid = false;
}
@ -133,17 +115,4 @@ public class FreeformCommander extends Constructed {
}
return valid;
}
public boolean cardHasValidColor(FilterMana commander, Card card) {
FilterMana cardColor = card.getColorIdentity();
return !(cardColor.isBlack() && !commander.isBlack()
|| cardColor.isBlue() && !commander.isBlue()
|| cardColor.isGreen() && !commander.isGreen()
|| cardColor.isRed() && !commander.isRed()
|| cardColor.isWhite() && !commander.isWhite());
}
public void generateFreeformHash() {
return;
}
}

View file

@ -4,6 +4,7 @@ import mage.cards.ExpansionSet;
import mage.cards.Sets;
import mage.cards.decks.Constructed;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
@ -15,7 +16,7 @@ public class Frontier extends Constructed {
public Frontier() {
super("Constructed - Frontier");
Date cutoff = new GregorianCalendar(2014, 6, 18).getTime(); // M15 release date
Date cutoff = new GregorianCalendar(2014, Calendar.JULY, 18).getTime(); // M15 release date
for (ExpansionSet set : Sets.getInstance().values()) {
if (set.getSetType().isStandardLegal() && (set.getReleaseDate().after(cutoff) || set.getReleaseDate().equals(cutoff))) {
setCodes.add(set.getCode());

View file

@ -12,9 +12,9 @@ public class InnistradBlock extends Constructed {
public InnistradBlock() {
super("Constructed - Innistrad Block");
setCodes.add("ISD");
setCodes.add("DKA");
setCodes.add("AVR");
setCodes.add(mage.sets.Innistrad.getInstance().getCode());
setCodes.add(mage.sets.DarkAscension.getInstance().getCode());
setCodes.add(mage.sets.AvacynRestored.getInstance().getCode());
}
}

View file

@ -11,7 +11,7 @@ public class IxalanBlock extends Constructed {
public IxalanBlock() {
super("Constructed - Ixalan Block");
setCodes.add("XLN");
setCodes.add("RIX");
setCodes.add(mage.sets.Ixalan.getInstance().getCode());
setCodes.add(mage.sets.RivalsOfIxalan.getInstance().getCode());
}
}

View file

@ -12,7 +12,7 @@ public class KaladeshBlock extends Constructed {
public KaladeshBlock() {
super("Constructed - Kaladesh Block");
setCodes.add("KLD");
setCodes.add("AER");
setCodes.add(mage.sets.Kaladesh.getInstance().getCode());
setCodes.add(mage.sets.AetherRevolt.getInstance().getCode());
}
}

View file

@ -12,9 +12,9 @@ public class KamigawaBlock extends Constructed {
public KamigawaBlock() {
super("Constructed - Kamigawa Block");
setCodes.add("CHK");
setCodes.add("BOK");
setCodes.add("SOK");
setCodes.add(mage.sets.ChampionsOfKamigawa.getInstance().getCode());
setCodes.add(mage.sets.BetrayersOfKamigawa.getInstance().getCode());
setCodes.add(mage.sets.SaviorsOfKamigawa.getInstance().getCode());
}
}

View file

@ -12,9 +12,9 @@ public class KhansOfTarkirBlock extends Constructed {
public KhansOfTarkirBlock() {
super("Constructed - Khans of Tarkir Block");
setCodes.add("KTK");
setCodes.add("FRF");
setCodes.add("DTK");
setCodes.add(mage.sets.KhansOfTarkir.getInstance().getCode());
setCodes.add(mage.sets.FateReforged.getInstance().getCode());
setCodes.add(mage.sets.DragonsOfTarkir.getInstance().getCode());
}
}

View file

@ -90,6 +90,7 @@ public class Legacy extends Constructed {
banned.add("Wheel of Fortune");
banned.add("Windfall");
banned.add("Worldknit");
banned.add("Wrenn and Six");
banned.add("Yawgmoth's Bargain");
banned.add("Yawgmoth's Will");

View file

@ -11,7 +11,7 @@ public class LorwynBlock extends Constructed {
public LorwynBlock() {
super("Constructed - Lorwyn Block");
setCodes.add("LRW");
setCodes.add("MOR");
setCodes.add(mage.sets.Lorwyn.getInstance().getCode());
setCodes.add(mage.sets.Morningtide.getInstance().getCode());
}
}

View file

@ -4,6 +4,7 @@ import mage.cards.ExpansionSet;
import mage.cards.Sets;
import mage.cards.decks.Constructed;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
@ -15,7 +16,7 @@ public class Modern extends Constructed {
public Modern() {
super("Constructed - Modern");
Date cutoff = new GregorianCalendar(2003, 6, 28).getTime(); // Eight edition release date
Date cutoff = new GregorianCalendar(2003, Calendar.JULY, 28).getTime(); // Eight edition release date
for (ExpansionSet set : Sets.getInstance().values()) {
if (set.getSetType().isModernLegal() && (set.getReleaseDate().after(cutoff) || set.getReleaseDate().equals(cutoff))) {
setCodes.add(set.getCode());
@ -25,6 +26,7 @@ public class Modern extends Constructed {
banned.add("Ancient Den");
banned.add("Birthing Pod");
banned.add("Blazing Shoal");
banned.add("Bridge from Below");
banned.add("Chrome Mox");
banned.add("Cloudpost");
banned.add("Dark Depths");
@ -32,11 +34,13 @@ public class Modern extends Constructed {
banned.add("Dig Through Time");
banned.add("Dread Return");
banned.add("Eye of Ugin");
banned.add("Faithless Looting");
banned.add("Gitaxian Probe");
banned.add("Glimpse of Nature");
banned.add("Golgari Grave-Troll");
banned.add("Great Furnace");
banned.add("Green Sun's Zenith");
banned.add("Hogaak, Arisen Necropolis");
banned.add("Hypergenesis");
banned.add("Krark-Clan Ironworks");
banned.add("Mental Misstep");
@ -48,7 +52,6 @@ public class Modern extends Constructed {
banned.add("Second Sunrise");
banned.add("Seething Song");
banned.add("Sensei's Divining Top");
banned.add("Stoneforge Mystic");
banned.add("Skullclamp");
banned.add("Splinter Twin");
banned.add("Summer Bloom");

View file

@ -4,6 +4,7 @@ import mage.cards.ExpansionSet;
import mage.cards.Sets;
import mage.cards.decks.Constructed;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
@ -15,7 +16,7 @@ public class ModernNoBannedList extends Constructed {
public ModernNoBannedList() {
super("Constructed - Modern - No Banned List");
Date cutoff = new GregorianCalendar(2003, 6, 28).getTime(); // Eight edition release date
Date cutoff = new GregorianCalendar(2003, Calendar.JULY, 28).getTime(); // Eight edition release date
for (ExpansionSet set : Sets.getInstance().values()) {
if (set.getSetType().isModernLegal() && (set.getReleaseDate().after(cutoff) || set.getReleaseDate().equals(cutoff))) {
setCodes.add(set.getCode());

View file

@ -0,0 +1,205 @@
package mage.deck;
import mage.abilities.Ability;
import mage.abilities.keyword.PartnerAbility;
import mage.abilities.keyword.PartnerWithAbility;
import mage.cards.Card;
import mage.cards.decks.Deck;
import mage.filter.FilterMana;
import mage.util.ManaUtil;
import java.util.*;
/**
* @author JayDi85
*/
public class Oathbreaker extends Vintage {
protected List<String> bannedCommander = new ArrayList<>();
private static final Map<String, Integer> pdAllowed = new HashMap<>();
public Oathbreaker() {
super();
this.name = "Oathbreaker";
// banned = vintage + oathbreaker's list: https://weirdcards.org/oathbreaker-ban-list
// last updated 8/2/19 - Primeval Titan unbanned
banned.add("Ad Nauseam");
banned.add("Ancestral Recall");
banned.add("Balance");
banned.add("Biorhythm");
banned.add("Black Lotus");
banned.add("Channel");
banned.add("Doomsday");
banned.add("Emrakul, the Aeons Torn");
banned.add("Expropriate");
banned.add("Fastbond");
banned.add("Gifts Ungiven");
banned.add("Griselbrand");
banned.add("High Tide");
banned.add("Library of Alexandria");
banned.add("Limited Resources");
banned.add("Lion's Eye Diamond");
banned.add("Mana Crypt");
banned.add("Mana Geyser");
banned.add("Mana Vault");
banned.add("Mox Emerald");
banned.add("Mox Jet");
banned.add("Mox Pearl");
banned.add("Mox Ruby");
banned.add("Mox Sapphire");
banned.add("Natural Order");
banned.add("Painter's Servant");
banned.add("Panoptic Mirror");
banned.add("Primal Surge");
banned.add("Saheeli, the Gifted");
banned.add("Sol Ring");
banned.add("Sundering Titan");
banned.add("Sway of the Stars");
banned.add("Sylvan Primordial");
banned.add("Time Vault");
banned.add("Time Walk");
banned.add("Tinker");
banned.add("Tolarian Academy");
banned.add("Tooth and Nail");
banned.add("Trade Secrets");
banned.add("Upheaval");
banned.add("Worldfire");
banned.add("Yawgmoth's Bargain");
}
@Override
public int getDeckMinSize() {
return 60 - (2 + 2); // 2 x spells + 2 x partner oathbreakers
}
@Override
public int getSideboardMinSize() {
return 2; // spell + oathbreaker
}
@Override
public boolean validate(Deck deck) {
boolean valid = true;
if (deck.getCards().size() + deck.getSideboard().size() != 60) {
invalid.put("Deck", "Must contain " + 60 + " cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards");
valid = false;
}
Map<String, Integer> counts = new HashMap<>();
countCards(counts, deck.getCards());
countCards(counts, deck.getSideboard());
for (String bannedCard : banned) {
if (counts.containsKey(bannedCard)) {
invalid.put(bannedCard, "Banned");
valid = false;
}
}
valid = checkCounts(1, counts) && valid;
Set<String> commanderNames = new HashSet<>();
Set<String> signatureSpells = new HashSet<>();
FilterMana allCommandersColor = new FilterMana();
if (deck.getSideboard().size() < 2 || deck.getSideboard().size() > 4) {
invalid.put("Oathbreaker", "Sideboard must contain only 2 or 4 cards (oathbreaker + signature spell)");
valid = false;
} else {
// collect data
for (Card commander : deck.getSideboard()) {
if (commander.isInstantOrSorcery()) {
signatureSpells.add(commander.getName());
} else {
if (commander.isPlaneswalker()) {
commanderNames.add(commander.getName());
// color identity from commanders only, not spell
ManaUtil.collectColorIdentity(allCommandersColor, commander.getColorIdentity());
} else {
invalid.put("Oathbreaker", "Only planeswalker can be Oathbreaker, not " + commander.getName());
valid = false;
}
}
}
// check size (1+1 or 2+2 allows)
if (commanderNames.isEmpty() || commanderNames.size() > 2) {
invalid.put("Oathbreaker", "Sideboard must contains 1 or 2 oathbreakers, but found: " + commanderNames.size());
valid = false;
}
if (signatureSpells.isEmpty() || signatureSpells.size() > 2) {
invalid.put("Signature Spell", "Sideboard must contains 1 or 2 signature spells, but found: " + signatureSpells.size());
valid = false;
}
if (signatureSpells.size() != commanderNames.size()) {
invalid.put("Oathbreaker", "Sideboard must contains 1 + 1 or 2 + 2 cards, but found: " + commanderNames.size() + " + " + signatureSpells.size());
valid = false;
}
// check partners
for (Card commander : deck.getSideboard()) {
if (commanderNames.contains(commander.getName())) {
// partner checks
if (commanderNames.size() == 2 && !commander.getAbilities().contains(PartnerAbility.getInstance())) {
boolean partnersWith = false;
for (Ability ability : commander.getAbilities()) {
if (ability instanceof PartnerWithAbility && commanderNames.contains(((PartnerWithAbility) ability).getPartnerName())) {
partnersWith = true;
break;
}
}
if (!partnersWith) {
invalid.put("Oathbreaker", "Oathbreaker without Partner (" + commander.getName() + ')');
valid = false;
}
}
}
}
// check spell color (one spell must be used by one oathbreaker)
// xmage doesn't allows to select pairs of spell + oathbreaker, what's why it requires one color combo minimum
for (Card spell : deck.getSideboard()) {
if (signatureSpells.contains(spell.getName())) {
FilterMana spellColor = spell.getColorIdentity();
boolean haveSameColor = false;
for (Card commander : deck.getSideboard()) {
if (commanderNames.contains(commander.getName())) {
FilterMana commanderColor = commander.getColorIdentity();
if (ManaUtil.isColorIdentityCompatible(commanderColor, spellColor)) {
haveSameColor = true;
}
}
}
if (!haveSameColor) {
invalid.put("Signature Spell", "Can't find oathbreaker with compatible color identity (" + spell.getName() + " - " + spellColor + ")");
valid = false;
}
}
}
}
// no needs in cards check on wrong commanders
if (!valid) {
return false;
}
for (Card card : deck.getCards()) {
if (!ManaUtil.isColorIdentityCompatible(allCommandersColor, card.getColorIdentity())) {
invalid.put(card.getName(), "Invalid color (" + card.getColorIdentity() + ')');
valid = false;
}
}
for (Card card : deck.getSideboard()) {
if (!isSetAllowed(card.getExpansionSetCode())) {
if (!legalSets(card)) {
invalid.put(card.getName(), "Not allowed Set: " + card.getExpansionSetCode());
valid = false;
}
}
}
return valid;
}
}

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