Merge branch 'master' into refactor/multiple-names
|
|
@ -6,7 +6,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.mage</groupId>
|
<groupId>org.mage</groupId>
|
||||||
<artifactId>mage-root</artifactId>
|
<artifactId>mage-root</artifactId>
|
||||||
<version>1.4.54</version>
|
<version>1.4.57</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>mage-client</artifactId>
|
<artifactId>mage-client</artifactId>
|
||||||
|
|
|
||||||
|
|
@ -4,4 +4,4 @@ set JAVA_HOME="C:\Program Files\Java\jre7\"
|
||||||
set CLASSPATH=%JAVA_HOME%/bin;%CLASSPATH%
|
set CLASSPATH=%JAVA_HOME%/bin;%CLASSPATH%
|
||||||
set PATH=%JAVA_HOME%/bin;%PATH%
|
set PATH=%JAVA_HOME%/bin;%PATH%
|
||||||
:NOJAVADIR
|
:NOJAVADIR
|
||||||
java -Xmx1024m -Dfile.encoding=UTF-8 -Djava.net.preferIPv4Stack=true -jar .\lib\mage-client-${project.version}.jar
|
java -Xmx2000m -Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8 -Djava.net.preferIPv4Stack=true -jar .\lib\mage-client-${project.version}.jar
|
||||||
|
|
@ -2,4 +2,4 @@
|
||||||
|
|
||||||
cd "`dirname "$0"`"
|
cd "`dirname "$0"`"
|
||||||
|
|
||||||
java -Xmx1024m -Dfile.encoding=UTF-8 -Djava.net.preferIPv4Stack=true -jar ./lib/mage-client-${project.version}.jar &
|
java -Xmx2000m -Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8 -Djava.net.preferIPv4Stack=true -jar ./lib/mage-client-${project.version}.jar &
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
java -Xmx1024m -Dfile.encoding=UTF-8 -Djava.net.preferIPv4Stack=true -jar ./lib/mage-client-${project.version}.jar &
|
java -Xmx2000m -Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8 -Djava.net.preferIPv4Stack=true -jar ./lib/mage-client-${project.version}.jar &
|
||||||
|
|
@ -4,4 +4,4 @@ set JAVA_HOME="C:\Program Files (x86)\Java\jre7\"
|
||||||
set CLASSPATH=%JAVA_HOME%/bin;%CLASSPATH%
|
set CLASSPATH=%JAVA_HOME%/bin;%CLASSPATH%
|
||||||
set PATH=%JAVA_HOME%/bin;%PATH%
|
set PATH=%JAVA_HOME%/bin;%PATH%
|
||||||
:NOJAVADIR
|
:NOJAVADIR
|
||||||
java -Xmx1024m -Dfile.encoding=UTF-8 -Djava.net.preferIPv4Stack=true -Dfile.encoding=UTF-8 -jar .\lib\mage-client-${project.version}.jar
|
java -Xmx2000m -Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8 -Djava.net.preferIPv4Stack=true -Dfile.encoding=UTF-8 -jar .\lib\mage-client-${project.version}.jar
|
||||||
|
|
@ -26,6 +26,7 @@ import mage.client.plugins.adapters.MageActionCallback;
|
||||||
import mage.client.plugins.impl.Plugins;
|
import mage.client.plugins.impl.Plugins;
|
||||||
import mage.client.preference.MagePreferences;
|
import mage.client.preference.MagePreferences;
|
||||||
import mage.client.remote.CallbackClientImpl;
|
import mage.client.remote.CallbackClientImpl;
|
||||||
|
import mage.client.remote.XmageURLConnection;
|
||||||
import mage.client.table.TablesPane;
|
import mage.client.table.TablesPane;
|
||||||
import mage.client.table.TablesPanel;
|
import mage.client.table.TablesPanel;
|
||||||
import mage.client.tournament.TournamentPane;
|
import mage.client.tournament.TournamentPane;
|
||||||
|
|
@ -54,6 +55,7 @@ import net.java.truevfs.access.TArchiveDetector;
|
||||||
import net.java.truevfs.access.TConfig;
|
import net.java.truevfs.access.TConfig;
|
||||||
import net.java.truevfs.kernel.spec.FsAccessOption;
|
import net.java.truevfs.kernel.spec.FsAccessOption;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
import org.junit.Assert;
|
||||||
import org.mage.card.arcane.ManaSymbols;
|
import org.mage.card.arcane.ManaSymbols;
|
||||||
import org.mage.card.arcane.SvgUtils;
|
import org.mage.card.arcane.SvgUtils;
|
||||||
import org.mage.plugins.card.images.DownloadPicturesService;
|
import org.mage.plugins.card.images.DownloadPicturesService;
|
||||||
|
|
@ -196,19 +198,6 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
public MageFrame() throws MageException {
|
public MageFrame() throws MageException {
|
||||||
File cacertsFile = new File(System.getProperty("user.dir") + "/release/cacerts").getAbsoluteFile();
|
|
||||||
if (!cacertsFile.exists()) { // When running from the jar file the contents of the /release folder will have been expanded into the home folder as part of packaging
|
|
||||||
cacertsFile = new File(System.getProperty("user.dir") + "/cacerts").getAbsoluteFile();
|
|
||||||
}
|
|
||||||
if (cacertsFile.exists()) {
|
|
||||||
LOGGER.info("Custom (or bundled) Java certificate file (cacerts) file found");
|
|
||||||
String cacertsPath = cacertsFile.getPath();
|
|
||||||
System.setProperty("javax.net.ssl.trustStore", cacertsPath);
|
|
||||||
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
|
|
||||||
} else {
|
|
||||||
LOGGER.info("custom Java certificate file not found at: " + cacertsFile.getAbsolutePath());
|
|
||||||
}
|
|
||||||
|
|
||||||
setWindowTitle();
|
setWindowTitle();
|
||||||
|
|
||||||
// mac os only: enable full screen support in java 8 (java 11+ try to use it all the time)
|
// mac os only: enable full screen support in java 8 (java 11+ try to use it all the time)
|
||||||
|
|
@ -403,6 +392,41 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Init certificates store for https work (if java version is outdated)
|
||||||
|
* Debug with -Djavax.net.debug=SSL,trustmanager
|
||||||
|
*/
|
||||||
|
@Deprecated // TODO: replaced by enableAIAcaIssuers, delete that code after few releases (2025-01-01)
|
||||||
|
private void initSSLCertificates() {
|
||||||
|
// from dev build (runtime)
|
||||||
|
boolean cacertsUsed = false;
|
||||||
|
File cacertsFile = new File(System.getProperty("user.dir") + "/release/cacerts").getAbsoluteFile();
|
||||||
|
if (cacertsFile.exists()) {
|
||||||
|
cacertsUsed = true;
|
||||||
|
LOGGER.info("SSL certificates: used runtime cacerts bundle");
|
||||||
|
}
|
||||||
|
|
||||||
|
// from release build (jar)
|
||||||
|
// When running from the jar file the contents of the /release folder will have been expanded into the home folder as part of packaging
|
||||||
|
if (!cacertsUsed) {
|
||||||
|
cacertsFile = new File(System.getProperty("user.dir") + "/cacerts").getAbsoluteFile();
|
||||||
|
if (cacertsFile.exists()) {
|
||||||
|
cacertsUsed = true;
|
||||||
|
LOGGER.info("SSL certificates: used release cacerts bundle");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cacertsUsed && cacertsFile.exists()) {
|
||||||
|
String cacertsPath = cacertsFile.getPath();
|
||||||
|
System.setProperty("javax.net.ssl.trustStoreType", "PKCS12"); // cacerts file format from java 9+ instead "jks" from java 8
|
||||||
|
System.setProperty("javax.net.ssl.trustStore", cacertsPath);
|
||||||
|
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
|
||||||
|
} else {
|
||||||
|
LOGGER.info("SSL certificates: used default cacerts bundle from " + System.getProperty("java.version"));
|
||||||
|
}
|
||||||
|
System.setProperty("com.sun.security.enableAIAcaIssuers", "true");
|
||||||
|
}
|
||||||
|
|
||||||
private void bootstrapSetsAndFormats() {
|
private void bootstrapSetsAndFormats() {
|
||||||
LOGGER.info("Loading sets and formats...");
|
LOGGER.info("Loading sets and formats...");
|
||||||
ConstructedFormats.ensureLists();
|
ConstructedFormats.ensureLists();
|
||||||
|
|
@ -925,11 +949,15 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
|
||||||
} catch (SocketException ex) {
|
} catch (SocketException ex) {
|
||||||
}
|
}
|
||||||
currentConnection.setUserIdStr(System.getProperty("user.name") + ":" + System.getProperty("os.name") + ":" + MagePreferences.getUserNames() + ":" + allMAC);
|
currentConnection.setUserIdStr(System.getProperty("user.name") + ":" + System.getProperty("os.name") + ":" + MagePreferences.getUserNames() + ":" + allMAC);
|
||||||
currentConnection.setProxyType(proxyType);
|
if (PreferencesDialog.NETWORK_ENABLE_PROXY_SUPPORT) {
|
||||||
currentConnection.setProxyHost(proxyServer);
|
currentConnection.setProxyType(proxyType);
|
||||||
currentConnection.setProxyPort(proxyPort);
|
currentConnection.setProxyHost(proxyServer);
|
||||||
currentConnection.setProxyUsername(proxyUsername);
|
currentConnection.setProxyPort(proxyPort);
|
||||||
currentConnection.setProxyPassword(proxyPassword);
|
currentConnection.setProxyUsername(proxyUsername);
|
||||||
|
currentConnection.setProxyPassword(proxyPassword);
|
||||||
|
} else {
|
||||||
|
currentConnection.setProxyType(ProxyType.NONE);
|
||||||
|
}
|
||||||
setUserPrefsToConnection(currentConnection);
|
setUserPrefsToConnection(currentConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1502,7 +1530,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
|
||||||
if (!Charset.defaultCharset().toString().equals("UTF-8")) {
|
if (!Charset.defaultCharset().toString().equals("UTF-8")) {
|
||||||
LOGGER.warn("WARNING, bad charset. Some images will not be downloaded. You must:");
|
LOGGER.warn("WARNING, bad charset. Some images will not be downloaded. You must:");
|
||||||
LOGGER.warn("* Open launcher -> settings -> java -> client java options");
|
LOGGER.warn("* Open launcher -> settings -> java -> client java options");
|
||||||
LOGGER.warn("* Insert additional command at the the end: -Dfile.encoding=UTF-8");
|
LOGGER.warn("* Insert at the the end: -Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8");
|
||||||
}
|
}
|
||||||
|
|
||||||
startTime = System.currentTimeMillis();
|
startTime = System.currentTimeMillis();
|
||||||
|
|
|
||||||
|
|
@ -114,12 +114,12 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
|
||||||
int cardWidth = getCardWidth();
|
int cardWidth = getCardWidth();
|
||||||
int cardHeight = getCardHeight();
|
int cardHeight = getCardHeight();
|
||||||
int cardTopHeight = CardRenderer.getCardTopHeight(cardWidth);
|
int cardTopHeight = CardRenderer.getCardTopHeight(cardWidth);
|
||||||
int dx = x % (cardWidth + GRID_PADDING);
|
int dx = x % (cardWidth + getGridPadding());
|
||||||
int col = x / (cardWidth + GRID_PADDING);
|
int col = x / (cardWidth + getGridPadding());
|
||||||
int gridWidth = cardGrid.isEmpty() ? 0 : cardGrid.get(0).size();
|
int gridWidth = cardGrid.isEmpty() ? 0 : cardGrid.get(0).size();
|
||||||
|
|
||||||
int countLabelHeight = getCountLabelHeight();
|
int countLabelHeight = getCountLabelHeight();
|
||||||
if (dx < GRID_PADDING && col < gridWidth) {
|
if (dx < getGridPadding() && col < gridWidth) {
|
||||||
// Which row to add to?
|
// Which row to add to?
|
||||||
int curY = countLabelHeight;
|
int curY = countLabelHeight;
|
||||||
int rowIndex = 0;
|
int rowIndex = 0;
|
||||||
|
|
@ -142,7 +142,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
|
||||||
// Insert between two columns
|
// Insert between two columns
|
||||||
insertArrow.setIcon(INSERT_COL_ICON);
|
insertArrow.setIcon(INSERT_COL_ICON);
|
||||||
insertArrow.setSize(64, 64);
|
insertArrow.setSize(64, 64);
|
||||||
insertArrow.setLocation((cardWidth + GRID_PADDING) * col + GRID_PADDING / 2 - 32, curY);
|
insertArrow.setLocation((cardWidth + getGridPadding()) * col + getGridPadding() / 2 - 32, curY);
|
||||||
} else {
|
} else {
|
||||||
// Clamp to a new col one after the current last one
|
// Clamp to a new col one after the current last one
|
||||||
col = Math.min(col, gridWidth);
|
col = Math.min(col, gridWidth);
|
||||||
|
|
@ -184,7 +184,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
|
||||||
// Position arrow
|
// Position arrow
|
||||||
insertArrow.setIcon(INSERT_ROW_ICON);
|
insertArrow.setIcon(INSERT_ROW_ICON);
|
||||||
insertArrow.setSize(64, 32);
|
insertArrow.setSize(64, 32);
|
||||||
insertArrow.setLocation((cardWidth + GRID_PADDING) * col + GRID_PADDING + cardWidth / 2 - 32, curY + stackInsertIndex * cardTopHeight - 32);
|
insertArrow.setLocation((cardWidth + getGridPadding()) * col + getGridPadding() + cardWidth / 2 - 32, curY + stackInsertIndex * cardTopHeight - 32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -225,12 +225,12 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
|
||||||
int cardWidth = getCardWidth();
|
int cardWidth = getCardWidth();
|
||||||
int cardHeight = getCardHeight();
|
int cardHeight = getCardHeight();
|
||||||
int cardTopHeight = CardRenderer.getCardTopHeight(cardWidth);
|
int cardTopHeight = CardRenderer.getCardTopHeight(cardWidth);
|
||||||
int dx = x % (cardWidth + GRID_PADDING);
|
int dx = x % (cardWidth + getGridPadding());
|
||||||
int col = x / (cardWidth + GRID_PADDING);
|
int col = x / (cardWidth + getGridPadding());
|
||||||
int gridWidth = cardGrid.isEmpty() ? 0 : cardGrid.get(0).size();
|
int gridWidth = cardGrid.isEmpty() ? 0 : cardGrid.get(0).size();
|
||||||
|
|
||||||
int countLabelHeight = getCountLabelHeight();
|
int countLabelHeight = getCountLabelHeight();
|
||||||
if (dx < GRID_PADDING && col < gridWidth) {
|
if (dx < getGridPadding() && col < gridWidth) {
|
||||||
// Which row to add to?
|
// Which row to add to?
|
||||||
int curY = countLabelHeight;
|
int curY = countLabelHeight;
|
||||||
int rowIndex = 0;
|
int rowIndex = 0;
|
||||||
|
|
@ -334,7 +334,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
|
||||||
// Add new cards to grid
|
// Add new cards to grid
|
||||||
for (CardView card : cards) {
|
for (CardView card : cards) {
|
||||||
card.setSelected(true);
|
card.setSelected(true);
|
||||||
addCardView(card, false);
|
addCardView(card, null);
|
||||||
eventSource.fireEvent(card, ClientEventType.DECK_ADD_SPECIFIC_CARD);
|
eventSource.fireEvent(card, ClientEventType.DECK_ADD_SPECIFIC_CARD);
|
||||||
}
|
}
|
||||||
layoutGrid();
|
layoutGrid();
|
||||||
|
|
@ -575,7 +575,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
private static final int DEFAULT_COUNT_LABEL_HEIGHT = 40; // can contain 1 or 2 lines
|
private static final int DEFAULT_COUNT_LABEL_HEIGHT = 40; // can contain 1 or 2 lines
|
||||||
public static final int GRID_PADDING = 10;
|
public static final int GRID_PADDING = 20;
|
||||||
|
|
||||||
private static final ImageIcon INSERT_ROW_ICON = new ImageIcon(DragCardGrid.class.getClassLoader().getResource("editor_insert_row.png"));
|
private static final ImageIcon INSERT_ROW_ICON = new ImageIcon(DragCardGrid.class.getClassLoader().getResource("editor_insert_row.png"));
|
||||||
private static final ImageIcon INSERT_COL_ICON = new ImageIcon(DragCardGrid.class.getClassLoader().getResource("editor_insert_col.png"));
|
private static final ImageIcon INSERT_COL_ICON = new ImageIcon(DragCardGrid.class.getClassLoader().getResource("editor_insert_col.png"));
|
||||||
|
|
@ -1044,7 +1044,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
|
||||||
selectBySearchPanelC.fill = GridBagConstraints.VERTICAL;
|
selectBySearchPanelC.fill = GridBagConstraints.VERTICAL;
|
||||||
|
|
||||||
searchByTextField = new JTextField();
|
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.setToolTipText("Search cards by any data like name or mana symbols like {W}, {U}, {C}, etc (use quotes for exact search)");
|
||||||
searchByTextField.addKeyListener(new KeyAdapter() {
|
searchByTextField.addKeyListener(new KeyAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void keyReleased(KeyEvent e) {
|
public void keyReleased(KeyEvent e) {
|
||||||
|
|
@ -1253,10 +1253,10 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
|
||||||
selectionPanel.setSize(x2 - x1, y2 - y1);
|
selectionPanel.setSize(x2 - x1, y2 - y1);
|
||||||
|
|
||||||
// First and last cols
|
// First and last cols
|
||||||
int col1 = x1 / (cardWidth + GRID_PADDING);
|
int col1 = x1 / (cardWidth + getGridPadding());
|
||||||
int col2 = x2 / (cardWidth + GRID_PADDING);
|
int col2 = x2 / (cardWidth + getGridPadding());
|
||||||
int offsetIntoCol2 = x2 % (cardWidth + GRID_PADDING);
|
int offsetIntoCol2 = x2 % (cardWidth + getGridPadding());
|
||||||
if (offsetIntoCol2 < GRID_PADDING) {
|
if (offsetIntoCol2 < getGridPadding()) {
|
||||||
--col2;
|
--col2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1322,7 +1322,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
|
||||||
|
|
||||||
// re-insert
|
// re-insert
|
||||||
for (CardView card : allCards) {
|
for (CardView card : allCards) {
|
||||||
sortIntoGrid(card);
|
sortIntoGrid(card, null);
|
||||||
}
|
}
|
||||||
trimGrid();
|
trimGrid();
|
||||||
|
|
||||||
|
|
@ -1717,7 +1717,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
|
||||||
|
|
||||||
if (acard.getName().equals(card.getName())) {
|
if (acard.getName().equals(card.getName())) {
|
||||||
CardView pimpedCard = new CardView(acard);
|
CardView pimpedCard = new CardView(acard);
|
||||||
addCardView(pimpedCard, false);
|
addCardView(pimpedCard, null);
|
||||||
eventSource.fireEvent(pimpedCard, ClientEventType.DECK_ADD_SPECIFIC_CARD);
|
eventSource.fireEvent(pimpedCard, ClientEventType.DECK_ADD_SPECIFIC_CARD);
|
||||||
pimpedCards.put(pimpedCard, 1);
|
pimpedCards.put(pimpedCard, 1);
|
||||||
didModify = true;
|
didModify = true;
|
||||||
|
|
@ -1729,7 +1729,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
|
||||||
|
|
||||||
if (didModify) {
|
if (didModify) {
|
||||||
for (CardView c : pimpedCards.keySet()) {
|
for (CardView c : pimpedCards.keySet()) {
|
||||||
sortIntoGrid(c);
|
sortIntoGrid(c, null);
|
||||||
}
|
}
|
||||||
trimGrid();
|
trimGrid();
|
||||||
|
|
||||||
|
|
@ -1762,7 +1762,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
|
||||||
CardView oldestCardView = new CardView(oldestCardInfo.createMockCard());
|
CardView oldestCardView = new CardView(oldestCardInfo.createMockCard());
|
||||||
this.removeCardView(card);
|
this.removeCardView(card);
|
||||||
eventSource.fireEvent(card, ClientEventType.DECK_REMOVE_SPECIFIC_CARD);
|
eventSource.fireEvent(card, ClientEventType.DECK_REMOVE_SPECIFIC_CARD);
|
||||||
this.addCardView(oldestCardView, false);
|
this.addCardView(oldestCardView, null);
|
||||||
eventSource.fireEvent(oldestCardView, ClientEventType.DECK_ADD_SPECIFIC_CARD);
|
eventSource.fireEvent(oldestCardView, ClientEventType.DECK_ADD_SPECIFIC_CARD);
|
||||||
newStack.add(oldestCardView);
|
newStack.add(oldestCardView);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1814,10 +1814,10 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
|
||||||
for (CardView newCard : cardsView.values()) {
|
for (CardView newCard : cardsView.values()) {
|
||||||
if (!cardViews.containsKey(newCard.getId())) {
|
if (!cardViews.containsKey(newCard.getId())) {
|
||||||
// Is a new card
|
// Is a new card
|
||||||
addCardView(newCard, false);
|
addCardView(newCard, null);
|
||||||
|
|
||||||
// Put it into the appropirate place in the grid given the current sort
|
// Put it into the appropirate place in the grid given the current sort
|
||||||
sortIntoGrid(newCard);
|
sortIntoGrid(newCard, null);
|
||||||
|
|
||||||
// Mark
|
// Mark
|
||||||
didModify = true;
|
didModify = true;
|
||||||
|
|
@ -1837,7 +1837,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
|
||||||
for (CardView newCard : cardsView.values()) {
|
for (CardView newCard : cardsView.values()) {
|
||||||
if (!cardViews.containsKey(newCard.getId())) {
|
if (!cardViews.containsKey(newCard.getId())) {
|
||||||
// Add the new card
|
// Add the new card
|
||||||
addCardView(newCard, false);
|
addCardView(newCard, null);
|
||||||
|
|
||||||
// Add the new card to tracking
|
// Add the new card to tracking
|
||||||
Map<String, List<CardView>> forSetCode;
|
Map<String, List<CardView>> forSetCode;
|
||||||
|
|
@ -1889,7 +1889,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
|
||||||
for (List<CardView> orphans : tracked.values()) {
|
for (List<CardView> orphans : tracked.values()) {
|
||||||
for (CardView orphan : orphans) {
|
for (CardView orphan : orphans) {
|
||||||
logger.info("Orphan when setting with layout: ");
|
logger.info("Orphan when setting with layout: ");
|
||||||
sortIntoGrid(orphan);
|
sortIntoGrid(orphan, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1984,7 +1984,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
|
||||||
menu.show(e.getComponent(), e.getX(), e.getY());
|
menu.show(e.getComponent(), e.getX(), e.getY());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addCardView(final CardView card, boolean duplicated) {
|
public void addCardView(final CardView card, final CardView duplicatedFromCard) {
|
||||||
allCards.add(card);
|
allCards.add(card);
|
||||||
|
|
||||||
// Update counts
|
// Update counts
|
||||||
|
|
@ -2019,8 +2019,8 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
|
||||||
cardContent.add(cardPanel);
|
cardContent.add(cardPanel);
|
||||||
cardViews.put(card.getId(), cardPanel);
|
cardViews.put(card.getId(), cardPanel);
|
||||||
|
|
||||||
if (duplicated) {
|
if (duplicatedFromCard != null) {
|
||||||
sortIntoGrid(card);
|
sortIntoGrid(card, duplicatedFromCard);
|
||||||
eventSource.fireEvent(card, ClientEventType.DECK_ADD_SPECIFIC_CARD);
|
eventSource.fireEvent(card, ClientEventType.DECK_ADD_SPECIFIC_CARD);
|
||||||
|
|
||||||
// clear grid from empty rows
|
// clear grid from empty rows
|
||||||
|
|
@ -2094,7 +2094,21 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
|
||||||
*
|
*
|
||||||
* @param newCard Card to add to the cardGrid array.
|
* @param newCard Card to add to the cardGrid array.
|
||||||
*/
|
*/
|
||||||
private void sortIntoGrid(CardView newCard) {
|
private void sortIntoGrid(CardView newCard, CardView duplicatedFromCard) {
|
||||||
|
// fast put duplicated card to the same place as original
|
||||||
|
if (duplicatedFromCard != null) {
|
||||||
|
for (List<List<CardView>> gridRow : cardGrid) {
|
||||||
|
for (List<CardView> gridStack : gridRow) {
|
||||||
|
for (int i = 0; i < gridStack.size(); i++) {
|
||||||
|
if (gridStack.get(i).equals(duplicatedFromCard)) {
|
||||||
|
gridStack.add(i, newCard);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// row 1 must exists
|
// row 1 must exists
|
||||||
if (cardGrid.isEmpty()) {
|
if (cardGrid.isEmpty()) {
|
||||||
cardGrid.add(0, new ArrayList<>());
|
cardGrid.add(0, new ArrayList<>());
|
||||||
|
|
@ -2336,7 +2350,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
|
||||||
} else {
|
} else {
|
||||||
String description = cardSort.getComparator().getCategoryName(stack.get(0));
|
String description = cardSort.getComparator().getCategoryName(stack.get(0));
|
||||||
DragCardGrid.updateCountLabel(countLabel, stack.size(), description);
|
DragCardGrid.updateCountLabel(countLabel, stack.size(), description);
|
||||||
countLabel.setLocation(GRID_PADDING + (cardWidth + GRID_PADDING) * colIndex, currentY - countLabelHeight);
|
countLabel.setLocation(getGridPadding() + (cardWidth + getGridPadding()) * colIndex, currentY - countLabelHeight);
|
||||||
countLabel.setSize(cardWidth, countLabelHeight);
|
countLabel.setSize(cardWidth, countLabelHeight);
|
||||||
countLabel.setVisible(true);
|
countLabel.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
@ -2348,7 +2362,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
|
||||||
for (int i = 0; i < stack.size(); ++i) {
|
for (int i = 0; i < stack.size(); ++i) {
|
||||||
CardView card = stack.get(i);
|
CardView card = stack.get(i);
|
||||||
MageCard view = cardViews.get(card.getId());
|
MageCard view = cardViews.get(card.getId());
|
||||||
int x = GRID_PADDING + (cardWidth + GRID_PADDING) * colIndex;
|
int x = getGridPadding() + (cardWidth + getGridPadding()) * colIndex;
|
||||||
int y = currentY + i * cardTopHeight;
|
int y = currentY + i * cardTopHeight;
|
||||||
view.setCardBounds(x, y, cardWidth, cardHeight);
|
view.setCardBounds(x, y, cardWidth, cardHeight);
|
||||||
cardContent.setLayer(view, layerIndex++);
|
cardContent.setLayer(view, layerIndex++);
|
||||||
|
|
@ -2356,14 +2370,18 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the max stack size for this row and the max width
|
// Update the max stack size for this row and the max width
|
||||||
maxWidth = Math.max(maxWidth, GRID_PADDING + (GRID_PADDING + cardWidth) * gridRow.size());
|
maxWidth = Math.max(maxWidth, getGridPadding() + (getGridPadding() + cardWidth) * gridRow.size());
|
||||||
maxStackSize.set(rowIndex, rowMaxStackSize);
|
maxStackSize.set(rowIndex, rowMaxStackSize);
|
||||||
currentY += (cardTopHeight * (rowMaxStackSize - 1) + cardHeight) + countLabelHeight;
|
currentY += (cardTopHeight * (rowMaxStackSize - 1) + cardHeight) + countLabelHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resize card container
|
// Resize card container
|
||||||
cardContent.setPreferredSize(new Dimension(maxWidth, currentY - countLabelHeight + GRID_PADDING));
|
cardContent.setPreferredSize(new Dimension(maxWidth, currentY - countLabelHeight + getGridPadding()));
|
||||||
//cardContent.setSize(maxWidth, currentY - COUNT_LABEL_HEIGHT + GRID_PADDING);
|
//cardContent.setSize(maxWidth, currentY - COUNT_LABEL_HEIGHT + getGridPadding());
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getGridPadding() {
|
||||||
|
return Math.max(GRID_PADDING, Math.round(cardSizeMod * GRID_PADDING * GUISizeHelper.dialogGuiScale));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getCountLabelHeight() {
|
public static int getCountLabelHeight() {
|
||||||
|
|
|
||||||
|
|
@ -265,7 +265,7 @@ public class ChatPanelBasic extends javax.swing.JPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
String cachedProfanityFilterValue = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAME_USE_PROFANITY_FILTER, "0");
|
String cachedProfanityFilterValue = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAME_USE_PROFANITY_FILTER, "0");
|
||||||
boolean isContainsSwearing = !containsSwearing(messageToTest, cachedProfanityFilterValue);
|
boolean isContainsSwearing = containsSwearing(messageToTest, cachedProfanityFilterValue);
|
||||||
boolean isUserInfoOrGameOrStatus = messageType == MessageType.USER_INFO || messageType == MessageType.GAME || messageType == MessageType.STATUS;
|
boolean isUserInfoOrGameOrStatus = messageType == MessageType.USER_INFO || messageType == MessageType.GAME || messageType == MessageType.STATUS;
|
||||||
if (isUserInfoOrGameOrStatus || cachedProfanityFilterValue.equals("0") || (!cachedProfanityFilterValue.equals("0") && !isContainsSwearing)) {
|
if (isUserInfoOrGameOrStatus || cachedProfanityFilterValue.equals("0") || (!cachedProfanityFilterValue.equals("0") && !isContainsSwearing)) {
|
||||||
if (username != null && !username.isEmpty()) {
|
if (username != null && !username.isEmpty()) {
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ public enum CombatManager {
|
||||||
UUID defenderId = group.getDefenderId();
|
UUID defenderId = group.getDefenderId();
|
||||||
if (defenderId != null) {
|
if (defenderId != null) {
|
||||||
// if attacker was blocked then use another arrow color
|
// if attacker was blocked then use another arrow color
|
||||||
Color attackColor = group.getBlockers().isEmpty() ? ARROW_COLOR_ATTACKER : ARROW_COLOR_BLOCKED_ATTACKER;
|
Color attackColor = group.isBlocked() ? ARROW_COLOR_BLOCKED_ATTACKER : ARROW_COLOR_ATTACKER;
|
||||||
parentPoint = getParentPoint(attackerCard);
|
parentPoint = getParentPoint(attackerCard);
|
||||||
PlayAreaPanel p = MageFrame.getGamePlayers(gameId).get(defenderId);
|
PlayAreaPanel p = MageFrame.getGamePlayers(gameId).get(defenderId);
|
||||||
if (p != null) {
|
if (p != null) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,343 @@
|
||||||
|
package mage.client.components;
|
||||||
|
|
||||||
|
import mage.MageObject;
|
||||||
|
import mage.cards.Card;
|
||||||
|
import mage.cards.decks.Deck;
|
||||||
|
import mage.client.util.GUISizeHelper;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inject bracket level inside validation panel
|
||||||
|
* See more details at <a href="https://mtg.wiki/page/Commander_Brackets">wiki</a>
|
||||||
|
* <p>
|
||||||
|
* Support:
|
||||||
|
* - [x] game changers
|
||||||
|
* - [ ] infinite combos
|
||||||
|
* - [x] mass land destruction
|
||||||
|
* - [x] extra turns
|
||||||
|
* - [x] tutors
|
||||||
|
*
|
||||||
|
* @author JayDi85
|
||||||
|
*/
|
||||||
|
public class BracketLegalityLabel extends LegalityLabel {
|
||||||
|
|
||||||
|
private static final String GROUP_GAME_CHANGES = "Game Changers";
|
||||||
|
private static final String GROUP_INFINITE_COMBOS = "Infinite Combos (unsupported)";
|
||||||
|
private static final String GROUP_MASS_LAND_DESTRUCTION = "Mass Land Destruction";
|
||||||
|
private static final String GROUP_EXTRA_TURN = "Extra Turns";
|
||||||
|
private static final String GROUP_TUTORS = "Tutors";
|
||||||
|
|
||||||
|
private final BracketLevel level;
|
||||||
|
|
||||||
|
private final List<String> foundGameChangers = new ArrayList<>();
|
||||||
|
private final List<String> foundInfiniteCombos = new ArrayList<>();
|
||||||
|
private final List<String> foundMassLandDestruction = new ArrayList<>();
|
||||||
|
private final List<String> foundExtraTurn = new ArrayList<>();
|
||||||
|
private final List<String> foundTutors = new ArrayList<>();
|
||||||
|
|
||||||
|
private final List<String> badCards = new ArrayList<>();
|
||||||
|
private final List<String> fullGameChanges = new ArrayList<>();
|
||||||
|
|
||||||
|
public enum BracketLevel {
|
||||||
|
BRACKET_1("Bracket 1"),
|
||||||
|
BRACKET_2_3("Bracket 2-3"),
|
||||||
|
BRACKET_4_5("Bracket 4-5");
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
BracketLevel(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public BracketLegalityLabel(BracketLevel level) {
|
||||||
|
super(level.toString(), null);
|
||||||
|
this.level = level;
|
||||||
|
setPreferredSize(DIM_PREFERRED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> selectCards() {
|
||||||
|
return new ArrayList<>(this.badCards);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateBracketLevel() {
|
||||||
|
this.badCards.clear();
|
||||||
|
switch (this.level) {
|
||||||
|
case BRACKET_1:
|
||||||
|
// No cards from the Game Changer list.
|
||||||
|
// No intentional two-card infinite combos.
|
||||||
|
// No mass land destruction.
|
||||||
|
// No extra turn cards.
|
||||||
|
// Tutors should be sparse.
|
||||||
|
this.badCards.addAll(this.foundGameChangers);
|
||||||
|
this.badCards.addAll(this.foundInfiniteCombos);
|
||||||
|
this.badCards.addAll(this.foundMassLandDestruction);
|
||||||
|
this.badCards.addAll(this.foundExtraTurn);
|
||||||
|
if (this.foundTutors.size() > 3) {
|
||||||
|
this.badCards.addAll(this.foundTutors);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BRACKET_2_3:
|
||||||
|
// 2
|
||||||
|
// No cards from the Game Changer list.
|
||||||
|
// No intentional two-card infinite combos.
|
||||||
|
// No mass land destruction.
|
||||||
|
// Extra turn cards should only appear in low quantities and should not be chained in succession or looped.
|
||||||
|
// Tutors should be sparse.
|
||||||
|
// 3
|
||||||
|
// Up to three (3) cards from the Game Changer list.
|
||||||
|
// No intentional early game two-card infinite combos.
|
||||||
|
// No mass land destruction.
|
||||||
|
// Extra turn cards should only appear in low quantities and should not be chained in succession or looped.
|
||||||
|
if (this.foundGameChangers.size() > 3) {
|
||||||
|
this.badCards.addAll(this.foundGameChangers);
|
||||||
|
}
|
||||||
|
this.badCards.addAll(this.foundInfiniteCombos);
|
||||||
|
this.badCards.addAll(this.foundMassLandDestruction);
|
||||||
|
if (this.foundExtraTurn.size() > 3) {
|
||||||
|
this.badCards.addAll(this.foundExtraTurn);
|
||||||
|
}
|
||||||
|
// this.badCards.addAll(this.foundTutors); // allow any amount
|
||||||
|
break;
|
||||||
|
case BRACKET_4_5:
|
||||||
|
// allow any cards
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unsupported level: " + this.level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validateDeck(Deck deck) {
|
||||||
|
collectAll(deck);
|
||||||
|
validateBracketLevel();
|
||||||
|
|
||||||
|
int infoFontSize = Math.round(GUISizeHelper.cardTooltipFont.getSize() * 0.6f);
|
||||||
|
|
||||||
|
// show all found cards in any use cases
|
||||||
|
Color showColor = this.badCards.isEmpty() ? COLOR_LEGAL : COLOR_NOT_LEGAL;
|
||||||
|
|
||||||
|
List<String> showInfo = new ArrayList<>();
|
||||||
|
if (this.badCards.isEmpty()) {
|
||||||
|
showInfo.add("<p>Deck is <span style='color:green;font-weight:bold;'>GOOD</span> for " + this.level + "</p>");
|
||||||
|
} else {
|
||||||
|
showInfo.add("<p>Deck is <span style='color:#BF544A;font-weight:bold;'>BAD</span> for " + this.level + "</p>");
|
||||||
|
showInfo.add("<p>(click here to select all bad cards)</p>");
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, List<String>> groups = new LinkedHashMap<>();
|
||||||
|
groups.put(GROUP_GAME_CHANGES, this.foundGameChangers);
|
||||||
|
groups.put(GROUP_INFINITE_COMBOS, this.foundInfiniteCombos);
|
||||||
|
groups.put(GROUP_MASS_LAND_DESTRUCTION, this.foundMassLandDestruction);
|
||||||
|
groups.put(GROUP_EXTRA_TURN, this.foundExtraTurn);
|
||||||
|
groups.put(GROUP_TUTORS, this.foundTutors);
|
||||||
|
groups.forEach((group, cards) -> {
|
||||||
|
showInfo.add("<br>");
|
||||||
|
showInfo.add("<br>");
|
||||||
|
showInfo.add("<span style='font-weight:bold;'>" + group + ": " + cards.size() + "</span>");
|
||||||
|
if (!cards.isEmpty()) {
|
||||||
|
showInfo.add("<ul style=\"font-size: " + infoFontSize + "px; width: " + TOOLTIP_TABLE_WIDTH + "px; padding-left: 10px; margin: 0;\">");
|
||||||
|
cards.forEach(s -> showInfo.add(String.format("<li style=\"margin-bottom: 2px;\">%s</li>", s)));
|
||||||
|
showInfo.add("</ul>");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
String showText = "<html><body>" + String.join("\n", showInfo) + "</body></html>";
|
||||||
|
showState(showColor, showText, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collectAll(Deck deck) {
|
||||||
|
collectGameChangers(deck);
|
||||||
|
collectInfiniteCombos(deck);
|
||||||
|
collectMassLandDestruction(deck);
|
||||||
|
collectExtraTurn(deck);
|
||||||
|
collectTutors(deck);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collectGameChangers(Deck deck) {
|
||||||
|
this.foundGameChangers.clear();
|
||||||
|
|
||||||
|
if (fullGameChanges.isEmpty()) {
|
||||||
|
// https://mtg.wiki/page/Game_Changers
|
||||||
|
// TODO: share list with AbstractCommander and edh power level
|
||||||
|
fullGameChanges.addAll(Arrays.asList(
|
||||||
|
"Ad Nauseam",
|
||||||
|
"Ancient Tomb",
|
||||||
|
"Aura Shards",
|
||||||
|
"Bolas's Citadel",
|
||||||
|
"Braids, Cabal Minion",
|
||||||
|
"Demonic Tutor",
|
||||||
|
"Drannith Magistrate",
|
||||||
|
"Chrome Mox",
|
||||||
|
"Coalition Victory",
|
||||||
|
"Consecrated Sphinx",
|
||||||
|
"Crop Rotation",
|
||||||
|
"Cyclonic Rift",
|
||||||
|
"Deflecting Swat",
|
||||||
|
"Enlightened Tutor",
|
||||||
|
"Expropriate",
|
||||||
|
"Field of the Dead",
|
||||||
|
"Fierce Guardianship",
|
||||||
|
"Food Chain",
|
||||||
|
"Force of Will",
|
||||||
|
"Gaea's Cradle",
|
||||||
|
"Gamble",
|
||||||
|
"Gifts Ungiven",
|
||||||
|
"Glacial Chasm",
|
||||||
|
"Grand Arbiter Augustin IV",
|
||||||
|
"Grim Monolith",
|
||||||
|
"Humility",
|
||||||
|
"Imperial Seal",
|
||||||
|
"Intuition",
|
||||||
|
"Jeska's Will",
|
||||||
|
"Jin-Gitaxias, Core Augur",
|
||||||
|
"Kinnan, Bonder Prodigy",
|
||||||
|
"Lion's Eye Diamond",
|
||||||
|
"Mana Vault",
|
||||||
|
"Mishra's Workshop",
|
||||||
|
"Mox Diamond",
|
||||||
|
"Mystical Tutor",
|
||||||
|
"Narset, Parter of Veils",
|
||||||
|
"Natural Order",
|
||||||
|
"Necropotence",
|
||||||
|
"Notion Thief",
|
||||||
|
"Rhystic Study",
|
||||||
|
"Opposition Agent",
|
||||||
|
"Orcish Bowmasters",
|
||||||
|
"Panoptic Mirror",
|
||||||
|
"Seedborn Muse",
|
||||||
|
"Serra's Sanctum",
|
||||||
|
"Smothering Tithe",
|
||||||
|
"Survival of the Fittest",
|
||||||
|
"Sway of the Stars",
|
||||||
|
"Teferi's Protection",
|
||||||
|
"Tergrid, God of Fright",
|
||||||
|
"Thassa's Oracle",
|
||||||
|
"The One Ring",
|
||||||
|
"The Tabernacle at Pendrell Vale",
|
||||||
|
"Underworld Breach",
|
||||||
|
"Urza, Lord High Artificer",
|
||||||
|
"Vampiric Tutor",
|
||||||
|
"Vorinclex, Voice of Hunger",
|
||||||
|
"Yuriko, the Tiger's Shadow",
|
||||||
|
"Winota, Joiner of Forces",
|
||||||
|
"Worldly Tutor"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream.concat(deck.getCards().stream(), deck.getSideboard().stream())
|
||||||
|
.map(MageObject::getName)
|
||||||
|
.filter(fullGameChanges::contains)
|
||||||
|
.sorted()
|
||||||
|
.forEach(this.foundGameChangers::add);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collectInfiniteCombos(Deck deck) {
|
||||||
|
// TODO: implement
|
||||||
|
this.foundInfiniteCombos.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collectMassLandDestruction(Deck deck) {
|
||||||
|
// https://mtg.wiki/page/Land_destruction
|
||||||
|
// https://draftsim.com/mtg-mass-land-destruction/
|
||||||
|
this.foundMassLandDestruction.clear();
|
||||||
|
Stream.concat(deck.getCards().stream(), deck.getSideboard().stream())
|
||||||
|
.filter(card -> card.getRules().stream()
|
||||||
|
.map(s -> s.toLowerCase(Locale.ENGLISH))
|
||||||
|
.anyMatch(s -> (s.contains("destroy") || s.contains("sacrifice"))
|
||||||
|
&& (s.contains("all") || s.contains("x target") || s.contains("{x} target"))
|
||||||
|
&& isTextContainsLandName(s)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.map(Card::getName)
|
||||||
|
.sorted()
|
||||||
|
.forEach(this.foundMassLandDestruction::add);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collectExtraTurn(Deck deck) {
|
||||||
|
this.foundExtraTurn.clear();
|
||||||
|
Stream.concat(deck.getCards().stream(), deck.getSideboard().stream())
|
||||||
|
.filter(card -> card.getRules().stream()
|
||||||
|
.map(s -> s.toLowerCase(Locale.ENGLISH))
|
||||||
|
.anyMatch(s -> s.contains("extra turn"))
|
||||||
|
)
|
||||||
|
.map(Card::getName)
|
||||||
|
.sorted()
|
||||||
|
.forEach(this.foundExtraTurn::add);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collectTutors(Deck deck) {
|
||||||
|
// edh power level uses search for land and non-land card, but bracket need only non-land cards searching
|
||||||
|
this.foundTutors.clear();
|
||||||
|
Stream.concat(deck.getCards().stream(), deck.getSideboard().stream())
|
||||||
|
.filter(card -> card.getRules().stream()
|
||||||
|
.map(s -> s.toLowerCase(Locale.ENGLISH))
|
||||||
|
.anyMatch(s -> s.contains("search your library") && !isTextContainsLandCard(s))
|
||||||
|
)
|
||||||
|
.map(Card::getName)
|
||||||
|
.sorted()
|
||||||
|
.forEach(this.foundTutors::add);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isTextContainsLandCard(String lowerText) {
|
||||||
|
// TODO: share code with AbstractCommander and edh power level
|
||||||
|
// TODO: add tests
|
||||||
|
return lowerText.contains("basic ")
|
||||||
|
|| lowerText.contains("plains card")
|
||||||
|
|| lowerText.contains("island card")
|
||||||
|
|| lowerText.contains("swamp card")
|
||||||
|
|| lowerText.contains("mountain card")
|
||||||
|
|| lowerText.contains("forest card");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isTextContainsLandName(String lowerText) {
|
||||||
|
// TODO: add tests to find all cards from https://mtg.wiki/page/Land_destruction
|
||||||
|
// TODO: add tests
|
||||||
|
/*
|
||||||
|
// mass land destruction
|
||||||
|
Ajani Vengeant
|
||||||
|
Armageddon
|
||||||
|
Avalanche
|
||||||
|
Bend or Break
|
||||||
|
Boil
|
||||||
|
Boiling Seas
|
||||||
|
Boom // Bust
|
||||||
|
Burning of Xinye
|
||||||
|
Catastrophe
|
||||||
|
Decree of Annihilation
|
||||||
|
Desolation Angel
|
||||||
|
Devastation
|
||||||
|
Fall of the Thran
|
||||||
|
From the Ashes
|
||||||
|
Impending Disaster
|
||||||
|
Jokulhaups
|
||||||
|
Myojin of Infinite Rage
|
||||||
|
Numot, the Devastator
|
||||||
|
Obliterate
|
||||||
|
Orcish Settlers
|
||||||
|
Ravages of War
|
||||||
|
Ruination
|
||||||
|
Rumbling Crescendo
|
||||||
|
Scorched Earth
|
||||||
|
Tsunami
|
||||||
|
Wake of Destruction
|
||||||
|
Wildfire
|
||||||
|
*/
|
||||||
|
return lowerText.contains("lands")
|
||||||
|
|| lowerText.contains("plains")
|
||||||
|
|| lowerText.contains("island")
|
||||||
|
|| lowerText.contains("swamp")
|
||||||
|
|| lowerText.contains("mountain")
|
||||||
|
|| lowerText.contains("forest");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
package mage.client.components;
|
||||||
|
|
||||||
|
import mage.cards.decks.Deck;
|
||||||
|
import mage.client.util.GUISizeHelper;
|
||||||
|
import mage.client.util.gui.GuiDisplayUtil;
|
||||||
|
import mage.deck.Commander;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inject power level info inside validation panel
|
||||||
|
*
|
||||||
|
* @author JayDi85
|
||||||
|
*/
|
||||||
|
public class EdhPowerLevelLegalityLabel extends LegalityLabel {
|
||||||
|
|
||||||
|
private final Commander commanderDeckType = new Commander();
|
||||||
|
private final List<String> foundPowerCards = new ArrayList<>();
|
||||||
|
|
||||||
|
public EdhPowerLevelLegalityLabel() {
|
||||||
|
super("EDH Power Level: ?", null);
|
||||||
|
setPreferredSize(DIM_PREFERRED_X3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> selectCards() {
|
||||||
|
// choose cards with power level
|
||||||
|
return this.foundPowerCards;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validateDeck(Deck deck) {
|
||||||
|
// find and save power level and card hints
|
||||||
|
|
||||||
|
List<String> foundInfo = new ArrayList<>();
|
||||||
|
int level = this.commanderDeckType.getEdhPowerLevel(deck, foundPowerCards, foundInfo);
|
||||||
|
this.setText(String.format("EDH Power Level: %d", level));
|
||||||
|
|
||||||
|
// sort by score "+5 from xxx"
|
||||||
|
Pattern pattern = Pattern.compile("\\+(\\d+)");
|
||||||
|
foundInfo.sort((o1, o2) -> {
|
||||||
|
Matcher matcher = pattern.matcher(o1);
|
||||||
|
int score1 = matcher.find() ? Integer.parseInt(matcher.group(1)) : 0;
|
||||||
|
matcher = pattern.matcher(o2);
|
||||||
|
int score2 = matcher.find() ? Integer.parseInt(matcher.group(1)) : 0;
|
||||||
|
if (score1 != score2) {
|
||||||
|
return Integer.compare(score2, score1);
|
||||||
|
}
|
||||||
|
return o1.compareTo(o2);
|
||||||
|
});
|
||||||
|
|
||||||
|
showStateInfo(formatCardsInfoTooltip(level, foundInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String formatCardsInfoTooltip(int level, List<String> foundInfo) {
|
||||||
|
// use 60% font for better and compatible list
|
||||||
|
int infoFontSize = Math.round(GUISizeHelper.cardTooltipFont.getSize() * 0.6f);
|
||||||
|
int maxLimit = 25;
|
||||||
|
String extraInfo = this.foundPowerCards.size() <= maxLimit ? "" : String.format("<li style=\"margin-bottom: 2px;\">and %d more cards</li>", this.foundPowerCards.size() - maxLimit);
|
||||||
|
return foundInfo.stream()
|
||||||
|
.limit(maxLimit)
|
||||||
|
.reduce("<html><body>"
|
||||||
|
+ "<p>EDH Power Level: <span style='color:#b8860b;font-weight:bold;'>" + level + "</span></p>"
|
||||||
|
+ "<br>"
|
||||||
|
+ "<u>Found <span style='font-weight:bold;'>" + this.foundPowerCards.size() + "</span> cards with power levels (click to select it)</u>"
|
||||||
|
+ "<br>"
|
||||||
|
+ "<ul style=\"font-size: " + infoFontSize + "px; width: " + TOOLTIP_TABLE_WIDTH + "px; padding-left: 10px; margin: 0;\">",
|
||||||
|
(str, info) -> str + String.format("<li style=\"margin-bottom: 2px;\">%s</li>", info), String::concat)
|
||||||
|
+ extraInfo
|
||||||
|
+ "</ul>"
|
||||||
|
+ "</body></html>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,17 +3,18 @@ package mage.client.components;
|
||||||
import mage.cards.decks.Deck;
|
import mage.cards.decks.Deck;
|
||||||
import mage.cards.decks.DeckValidator;
|
import mage.cards.decks.DeckValidator;
|
||||||
import mage.cards.decks.DeckValidatorError;
|
import mage.cards.decks.DeckValidatorError;
|
||||||
import mage.cards.decks.importer.DeckImporter;
|
|
||||||
import org.unbescape.html.HtmlEscape;
|
import org.unbescape.html.HtmlEscape;
|
||||||
import org.unbescape.html.HtmlEscapeLevel;
|
import org.unbescape.html.HtmlEscapeLevel;
|
||||||
import org.unbescape.html.HtmlEscapeType;
|
import org.unbescape.html.HtmlEscapeType;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.io.File;
|
import java.util.Collections;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Elandril
|
* @author Elandril, JayDi85
|
||||||
*/
|
*/
|
||||||
public class LegalityLabel extends JLabel {
|
public class LegalityLabel extends JLabel {
|
||||||
|
|
||||||
|
|
@ -25,8 +26,10 @@ public class LegalityLabel extends JLabel {
|
||||||
protected static final Dimension DIM_MINIMUM = new Dimension(75, 25);
|
protected static final Dimension DIM_MINIMUM = new Dimension(75, 25);
|
||||||
protected static final Dimension DIM_MAXIMUM = new Dimension(150, 75);
|
protected static final Dimension DIM_MAXIMUM = new Dimension(150, 75);
|
||||||
protected static final Dimension DIM_PREFERRED = new Dimension(75, 25);
|
protected static final Dimension DIM_PREFERRED = new Dimension(75, 25);
|
||||||
|
protected static final Dimension DIM_PREFERRED_X2 = new Dimension(DIM_PREFERRED.width * 2 + 5, 25);
|
||||||
|
protected static final Dimension DIM_PREFERRED_X3 = new Dimension(DIM_PREFERRED.width * 3 + 5 + 5, 25);
|
||||||
|
|
||||||
protected static final int TOOLTIP_TABLE_WIDTH = 300; // size of the label's tooltip
|
protected static final int TOOLTIP_TABLE_WIDTH = 400; // size of the label's tooltip
|
||||||
protected static final int TOOLTIP_MAX_ERRORS = 20; // max errors to show in tooltip
|
protected static final int TOOLTIP_MAX_ERRORS = 20; // max errors to show in tooltip
|
||||||
|
|
||||||
protected Deck currentDeck;
|
protected Deck currentDeck;
|
||||||
|
|
@ -92,19 +95,6 @@ public class LegalityLabel extends JLabel {
|
||||||
return button;
|
return button;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getErrorMessage() {
|
|
||||||
return errorMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DeckValidator getValidator() {
|
|
||||||
return validator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setValidator(DeckValidator validator) {
|
|
||||||
this.validator = validator;
|
|
||||||
revalidateDeck();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String escapeHtml(String string) {
|
protected String escapeHtml(String string) {
|
||||||
return HtmlEscape.escapeHtml(string, HtmlEscapeType.HTML4_NAMED_REFERENCES_DEFAULT_TO_HEXA, HtmlEscapeLevel.LEVEL_0_ONLY_MARKUP_SIGNIFICANT_EXCEPT_APOS);
|
return HtmlEscape.escapeHtml(string, HtmlEscapeType.HTML4_NAMED_REFERENCES_DEFAULT_TO_HEXA, HtmlEscapeLevel.LEVEL_0_ONLY_MARKUP_SIGNIFICANT_EXCEPT_APOS);
|
||||||
}
|
}
|
||||||
|
|
@ -146,25 +136,33 @@ public class LegalityLabel extends JLabel {
|
||||||
setBackground(color);
|
setBackground(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showState(Color color, String tooltip) {
|
public void showState(Color color, String tooltip, boolean useErrors) {
|
||||||
setBackground(color);
|
setBackground(color);
|
||||||
setToolTipText(appendErrorMessage(tooltip));
|
if (useErrors) {
|
||||||
|
setToolTipText(appendErrorMessage(tooltip));
|
||||||
|
} else {
|
||||||
|
setToolTipText(tooltip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showStateInfo(String tooltip) {
|
||||||
|
showState(COLOR_LEGAL, tooltip, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showStateUnknown(String tooltip) {
|
public void showStateUnknown(String tooltip) {
|
||||||
showState(COLOR_UNKNOWN, tooltip);
|
showState(COLOR_UNKNOWN, tooltip, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showStateLegal(String tooltip) {
|
public void showStateLegal(String tooltip) {
|
||||||
showState(COLOR_LEGAL, tooltip);
|
showState(COLOR_LEGAL, tooltip, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showStatePartlyLegal(String tooltip) {
|
public void showStatePartlyLegal(String tooltip) {
|
||||||
showState(COLOR_PARTLY_LEGAL, tooltip);
|
showState(COLOR_PARTLY_LEGAL, tooltip, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showStateNotLegal(String tooltip) {
|
public void showStateNotLegal(String tooltip) {
|
||||||
showState(COLOR_NOT_LEGAL, tooltip);
|
showState(COLOR_NOT_LEGAL, tooltip, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void validateDeck(Deck deck) {
|
public void validateDeck(Deck deck) {
|
||||||
|
|
@ -191,28 +189,13 @@ public class LegalityLabel extends JLabel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void validateDeck(File deckFile) {
|
public java.util.List<String> selectCards() {
|
||||||
deckFile = deckFile.getAbsoluteFile();
|
if (this.validator == null) {
|
||||||
if (!deckFile.exists()) {
|
return Collections.emptyList();
|
||||||
errorMessage = String.format("Deck file '%s' does not exist.", deckFile.getAbsolutePath());
|
|
||||||
showStateUnknown("<html><body><b>No Deck loaded!</b></body></html>");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
try {
|
return this.validator.getErrorsList().stream()
|
||||||
StringBuilder errorMessages = new StringBuilder();
|
.map(DeckValidatorError::getCardName)
|
||||||
Deck deck = Deck.load(DeckImporter.importDeckFromFile(deckFile.getAbsolutePath(), errorMessages, false), true, true);
|
.filter(Objects::nonNull)
|
||||||
errorMessage = errorMessages.toString();
|
.collect(Collectors.toList());
|
||||||
validateDeck(deck);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
errorMessage = String.format("Error importing deck from file '%s'!", deckFile.getAbsolutePath());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void revalidateDeck() {
|
|
||||||
validateDeck(currentDeck);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void validateDeck(String deckFile) {
|
|
||||||
validateDeck(new File(deckFile));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ public class MageTextArea extends MageEditorPane {
|
||||||
|
|
||||||
// prepare text format as header and details texts
|
// prepare text format as header and details texts
|
||||||
|
|
||||||
final StringBuilder buffer = new StringBuilder(512);
|
final StringBuilder buffer = new StringBuilder();
|
||||||
// Dialog is a java logical font family, so it should work on all systems
|
// Dialog is a java logical font family, so it should work on all systems
|
||||||
buffer.append("<body style='font-family:Dialog;font-size:");
|
buffer.append("<body style='font-family:Dialog;font-size:");
|
||||||
buffer.append(GUISizeHelper.gameFeedbackPanelMainMessageFontSize);
|
buffer.append(GUISizeHelper.gameFeedbackPanelMainMessageFontSize);
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,7 @@ public class AbilityPicker extends JXPanel implements MouseWheelListener {
|
||||||
setBackgroundPainter(mwPanelPainter);
|
setBackgroundPainter(mwPanelPainter);
|
||||||
|
|
||||||
title = new ColorPane();
|
title = new ColorPane();
|
||||||
title.setFont(new Font("Times New Roman", 1, sizeMod(15)));
|
title.setFont(new Font("Times New Roman", Font.BOLD, sizeMod(15)));
|
||||||
title.setEditable(false);
|
title.setEditable(false);
|
||||||
title.setFocusCycleRoot(false);
|
title.setFocusCycleRoot(false);
|
||||||
title.setOpaque(false);
|
title.setOpaque(false);
|
||||||
|
|
@ -186,11 +186,12 @@ public class AbilityPicker extends JXPanel implements MouseWheelListener {
|
||||||
rows.addMouseListener(new MouseAdapter() {
|
rows.addMouseListener(new MouseAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void mousePressed(MouseEvent evt) {
|
public void mousePressed(MouseEvent evt) {
|
||||||
if (SwingUtilities.isLeftMouseButton(evt)) {
|
if (SwingUtilities.isLeftMouseButton(evt) && !rows.isSelectionEmpty()) {
|
||||||
objectMouseClicked(evt);
|
objectMouseClicked(evt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
rows.setSelectedIndex(0);
|
rows.setSelectedIndex(0);
|
||||||
rows.setFont(new Font("Times New Roman", 1, sizeMod(17)));
|
rows.setFont(new Font("Times New Roman", 1, sizeMod(17)));
|
||||||
rows.setBorder(BorderFactory.createEmptyBorder());
|
rows.setBorder(BorderFactory.createEmptyBorder());
|
||||||
|
|
@ -233,18 +234,16 @@ public class AbilityPicker extends JXPanel implements MouseWheelListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseWheelMoved(MouseWheelEvent e) {
|
public void mouseWheelMoved(MouseWheelEvent e) {
|
||||||
int notches = e.getWheelRotation();
|
int direction = e.getWheelRotation() < 0 ? -1 : +1;
|
||||||
int index = rows.getSelectedIndex();
|
int index = rows.getSelectedIndex() + direction;
|
||||||
|
if (index < 0) {
|
||||||
if (notches < 0) {
|
index = 0;
|
||||||
if (index > 0) {
|
} else if (index >= choices.size()) {
|
||||||
rows.setSelectedIndex(index - 1);
|
index = choices.size() - 1;
|
||||||
rows.repaint();
|
|
||||||
}
|
|
||||||
} else if (index < choices.size() - 1) {
|
|
||||||
rows.setSelectedIndex(index + 1);
|
|
||||||
rows.repaint();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rows.setSelectedIndex(index);
|
||||||
|
rows.repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void objectMouseClicked(MouseEvent event) {
|
private void objectMouseClicked(MouseEvent event) {
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ public class DialogContainer extends JPanel {
|
||||||
case EMBLEMS: {
|
case EMBLEMS: {
|
||||||
backgroundColor = new Color(0, 0, 50, 110);
|
backgroundColor = new Color(0, 0, 50, 110);
|
||||||
alpha = 0;
|
alpha = 0;
|
||||||
ChoiceDialog dlg = new ChoiceDialog(params, "Command Zone (Commander, Emblems and Planes)");
|
ChoiceDialog dlg = new ChoiceDialog(params, "Command Zone (Commanders, Emblems, and Planes)");
|
||||||
add(dlg);
|
add(dlg);
|
||||||
dlg.setLocation(X_OFFSET + 10, Y_OFFSET + 10);
|
dlg.setLocation(X_OFFSET + 10, Y_OFFSET + 10);
|
||||||
dlg.updateSize(params.rect.width - 80, params.rect.height - 80);
|
dlg.updateSize(params.rect.width - 80, params.rect.height - 80);
|
||||||
|
|
|
||||||
|
|
@ -5,20 +5,21 @@ import mage.cards.decks.Deck;
|
||||||
import mage.cards.repository.CardCriteria;
|
import mage.cards.repository.CardCriteria;
|
||||||
import mage.cards.repository.CardInfo;
|
import mage.cards.repository.CardInfo;
|
||||||
import mage.cards.repository.ExpansionRepository;
|
import mage.cards.repository.ExpansionRepository;
|
||||||
import mage.client.dialog.PreferencesDialog;
|
|
||||||
import mage.client.util.sets.ConstructedFormats;
|
import mage.client.util.sets.ConstructedFormats;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.ColoredManaSymbol;
|
import mage.constants.ColoredManaSymbol;
|
||||||
import mage.constants.SuperType;
|
import mage.constants.SuperType;
|
||||||
import mage.util.RandomUtil;
|
import mage.util.RandomUtil;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates random card pool and builds a deck.
|
* Generates random card pool and builds a deck.
|
||||||
*
|
*
|
||||||
* @author nantuko
|
* @author nantuko, Simown, JayDi85
|
||||||
* @author Simown
|
|
||||||
*/
|
*/
|
||||||
public final class DeckGenerator {
|
public final class DeckGenerator {
|
||||||
|
|
||||||
|
|
@ -124,7 +125,7 @@ public final class DeckGenerator {
|
||||||
|
|
||||||
genPool = new DeckGeneratorPool(deckSize, genDialog.getCreaturePercentage(), genDialog.getNonCreaturePercentage(),
|
genPool = new DeckGeneratorPool(deckSize, genDialog.getCreaturePercentage(), genDialog.getNonCreaturePercentage(),
|
||||||
genDialog.getLandPercentage(), allowedColors, genDialog.isSingleton(), genDialog.isColorless(),
|
genDialog.getLandPercentage(), allowedColors, genDialog.isSingleton(), genDialog.isColorless(),
|
||||||
genDialog.isAdvanced(), genDialog.getDeckGeneratorCMC());
|
genDialog.isCommander(), genDialog.isAdvanced(), genDialog.getDeckGeneratorCMC());
|
||||||
|
|
||||||
final String[] sets = setsToUse.toArray(new String[setsToUse.size()]);
|
final String[] sets = setsToUse.toArray(new String[setsToUse.size()]);
|
||||||
|
|
||||||
|
|
@ -155,8 +156,8 @@ public final class DeckGenerator {
|
||||||
// Generate basic land cards
|
// Generate basic land cards
|
||||||
Map<String, List<CardInfo>> basicLands = DeckGeneratorPool.generateBasicLands(setsToUse);
|
Map<String, List<CardInfo>> basicLands = DeckGeneratorPool.generateBasicLands(setsToUse);
|
||||||
|
|
||||||
DeckGeneratorPool.generateSpells(creatureCriteria, genPool.getCreatureCount());
|
DeckGeneratorPool.generateSpells(creatureCriteria, genPool.getCreatureCount(), genPool.getCommandersCount());
|
||||||
DeckGeneratorPool.generateSpells(nonCreatureCriteria, genPool.getNonCreatureCount());
|
DeckGeneratorPool.generateSpells(nonCreatureCriteria, genPool.getNonCreatureCount(), 0);
|
||||||
DeckGeneratorPool.generateLands(genDialog.useNonBasicLand(), nonBasicLandCriteria, basicLands);
|
DeckGeneratorPool.generateLands(genDialog.useNonBasicLand(), nonBasicLandCriteria, basicLands);
|
||||||
|
|
||||||
// Reconstructs the final deck and adjusts for Math rounding and/or missing cards
|
// Reconstructs the final deck and adjusts for Math rounding and/or missing cards
|
||||||
|
|
|
||||||
|
|
@ -1,46 +1,76 @@
|
||||||
|
|
||||||
package mage.client.deck.generator;
|
package mage.client.deck.generator;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mana value distribution between cards in diff deck sizes
|
||||||
|
*/
|
||||||
public enum DeckGeneratorCMC {
|
public enum DeckGeneratorCMC {
|
||||||
|
|
||||||
Low(ImmutableList.<CMC>builder()
|
Low(
|
||||||
.add(new CMC(0, 2, 0.60f))
|
// 100
|
||||||
.add(new CMC(3, 4, 0.30f))
|
ImmutableList.<CMC>builder()
|
||||||
.add(new CMC(5, 6, 0.10f)).build(),
|
.add(new CMC(0, 2, 0.55f))
|
||||||
|
.add(new CMC(3, 4, 0.30f))
|
||||||
|
.add(new CMC(5, 6, 0.15f)).build(),
|
||||||
|
// 60
|
||||||
|
ImmutableList.<CMC>builder()
|
||||||
|
.add(new CMC(0, 2, 0.60f))
|
||||||
|
.add(new CMC(3, 4, 0.30f))
|
||||||
|
.add(new CMC(5, 6, 0.10f)).build(),
|
||||||
|
// 40
|
||||||
ImmutableList.<CMC>builder()
|
ImmutableList.<CMC>builder()
|
||||||
.add(new CMC(0, 2, 0.65f))
|
.add(new CMC(0, 2, 0.65f))
|
||||||
.add(new CMC(3, 4, 0.30f))
|
.add(new CMC(3, 4, 0.30f))
|
||||||
.add(new CMC(5, 5, 0.05f)).build()),
|
.add(new CMC(5, 5, 0.05f)).build()),
|
||||||
Default(ImmutableList.<CMC>builder()
|
Default(
|
||||||
.add(new CMC(0, 2, 0.20f))
|
// 100
|
||||||
.add(new CMC(3, 5, 0.50f))
|
ImmutableList.<CMC>builder()
|
||||||
.add(new CMC(6, 7, 0.25f))
|
.add(new CMC(0, 2, 0.15f))
|
||||||
.add(new CMC(8, 100, 0.05f)).build(),
|
.add(new CMC(3, 5, 0.50f))
|
||||||
|
.add(new CMC(6, 7, 0.30f))
|
||||||
|
.add(new CMC(8, 100, 0.05f)).build(),
|
||||||
|
// 60
|
||||||
|
ImmutableList.<CMC>builder()
|
||||||
|
.add(new CMC(0, 2, 0.20f))
|
||||||
|
.add(new CMC(3, 5, 0.50f))
|
||||||
|
.add(new CMC(6, 7, 0.25f))
|
||||||
|
.add(new CMC(8, 100, 0.05f)).build(),
|
||||||
|
// 40
|
||||||
ImmutableList.<CMC>builder()
|
ImmutableList.<CMC>builder()
|
||||||
.add(new CMC(0, 2, 0.30f))
|
.add(new CMC(0, 2, 0.30f))
|
||||||
.add(new CMC(3, 4, 0.45f))
|
.add(new CMC(3, 4, 0.45f))
|
||||||
.add(new CMC(5, 6, 0.20f))
|
.add(new CMC(5, 6, 0.20f))
|
||||||
.add(new CMC(7, 100, 0.05f)).build()),
|
.add(new CMC(7, 100, 0.05f)).build()),
|
||||||
|
|
||||||
High(ImmutableList.<CMC>builder().
|
High(
|
||||||
add(new CMC(0, 2, 0.05f))
|
// 100
|
||||||
.add(new CMC(3, 5, 0.35f))
|
ImmutableList.<CMC>builder().
|
||||||
.add(new CMC(6, 7, 0.40f))
|
add(new CMC(0, 2, 0.05f))
|
||||||
.add(new CMC(8, 100, 0.15f)).build(),
|
.add(new CMC(3, 5, 0.40f))
|
||||||
|
.add(new CMC(6, 7, 0.40f))
|
||||||
|
.add(new CMC(8, 100, 0.15f)).build(),
|
||||||
|
// 60
|
||||||
|
ImmutableList.<CMC>builder().
|
||||||
|
add(new CMC(0, 2, 0.05f))
|
||||||
|
.add(new CMC(3, 5, 0.35f))
|
||||||
|
.add(new CMC(6, 7, 0.40f))
|
||||||
|
.add(new CMC(8, 100, 0.15f)).build(),
|
||||||
|
// 40
|
||||||
ImmutableList.<CMC>builder().
|
ImmutableList.<CMC>builder().
|
||||||
add(new CMC(0, 2, 0.10f))
|
add(new CMC(0, 2, 0.10f))
|
||||||
.add(new CMC(3, 4, 0.30f))
|
.add(new CMC(3, 4, 0.30f))
|
||||||
.add(new CMC(5, 6, 0.45f))
|
.add(new CMC(5, 6, 0.45f))
|
||||||
.add(new CMC(7, 100, 0.15f)).build());
|
.add(new CMC(7, 100, 0.15f)).build());
|
||||||
|
|
||||||
|
private final List<CMC> poolCMCs100;
|
||||||
private final List<CMC> poolCMCs60;
|
private final List<CMC> poolCMCs60;
|
||||||
private final List<CMC> poolCMCs40;
|
private final List<CMC> poolCMCs40;
|
||||||
|
|
||||||
DeckGeneratorCMC(List<CMC> CMCs60, List<CMC> CMCs40) {
|
DeckGeneratorCMC(List<CMC> CMCs100, List<CMC> CMCs60, List<CMC> CMCs40) {
|
||||||
|
this.poolCMCs100 = CMCs100;
|
||||||
this.poolCMCs60 = CMCs60;
|
this.poolCMCs60 = CMCs60;
|
||||||
this.poolCMCs40 = CMCs40;
|
this.poolCMCs40 = CMCs40;
|
||||||
}
|
}
|
||||||
|
|
@ -53,6 +83,10 @@ public enum DeckGeneratorCMC {
|
||||||
return this.poolCMCs60;
|
return this.poolCMCs60;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<CMC> get100CardPoolCMC() {
|
||||||
|
return this.poolCMCs100;
|
||||||
|
}
|
||||||
|
|
||||||
static class CMC {
|
static class CMC {
|
||||||
public final int min;
|
public final int min;
|
||||||
public final int max;
|
public final int max;
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ public class DeckGeneratorDialog {
|
||||||
private static String selectedColors;
|
private static String selectedColors;
|
||||||
private static JComboBox cbSets, cbDeckSize, cbCMC;
|
private static JComboBox cbSets, cbDeckSize, cbCMC;
|
||||||
private static JButton btnGenerate, btnCancel, btnReset;
|
private static JButton btnGenerate, btnCancel, btnReset;
|
||||||
private static JCheckBox cArtifacts, cSingleton, cNonBasicLands, cColorless, cAdvanced;
|
private static JCheckBox cArtifacts, cSingleton, cNonBasicLands, cColorless, cAdvanced, cCommander;
|
||||||
private static JLabel averageCMCLabel;
|
private static JLabel averageCMCLabel;
|
||||||
private static SimpleDateFormat dateFormat;
|
private static SimpleDateFormat dateFormat;
|
||||||
private static RatioAdjustingSliderPanel adjustingSliderPanel;
|
private static RatioAdjustingSliderPanel adjustingSliderPanel;
|
||||||
|
|
@ -63,7 +63,7 @@ public class DeckGeneratorDialog {
|
||||||
c.insets = new Insets(5, 10, 0, 10);
|
c.insets = new Insets(5, 10, 0, 10);
|
||||||
c.gridx = 1;
|
c.gridx = 1;
|
||||||
c.gridy = 0;
|
c.gridy = 0;
|
||||||
String chosen = MageFrame.getPreferences().get("genDeckColor", "u");
|
String chosen = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_DECK_GENERATOR_COLORS, "u");
|
||||||
final ColorsChooser colorsChooser = new ColorsChooser(chosen);
|
final ColorsChooser colorsChooser = new ColorsChooser(chosen);
|
||||||
mainPanel.add(colorsChooser, c);
|
mainPanel.add(colorsChooser, c);
|
||||||
|
|
||||||
|
|
@ -135,7 +135,7 @@ public class DeckGeneratorDialog {
|
||||||
c.ipadx = 30;
|
c.ipadx = 30;
|
||||||
c.insets = new Insets(5, 10, 0, 10);
|
c.insets = new Insets(5, 10, 0, 10);
|
||||||
c.weightx = 0.90;
|
c.weightx = 0.90;
|
||||||
cbDeckSize = new JComboBox<>(new String[]{"40", "60"});
|
cbDeckSize = new JComboBox<>(new String[]{"40", "60", "100"});
|
||||||
cbDeckSize.setSelectedIndex(0);
|
cbDeckSize.setSelectedIndex(0);
|
||||||
cbDeckSize.setAlignmentX(Component.LEFT_ALIGNMENT);
|
cbDeckSize.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||||
mainPanel.add(cbDeckSize, c);
|
mainPanel.add(cbDeckSize, c);
|
||||||
|
|
@ -148,31 +148,33 @@ public class DeckGeneratorDialog {
|
||||||
JPanel jCheckBoxes = new JPanel(new FlowLayout(FlowLayout.LEFT));
|
JPanel jCheckBoxes = new JPanel(new FlowLayout(FlowLayout.LEFT));
|
||||||
|
|
||||||
// Singletons
|
// Singletons
|
||||||
|
boolean commanderEnabled = Boolean.parseBoolean(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_DECK_GENERATOR_COMMANDER, "false"));
|
||||||
cSingleton = new JCheckBox("Singleton", false);
|
cSingleton = new JCheckBox("Singleton", false);
|
||||||
cSingleton.setToolTipText("Allow only a single copy of each non-land card in your deck.");
|
cSingleton.setToolTipText("Allow only a single copy of each non-land card in your deck.");
|
||||||
String singletonEnabled = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_DECK_GENERATOR_SINGLETON, "false");
|
String singletonEnabled = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_DECK_GENERATOR_SINGLETON, "false");
|
||||||
cSingleton.setSelected(Boolean.valueOf(singletonEnabled));
|
cSingleton.setSelected(Boolean.parseBoolean(singletonEnabled));
|
||||||
jCheckBoxes.add(cSingleton);
|
jCheckBoxes.add(cSingleton);
|
||||||
|
cSingleton.setEnabled(!commanderEnabled);
|
||||||
|
|
||||||
// Artifacts
|
// Artifacts
|
||||||
cArtifacts = new JCheckBox("Artifacts", false);
|
cArtifacts = new JCheckBox("Artifacts", false);
|
||||||
cArtifacts.setToolTipText("Use artifacts and artifact creatures in your deck.");
|
cArtifacts.setToolTipText("Use artifacts and artifact creatures in your deck.");
|
||||||
String artifactEnabled = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_DECK_GENERATOR_ARTIFACTS, "false");
|
String artifactEnabled = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_DECK_GENERATOR_ARTIFACTS, "false");
|
||||||
cArtifacts.setSelected(Boolean.valueOf(artifactEnabled));
|
cArtifacts.setSelected(Boolean.parseBoolean(artifactEnabled));
|
||||||
jCheckBoxes.add(cArtifacts);
|
jCheckBoxes.add(cArtifacts);
|
||||||
|
|
||||||
// Non-basic lands
|
// Non-basic lands
|
||||||
cNonBasicLands = new JCheckBox("Non-basic Lands", false);
|
cNonBasicLands = new JCheckBox("Non-basic Lands", false);
|
||||||
cNonBasicLands.setToolTipText("Use non-basic lands in your deck (if applicable).");
|
cNonBasicLands.setToolTipText("Use non-basic lands in your deck (if applicable).");
|
||||||
String nonBasicEnabled = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_DECK_GENERATOR_NON_BASIC_LANDS, "false");
|
String nonBasicEnabled = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_DECK_GENERATOR_NON_BASIC_LANDS, "false");
|
||||||
cNonBasicLands.setSelected(Boolean.valueOf(nonBasicEnabled));
|
cNonBasicLands.setSelected(Boolean.parseBoolean(nonBasicEnabled));
|
||||||
jCheckBoxes.add(cNonBasicLands);
|
jCheckBoxes.add(cNonBasicLands);
|
||||||
|
|
||||||
// Colorless mana
|
// Colorless mana
|
||||||
cColorless = new JCheckBox("Colorless mana", false);
|
cColorless = new JCheckBox("Colorless mana", false);
|
||||||
cColorless.setToolTipText("Allow cards with colorless mana cost.");
|
cColorless.setToolTipText("Allow cards with colorless mana cost.");
|
||||||
String colorlessEnabled = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_DECK_GENERATOR_COLORLESS, "false");
|
String colorlessEnabled = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_DECK_GENERATOR_COLORLESS, "false");
|
||||||
cColorless.setSelected(Boolean.valueOf(colorlessEnabled));
|
cColorless.setSelected(Boolean.parseBoolean(colorlessEnabled));
|
||||||
jCheckBoxes.add(cColorless);
|
jCheckBoxes.add(cColorless);
|
||||||
c.ipadx = 0;
|
c.ipadx = 0;
|
||||||
c.gridx = 0;
|
c.gridx = 0;
|
||||||
|
|
@ -181,12 +183,28 @@ public class DeckGeneratorDialog {
|
||||||
c.gridwidth = 3;
|
c.gridwidth = 3;
|
||||||
mainPanel.add(jCheckBoxes, c);
|
mainPanel.add(jCheckBoxes, c);
|
||||||
|
|
||||||
|
// Commander
|
||||||
|
cCommander = new JCheckBox("Commander", false);
|
||||||
|
cCommander.setToolTipText("Add legendary creature as commander");
|
||||||
|
cCommander.setSelected(commanderEnabled);
|
||||||
|
jCheckBoxes.add(cCommander);
|
||||||
|
c.ipadx = 0;
|
||||||
|
c.gridx = 0;
|
||||||
|
c.gridy = 3;
|
||||||
|
c.weightx = 1;
|
||||||
|
c.gridwidth = 3;
|
||||||
|
mainPanel.add(jCheckBoxes, c);
|
||||||
|
cCommander.addItemListener(itemEvent -> {
|
||||||
|
// commander require singletone mode
|
||||||
|
cSingleton.setEnabled(!cCommander.isSelected());
|
||||||
|
});
|
||||||
|
|
||||||
// Create the advanced configuration panel
|
// Create the advanced configuration panel
|
||||||
JPanel advancedPanel = createAdvancedPanel();
|
JPanel advancedPanel = createAdvancedPanel();
|
||||||
|
|
||||||
// Advanced checkbox (enable/disable advanced configuration)
|
// Advanced checkbox (enable/disable advanced configuration)
|
||||||
cAdvanced = new JCheckBox("Advanced");
|
cAdvanced = new JCheckBox("Customize distribution");
|
||||||
cAdvanced.setToolTipText("Enable advanced configuration options");
|
cAdvanced.setToolTipText("Customize cards distribution due mana values and types");
|
||||||
cAdvanced.addItemListener(itemEvent -> {
|
cAdvanced.addItemListener(itemEvent -> {
|
||||||
boolean enable = cAdvanced.isSelected();
|
boolean enable = cAdvanced.isSelected();
|
||||||
enableAdvancedPanel(enable);
|
enableAdvancedPanel(enable);
|
||||||
|
|
@ -194,7 +212,7 @@ public class DeckGeneratorDialog {
|
||||||
|
|
||||||
// Advanced Checkbox
|
// Advanced Checkbox
|
||||||
String advancedSavedValue = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_DECK_GENERATOR_ADVANCED, "false");
|
String advancedSavedValue = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_DECK_GENERATOR_ADVANCED, "false");
|
||||||
boolean advancedEnabled = Boolean.valueOf(advancedSavedValue);
|
boolean advancedEnabled = Boolean.parseBoolean(advancedSavedValue);
|
||||||
enableAdvancedPanel(advancedEnabled);
|
enableAdvancedPanel(advancedEnabled);
|
||||||
cAdvanced.setSelected(advancedEnabled);
|
cAdvanced.setSelected(advancedEnabled);
|
||||||
c.gridy = 4;
|
c.gridy = 4;
|
||||||
|
|
@ -212,7 +230,7 @@ public class DeckGeneratorDialog {
|
||||||
colorsChooser.setEnabled(false);
|
colorsChooser.setEnabled(false);
|
||||||
selectedColors = (String) colorsChooser.getSelectedItem();
|
selectedColors = (String) colorsChooser.getSelectedItem();
|
||||||
dlg.setVisible(false);
|
dlg.setVisible(false);
|
||||||
MageFrame.getPreferences().put("genDeckColor", selectedColors);
|
PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_DECK_GENERATOR_COLORS, selectedColors);
|
||||||
});
|
});
|
||||||
btnCancel = new JButton("Cancel");
|
btnCancel = new JButton("Cancel");
|
||||||
btnCancel.addActionListener(e -> {
|
btnCancel.addActionListener(e -> {
|
||||||
|
|
@ -297,7 +315,7 @@ public class DeckGeneratorDialog {
|
||||||
c.gridwidth = 1;
|
c.gridwidth = 1;
|
||||||
c.gridy = 2;
|
c.gridy = 2;
|
||||||
btnReset = new JButton("Reset");
|
btnReset = new JButton("Reset");
|
||||||
btnReset.setToolTipText("Reset advanced dialog to default values");
|
btnReset.setToolTipText("Reset custom cards distribution to default values");
|
||||||
btnReset.addActionListener(actionEvent -> {
|
btnReset.addActionListener(actionEvent -> {
|
||||||
cbCMC.setSelectedItem(DeckGeneratorCMC.Default);
|
cbCMC.setSelectedItem(DeckGeneratorCMC.Default);
|
||||||
adjustingSliderPanel.resetValues();
|
adjustingSliderPanel.resetValues();
|
||||||
|
|
@ -374,6 +392,12 @@ public class DeckGeneratorDialog {
|
||||||
return selected;
|
return selected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isCommander() {
|
||||||
|
boolean selected = cCommander.isSelected();
|
||||||
|
PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_DECK_GENERATOR_COMMANDER, Boolean.toString(selected));
|
||||||
|
return selected;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isAdvanced() {
|
public boolean isAdvanced() {
|
||||||
boolean selected = cAdvanced.isSelected();
|
boolean selected = cAdvanced.isSelected();
|
||||||
PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_DECK_GENERATOR_ADVANCED, Boolean.toString(selected));
|
PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_DECK_GENERATOR_ADVANCED, Boolean.toString(selected));
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
package mage.client.deck.generator;
|
package mage.client.deck.generator;
|
||||||
|
|
||||||
|
import mage.ObjectColor;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.cards.decks.Deck;
|
import mage.cards.decks.Deck;
|
||||||
|
|
@ -11,16 +11,17 @@ import mage.constants.ColoredManaSymbol;
|
||||||
import mage.constants.Rarity;
|
import mage.constants.Rarity;
|
||||||
import mage.util.RandomUtil;
|
import mage.util.RandomUtil;
|
||||||
import mage.util.TournamentUtil;
|
import mage.util.TournamentUtil;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* @author Simown, JayDi85
|
||||||
* @author Simown
|
|
||||||
*/
|
*/
|
||||||
public class DeckGeneratorPool
|
public class DeckGeneratorPool {
|
||||||
{
|
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(DeckGeneratorPool.class);
|
||||||
|
|
||||||
public static final int DEFAULT_CREATURE_PERCENTAGE = 38;
|
public static final int DEFAULT_CREATURE_PERCENTAGE = 38;
|
||||||
public static final int DEFAULT_NON_CREATURE_PERCENTAGE = 21;
|
public static final int DEFAULT_NON_CREATURE_PERCENTAGE = 21;
|
||||||
|
|
@ -31,6 +32,7 @@ public class DeckGeneratorPool
|
||||||
private final List<DeckGeneratorCMC.CMC> poolCMCs;
|
private final List<DeckGeneratorCMC.CMC> poolCMCs;
|
||||||
private final int creatureCount;
|
private final int creatureCount;
|
||||||
private final int nonCreatureCount;
|
private final int nonCreatureCount;
|
||||||
|
private final int commandersCount;
|
||||||
private final int landCount;
|
private final int landCount;
|
||||||
private final boolean isSingleton;
|
private final boolean isSingleton;
|
||||||
private final int deckSize;
|
private final int deckSize;
|
||||||
|
|
@ -48,65 +50,83 @@ public class DeckGeneratorPool
|
||||||
/**
|
/**
|
||||||
* Creates a card pool with specified criterea used when generating a deck.
|
* Creates a card pool with specified criterea used when generating a deck.
|
||||||
*
|
*
|
||||||
* @param deckSize the size of the complete deck
|
* @param deckSize the size of the complete deck
|
||||||
* @param creaturePercentage what percentage of creatures to use when generating the deck.
|
* @param creaturePercentage what percentage of creatures to use when generating the deck.
|
||||||
* @param nonCreaturePercentage percentage of non-creatures to use when generating the deck.
|
* @param nonCreaturePercentage percentage of non-creatures to use when generating the deck.
|
||||||
* @param landPercentage percentage of lands to use when generating the deck.
|
* @param landPercentage percentage of lands to use when generating the deck.
|
||||||
* @param allowedColors which card colors are allowed in the generated deck.
|
* @param allowedColors which card colors are allowed in the generated deck.
|
||||||
* @param isSingleton if the deck only has 1 copy of each non-land card.
|
* @param isSingleton if the deck only has 1 copy of each non-land card.
|
||||||
* @param colorlessAllowed if colourless mana symbols are allowed in costs in the deck.
|
* @param colorlessAllowed if colourless mana symbols are allowed in costs in the deck.
|
||||||
* @param isAdvanced if the user has provided advanced options to generate the deck.
|
* @param isAdvanced if the user has provided advanced options to generate the deck.
|
||||||
* @param deckGeneratorCMC the CMC curve to use for this deck
|
* @param isCommander reserve commander card
|
||||||
|
* @param deckGeneratorCMC the CMC curve to use for this deck
|
||||||
*/
|
*/
|
||||||
public DeckGeneratorPool(final int deckSize, final int creaturePercentage, final int nonCreaturePercentage, final int landPercentage,
|
public DeckGeneratorPool(final int deckSize, final int creaturePercentage, final int nonCreaturePercentage, final int landPercentage,
|
||||||
final List<ColoredManaSymbol> allowedColors, boolean isSingleton, boolean colorlessAllowed, boolean isAdvanced, DeckGeneratorCMC deckGeneratorCMC)
|
final List<ColoredManaSymbol> allowedColors, boolean isSingleton, boolean colorlessAllowed, boolean isCommander,
|
||||||
{
|
boolean isAdvanced, DeckGeneratorCMC deckGeneratorCMC) {
|
||||||
this.deckSize = deckSize;
|
this.deckSize = deckSize;
|
||||||
this.allowedColors = allowedColors;
|
this.allowedColors = allowedColors;
|
||||||
this.isSingleton = isSingleton;
|
|
||||||
this.colorlessAllowed = colorlessAllowed;
|
this.colorlessAllowed = colorlessAllowed;
|
||||||
|
this.commandersCount = isCommander ? 1 : 0;
|
||||||
|
this.isSingleton = isSingleton || isCommander; // commander must use singleton mode only
|
||||||
|
|
||||||
this.deck = new Deck();
|
this.deck = new Deck();
|
||||||
|
|
||||||
// Advanced (CMC Slider panel and curve drop-down in the dialog)
|
// Advanced (CMC Slider panel and curve drop-down in the dialog)
|
||||||
if(isAdvanced) {
|
if (isAdvanced) {
|
||||||
this.creatureCount = (int)Math.ceil((deckSize / 100.0) * creaturePercentage);
|
this.creatureCount = (int) Math.ceil((deckSize / 100.0) * creaturePercentage);
|
||||||
this.nonCreatureCount = (int)Math.ceil((deckSize / 100.0)* nonCreaturePercentage);
|
this.nonCreatureCount = (int) Math.ceil((deckSize / 100.0) * nonCreaturePercentage);
|
||||||
this.landCount = (int)Math.ceil((deckSize / 100.0)* landPercentage);
|
this.landCount = (int) Math.ceil((deckSize / 100.0) * landPercentage);
|
||||||
if(this.deckSize == 60) {
|
switch (this.deckSize) {
|
||||||
this.poolCMCs = deckGeneratorCMC.get60CardPoolCMC();
|
case 100:
|
||||||
} else {
|
this.poolCMCs = deckGeneratorCMC.get100CardPoolCMC();
|
||||||
this.poolCMCs = deckGeneratorCMC.get40CardPoolCMC();
|
break;
|
||||||
|
case 60:
|
||||||
|
this.poolCMCs = deckGeneratorCMC.get60CardPoolCMC();
|
||||||
|
break;
|
||||||
|
case 40:
|
||||||
|
this.poolCMCs = deckGeneratorCMC.get40CardPoolCMC();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unsupported deck size: " + this.deckSize);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Ignore the advanced group, just use defaults
|
// Ignore the advanced group, just use defaults
|
||||||
this.creatureCount = (int)Math.ceil((deckSize / 100.0) * DEFAULT_CREATURE_PERCENTAGE);
|
this.creatureCount = (int) Math.ceil((deckSize / 100.0) * DEFAULT_CREATURE_PERCENTAGE);
|
||||||
this.nonCreatureCount = (int)Math.ceil((deckSize / 100.0) * DEFAULT_NON_CREATURE_PERCENTAGE);
|
this.nonCreatureCount = (int) Math.ceil((deckSize / 100.0) * DEFAULT_NON_CREATURE_PERCENTAGE);
|
||||||
this.landCount = (int)Math.ceil((deckSize / 100.0) * DEFAULT_LAND_PERCENTAGE);
|
this.landCount = (int) Math.ceil((deckSize / 100.0) * DEFAULT_LAND_PERCENTAGE);
|
||||||
if(this.deckSize == 60) {
|
switch (this.deckSize) {
|
||||||
this.poolCMCs = DeckGeneratorCMC.Default.get60CardPoolCMC();
|
case 100:
|
||||||
} else {
|
this.poolCMCs = DeckGeneratorCMC.Default.get100CardPoolCMC();
|
||||||
this.poolCMCs = DeckGeneratorCMC.Default.get40CardPoolCMC();
|
break;
|
||||||
|
case 60:
|
||||||
|
this.poolCMCs = DeckGeneratorCMC.Default.get60CardPoolCMC();
|
||||||
|
break;
|
||||||
|
case 40:
|
||||||
|
this.poolCMCs = DeckGeneratorCMC.Default.get40CardPoolCMC();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unsupported deck size: " + this.deckSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(allowedColors.size() == 1) {
|
if (allowedColors.size() == 1) {
|
||||||
monoColored = true;
|
monoColored = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adjusts the number of spell cards that should be in a converted mana cost (CMC) range, given the amount of cards total.
|
* Adjusts the number of spell cards that should be in a converted mana cost (CMC) range, given the amount of cards total.
|
||||||
|
*
|
||||||
* @param cardsCount the number of total cards.
|
* @param cardsCount the number of total cards.
|
||||||
* @return a list of CMC ranges, with the amount of cards for each CMC range
|
* @return a list of CMC ranges, with the amount of cards for each CMC range
|
||||||
*/
|
*/
|
||||||
public List<DeckGeneratorCMC.CMC> getCMCsForSpellCount(int cardsCount) {
|
public List<DeckGeneratorCMC.CMC> getCMCsForSpellCount(int cardsCount) {
|
||||||
List<DeckGeneratorCMC.CMC> adjustedCMCs = new ArrayList<>(this.poolCMCs);
|
List<DeckGeneratorCMC.CMC> adjustedCMCs = new ArrayList<>(this.poolCMCs);
|
||||||
// For each CMC calculate how many spell cards are needed, given the total amount of cards
|
// For each CMC calculate how many spell cards are needed, given the total amount of cards
|
||||||
for(DeckGeneratorCMC.CMC deckCMC : adjustedCMCs) {
|
for (DeckGeneratorCMC.CMC deckCMC : adjustedCMCs) {
|
||||||
deckCMC.setAmount((int)Math.ceil(deckCMC.percentage * cardsCount));
|
deckCMC.setAmount((int) Math.ceil(deckCMC.percentage * cardsCount));
|
||||||
}
|
}
|
||||||
return adjustedCMCs;
|
return adjustedCMCs;
|
||||||
}
|
}
|
||||||
|
|
@ -115,15 +135,15 @@ public class DeckGeneratorPool
|
||||||
* Verifies if the spell card supplied is valid for this pool of cards.
|
* Verifies if the spell card supplied is valid for this pool of cards.
|
||||||
* Checks that there isn't too many copies of this card in the deck.
|
* Checks that there isn't too many copies of this card in the deck.
|
||||||
* Checks that the card fits the chosen colors for this pool.
|
* Checks that the card fits the chosen colors for this pool.
|
||||||
|
*
|
||||||
* @param card the spell card
|
* @param card the spell card
|
||||||
* @return if the spell card is valid for this pool.
|
* @return if the spell card is valid for this pool.
|
||||||
*/
|
*/
|
||||||
public boolean isValidSpellCard(Card card)
|
public boolean isValidSpellCard(Card card) {
|
||||||
{
|
|
||||||
int cardCount = getCardCount((card.getName()));
|
int cardCount = getCardCount((card.getName()));
|
||||||
// Check it hasn't already got the maximum number of copies in a deck
|
// Check it hasn't already got the maximum number of copies in a deck
|
||||||
if(cardCount < (isSingleton ? 1 : 4)) {
|
if (cardCount < (isSingleton ? 1 : 4)) {
|
||||||
if(cardFitsChosenColors(card)) {
|
if (cardFitsChosenColors(card)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -132,11 +152,11 @@ public class DeckGeneratorPool
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verifies if the non-basic land card supplied is valid for this pool of cards.
|
* Verifies if the non-basic land card supplied is valid for this pool of cards.
|
||||||
|
*
|
||||||
* @param card the non-basic land card
|
* @param card the non-basic land card
|
||||||
* @return if the land card generates the allowed colors for this pool.
|
* @return if the land card generates the allowed colors for this pool.
|
||||||
*/
|
*/
|
||||||
public boolean isValidLandCard(Card card)
|
public boolean isValidLandCard(Card card) {
|
||||||
{
|
|
||||||
int cardCount = getCardCount((card.getName()));
|
int cardCount = getCardCount((card.getName()));
|
||||||
// No need to check if the land is valid for the colors chosen
|
// No need to check if the land is valid for the colors chosen
|
||||||
// They are all filtered before searching for lands to include in the deck.
|
// They are all filtered before searching for lands to include in the deck.
|
||||||
|
|
@ -146,60 +166,56 @@ public class DeckGeneratorPool
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a card to the pool and updates the count of this card.
|
* Adds a card to the pool and updates the count of this card.
|
||||||
|
*
|
||||||
* @param card the card to add.
|
* @param card the card to add.
|
||||||
*/
|
*/
|
||||||
public void addCard(Card card)
|
public void addCard(Card card) {
|
||||||
{
|
|
||||||
Object cnt = cardCounts.get((card.getName()));
|
Object cnt = cardCounts.get((card.getName()));
|
||||||
if(cnt == null)
|
if (cnt == null)
|
||||||
cardCounts.put(card.getName(), 0);
|
cardCounts.put(card.getName(), 0);
|
||||||
int existingCount = cardCounts.get((card.getName()));
|
int existingCount = cardCounts.get((card.getName()));
|
||||||
cardCounts.put(card.getName(), existingCount+1);
|
cardCounts.put(card.getName(), existingCount + 1);
|
||||||
deckCards.add(card);
|
deckCards.add(card);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void clearCards(boolean isClearReserve) {
|
||||||
|
cardCounts.clear();
|
||||||
|
deckCards.clear();
|
||||||
|
if (isClearReserve) {
|
||||||
|
reserveSpells.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a card to the reserve pool.
|
* Adds a card to the reserve pool.
|
||||||
* Reserve pool is used when the deck generation fails to build a complete deck, or
|
* Reserve pool is used when the deck generation fails to build a complete deck, or
|
||||||
* a partially complete deck (e.g. if there are no cards found that match a CMC)
|
* a partially complete deck (e.g. if there are no cards found that match a CMC)
|
||||||
* @param card the card to add
|
*
|
||||||
|
* @param card the card to add
|
||||||
* @param cardCMC the converted mana cost of the card
|
* @param cardCMC the converted mana cost of the card
|
||||||
*/
|
*/
|
||||||
public boolean tryAddReserve(Card card, int cardCMC) {
|
public boolean tryAddReserve(Card card, int cardCMC) {
|
||||||
// Only cards with CMC < 7 and don't already exist in the deck
|
// Only cards with CMC < 7 and don't already exist in the deck
|
||||||
// can be added to our reserve pool as not to overwhelm the curve
|
// can be added to our reserve pool as not to overwhelm the curve
|
||||||
// with high CMC cards and duplicates.
|
// with high CMC cards and duplicates.
|
||||||
if(cardCMC < 7 && getCardCount(card.getName()) == 0) {
|
if (cardCMC < 7 && getCardCount(card.getName()) == 0) {
|
||||||
this.reserveSpells.add(card);
|
this.reserveSpells.add(card);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the mana symbols in the card all match the allowed colors for this pool.
|
|
||||||
* @param card the spell card to check.
|
|
||||||
* @return if all the mana symbols fit the chosen colors.
|
|
||||||
*/
|
|
||||||
private boolean cardFitsChosenColors(Card card) {
|
private boolean cardFitsChosenColors(Card card) {
|
||||||
for (String symbol : card.getManaCostSymbols()) {
|
Set<String> needColors = allowedColors.stream().map(ColoredManaSymbol::toString).collect(Collectors.toSet());
|
||||||
boolean found = false;
|
List<ObjectColor> cardColors = card.getColorIdentity().getColors();
|
||||||
symbol = symbol.replace("{", "").replace("}", "");
|
for (ObjectColor cardColor : cardColors) {
|
||||||
if (isColoredManaSymbol(symbol)) {
|
if (!needColors.contains(cardColor.toString())) {
|
||||||
for (ColoredManaSymbol allowed : allowedColors) {
|
|
||||||
if (symbol.contains(allowed.toString())) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (symbol.equals("C") && !colorlessAllowed) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (cardColors.isEmpty() && !colorlessAllowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -208,6 +224,7 @@ public class DeckGeneratorPool
|
||||||
* Calculates the percentage of colored mana symbols over all spell cards in the deck.
|
* Calculates the percentage of colored mana symbols over all spell cards in the deck.
|
||||||
* Used to balance the generation of basic lands so the amount of lands matches the
|
* Used to balance the generation of basic lands so the amount of lands matches the
|
||||||
* cards mana costs.
|
* cards mana costs.
|
||||||
|
*
|
||||||
* @return a list of colored mana symbols and the percentage of symbols seen in cards mana costs.
|
* @return a list of colored mana symbols and the percentage of symbols seen in cards mana costs.
|
||||||
*/
|
*/
|
||||||
public Map<String, Double> calculateSpellColorPercentages() {
|
public Map<String, Double> calculateSpellColorPercentages() {
|
||||||
|
|
@ -221,14 +238,14 @@ public class DeckGeneratorPool
|
||||||
int totalCount = 0;
|
int totalCount = 0;
|
||||||
|
|
||||||
List<Card> fixedSpells = getFixedSpells();
|
List<Card> fixedSpells = getFixedSpells();
|
||||||
for(Card spell: fixedSpells) {
|
for (Card spell : fixedSpells) {
|
||||||
for (String symbol : spell.getManaCostSymbols()) {
|
for (String symbol : spell.getManaCostSymbols()) {
|
||||||
symbol = symbol.replace("{", "").replace("}", "");
|
symbol = symbol.replace("{", "").replace("}", "");
|
||||||
if (isColoredManaSymbol(symbol)) {
|
if (isColoredManaSymbol(symbol)) {
|
||||||
for (ColoredManaSymbol allowed : allowedColors) {
|
for (ColoredManaSymbol allowed : allowedColors) {
|
||||||
if (symbol.contains(allowed.toString())) {
|
if (symbol.contains(allowed.toString())) {
|
||||||
int cnt = colorCount.get(allowed.toString());
|
int cnt = colorCount.get(allowed.toString());
|
||||||
colorCount.put(allowed.toString(), cnt+1);
|
colorCount.put(allowed.toString(), cnt + 1);
|
||||||
totalCount++;
|
totalCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -236,7 +253,7 @@ public class DeckGeneratorPool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final Map<String, Double> percentages = new HashMap<>();
|
final Map<String, Double> percentages = new HashMap<>();
|
||||||
for(Map.Entry<String, Integer> singleCount: colorCount.entrySet()) {
|
for (Map.Entry<String, Integer> singleCount : colorCount.entrySet()) {
|
||||||
String color = singleCount.getKey();
|
String color = singleCount.getKey();
|
||||||
int count = singleCount.getValue();
|
int count = singleCount.getValue();
|
||||||
// Calculate the percentage this color has out of the total color counts
|
// Calculate the percentage this color has out of the total color counts
|
||||||
|
|
@ -248,20 +265,20 @@ public class DeckGeneratorPool
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates how many of each mana the non-basic lands produce.
|
* Calculates how many of each mana the non-basic lands produce.
|
||||||
|
*
|
||||||
* @param deckLands the non-basic lands which will be used in the deck.
|
* @param deckLands the non-basic lands which will be used in the deck.
|
||||||
* @return a mapping of colored mana symbol to the amount that can be produced.
|
* @return a mapping of colored mana symbol to the amount that can be produced.
|
||||||
*/
|
*/
|
||||||
public Map<String,Integer> countManaProduced(List<Card> deckLands)
|
public Map<String, Integer> countManaProduced(List<Card> deckLands) {
|
||||||
{
|
|
||||||
Map<String, Integer> manaCounts = new HashMap<>();
|
Map<String, Integer> manaCounts = new HashMap<>();
|
||||||
for (final ColoredManaSymbol color : ColoredManaSymbol.values()) {
|
for (final ColoredManaSymbol color : ColoredManaSymbol.values()) {
|
||||||
manaCounts.put(color.toString(), 0);
|
manaCounts.put(color.toString(), 0);
|
||||||
}
|
}
|
||||||
for(Card land: deckLands) {
|
for (Card land : deckLands) {
|
||||||
for(Ability landAbility: land.getAbilities()) {
|
for (Ability landAbility : land.getAbilities()) {
|
||||||
for (ColoredManaSymbol symbol : allowedColors) {
|
for (ColoredManaSymbol symbol : allowedColors) {
|
||||||
String abilityString = landAbility.getRule();
|
String abilityString = landAbility.getRule();
|
||||||
if(landTapsForAllowedColor(abilityString, symbol.toString())) {
|
if (landTapsForAllowedColor(abilityString, symbol.toString())) {
|
||||||
Integer count = manaCounts.get(symbol.toString());
|
Integer count = manaCounts.get(symbol.toString());
|
||||||
manaCounts.put(symbol.toString(), count + 1);
|
manaCounts.put(symbol.toString(), count + 1);
|
||||||
}
|
}
|
||||||
|
|
@ -271,15 +288,17 @@ public class DeckGeneratorPool
|
||||||
return manaCounts;
|
return manaCounts;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Filter all the non-basic lands retrieved from the database.
|
/**
|
||||||
|
* Filter all the non-basic lands retrieved from the database.
|
||||||
|
*
|
||||||
* @param landCardsInfo information about all the cards.
|
* @param landCardsInfo information about all the cards.
|
||||||
* @return a list of cards that produce the allowed colors for this pool.
|
* @return a list of cards that produce the allowed colors for this pool.
|
||||||
*/
|
*/
|
||||||
public List<Card> filterLands(List<CardInfo> landCardsInfo) {
|
public List<Card> filterLands(List<CardInfo> landCardsInfo) {
|
||||||
List<Card> matchingLandList = new ArrayList<>();
|
List<Card> matchingLandList = new ArrayList<>();
|
||||||
for(CardInfo landCardInfo: landCardsInfo) {
|
for (CardInfo landCardInfo : landCardsInfo) {
|
||||||
Card landCard = landCardInfo.createMockCard();
|
Card landCard = landCardInfo.createMockCard();
|
||||||
if(landProducesChosenColors(landCard)) {
|
if (landProducesChosenColors(landCard)) {
|
||||||
matchingLandList.add(landCard);
|
matchingLandList.add(landCard);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -288,11 +307,12 @@ public class DeckGeneratorPool
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the card name that represents the basic land for this color.
|
* Returns the card name that represents the basic land for this color.
|
||||||
|
*
|
||||||
* @param symbolString the colored mana symbol.
|
* @param symbolString the colored mana symbol.
|
||||||
* @return the name of a basic land card.
|
* @return the name of a basic land card.
|
||||||
*/
|
*/
|
||||||
public static String getBasicLandName(String symbolString) {
|
public static String getBasicLandName(String symbolString) {
|
||||||
switch(symbolString) {
|
switch (symbolString) {
|
||||||
case "B":
|
case "B":
|
||||||
return "Swamp";
|
return "Swamp";
|
||||||
case "G":
|
case "G":
|
||||||
|
|
@ -311,25 +331,50 @@ public class DeckGeneratorPool
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a complete deck.
|
* Returns a complete deck.
|
||||||
|
*
|
||||||
* @return the deck.
|
* @return the deck.
|
||||||
*/
|
*/
|
||||||
public Deck getDeck() {
|
public Deck getDeck() {
|
||||||
Set<Card> actualDeck = deck.getCards();
|
deck.getCards().clear();
|
||||||
actualDeck.addAll(deckCards);
|
deck.getSideboard().clear();
|
||||||
|
|
||||||
|
List<Card> useCards = new ArrayList<>(deckCards);
|
||||||
|
List<Card> useCommanders = new ArrayList<>();
|
||||||
|
|
||||||
|
// take random commanders
|
||||||
|
if (commandersCount > 0) {
|
||||||
|
List<Card> possibleCommanders = deckCards.stream()
|
||||||
|
.filter(this::isValidCommander)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
Card nextCommander = RandomUtil.randomFromCollection(possibleCommanders);
|
||||||
|
while (nextCommander != null && useCommanders.size() < commandersCount) {
|
||||||
|
useCards.remove(nextCommander);
|
||||||
|
useCommanders.add(nextCommander);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deck.getCards().addAll(useCards);
|
||||||
|
deck.getSideboard().addAll(useCommanders);
|
||||||
return deck;
|
return deck;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of creatures needed in this pool.
|
* Returns the number of creatures needed in this pool.
|
||||||
|
*
|
||||||
* @return the number of creatures.
|
* @return the number of creatures.
|
||||||
*/
|
*/
|
||||||
public int getCreatureCount() {
|
public int getCreatureCount() {
|
||||||
return creatureCount;
|
return creatureCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getCommandersCount() {
|
||||||
|
return commandersCount;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of non-creatures needed in this pool.
|
* Returns the number of non-creatures needed in this pool.
|
||||||
|
*
|
||||||
* @return the number of non-creatures.
|
* @return the number of non-creatures.
|
||||||
*/
|
*/
|
||||||
public int getNonCreatureCount() {
|
public int getNonCreatureCount() {
|
||||||
|
|
@ -338,6 +383,7 @@ public class DeckGeneratorPool
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of lands (basic + non-basic) needed in this pool.
|
* Returns the number of lands (basic + non-basic) needed in this pool.
|
||||||
|
*
|
||||||
* @return the number of lands.
|
* @return the number of lands.
|
||||||
*/
|
*/
|
||||||
public int getLandCount() {
|
public int getLandCount() {
|
||||||
|
|
@ -346,6 +392,7 @@ public class DeckGeneratorPool
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns if this pool only uses one color.
|
* Returns if this pool only uses one color.
|
||||||
|
*
|
||||||
* @return if this pool is monocolored.
|
* @return if this pool is monocolored.
|
||||||
*/
|
*/
|
||||||
public boolean isMonoColoredDeck() {
|
public boolean isMonoColoredDeck() {
|
||||||
|
|
@ -354,6 +401,7 @@ public class DeckGeneratorPool
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the size of the deck to generate from this pool.
|
* Returns the size of the deck to generate from this pool.
|
||||||
|
*
|
||||||
* @return the deck size.
|
* @return the deck size.
|
||||||
*/
|
*/
|
||||||
public int getDeckSize() {
|
public int getDeckSize() {
|
||||||
|
|
@ -364,20 +412,20 @@ public class DeckGeneratorPool
|
||||||
* Fixes undersized or oversized decks that have been generated.
|
* Fixes undersized or oversized decks that have been generated.
|
||||||
* Removes random cards from an oversized deck until it is the correct size.
|
* Removes random cards from an oversized deck until it is the correct size.
|
||||||
* Uses the reserve pool to fill up and undersized deck with cards.
|
* Uses the reserve pool to fill up and undersized deck with cards.
|
||||||
|
*
|
||||||
* @return a fixed list of cards for this deck.
|
* @return a fixed list of cards for this deck.
|
||||||
*/
|
*/
|
||||||
private List<Card> getFixedSpells()
|
private List<Card> getFixedSpells() {
|
||||||
{
|
|
||||||
int spellSize = deckCards.size();
|
int spellSize = deckCards.size();
|
||||||
int nonLandSize = (deckSize - landCount);
|
int nonLandSize = (deckSize - landCount);
|
||||||
|
|
||||||
// Less spells than needed
|
// Less spells than needed
|
||||||
if(spellSize < nonLandSize) {
|
if (spellSize < nonLandSize) {
|
||||||
|
|
||||||
int spellsNeeded = nonLandSize-spellSize;
|
int spellsNeeded = nonLandSize - spellSize;
|
||||||
|
|
||||||
// If we haven't got enough spells in reserve to fulfil the amount we need, skip adding any.
|
// If we haven't got enough spells in reserve to fulfil the amount we need, skip adding any.
|
||||||
if(reserveSpells.size() >= spellsNeeded) {
|
if (reserveSpells.size() >= spellsNeeded) {
|
||||||
|
|
||||||
List<Card> spellsToAdd = new ArrayList<>(spellsNeeded);
|
List<Card> spellsToAdd = new ArrayList<>(spellsNeeded);
|
||||||
|
|
||||||
|
|
@ -398,16 +446,16 @@ public class DeckGeneratorPool
|
||||||
}
|
}
|
||||||
|
|
||||||
// More spells than needed
|
// More spells than needed
|
||||||
else if(spellSize > (deckSize - landCount)) {
|
else if (spellSize > (deckSize - landCount)) {
|
||||||
int spellsRemoved = (spellSize)-(deckSize-landCount);
|
int spellsRemoved = (spellSize) - (deckSize - landCount);
|
||||||
for(int i = 0; i < spellsRemoved; ++i) {
|
for (int i = 0; i < spellsRemoved; ++i) {
|
||||||
deckCards.remove(RandomUtil.nextInt(deckCards.size()));
|
deckCards.remove(RandomUtil.nextInt(deckCards.size()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check we have exactly the right amount of cards for a deck.
|
// Check we have exactly the right amount of cards for a deck.
|
||||||
if(deckCards.size() != nonLandSize) {
|
if (deckCards.size() != nonLandSize) {
|
||||||
throw new IllegalStateException("Not enough cards found to generate deck.");
|
logger.info("Can't generate full deck for selected settings - try again or choose more sets and less colors");
|
||||||
}
|
}
|
||||||
// Return the fixed amount
|
// Return the fixed amount
|
||||||
return deckCards;
|
return deckCards;
|
||||||
|
|
@ -416,16 +464,18 @@ public class DeckGeneratorPool
|
||||||
/**
|
/**
|
||||||
* Returns if this land taps for the given color.
|
* Returns if this land taps for the given color.
|
||||||
* Basic string matching to check the ability adds one of the chosen mana when tapped.
|
* Basic string matching to check the ability adds one of the chosen mana when tapped.
|
||||||
|
*
|
||||||
* @param ability MockAbility of the land card
|
* @param ability MockAbility of the land card
|
||||||
* @param symbol colored mana symbol.
|
* @param symbol colored mana symbol.
|
||||||
* @return if the ability is tapping to produce the mana the symbol represents.
|
* @return if the ability is tapping to produce the mana the symbol represents.
|
||||||
*/
|
*/
|
||||||
private boolean landTapsForAllowedColor(String ability, String symbol) {
|
private boolean landTapsForAllowedColor(String ability, String symbol) {
|
||||||
return ability.matches(".*Add \\{" + symbol + "\\}.");
|
return ability.matches(".*Add \\{" + symbol + "\\}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns if this land will produce the chosen colors for this pool.
|
* Returns if this land will produce the chosen colors for this pool.
|
||||||
|
*
|
||||||
* @param card a non-basic land card.
|
* @param card a non-basic land card.
|
||||||
* @return if this land card taps to produces the colors chosen.
|
* @return if this land card taps to produces the colors chosen.
|
||||||
*/
|
*/
|
||||||
|
|
@ -434,32 +484,49 @@ public class DeckGeneratorPool
|
||||||
// and other Abilities so we have to do some basic string matching on land cards for now.
|
// and other Abilities so we have to do some basic string matching on land cards for now.
|
||||||
List<Ability> landAbilities = card.getAbilities();
|
List<Ability> landAbilities = card.getAbilities();
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for(Ability ability : landAbilities) {
|
for (Ability ability : landAbilities) {
|
||||||
String abilityString = ability.getRule();
|
String abilityString = ability.getRule();
|
||||||
// Lands that tap to produce mana of the chosen colors
|
// Lands that tap to produce mana of the chosen colors
|
||||||
for(ColoredManaSymbol symbol : allowedColors) {
|
for (ColoredManaSymbol symbol : allowedColors) {
|
||||||
if(landTapsForAllowedColor(abilityString, symbol.toString())) {
|
if (landTapsForAllowedColor(abilityString, symbol.toString())) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(count > 1) {
|
if (count > 1) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isValidCommander(Card card) {
|
||||||
|
// commander must be legendary creature
|
||||||
|
if (!card.isCreature() || !card.isLegendary()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// commander must have all chosen colors
|
||||||
|
for (ColoredManaSymbol symbol : allowedColors) {
|
||||||
|
if (!card.getColor().contains(new ObjectColor(symbol.toString()))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns if the symbol is a colored mana symbol.
|
* Returns if the symbol is a colored mana symbol.
|
||||||
|
*
|
||||||
* @param symbol the symbol to check.
|
* @param symbol the symbol to check.
|
||||||
* @return If it is a basic mana symbol or a hybrid mana symbol.
|
* @return If it is a basic mana symbol or a hybrid mana symbol.
|
||||||
*/
|
*/
|
||||||
private static boolean isColoredManaSymbol(String symbol) {
|
private static boolean isColoredManaSymbol(String symbol) {
|
||||||
// Hybrid mana
|
// Hybrid mana
|
||||||
if(symbol.contains("/")) {
|
if (symbol.contains("/")) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
for(ColoredManaSymbol c: ColoredManaSymbol.values()) {
|
for (ColoredManaSymbol c : ColoredManaSymbol.values()) {
|
||||||
if (symbol.charAt(0) == (c.toString().charAt(0))) {
|
if (symbol.charAt(0) == (c.toString().charAt(0))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -470,14 +537,15 @@ public class DeckGeneratorPool
|
||||||
/**
|
/**
|
||||||
* Returns how many of this card is in the pool.
|
* Returns how many of this card is in the pool.
|
||||||
* If there are none in the pool it will initalise the card count.
|
* If there are none in the pool it will initalise the card count.
|
||||||
|
*
|
||||||
* @param cardName the name of the card to check.
|
* @param cardName the name of the card to check.
|
||||||
* @return the number of cards in the pool of this name.
|
* @return the number of cards in the pool of this name.
|
||||||
*/
|
*/
|
||||||
private int getCardCount(String cardName) {
|
private int getCardCount(String cardName) {
|
||||||
Object cC = cardCounts.get((cardName));
|
Object cC = cardCounts.get((cardName));
|
||||||
if(cC == null)
|
if (cC == null)
|
||||||
cardCounts.put(cardName, 0);
|
cardCounts.put(cardName, 0);
|
||||||
return cardCounts.get((cardName));
|
return cardCounts.get((cardName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -490,8 +558,8 @@ public class DeckGeneratorPool
|
||||||
* color of cards.
|
* color of cards.
|
||||||
*
|
*
|
||||||
* @param useNonBasicLand
|
* @param useNonBasicLand
|
||||||
* @param criteria the criteria of the lands to search for in the database.
|
* @param criteria the criteria of the lands to search for in the database.
|
||||||
* @param basicLands information about the basic lands from the sets used.
|
* @param basicLands information about the basic lands from the sets used.
|
||||||
*/
|
*/
|
||||||
protected static void generateLands(boolean useNonBasicLand, CardCriteria criteria, Map<String, List<CardInfo>> basicLands) {
|
protected static void generateLands(boolean useNonBasicLand, CardCriteria criteria, Map<String, List<CardInfo>> basicLands) {
|
||||||
DeckGeneratorPool genPool = DeckGenerator.genPool;
|
DeckGeneratorPool genPool = DeckGenerator.genPool;
|
||||||
|
|
@ -541,45 +609,69 @@ public class DeckGeneratorPool
|
||||||
* non-creatures are retrieved separately to ensure the deck contains a
|
* non-creatures are retrieved separately to ensure the deck contains a
|
||||||
* reasonable mix of both.
|
* reasonable mix of both.
|
||||||
*
|
*
|
||||||
* @param criteria the criteria to search for in the database.
|
* @param criteria the criteria to search for in the database.
|
||||||
* @param spellCount the number of spells that match the criteria needed in
|
* @param needCardsCount the number of spells that match the criteria needed in
|
||||||
* the deck.
|
* the deck.
|
||||||
|
* @param needCommandersCount make sure it contains commander creature (must be uses on first generateSpells only)
|
||||||
*/
|
*/
|
||||||
protected static void generateSpells(CardCriteria criteria, int spellCount) {
|
protected static void generateSpells(CardCriteria criteria, int needCardsCount, int needCommandersCount) {
|
||||||
DeckGeneratorPool genPool = DeckGenerator.genPool;
|
DeckGeneratorPool genPool = DeckGenerator.genPool;
|
||||||
|
if (needCommandersCount > 0 && !genPool.cardCounts.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("Wrong code usage: generateSpells with creatures and commanders must be called as first");
|
||||||
|
}
|
||||||
List<CardInfo> cardPool = CardRepository.instance.findCards(criteria);
|
List<CardInfo> cardPool = CardRepository.instance.findCards(criteria);
|
||||||
int retrievedCount = cardPool.size();
|
List<DeckGeneratorCMC.CMC> deckCMCs = genPool.getCMCsForSpellCount(needCardsCount);
|
||||||
List<DeckGeneratorCMC.CMC> deckCMCs = genPool.getCMCsForSpellCount(spellCount);
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
int validCommanders = 0;
|
||||||
int reservesAdded = 0;
|
int reservesAdded = 0;
|
||||||
boolean added;
|
if (cardPool.size() > 0 && cardPool.size() >= needCardsCount) {
|
||||||
if (retrievedCount > 0 && retrievedCount >= spellCount) {
|
|
||||||
int tries = 0;
|
int tries = 0;
|
||||||
while (count < spellCount) {
|
while (true) {
|
||||||
Card card = cardPool.get(RandomUtil.nextInt(retrievedCount)).createMockCard();
|
tries++;
|
||||||
if (genPool.isValidSpellCard(card)) {
|
|
||||||
int cardCMC = card.getManaValue();
|
// can't finish deck, stop and use reserved cards later
|
||||||
for (DeckGeneratorCMC.CMC deckCMC : deckCMCs) {
|
if (tries > DeckGenerator.MAX_TRIES) {
|
||||||
if (cardCMC >= deckCMC.min && cardCMC <= deckCMC.max) {
|
logger.info("Can't generate full deck for selected settings - try again or choose more sets and less colors");
|
||||||
int currentAmount = deckCMC.getAmount();
|
break;
|
||||||
if (currentAmount > 0) {
|
}
|
||||||
deckCMC.setAmount(currentAmount - 1);
|
|
||||||
genPool.addCard(card.copy());
|
// can finish deck - but make sure it has commander
|
||||||
count++;
|
if (count >= needCardsCount) {
|
||||||
}
|
if (validCommanders < needCommandersCount) {
|
||||||
} else if (reservesAdded < (genPool.getDeckSize() / 2)) {
|
// reset deck search from scratch (except reserved cards)
|
||||||
added = genPool.tryAddReserve(card, cardCMC);
|
count = 0;
|
||||||
if (added) {
|
validCommanders = 0;
|
||||||
reservesAdded++;
|
deckCMCs = genPool.getCMCsForSpellCount(needCardsCount);
|
||||||
|
genPool.clearCards(false);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Card card = cardPool.get(RandomUtil.nextInt(cardPool.size())).createMockCard();
|
||||||
|
if (!genPool.isValidSpellCard(card)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cardCMC = card.getManaValue();
|
||||||
|
for (DeckGeneratorCMC.CMC deckCMC : deckCMCs) {
|
||||||
|
if (cardCMC >= deckCMC.min && cardCMC <= deckCMC.max) {
|
||||||
|
int currentAmount = deckCMC.getAmount();
|
||||||
|
if (currentAmount > 0) {
|
||||||
|
deckCMC.setAmount(currentAmount - 1);
|
||||||
|
genPool.addCard(card.copy());
|
||||||
|
count++;
|
||||||
|
// make sure it has compatible commanders
|
||||||
|
if (genPool.isValidCommander(card)) {
|
||||||
|
validCommanders++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (reservesAdded < (genPool.getDeckSize() / 2)) {
|
||||||
|
if (genPool.tryAddReserve(card, cardCMC)) {
|
||||||
|
reservesAdded++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tries++;
|
|
||||||
if (tries > DeckGenerator.MAX_TRIES) {
|
|
||||||
// Break here, we'll fill in random missing ones later
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("Not enough cards to generate deck.");
|
throw new IllegalStateException("Not enough cards to generate deck.");
|
||||||
|
|
|
||||||
|
|
@ -780,7 +780,7 @@
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JTextField" name="jTextFieldSearch">
|
<Component class="javax.swing.JTextField" name="jTextFieldSearch">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="toolTipText" type="java.lang.String" value="Searches for card names and in the rule text of the card."/>
|
<Property name="toolTipText" type="java.lang.String" value="Search cards by any data like name or mana symbols like {W}, {U}, {C}, etc (use quotes for exact search)"/>
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JCheckBox" name="chkNames">
|
<Component class="javax.swing.JCheckBox" name="chkNames">
|
||||||
|
|
|
||||||
|
|
@ -1085,7 +1085,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
jTextFieldSearch.setToolTipText("Searches for card names and in the rule text of the card.");
|
jTextFieldSearch.setToolTipText("Search cards by any data like name or mana symbols like {W}, {U}, {C}, etc (use quotes for exact search)");
|
||||||
|
|
||||||
chkNames.setSelected(true);
|
chkNames.setSelected(true);
|
||||||
chkNames.setText("Names");
|
chkNames.setText("Names");
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ public class DeckArea extends javax.swing.JPanel {
|
||||||
sideboardList.deselectAll();
|
sideboardList.deselectAll();
|
||||||
for (CardView card : cards) {
|
for (CardView card : cards) {
|
||||||
CardView newCard = new CardView(card);
|
CardView newCard = new CardView(card);
|
||||||
deckList.addCardView(newCard, true);
|
deckList.addCardView(newCard, card);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -150,7 +150,7 @@ public class DeckArea extends javax.swing.JPanel {
|
||||||
deckList.deselectAll();
|
deckList.deselectAll();
|
||||||
for (CardView card : cards) {
|
for (CardView card : cards) {
|
||||||
CardView newCard = new CardView(card);
|
CardView newCard = new CardView(card);
|
||||||
sideboardList.addCardView(newCard, true);
|
sideboardList.addCardView(newCard, card);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -533,10 +533,10 @@
|
||||||
<Component class="mage.client.deckeditor.DeckLegalityPanel" name="deckLegalityDisplay">
|
<Component class="mage.client.deckeditor.DeckLegalityPanel" name="deckLegalityDisplay">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
<Dimension value="[245, 155]"/>
|
<Dimension value="[245, 255]"/>
|
||||||
</Property>
|
</Property>
|
||||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
<Dimension value="[85, 155]"/>
|
<Dimension value="[85, 255]"/>
|
||||||
</Property>
|
</Property>
|
||||||
<Property name="opaque" type="boolean" value="false"/>
|
<Property name="opaque" type="boolean" value="false"/>
|
||||||
</Properties>
|
</Properties>
|
||||||
|
|
|
||||||
|
|
@ -121,12 +121,8 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
||||||
if (!SwingUtilities.isLeftMouseButton(e)) {
|
if (!SwingUtilities.isLeftMouseButton(e)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
List<String> cardNames = new ArrayList<>();
|
|
||||||
LegalityLabel label = (LegalityLabel) e.getComponent();
|
LegalityLabel label = (LegalityLabel) e.getComponent();
|
||||||
label.getValidator().getErrorsList().stream()
|
List<String> cardNames = new ArrayList<>(label.selectCards());
|
||||||
.map(DeckValidatorError::getCardName)
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.forEach(cardNames::add);
|
|
||||||
deckArea.getDeckList().deselectAll();
|
deckArea.getDeckList().deselectAll();
|
||||||
deckArea.getDeckList().selectByName(cardNames);
|
deckArea.getDeckList().selectByName(cardNames);
|
||||||
deckArea.getSideboardList().deselectAll();
|
deckArea.getSideboardList().deselectAll();
|
||||||
|
|
@ -1290,8 +1286,8 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
||||||
|
|
||||||
panelInfo.setOpaque(false);
|
panelInfo.setOpaque(false);
|
||||||
|
|
||||||
deckLegalityDisplay.setMaximumSize(new java.awt.Dimension(245, 155));
|
deckLegalityDisplay.setMaximumSize(new java.awt.Dimension(245, 255));
|
||||||
deckLegalityDisplay.setMinimumSize(new java.awt.Dimension(85, 155));
|
deckLegalityDisplay.setMinimumSize(new java.awt.Dimension(85, 255));
|
||||||
deckLegalityDisplay.setOpaque(false);
|
deckLegalityDisplay.setOpaque(false);
|
||||||
deckLegalityDisplay.setVisible(false);
|
deckLegalityDisplay.setVisible(false);
|
||||||
|
|
||||||
|
|
@ -1313,7 +1309,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
||||||
panelInfoLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
panelInfoLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addGroup(panelInfoLayout.createSequentialGroup()
|
.addGroup(panelInfoLayout.createSequentialGroup()
|
||||||
.addContainerGap()
|
.addContainerGap()
|
||||||
.addComponent(deckLegalityDisplay, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addComponent(deckLegalityDisplay, javax.swing.GroupLayout.PREFERRED_SIZE, 255, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||||
.addComponent(bigCard, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addComponent(bigCard, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
.addContainerGap())
|
.addContainerGap())
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ import mage.cards.decks.Deck;
|
||||||
import mage.cards.decks.DeckValidator;
|
import mage.cards.decks.DeckValidator;
|
||||||
import mage.cards.mock.MockCard;
|
import mage.cards.mock.MockCard;
|
||||||
import mage.cards.mock.MockSplitCard;
|
import mage.cards.mock.MockSplitCard;
|
||||||
|
import mage.client.components.BracketLegalityLabel;
|
||||||
|
import mage.client.components.EdhPowerLevelLegalityLabel;
|
||||||
import mage.client.components.LegalityLabel;
|
import mage.client.components.LegalityLabel;
|
||||||
import mage.deck.*;
|
import mage.deck.*;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
@ -15,7 +17,7 @@ import java.util.stream.Stream;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Elandril
|
* @author Elandril, JayDi85
|
||||||
*/
|
*/
|
||||||
public class DeckLegalityPanel extends javax.swing.JPanel {
|
public class DeckLegalityPanel extends javax.swing.JPanel {
|
||||||
|
|
||||||
|
|
@ -101,6 +103,14 @@ public class DeckLegalityPanel extends javax.swing.JPanel {
|
||||||
new Frontier(), new HistoricalType2(), new PennyDreadfulCommander(), new EuropeanHighlander(), new CanadianHighlander()
|
new Frontier(), new HistoricalType2(), new PennyDreadfulCommander(), new EuropeanHighlander(), new CanadianHighlander()
|
||||||
// not used: new Eternal(), new Momir(), new TinyLeaders()
|
// not used: new Eternal(), new Momir(), new TinyLeaders()
|
||||||
).forEach(this::addLegalityLabel);
|
).forEach(this::addLegalityLabel);
|
||||||
|
|
||||||
|
// extra buttons like score
|
||||||
|
this.add(new EdhPowerLevelLegalityLabel());
|
||||||
|
// only 3 buttons allowed for one line
|
||||||
|
this.add(new BracketLegalityLabel(BracketLegalityLabel.BracketLevel.BRACKET_1));
|
||||||
|
this.add(new BracketLegalityLabel(BracketLegalityLabel.BracketLevel.BRACKET_2_3));
|
||||||
|
this.add(new BracketLegalityLabel(BracketLegalityLabel.BracketLevel.BRACKET_4_5));
|
||||||
|
|
||||||
addHidePanelButton();
|
addHidePanelButton();
|
||||||
|
|
||||||
revalidate();
|
revalidate();
|
||||||
|
|
@ -147,5 +157,4 @@ public class DeckLegalityPanel extends javax.swing.JPanel {
|
||||||
.map(LegalityLabel.class::cast)
|
.map(LegalityLabel.class::cast)
|
||||||
.forEach(label -> label.validateDeck(deckToValidate));
|
.forEach(label -> label.validateDeck(deckToValidate));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -180,7 +180,6 @@
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JLabel" name="lblForestIcon">
|
<Component class="javax.swing.JLabel" name="lblForestIcon">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="toolTipText" type="java.lang.String" value=""/>
|
|
||||||
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
<Dimension value="[22, 20]"/>
|
<Dimension value="[22, 20]"/>
|
||||||
</Property>
|
</Property>
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ public class AddLandDialog extends MageDialog {
|
||||||
landSetNames.add(expansionInfo.getName());
|
landSetNames.add(expansionInfo.getName());
|
||||||
}
|
}
|
||||||
if (landSetNames.isEmpty()) {
|
if (landSetNames.isEmpty()) {
|
||||||
throw new IllegalArgumentException("No set with basic land was found");
|
throw new IllegalArgumentException("No set with basic land was found (possible memory problems, need client restart)");
|
||||||
}
|
}
|
||||||
if (landSetNames.size() > 1) {
|
if (landSetNames.size() > 1) {
|
||||||
landSetNames.add("<Random lands>");
|
landSetNames.add("<Random lands>");
|
||||||
|
|
@ -271,7 +271,6 @@ public class AddLandDialog extends MageDialog {
|
||||||
|
|
||||||
spnForest.setModel(new javax.swing.SpinnerNumberModel(0, 0, null, 1));
|
spnForest.setModel(new javax.swing.SpinnerNumberModel(0, 0, null, 1));
|
||||||
|
|
||||||
lblForestIcon.setToolTipText("");
|
|
||||||
lblForestIcon.setMaximumSize(new java.awt.Dimension(22, 20));
|
lblForestIcon.setMaximumSize(new java.awt.Dimension(22, 20));
|
||||||
lblForestIcon.setMinimumSize(new java.awt.Dimension(22, 20));
|
lblForestIcon.setMinimumSize(new java.awt.Dimension(22, 20));
|
||||||
lblForestIcon.setPreferredSize(new java.awt.Dimension(22, 20));
|
lblForestIcon.setPreferredSize(new java.awt.Dimension(22, 20));
|
||||||
|
|
@ -477,6 +476,7 @@ public class AddLandDialog extends MageDialog {
|
||||||
}//GEN-LAST:event_btnSetFastSearchActionPerformed
|
}//GEN-LAST:event_btnSetFastSearchActionPerformed
|
||||||
|
|
||||||
private void autoAddLands() {
|
private void autoAddLands() {
|
||||||
|
// suggest lands amount for deck without lands
|
||||||
int deckSize = ((Number) spnDeckSize.getValue()).intValue();
|
int deckSize = ((Number) spnDeckSize.getValue()).intValue();
|
||||||
int[] lands = DeckBuildUtils.landCountSuggestion(deckSize, deck.getMaindeckCards());
|
int[] lands = DeckBuildUtils.landCountSuggestion(deckSize, deck.getMaindeckCards());
|
||||||
spnPlains.setValue(lands[0]);
|
spnPlains.setValue(lands[0]);
|
||||||
|
|
|
||||||
|
|
@ -177,7 +177,7 @@ public class CardInfoWindowDialog extends MageDialog implements MageDesktopIconi
|
||||||
super.show();
|
super.show();
|
||||||
|
|
||||||
// auto-position on first usage
|
// auto-position on first usage
|
||||||
if (positioned) {
|
if (!positioned) {
|
||||||
showAndPositionWindow();
|
showAndPositionWindow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -190,9 +190,23 @@ public class CardInfoWindowDialog extends MageDialog implements MageDesktopIconi
|
||||||
Point centered = SettingsManager.instance.getComponentPosition(width, height);
|
Point centered = SettingsManager.instance.getComponentPosition(width, height);
|
||||||
if (!positioned) {
|
if (!positioned) {
|
||||||
// starting position
|
// starting position
|
||||||
|
|
||||||
|
// auto-resize window, but keep it GUI friendly on too many cards (do not overlap a full screen)
|
||||||
|
int minWidth = CardInfoWindowDialog.this.getWidth();
|
||||||
|
int maxWidth = SettingsManager.instance.getScreenWidth() / 2;
|
||||||
|
int needWidth = CardInfoWindowDialog.this.cards.getPreferredSize().width;
|
||||||
|
needWidth = Math.max(needWidth, minWidth);
|
||||||
|
needWidth = Math.min(needWidth, maxWidth);
|
||||||
|
needWidth += GUISizeHelper.scrollBarSize; // more space, so no horizontal scrolls
|
||||||
|
int needHeight = CardInfoWindowDialog.this.getHeight(); // keep default height
|
||||||
|
CardInfoWindowDialog.this.setPreferredSize(new Dimension(needWidth, needHeight));
|
||||||
|
CardInfoWindowDialog.this.pack();
|
||||||
|
centered = SettingsManager.instance.getComponentPosition(needWidth, needHeight);
|
||||||
|
|
||||||
// little randomize to see multiple opened windows
|
// little randomize to see multiple opened windows
|
||||||
int xPos = centered.x / 2 + RandomUtil.nextInt(50);
|
int xPos = centered.x / 2 + RandomUtil.nextInt(50);
|
||||||
int yPos = centered.y / 2 + RandomUtil.nextInt(50);
|
int yPos = centered.y / 2 + RandomUtil.nextInt(50);
|
||||||
|
|
||||||
CardInfoWindowDialog.this.setLocation(xPos, yPos);
|
CardInfoWindowDialog.this.setLocation(xPos, yPos);
|
||||||
show();
|
show();
|
||||||
positioned = true;
|
positioned = true;
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ import mage.client.util.AppUtil;
|
||||||
import mage.client.util.GUISizeHelper;
|
import mage.client.util.GUISizeHelper;
|
||||||
import mage.util.CardUtil;
|
import mage.util.CardUtil;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GUI: error dialog with copyable error message
|
* GUI: error dialog with copyable error message
|
||||||
* // TODO: add game logs and data for game errors (client side info from GameView)
|
* // TODO: add game logs and data for game errors (client side info from GameView)
|
||||||
|
|
@ -28,7 +30,10 @@ public class ErrorDialog extends MageDialog {
|
||||||
|
|
||||||
// add additional info
|
// add additional info
|
||||||
String fullError = "Error type: " + fullTitle + "\n"
|
String fullError = "Error type: " + fullTitle + "\n"
|
||||||
|
+ "\n"
|
||||||
+ "Client version: " + MageFrame.getInstance().getVersion().toString() + "\n"
|
+ "Client version: " + MageFrame.getInstance().getVersion().toString() + "\n"
|
||||||
|
+ "Java version: " + System.getProperty("java.version") + "\n"
|
||||||
|
+ "Default charset: " + Charset.defaultCharset() + "\n"
|
||||||
+ "\n"
|
+ "\n"
|
||||||
+ errorText;
|
+ errorText;
|
||||||
this.textError.setText(fullError);
|
this.textError.setText(fullError);
|
||||||
|
|
@ -68,7 +73,8 @@ public class ErrorDialog extends MageDialog {
|
||||||
AppUtil.openUrlInSystemBrowser(url);
|
AppUtil.openUrlInSystemBrowser(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** This method is called from within the constructor to
|
/**
|
||||||
|
* This method is called from within the constructor to
|
||||||
* initialize the form.
|
* initialize the form.
|
||||||
* WARNING: Do NOT modify this code. The content of this method is
|
* WARNING: Do NOT modify this code. The content of this method is
|
||||||
* always regenerated by the Form Editor.
|
* always regenerated by the Form Editor.
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@
|
||||||
<MenuItem class="javax.swing.JMenuItem" name="menuLoadSettingsLast">
|
<MenuItem class="javax.swing.JMenuItem" name="menuLoadSettingsLast">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" value="Load from last time"/>
|
<Property name="text" type="java.lang.String" value="Load from last time"/>
|
||||||
<Property name="toolTipText" type="java.lang.String" value=""/>
|
|
||||||
</Properties>
|
</Properties>
|
||||||
<Events>
|
<Events>
|
||||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="menuLoadSettingsLastActionPerformed"/>
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="menuLoadSettingsLastActionPerformed"/>
|
||||||
|
|
@ -46,7 +45,6 @@
|
||||||
<MenuItem class="javax.swing.JMenuItem" name="menuLoadSettings1">
|
<MenuItem class="javax.swing.JMenuItem" name="menuLoadSettings1">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" value="Load from config 1"/>
|
<Property name="text" type="java.lang.String" value="Load from config 1"/>
|
||||||
<Property name="toolTipText" type="java.lang.String" value=""/>
|
|
||||||
</Properties>
|
</Properties>
|
||||||
<Events>
|
<Events>
|
||||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="menuLoadSettings1ActionPerformed"/>
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="menuLoadSettings1ActionPerformed"/>
|
||||||
|
|
@ -65,7 +63,6 @@
|
||||||
<MenuItem class="javax.swing.JMenuItem" name="menuLoadSettingsDefault">
|
<MenuItem class="javax.swing.JMenuItem" name="menuLoadSettingsDefault">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" value="Load default settings"/>
|
<Property name="text" type="java.lang.String" value="Load default settings"/>
|
||||||
<Property name="toolTipText" type="java.lang.String" value=""/>
|
|
||||||
</Properties>
|
</Properties>
|
||||||
<Events>
|
<Events>
|
||||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="menuLoadSettingsDefaultActionPerformed"/>
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="menuLoadSettingsDefaultActionPerformed"/>
|
||||||
|
|
@ -391,7 +388,6 @@
|
||||||
<Component class="javax.swing.JLabel" name="lblSkillLevel">
|
<Component class="javax.swing.JLabel" name="lblSkillLevel">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" value="Skill Level:"/>
|
<Property name="text" type="java.lang.String" value="Skill Level:"/>
|
||||||
<Property name="toolTipText" type="java.lang.String" value=""/>
|
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JComboBox" name="cbSkillLevel">
|
<Component class="javax.swing.JComboBox" name="cbSkillLevel">
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,6 @@ public class NewTableDialog extends MageDialog {
|
||||||
popupSaveSettings.add(menuSaveSettings2);
|
popupSaveSettings.add(menuSaveSettings2);
|
||||||
|
|
||||||
menuLoadSettingsLast.setText("Load from last time");
|
menuLoadSettingsLast.setText("Load from last time");
|
||||||
menuLoadSettingsLast.setToolTipText("");
|
|
||||||
menuLoadSettingsLast.addActionListener(new java.awt.event.ActionListener() {
|
menuLoadSettingsLast.addActionListener(new java.awt.event.ActionListener() {
|
||||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
menuLoadSettingsLastActionPerformed(evt);
|
menuLoadSettingsLastActionPerformed(evt);
|
||||||
|
|
@ -160,7 +159,6 @@ public class NewTableDialog extends MageDialog {
|
||||||
popupLoadSettings.add(separator1);
|
popupLoadSettings.add(separator1);
|
||||||
|
|
||||||
menuLoadSettings1.setText("Load from config 1");
|
menuLoadSettings1.setText("Load from config 1");
|
||||||
menuLoadSettings1.setToolTipText("");
|
|
||||||
menuLoadSettings1.addActionListener(new java.awt.event.ActionListener() {
|
menuLoadSettings1.addActionListener(new java.awt.event.ActionListener() {
|
||||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
menuLoadSettings1ActionPerformed(evt);
|
menuLoadSettings1ActionPerformed(evt);
|
||||||
|
|
@ -178,7 +176,6 @@ public class NewTableDialog extends MageDialog {
|
||||||
popupLoadSettings.add(separator2);
|
popupLoadSettings.add(separator2);
|
||||||
|
|
||||||
menuLoadSettingsDefault.setText("Load default settings");
|
menuLoadSettingsDefault.setText("Load default settings");
|
||||||
menuLoadSettingsDefault.setToolTipText("");
|
|
||||||
menuLoadSettingsDefault.addActionListener(new java.awt.event.ActionListener() {
|
menuLoadSettingsDefault.addActionListener(new java.awt.event.ActionListener() {
|
||||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
menuLoadSettingsDefaultActionPerformed(evt);
|
menuLoadSettingsDefaultActionPerformed(evt);
|
||||||
|
|
@ -228,7 +225,6 @@ public class NewTableDialog extends MageDialog {
|
||||||
});
|
});
|
||||||
|
|
||||||
lblSkillLevel.setText("Skill Level:");
|
lblSkillLevel.setText("Skill Level:");
|
||||||
lblSkillLevel.setToolTipText("");
|
|
||||||
|
|
||||||
cbSkillLevel.setToolTipText("<HTML>This option can be used to make it easier to find matches<br>\nwith opponents of the appropriate skill level.");
|
cbSkillLevel.setToolTipText("<HTML>This option can be used to make it easier to find matches<br>\nwith opponents of the appropriate skill level.");
|
||||||
|
|
||||||
|
|
@ -598,7 +594,7 @@ public class NewTableDialog extends MageDialog {
|
||||||
private MatchOptions getMatchOptions() {
|
private MatchOptions getMatchOptions() {
|
||||||
// current settings
|
// current settings
|
||||||
GameTypeView gameType = (GameTypeView) cbGameType.getSelectedItem();
|
GameTypeView gameType = (GameTypeView) cbGameType.getSelectedItem();
|
||||||
MatchOptions options = new MatchOptions(this.txtName.getText(), gameType.getName(), false, 2);
|
MatchOptions options = new MatchOptions(this.txtName.getText(), gameType.getName(), false);
|
||||||
options.getPlayerTypes().add(PlayerType.HUMAN);
|
options.getPlayerTypes().add(PlayerType.HUMAN);
|
||||||
for (TablePlayerPanel player : players) {
|
for (TablePlayerPanel player : players) {
|
||||||
options.getPlayerTypes().add(player.getPlayerType());
|
options.getPlayerTypes().add(player.getPlayerType());
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@
|
||||||
<MenuItem class="javax.swing.JMenuItem" name="menuLoadSettingsLast">
|
<MenuItem class="javax.swing.JMenuItem" name="menuLoadSettingsLast">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" value="Load from last time"/>
|
<Property name="text" type="java.lang.String" value="Load from last time"/>
|
||||||
<Property name="toolTipText" type="java.lang.String" value=""/>
|
|
||||||
</Properties>
|
</Properties>
|
||||||
<Events>
|
<Events>
|
||||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="menuLoadSettingsLastActionPerformed"/>
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="menuLoadSettingsLastActionPerformed"/>
|
||||||
|
|
@ -46,7 +45,6 @@
|
||||||
<MenuItem class="javax.swing.JMenuItem" name="menuLoadSettings1">
|
<MenuItem class="javax.swing.JMenuItem" name="menuLoadSettings1">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" value="Load from config 1"/>
|
<Property name="text" type="java.lang.String" value="Load from config 1"/>
|
||||||
<Property name="toolTipText" type="java.lang.String" value=""/>
|
|
||||||
</Properties>
|
</Properties>
|
||||||
<Events>
|
<Events>
|
||||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="menuLoadSettings1ActionPerformed"/>
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="menuLoadSettings1ActionPerformed"/>
|
||||||
|
|
@ -65,7 +63,6 @@
|
||||||
<MenuItem class="javax.swing.JMenuItem" name="menuLoadSettingsDefault">
|
<MenuItem class="javax.swing.JMenuItem" name="menuLoadSettingsDefault">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" value="Load default settings"/>
|
<Property name="text" type="java.lang.String" value="Load default settings"/>
|
||||||
<Property name="toolTipText" type="java.lang.String" value=""/>
|
|
||||||
</Properties>
|
</Properties>
|
||||||
<Events>
|
<Events>
|
||||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="menuLoadSettingsDefaultActionPerformed"/>
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="menuLoadSettingsDefaultActionPerformed"/>
|
||||||
|
|
@ -102,19 +99,21 @@
|
||||||
<Component id="pnlPacks" alignment="1" max="32767" attributes="0"/>
|
<Component id="pnlPacks" alignment="1" max="32767" attributes="0"/>
|
||||||
<Group type="102" alignment="1" attributes="0">
|
<Group type="102" alignment="1" attributes="0">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Component id="lblPacks" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="lblPlayer1" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||||
<Group type="102" alignment="0" attributes="0">
|
<Group type="102" alignment="0" attributes="0">
|
||||||
<Component id="lblNbrPlayers" min="-2" max="-2" attributes="0"/>
|
<Component id="lblNbrPlayers" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Component id="spnNumPlayers" min="-2" pref="46" max="-2" attributes="0"/>
|
<Component id="spnNumPlayers" min="-2" pref="46" max="-2" attributes="0"/>
|
||||||
</Group>
|
|
||||||
<Group type="102" alignment="0" attributes="0">
|
|
||||||
<Component id="lblNbrSeats" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Component id="spnNumSeats" min="-2" pref="46" max="-2" attributes="0"/>
|
<Component id="lblNumWins" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="spnNumWins" min="-2" pref="50" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="chkSingleMultiplayerGame" min="-2" max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
<Component id="lblPacks" alignment="0" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="lblPlayer1" alignment="0" min="-2" max="-2" attributes="0"/>
|
|
||||||
</Group>
|
</Group>
|
||||||
|
<EmptySpace min="-2" pref="21" max="-2" attributes="0"/>
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Group type="102" attributes="0">
|
<Group type="102" attributes="0">
|
||||||
<EmptySpace min="-2" pref="28" max="-2" attributes="0"/>
|
<EmptySpace min="-2" pref="28" max="-2" attributes="0"/>
|
||||||
|
|
@ -122,10 +121,7 @@
|
||||||
<EmptySpace max="32767" attributes="0"/>
|
<EmptySpace max="32767" attributes="0"/>
|
||||||
<Component id="lblNumRounds" min="-2" max="-2" attributes="0"/>
|
<Component id="lblNumRounds" min="-2" max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
<Group type="102" attributes="0">
|
<Component id="lblConstructionTime" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace max="32767" attributes="0"/>
|
|
||||||
<Component id="lblConstructionTime" min="-2" max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
</Group>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
|
@ -203,11 +199,7 @@
|
||||||
<Component id="lbBufferTime" min="-2" max="-2" attributes="0"/>
|
<Component id="lbBufferTime" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Component id="cbBufferTime" min="-2" pref="101" max="-2" attributes="1"/>
|
<Component id="cbBufferTime" min="-2" pref="101" max="-2" attributes="1"/>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace min="-2" pref="87" max="-2" attributes="0"/>
|
||||||
<Component id="lblNumWins" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Component id="spnNumWins" min="-2" pref="50" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Component id="chkRollbackTurnsAllowed" min="-2" max="-2" attributes="0"/>
|
<Component id="chkRollbackTurnsAllowed" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Component id="cbAllowSpectators" min="-2" max="-2" attributes="0"/>
|
<Component id="cbAllowSpectators" min="-2" max="-2" attributes="0"/>
|
||||||
|
|
@ -225,8 +217,6 @@
|
||||||
<EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
|
<EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Group type="103" alignment="0" groupAlignment="3" attributes="0">
|
<Group type="103" alignment="0" groupAlignment="3" attributes="0">
|
||||||
<Component id="lblNumWins" alignment="3" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="spnNumWins" alignment="3" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="chkRollbackTurnsAllowed" alignment="3" min="-2" max="-2" attributes="0"/>
|
<Component id="chkRollbackTurnsAllowed" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
<Component id="cbAllowSpectators" alignment="3" max="32767" attributes="0"/>
|
<Component id="cbAllowSpectators" alignment="3" max="32767" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
@ -290,7 +280,7 @@
|
||||||
<Group type="102" attributes="0">
|
<Group type="102" attributes="0">
|
||||||
<Component id="pnlPacks" min="-2" max="-2" attributes="0"/>
|
<Component id="pnlPacks" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Component id="pnlRandomPacks" pref="9" max="32767" attributes="0"/>
|
<Component id="pnlRandomPacks" pref="20" max="32767" attributes="0"/>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Group type="103" groupAlignment="1" max="-2" attributes="0">
|
<Group type="103" groupAlignment="1" max="-2" attributes="0">
|
||||||
<Group type="103" alignment="1" groupAlignment="3" attributes="0">
|
<Group type="103" alignment="1" groupAlignment="3" attributes="0">
|
||||||
|
|
@ -298,15 +288,17 @@
|
||||||
<Component id="lblNumRounds" alignment="3" min="-2" max="-2" attributes="0"/>
|
<Component id="lblNumRounds" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
<Component id="lblNbrPlayers" alignment="1" max="32767" attributes="0"/>
|
<Component id="lblNbrPlayers" alignment="1" max="32767" attributes="0"/>
|
||||||
<Component id="spnNumPlayers" alignment="1" pref="23" max="32767" attributes="1"/>
|
<Group type="103" alignment="1" groupAlignment="3" attributes="0">
|
||||||
<Component id="pnlDraftOptions" alignment="1" pref="23" max="32767" attributes="1"/>
|
<Component id="spnNumPlayers" alignment="3" max="32767" attributes="1"/>
|
||||||
|
<Component id="chkSingleMultiplayerGame" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Group type="103" alignment="3" groupAlignment="3" attributes="0">
|
||||||
|
<Component id="lblNumWins" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="spnNumWins" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
<Component id="pnlDraftOptions" alignment="1" pref="0" max="32767" attributes="1"/>
|
||||||
</Group>
|
</Group>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace min="-2" pref="27" max="-2" attributes="0"/>
|
||||||
<Group type="103" groupAlignment="1" max="-2" attributes="0">
|
|
||||||
<Component id="lblNbrSeats" alignment="1" max="32767" attributes="0"/>
|
|
||||||
<Component id="spnNumSeats" alignment="1" max="32767" attributes="1"/>
|
|
||||||
</Group>
|
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Component id="lblPlayer1" min="-2" pref="25" max="-2" attributes="0"/>
|
<Component id="lblPlayer1" min="-2" pref="25" max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
<Group type="103" groupAlignment="3" attributes="0">
|
<Group type="103" groupAlignment="3" attributes="0">
|
||||||
|
|
@ -507,19 +499,18 @@
|
||||||
<Property name="text" type="java.lang.String" value="Players:"/>
|
<Property name="text" type="java.lang.String" value="Players:"/>
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JLabel" name="lblNbrSeats">
|
|
||||||
<Properties>
|
|
||||||
<Property name="text" type="java.lang.String" value="Seats:"/>
|
|
||||||
</Properties>
|
|
||||||
</Component>
|
|
||||||
<Component class="javax.swing.JSpinner" name="spnNumPlayers">
|
<Component class="javax.swing.JSpinner" name="spnNumPlayers">
|
||||||
<Events>
|
<Events>
|
||||||
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="spnNumPlayersStateChanged"/>
|
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="spnNumPlayersStateChanged"/>
|
||||||
</Events>
|
</Events>
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JSpinner" name="spnNumSeats">
|
<Component class="javax.swing.JCheckBox" name="chkSingleMultiplayerGame">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" value="play as single game"/>
|
||||||
|
<Property name="toolTipText" type="java.lang.String" value="<HTML>Allow to play single game with all tourney's players -- e.g. play one game after draft with 4 players"/>
|
||||||
|
</Properties>
|
||||||
<Events>
|
<Events>
|
||||||
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="spnNumSeatsStateChanged"/>
|
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="chkSingleMultiplayerGameItemStateChanged"/>
|
||||||
</Events>
|
</Events>
|
||||||
</Component>
|
</Component>
|
||||||
<Container class="javax.swing.JPanel" name="pnlDraftOptions">
|
<Container class="javax.swing.JPanel" name="pnlDraftOptions">
|
||||||
|
|
@ -618,7 +609,7 @@
|
||||||
</DimensionLayout>
|
</DimensionLayout>
|
||||||
<DimensionLayout dim="1">
|
<DimensionLayout dim="1">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Component id="pnlOtherPlayers" alignment="0" pref="8" max="32767" attributes="0"/>
|
<Component id="pnlOtherPlayers" alignment="0" pref="15" max="32767" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
</DimensionLayout>
|
</DimensionLayout>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
@ -663,7 +654,6 @@
|
||||||
<EtchetBorder/>
|
<EtchetBorder/>
|
||||||
</Border>
|
</Border>
|
||||||
</Property>
|
</Property>
|
||||||
<Property name="toolTipText" type="java.lang.String" value=""/>
|
|
||||||
</Properties>
|
</Properties>
|
||||||
|
|
||||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout">
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout">
|
||||||
|
|
@ -676,9 +666,6 @@
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JSpinner" name="spnQuitRatio">
|
<Component class="javax.swing.JSpinner" name="spnQuitRatio">
|
||||||
<Properties>
|
|
||||||
<Property name="toolTipText" type="java.lang.String" value=""/>
|
|
||||||
</Properties>
|
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JLabel" name="lblMinimumRating">
|
<Component class="javax.swing.JLabel" name="lblMinimumRating">
|
||||||
<Properties>
|
<Properties>
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,11 @@ public class NewTournamentDialog extends MageDialog {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(NewTournamentDialog.class);
|
private static final Logger logger = Logger.getLogger(NewTournamentDialog.class);
|
||||||
|
|
||||||
|
// it's ok to have 4 players at the screen, 6 is fine for big screens too
|
||||||
|
private static final int MAX_WORKABLE_PLAYERS_PER_GAME = 6;
|
||||||
|
|
||||||
|
private static final String CUBE_FROM_DECK_NAME = "Cube From Deck";
|
||||||
|
|
||||||
// temp settings on loading players list
|
// temp settings on loading players list
|
||||||
private final List<PlayerType> prefPlayerTypes = new ArrayList<>();
|
private final List<PlayerType> prefPlayerTypes = new ArrayList<>();
|
||||||
private final List<Integer> prefPlayerSkills = new ArrayList<>();
|
private final List<Integer> prefPlayerSkills = new ArrayList<>();
|
||||||
|
|
@ -77,12 +82,15 @@ public class NewTournamentDialog extends MageDialog {
|
||||||
|
|
||||||
private int getCurrentNumPlayers() {
|
private int getCurrentNumPlayers() {
|
||||||
int res = (Integer) spnNumPlayers.getValue();
|
int res = (Integer) spnNumPlayers.getValue();
|
||||||
return res > 0 ? res : 2;
|
return Math.max(2, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getCurrentNumSeats() {
|
private int getCurrentNumSeats() {
|
||||||
int res = (Integer) spnNumSeats.getValue();
|
if (chkSingleMultiplayerGame.isSelected()) {
|
||||||
return res > 0 ? res : 2;
|
return getCurrentNumPlayers();
|
||||||
|
} else {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showDialog(UUID roomId) {
|
public void showDialog(UUID roomId) {
|
||||||
|
|
@ -159,9 +167,8 @@ public class NewTournamentDialog extends MageDialog {
|
||||||
lblPacks = new javax.swing.JLabel();
|
lblPacks = new javax.swing.JLabel();
|
||||||
pnlPacks = new javax.swing.JPanel();
|
pnlPacks = new javax.swing.JPanel();
|
||||||
lblNbrPlayers = new javax.swing.JLabel();
|
lblNbrPlayers = new javax.swing.JLabel();
|
||||||
lblNbrSeats = new javax.swing.JLabel();
|
|
||||||
spnNumPlayers = new javax.swing.JSpinner();
|
spnNumPlayers = new javax.swing.JSpinner();
|
||||||
spnNumSeats = new javax.swing.JSpinner();
|
chkSingleMultiplayerGame = new javax.swing.JCheckBox();
|
||||||
pnlDraftOptions = new javax.swing.JPanel();
|
pnlDraftOptions = new javax.swing.JPanel();
|
||||||
jLabel6 = new javax.swing.JLabel();
|
jLabel6 = new javax.swing.JLabel();
|
||||||
cbDraftTiming = new javax.swing.JComboBox();
|
cbDraftTiming = new javax.swing.JComboBox();
|
||||||
|
|
@ -203,7 +210,6 @@ public class NewTournamentDialog extends MageDialog {
|
||||||
popupSaveSettings.add(menuSaveSettings2);
|
popupSaveSettings.add(menuSaveSettings2);
|
||||||
|
|
||||||
menuLoadSettingsLast.setText("Load from last time");
|
menuLoadSettingsLast.setText("Load from last time");
|
||||||
menuLoadSettingsLast.setToolTipText("");
|
|
||||||
menuLoadSettingsLast.addActionListener(new java.awt.event.ActionListener() {
|
menuLoadSettingsLast.addActionListener(new java.awt.event.ActionListener() {
|
||||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
menuLoadSettingsLastActionPerformed(evt);
|
menuLoadSettingsLastActionPerformed(evt);
|
||||||
|
|
@ -213,7 +219,6 @@ public class NewTournamentDialog extends MageDialog {
|
||||||
popupLoadSettings.add(separator1);
|
popupLoadSettings.add(separator1);
|
||||||
|
|
||||||
menuLoadSettings1.setText("Load from config 1");
|
menuLoadSettings1.setText("Load from config 1");
|
||||||
menuLoadSettings1.setToolTipText("");
|
|
||||||
menuLoadSettings1.addActionListener(new java.awt.event.ActionListener() {
|
menuLoadSettings1.addActionListener(new java.awt.event.ActionListener() {
|
||||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
menuLoadSettings1ActionPerformed(evt);
|
menuLoadSettings1ActionPerformed(evt);
|
||||||
|
|
@ -231,7 +236,6 @@ public class NewTournamentDialog extends MageDialog {
|
||||||
popupLoadSettings.add(separator2);
|
popupLoadSettings.add(separator2);
|
||||||
|
|
||||||
menuLoadSettingsDefault.setText("Load default settings");
|
menuLoadSettingsDefault.setText("Load default settings");
|
||||||
menuLoadSettingsDefault.setToolTipText("");
|
|
||||||
menuLoadSettingsDefault.addActionListener(new java.awt.event.ActionListener() {
|
menuLoadSettingsDefault.addActionListener(new java.awt.event.ActionListener() {
|
||||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
menuLoadSettingsDefaultActionPerformed(evt);
|
menuLoadSettingsDefaultActionPerformed(evt);
|
||||||
|
|
@ -324,17 +328,17 @@ public class NewTournamentDialog extends MageDialog {
|
||||||
|
|
||||||
lblNbrPlayers.setText("Players:");
|
lblNbrPlayers.setText("Players:");
|
||||||
|
|
||||||
lblNbrSeats.setText("Seats:");
|
|
||||||
|
|
||||||
spnNumPlayers.addChangeListener(new javax.swing.event.ChangeListener() {
|
spnNumPlayers.addChangeListener(new javax.swing.event.ChangeListener() {
|
||||||
public void stateChanged(javax.swing.event.ChangeEvent evt) {
|
public void stateChanged(javax.swing.event.ChangeEvent evt) {
|
||||||
spnNumPlayersStateChanged(evt);
|
spnNumPlayersStateChanged(evt);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
spnNumSeats.addChangeListener(new javax.swing.event.ChangeListener() {
|
chkSingleMultiplayerGame.setText("play as single game");
|
||||||
public void stateChanged(javax.swing.event.ChangeEvent evt) {
|
chkSingleMultiplayerGame.setToolTipText("<HTML>Allow to play single game with all tourney's players -- e.g. play one game after draft with 4 players");
|
||||||
spnNumSeatsStateChanged(evt);
|
chkSingleMultiplayerGame.addItemListener(new java.awt.event.ItemListener() {
|
||||||
|
public void itemStateChanged(java.awt.event.ItemEvent evt) {
|
||||||
|
chkSingleMultiplayerGameItemStateChanged(evt);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -393,7 +397,7 @@ public class NewTournamentDialog extends MageDialog {
|
||||||
);
|
);
|
||||||
pnlPlayersLayout.setVerticalGroup(
|
pnlPlayersLayout.setVerticalGroup(
|
||||||
pnlPlayersLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
pnlPlayersLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addComponent(pnlOtherPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, 8, Short.MAX_VALUE)
|
.addComponent(pnlOtherPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, 15, Short.MAX_VALUE)
|
||||||
);
|
);
|
||||||
|
|
||||||
btnOk.setText("Create");
|
btnOk.setText("Create");
|
||||||
|
|
@ -411,13 +415,10 @@ public class NewTournamentDialog extends MageDialog {
|
||||||
});
|
});
|
||||||
|
|
||||||
pnlRandomPacks.setBorder(javax.swing.BorderFactory.createEtchedBorder());
|
pnlRandomPacks.setBorder(javax.swing.BorderFactory.createEtchedBorder());
|
||||||
pnlRandomPacks.setToolTipText("");
|
|
||||||
pnlRandomPacks.setLayout(new javax.swing.BoxLayout(pnlRandomPacks, javax.swing.BoxLayout.Y_AXIS));
|
pnlRandomPacks.setLayout(new javax.swing.BoxLayout(pnlRandomPacks, javax.swing.BoxLayout.Y_AXIS));
|
||||||
|
|
||||||
lblQuitRatio.setText("Allowed quit %");
|
lblQuitRatio.setText("Allowed quit %");
|
||||||
|
|
||||||
spnQuitRatio.setToolTipText("");
|
|
||||||
|
|
||||||
lblMinimumRating.setText("Minimum rating:");
|
lblMinimumRating.setText("Minimum rating:");
|
||||||
lblMinimumRating.setToolTipText("Players with rating less than this value can't join this table");
|
lblMinimumRating.setToolTipText("Players with rating less than this value can't join this table");
|
||||||
|
|
||||||
|
|
@ -466,25 +467,26 @@ public class NewTournamentDialog extends MageDialog {
|
||||||
.addComponent(pnlPacks, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
.addComponent(pnlPacks, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addComponent(lblPacks)
|
||||||
|
.addComponent(lblPlayer1)
|
||||||
.addGroup(layout.createSequentialGroup()
|
.addGroup(layout.createSequentialGroup()
|
||||||
.addComponent(lblNbrPlayers)
|
.addComponent(lblNbrPlayers)
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
.addComponent(spnNumPlayers, javax.swing.GroupLayout.PREFERRED_SIZE, 46, javax.swing.GroupLayout.PREFERRED_SIZE))
|
.addComponent(spnNumPlayers, javax.swing.GroupLayout.PREFERRED_SIZE, 46, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
.addGroup(layout.createSequentialGroup()
|
|
||||||
.addComponent(lblNbrSeats)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
.addComponent(spnNumSeats, javax.swing.GroupLayout.PREFERRED_SIZE, 46, javax.swing.GroupLayout.PREFERRED_SIZE))
|
.addComponent(lblNumWins)
|
||||||
.addComponent(lblPacks)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
.addComponent(lblPlayer1))
|
.addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(chkSingleMultiplayerGame)))
|
||||||
|
.addGap(21, 21, 21)
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addGroup(layout.createSequentialGroup()
|
.addGroup(layout.createSequentialGroup()
|
||||||
.addGap(28, 28, 28)
|
.addGap(28, 28, 28)
|
||||||
.addComponent(pnlDraftOptions, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addComponent(pnlDraftOptions, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||||
.addComponent(lblNumRounds))
|
.addComponent(lblNumRounds))
|
||||||
.addGroup(layout.createSequentialGroup()
|
.addComponent(lblConstructionTime))
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
|
||||||
.addComponent(lblConstructionTime)))
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addComponent(spnConstructTime, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addComponent(spnConstructTime, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
|
|
@ -551,11 +553,7 @@ public class NewTournamentDialog extends MageDialog {
|
||||||
.addComponent(lbBufferTime)
|
.addComponent(lbBufferTime)
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
.addComponent(cbBufferTime, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addComponent(cbBufferTime, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
.addGap(87, 87, 87)
|
||||||
.addComponent(lblNumWins)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
||||||
.addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
||||||
.addComponent(chkRollbackTurnsAllowed)
|
.addComponent(chkRollbackTurnsAllowed)
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
.addComponent(cbAllowSpectators)))))
|
.addComponent(cbAllowSpectators)))))
|
||||||
|
|
@ -567,8 +565,6 @@ public class NewTournamentDialog extends MageDialog {
|
||||||
.addGap(2, 2, 2)
|
.addGap(2, 2, 2)
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||||
.addComponent(lblNumWins)
|
|
||||||
.addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
|
||||||
.addComponent(chkRollbackTurnsAllowed)
|
.addComponent(chkRollbackTurnsAllowed)
|
||||||
.addComponent(cbAllowSpectators, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
.addComponent(cbAllowSpectators, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||||
|
|
@ -618,20 +614,21 @@ public class NewTournamentDialog extends MageDialog {
|
||||||
.addGroup(layout.createSequentialGroup()
|
.addGroup(layout.createSequentialGroup()
|
||||||
.addComponent(pnlPacks, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addComponent(pnlPacks, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
.addComponent(pnlRandomPacks, javax.swing.GroupLayout.DEFAULT_SIZE, 9, Short.MAX_VALUE)
|
.addComponent(pnlRandomPacks, javax.swing.GroupLayout.DEFAULT_SIZE, 20, Short.MAX_VALUE)
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||||
.addComponent(spnNumRounds, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addComponent(spnNumRounds, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
.addComponent(lblNumRounds))
|
.addComponent(lblNumRounds))
|
||||||
.addComponent(lblNbrPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
.addComponent(lblNbrPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||||
.addComponent(spnNumPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, 23, Short.MAX_VALUE)
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||||
.addComponent(pnlDraftOptions, javax.swing.GroupLayout.PREFERRED_SIZE, 23, Short.MAX_VALUE))
|
.addComponent(spnNumPlayers)
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
.addComponent(chkSingleMultiplayerGame)
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||||
.addComponent(lblNbrSeats, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
.addComponent(lblNumWins)
|
||||||
.addComponent(spnNumSeats))
|
.addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
.addComponent(pnlDraftOptions, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))
|
||||||
|
.addGap(27, 27, 27)
|
||||||
.addComponent(lblPlayer1, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE))
|
.addComponent(lblPlayer1, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||||
.addComponent(spnConstructTime, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addComponent(spnConstructTime, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
|
|
@ -658,7 +655,7 @@ public class NewTournamentDialog extends MageDialog {
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
private void cbTournamentTypeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbTournamentTypeActionPerformed
|
private void cbTournamentTypeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbTournamentTypeActionPerformed
|
||||||
prepareTourneyView(false, prepareVersionStr(-1, false), getCurrentNumPlayers(), getCurrentNumSeats());
|
loadTourneyView(false, prepareVersionStr(-1, false), getCurrentNumPlayers(), chkSingleMultiplayerGame.isSelected());
|
||||||
|
|
||||||
jumpstartPacksFilename = "";
|
jumpstartPacksFilename = "";
|
||||||
if (cbTournamentType.getSelectedItem().toString().matches(".*Jumpstart.*Custom.*")) {
|
if (cbTournamentType.getSelectedItem().toString().matches(".*Jumpstart.*Custom.*")) {
|
||||||
|
|
@ -700,6 +697,38 @@ public class NewTournamentDialog extends MageDialog {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// players count limited by GUI size
|
||||||
|
// draft bots are loses and hide at the start, so count only human and AI
|
||||||
|
if (tOptions.getMatchOptions().isSingleGameTourney()) {
|
||||||
|
int workablePlayers = tOptions.getPlayerTypes().stream()
|
||||||
|
.mapToInt(p -> p.isWorkablePlayer() ? 1 : 0)
|
||||||
|
.sum();
|
||||||
|
if (workablePlayers > MAX_WORKABLE_PLAYERS_PER_GAME) {
|
||||||
|
JOptionPane.showMessageDialog(
|
||||||
|
MageFrame.getDesktop(),
|
||||||
|
String.format("Warning, in single game mode you can choose %d human/ai players but selected %d", MAX_WORKABLE_PLAYERS_PER_GAME, workablePlayers),
|
||||||
|
"Warning",
|
||||||
|
JOptionPane.WARNING_MESSAGE
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// cube from deck uses weird choose logic from combobox select, so players can forget or cancel it
|
||||||
|
if (tournamentType.isDraft()
|
||||||
|
&& tOptions.getLimitedOptions().getDraftCubeName() != null
|
||||||
|
&& tOptions.getLimitedOptions().getDraftCubeName().contains(CUBE_FROM_DECK_NAME)) {
|
||||||
|
if (tOptions.getLimitedOptions().getCubeFromDeck() == null || tOptions.getLimitedOptions().getCubeFromDeck().getCards().isEmpty()) {
|
||||||
|
JOptionPane.showMessageDialog(
|
||||||
|
MageFrame.getDesktop(),
|
||||||
|
"Found empty cube. You must choose Cube From Deck again and select existing deck file.",
|
||||||
|
"Warning",
|
||||||
|
JOptionPane.WARNING_MESSAGE
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// save last settings
|
// save last settings
|
||||||
onSaveSettings(0, tOptions);
|
onSaveSettings(0, tOptions);
|
||||||
|
|
||||||
|
|
@ -747,44 +776,29 @@ public class NewTournamentDialog extends MageDialog {
|
||||||
doClose();
|
doClose();
|
||||||
}//GEN-LAST:event_btnCancelActionPerformed
|
}//GEN-LAST:event_btnCancelActionPerformed
|
||||||
|
|
||||||
private void updateNumSeats() {
|
private void applyNewPlayersCount() {
|
||||||
int numSeats = (Integer) this.spnNumSeats.getValue();
|
// make sure players count is compatible
|
||||||
|
int numPlayers = getCurrentNumPlayers();
|
||||||
|
int compatiblePlayers = getCompatiblePlayersCount(numPlayers);
|
||||||
|
if (numPlayers != compatiblePlayers) {
|
||||||
|
numPlayers = compatiblePlayers;
|
||||||
|
spnNumPlayers.setValue(numPlayers);
|
||||||
|
}
|
||||||
|
createPlayers(numPlayers - 1);
|
||||||
|
|
||||||
if (numSeats > 2) {
|
// make sure wins is compatible
|
||||||
TournamentTypeView tournamentType = (TournamentTypeView) cbTournamentType.getSelectedItem();
|
// is's can be a too long match for 2+ wins in 4+ game
|
||||||
if (numSeats >= tournamentType.getMinPlayers()) {
|
if (chkSingleMultiplayerGame.isSelected()) {
|
||||||
createPlayers(numSeats - 1);
|
|
||||||
spnNumPlayers.setValue(numSeats);
|
|
||||||
} else {
|
|
||||||
numSeats = tournamentType.getMinPlayers();
|
|
||||||
createPlayers(numSeats - 1);
|
|
||||||
spnNumPlayers.setValue(numSeats);
|
|
||||||
spnNumSeats.setValue(numSeats);
|
|
||||||
}
|
|
||||||
spnNumWins.setValue(1);
|
spnNumWins.setValue(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void spnNumPlayersStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spnNumPlayersStateChanged
|
private void spnNumPlayersStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spnNumPlayersStateChanged
|
||||||
int numPlayers = getCurrentNumPlayers();
|
applyNewPlayersCount();
|
||||||
createPlayers(numPlayers - 1);
|
|
||||||
int numSeats = (Integer) this.spnNumSeats.getValue();
|
|
||||||
if (numSeats > 2 && numPlayers != numSeats) {
|
|
||||||
updateNumSeats();
|
|
||||||
}
|
|
||||||
}//GEN-LAST:event_spnNumPlayersStateChanged
|
}//GEN-LAST:event_spnNumPlayersStateChanged
|
||||||
|
|
||||||
private void spnNumSeatsStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spnNumSeatsStateChanged
|
|
||||||
int numSeats = (Integer) this.spnNumSeats.getValue();
|
|
||||||
this.spnNumPlayers.setEnabled(numSeats <= 2);
|
|
||||||
updateNumSeats();
|
|
||||||
}//GEN-LAST:event_spnNumSeatsStateChanged
|
|
||||||
|
|
||||||
private void spnNumWinsnumPlayersChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spnNumWinsnumPlayersChanged
|
private void spnNumWinsnumPlayersChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spnNumWinsnumPlayersChanged
|
||||||
int numSeats = getCurrentNumSeats();
|
applyNewPlayersCount();
|
||||||
if (numSeats > 2) {
|
|
||||||
spnNumWins.setValue(1);
|
|
||||||
}
|
|
||||||
}//GEN-LAST:event_spnNumWinsnumPlayersChanged
|
}//GEN-LAST:event_spnNumWinsnumPlayersChanged
|
||||||
|
|
||||||
private JFileChooser fcSelectDeck = null;
|
private JFileChooser fcSelectDeck = null;
|
||||||
|
|
@ -829,7 +843,7 @@ public class NewTournamentDialog extends MageDialog {
|
||||||
|
|
||||||
private void cbDraftCubeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbDraftCubeActionPerformed
|
private void cbDraftCubeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbDraftCubeActionPerformed
|
||||||
cubeFromDeckFilename = "";
|
cubeFromDeckFilename = "";
|
||||||
if (cbDraftCube.getSelectedItem().toString().equals("Cube From Deck")) {
|
if (cbDraftCube.getSelectedItem().toString().startsWith(CUBE_FROM_DECK_NAME)) {
|
||||||
cubeFromDeckFilename = playerLoadDeck();
|
cubeFromDeckFilename = playerLoadDeck();
|
||||||
}
|
}
|
||||||
}//GEN-LAST:event_cbDraftCubeActionPerformed
|
}//GEN-LAST:event_cbDraftCubeActionPerformed
|
||||||
|
|
@ -886,27 +900,52 @@ public class NewTournamentDialog extends MageDialog {
|
||||||
customOptions.showDialog();
|
customOptions.showDialog();
|
||||||
}//GEN-LAST:event_btnCustomOptionsActionPerformed
|
}//GEN-LAST:event_btnCustomOptionsActionPerformed
|
||||||
|
|
||||||
|
private void chkSingleMultiplayerGameItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_chkSingleMultiplayerGameItemStateChanged
|
||||||
|
// for checkboxes - it's important to use ItemStateChanged instead stateChanged
|
||||||
|
// (the last one will raise on moving mouse over, not on checkbox state change only)
|
||||||
|
applyNewPlayersCount();
|
||||||
|
}//GEN-LAST:event_chkSingleMultiplayerGameItemStateChanged
|
||||||
|
|
||||||
private void setGameOptions() {
|
private void setGameOptions() {
|
||||||
createPlayers(getCurrentNumPlayers() - 1);
|
createPlayers(getCurrentNumPlayers() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void prepareTourneyView(boolean loadPlayerSettings, String versionStr, int numPlayers, int numSeats) {
|
private int getCompatiblePlayersCount(int count) {
|
||||||
|
TournamentTypeView tournamentType = (TournamentTypeView) cbTournamentType.getSelectedItem();
|
||||||
|
if (tournamentType == null) {
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
int compatibleMin = tournamentType.getMinPlayers();
|
||||||
|
int compatibleMax = tournamentType.getMaxPlayers();
|
||||||
|
|
||||||
|
if (chkSingleMultiplayerGame.isSelected()) {
|
||||||
|
// user can select any amount of draft bots, real amount checks on submit
|
||||||
|
//compatibleMax = Math.min(MAX_PLAYERS_PER_GAME, compatibleMax);
|
||||||
|
}
|
||||||
|
|
||||||
|
int compatibleCount = count;
|
||||||
|
compatibleCount = Math.max(compatibleCount, compatibleMin);
|
||||||
|
compatibleCount = Math.min(compatibleCount, compatibleMax);
|
||||||
|
return compatibleCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadTourneyView(boolean loadPlayerSettings, String versionStr, int numPlayers, boolean isSingleMultiplayerGame) {
|
||||||
TournamentTypeView tournamentType = (TournamentTypeView) cbTournamentType.getSelectedItem();
|
TournamentTypeView tournamentType = (TournamentTypeView) cbTournamentType.getSelectedItem();
|
||||||
activatePanelElements(tournamentType);
|
activatePanelElements(tournamentType);
|
||||||
|
|
||||||
if (numPlayers < tournamentType.getMinPlayers() || numPlayers > tournamentType.getMaxPlayers()) {
|
numPlayers = getCompatiblePlayersCount(numPlayers);
|
||||||
numPlayers = tournamentType.getMinPlayers();
|
|
||||||
}
|
|
||||||
this.spnNumPlayers.setModel(new SpinnerNumberModel(numPlayers, tournamentType.getMinPlayers(), tournamentType.getMaxPlayers(), 1));
|
this.spnNumPlayers.setModel(new SpinnerNumberModel(numPlayers, tournamentType.getMinPlayers(), tournamentType.getMaxPlayers(), 1));
|
||||||
this.spnNumPlayers.setEnabled(tournamentType.getMinPlayers() != tournamentType.getMaxPlayers());
|
this.spnNumPlayers.setEnabled(tournamentType.getMinPlayers() != tournamentType.getMaxPlayers());
|
||||||
this.spnNumSeats.setModel(new SpinnerNumberModel(2, 2, tournamentType.getMaxPlayers(), 1));
|
|
||||||
|
|
||||||
// manual call change events to apply players/seats restrictions and create miss panels
|
// manual call change events to apply players restrictions and create miss panels before load player related settings
|
||||||
// TODO: refactor to use isLoading and restrictions from a code instead restrictions from a component
|
// TODO: refactor to use isLoading and restrictions from a code instead restrictions from a component
|
||||||
|
this.chkSingleMultiplayerGame.setSelected(isSingleMultiplayerGame);
|
||||||
this.spnNumPlayers.setValue(numPlayers);
|
this.spnNumPlayers.setValue(numPlayers);
|
||||||
spnNumPlayersStateChanged(null);
|
spnNumPlayersStateChanged(null);
|
||||||
this.spnNumSeats.setValue(numSeats);
|
|
||||||
spnNumSeatsStateChanged(null);
|
// wins must be loaded after chkSingleMultiplayerGame change, cause it can be limited by 1
|
||||||
|
int numWins = Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_NUMBER_OF_WINS + versionStr, "2"));
|
||||||
|
this.spnNumWins.setValue(numWins);
|
||||||
|
|
||||||
if (loadPlayerSettings) {
|
if (loadPlayerSettings) {
|
||||||
// load player data
|
// load player data
|
||||||
|
|
@ -1265,8 +1304,7 @@ public class NewTournamentDialog extends MageDialog {
|
||||||
|
|
||||||
private TournamentOptions getTournamentOptions() {
|
private TournamentOptions getTournamentOptions() {
|
||||||
TournamentTypeView tournamentType = (TournamentTypeView) cbTournamentType.getSelectedItem();
|
TournamentTypeView tournamentType = (TournamentTypeView) cbTournamentType.getSelectedItem();
|
||||||
int numSeats = (Integer) this.spnNumSeats.getValue();
|
TournamentOptions tOptions = new TournamentOptions(this.txtName.getText(), "", chkSingleMultiplayerGame.isSelected());
|
||||||
TournamentOptions tOptions = new TournamentOptions(this.txtName.getText(), "", numSeats);
|
|
||||||
tOptions.setTournamentType(tournamentType.getName());
|
tOptions.setTournamentType(tournamentType.getName());
|
||||||
tOptions.setPassword(txtPassword.getText());
|
tOptions.setPassword(txtPassword.getText());
|
||||||
tOptions.getPlayerTypes().add(PlayerType.HUMAN);
|
tOptions.getPlayerTypes().add(PlayerType.HUMAN);
|
||||||
|
|
@ -1429,7 +1467,6 @@ public class NewTournamentDialog extends MageDialog {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.spnNumWins.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_NUMBER_OF_WINS + versionStr, "2")));
|
|
||||||
this.spnQuitRatio.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_QUIT_RATIO + versionStr, "100")));
|
this.spnQuitRatio.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_QUIT_RATIO + versionStr, "100")));
|
||||||
this.spnMinimumRating.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_MINIMUM_RATING + versionStr, "0")));
|
this.spnMinimumRating.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_MINIMUM_RATING + versionStr, "0")));
|
||||||
|
|
||||||
|
|
@ -1437,7 +1474,6 @@ public class NewTournamentDialog extends MageDialog {
|
||||||
activatePanelElements(tournamentType);
|
activatePanelElements(tournamentType);
|
||||||
|
|
||||||
int defaultNumberPlayers = 2;
|
int defaultNumberPlayers = 2;
|
||||||
int defaultNumberSeats = 2;
|
|
||||||
if (tournamentType.isLimited()) {
|
if (tournamentType.isLimited()) {
|
||||||
if (tournamentType.isDraft()) {
|
if (tournamentType.isDraft()) {
|
||||||
defaultNumberPlayers = 4;
|
defaultNumberPlayers = 4;
|
||||||
|
|
@ -1468,8 +1504,8 @@ public class NewTournamentDialog extends MageDialog {
|
||||||
}
|
}
|
||||||
|
|
||||||
int numPlayers = Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_NUMBER_PLAYERS + versionStr, String.valueOf(defaultNumberPlayers)));
|
int numPlayers = Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_NUMBER_PLAYERS + versionStr, String.valueOf(defaultNumberPlayers)));
|
||||||
int numSeats = Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_NUMBER_SEATS + versionStr, String.valueOf(defaultNumberSeats)));
|
boolean isSingleMultiplayerGame = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_SINGLE_MULTIPLAYER_GAME + versionStr, "No").equals("Yes");
|
||||||
prepareTourneyView(true, versionStr, numPlayers, numSeats);
|
loadTourneyView(true, versionStr, numPlayers, isSingleMultiplayerGame);
|
||||||
|
|
||||||
this.customOptions.onLoadSettings(version);
|
this.customOptions.onLoadSettings(version);
|
||||||
}
|
}
|
||||||
|
|
@ -1517,7 +1553,7 @@ public class NewTournamentDialog extends MageDialog {
|
||||||
}
|
}
|
||||||
|
|
||||||
PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TOURNAMENT_NUMBER_PLAYERS + versionStr, Integer.toString(tOptions.getPlayerTypes().size()));
|
PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TOURNAMENT_NUMBER_PLAYERS + versionStr, Integer.toString(tOptions.getPlayerTypes().size()));
|
||||||
PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TOURNAMENT_NUMBER_SEATS + versionStr, Integer.toString((Integer) this.spnNumSeats.getValue()));
|
PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TOURNAMENT_SINGLE_MULTIPLAYER_GAME + versionStr, (tOptions.getMatchOptions().isSingleGameTourney() ? "Yes" : "No"));
|
||||||
|
|
||||||
// save player data
|
// save player data
|
||||||
// player type
|
// player type
|
||||||
|
|
@ -1558,6 +1594,7 @@ public class NewTournamentDialog extends MageDialog {
|
||||||
private javax.swing.JComboBox cbTournamentType;
|
private javax.swing.JComboBox cbTournamentType;
|
||||||
private javax.swing.JCheckBox chkRated;
|
private javax.swing.JCheckBox chkRated;
|
||||||
private javax.swing.JCheckBox chkRollbackTurnsAllowed;
|
private javax.swing.JCheckBox chkRollbackTurnsAllowed;
|
||||||
|
private javax.swing.JCheckBox chkSingleMultiplayerGame;
|
||||||
private javax.swing.JLabel jLabel6;
|
private javax.swing.JLabel jLabel6;
|
||||||
private javax.swing.JLabel lbBufferTime;
|
private javax.swing.JLabel lbBufferTime;
|
||||||
private javax.swing.JLabel lbDeckType;
|
private javax.swing.JLabel lbDeckType;
|
||||||
|
|
@ -1569,7 +1606,6 @@ public class NewTournamentDialog extends MageDialog {
|
||||||
private javax.swing.JLabel lblMinimumRating;
|
private javax.swing.JLabel lblMinimumRating;
|
||||||
private javax.swing.JLabel lblName;
|
private javax.swing.JLabel lblName;
|
||||||
private javax.swing.JLabel lblNbrPlayers;
|
private javax.swing.JLabel lblNbrPlayers;
|
||||||
private javax.swing.JLabel lblNbrSeats;
|
|
||||||
private javax.swing.JLabel lblNumRounds;
|
private javax.swing.JLabel lblNumRounds;
|
||||||
private javax.swing.JLabel lblNumWins;
|
private javax.swing.JLabel lblNumWins;
|
||||||
private javax.swing.JLabel lblPacks;
|
private javax.swing.JLabel lblPacks;
|
||||||
|
|
@ -1598,7 +1634,6 @@ public class NewTournamentDialog extends MageDialog {
|
||||||
private javax.swing.JSpinner spnMinimumRating;
|
private javax.swing.JSpinner spnMinimumRating;
|
||||||
private javax.swing.JSpinner spnNumPlayers;
|
private javax.swing.JSpinner spnNumPlayers;
|
||||||
private javax.swing.JSpinner spnNumRounds;
|
private javax.swing.JSpinner spnNumRounds;
|
||||||
private javax.swing.JSpinner spnNumSeats;
|
|
||||||
private javax.swing.JSpinner spnNumWins;
|
private javax.swing.JSpinner spnNumWins;
|
||||||
private javax.swing.JSpinner spnQuitRatio;
|
private javax.swing.JSpinner spnQuitRatio;
|
||||||
private javax.swing.JTextField txtName;
|
private javax.swing.JTextField txtName;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package mage.client.dialog;
|
package mage.client.dialog;
|
||||||
|
|
||||||
|
import mage.client.cards.BigCard;
|
||||||
|
import mage.client.components.MageTextArea;
|
||||||
import mage.constants.ColoredManaSymbol;
|
import mage.constants.ColoredManaSymbol;
|
||||||
import mage.util.MultiAmountMessage;
|
import mage.util.MultiAmountMessage;
|
||||||
|
|
||||||
|
|
@ -11,20 +13,24 @@ import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Game GUI: dialog to distribute values between multiple items
|
* Game GUI: dialog to distribute values between multiple items
|
||||||
* (used for some cards and add lands in cheat menu, search by MultiAmountMessage)
|
* (used for some cards and add lands in cheat menu, search by MultiAmountMessage)
|
||||||
*
|
*
|
||||||
* @author weirddan455
|
* @author weirddan455, JayDi85
|
||||||
*/
|
*/
|
||||||
public class PickMultiNumberDialog extends MageDialog {
|
public class PickMultiNumberDialog extends MageDialog {
|
||||||
|
|
||||||
private boolean cancel;
|
private boolean cancel;
|
||||||
private PickMultiNumberCallback callback = null;
|
private PickMultiNumberCallback callback = null;
|
||||||
|
|
||||||
private List<JLabel> labelList = null;
|
private UUID gameId = null;
|
||||||
|
private BigCard bigCard = null;
|
||||||
|
|
||||||
|
private List<MageTextArea> infoList = null;
|
||||||
private List<JSpinner> spinnerList = null;
|
private List<JSpinner> spinnerList = null;
|
||||||
|
|
||||||
public PickMultiNumberDialog() {
|
public PickMultiNumberDialog() {
|
||||||
|
|
@ -36,6 +42,11 @@ public class PickMultiNumberDialog extends MageDialog {
|
||||||
void onChoiceDone();
|
void onChoiceDone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void init(UUID gameId, BigCard bigCard) {
|
||||||
|
this.gameId = gameId;
|
||||||
|
this.bigCard = bigCard;
|
||||||
|
}
|
||||||
|
|
||||||
public void showDialog(List<MultiAmountMessage> messages, int min, int max, Map<String, Serializable> options, PickMultiNumberCallback callback) {
|
public void showDialog(List<MultiAmountMessage> messages, int min, int max, Map<String, Serializable> options, PickMultiNumberCallback callback) {
|
||||||
this.cancel = false;
|
this.cancel = false;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
|
|
@ -46,9 +57,10 @@ public class PickMultiNumberDialog extends MageDialog {
|
||||||
boolean canCancel = options.get("canCancel") != null && (boolean) options.get("canCancel");
|
boolean canCancel = options.get("canCancel") != null && (boolean) options.get("canCancel");
|
||||||
btnCancel.setVisible(canCancel);
|
btnCancel.setVisible(canCancel);
|
||||||
|
|
||||||
if (labelList != null) {
|
// clean
|
||||||
for (JLabel label : labelList) {
|
if (infoList != null) {
|
||||||
jPanel1.remove(label);
|
for (MageTextArea info : infoList) {
|
||||||
|
jPanel1.remove(info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (spinnerList != null) {
|
if (spinnerList != null) {
|
||||||
|
|
@ -56,14 +68,15 @@ public class PickMultiNumberDialog extends MageDialog {
|
||||||
jPanel1.remove(spinner);
|
jPanel1.remove(spinner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int size = messages.size();
|
int size = messages.size();
|
||||||
labelList = new ArrayList<>(size);
|
infoList = new ArrayList<>(size);
|
||||||
spinnerList = new ArrayList<>(size);
|
spinnerList = new ArrayList<>(size);
|
||||||
jPanel1.setLayout(new GridBagLayout());
|
jPanel1.setLayout(new GridBagLayout());
|
||||||
GridBagConstraints labelC = new GridBagConstraints();
|
|
||||||
GridBagConstraints spinnerC = new GridBagConstraints();
|
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
JLabel label = new JLabel();
|
MageTextArea info = new MageTextArea();
|
||||||
|
info.enableTextLabelMode();
|
||||||
|
info.setGameData(this.gameId, this.bigCard);
|
||||||
|
|
||||||
// mana mode
|
// mana mode
|
||||||
String manaText = null;
|
String manaText = null;
|
||||||
|
|
@ -86,24 +99,23 @@ public class PickMultiNumberDialog extends MageDialog {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (manaText != null) {
|
if (manaText != null) {
|
||||||
label.setText("<html>" + manaText);
|
// mana mode
|
||||||
Image image = ManaSymbols.getSizedManaSymbol(input);
|
info.setText("{" + input + "}" + " " + manaText);
|
||||||
if (image != null) {
|
|
||||||
label.setIcon(new ImageIcon(image));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// text mode
|
// text mode
|
||||||
label.setText("<html>" + ManaSymbols.replaceSymbolsWithHTML(input, ManaSymbols.Type.DIALOG));
|
info.setText(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
labelC.weightx = 0.5;
|
GridBagConstraints infoC = new GridBagConstraints();
|
||||||
labelC.gridx = 0;
|
infoC.weightx = 0.5;
|
||||||
labelC.gridy = i;
|
infoC.gridx = 0;
|
||||||
jPanel1.add(label, labelC);
|
infoC.gridy = i;
|
||||||
labelList.add(label);
|
jPanel1.add(info, infoC);
|
||||||
|
infoList.add(info);
|
||||||
|
|
||||||
JSpinner spinner = new JSpinner();
|
JSpinner spinner = new JSpinner();
|
||||||
spinner.setModel(new SpinnerNumberModel(messages.get(i).defaultValue, messages.get(i).min, messages.get(i).max, 1));
|
spinner.setModel(new SpinnerNumberModel(messages.get(i).defaultValue, messages.get(i).min, messages.get(i).max, 1));
|
||||||
|
GridBagConstraints spinnerC = new GridBagConstraints();
|
||||||
spinnerC.weightx = 0.5;
|
spinnerC.weightx = 0.5;
|
||||||
spinnerC.gridx = 1;
|
spinnerC.gridx = 1;
|
||||||
spinnerC.gridy = i;
|
spinnerC.gridy = i;
|
||||||
|
|
|
||||||
|
|
@ -2010,7 +2010,6 @@
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="horizontalAlignment" type="int" value="2"/>
|
<Property name="horizontalAlignment" type="int" value="2"/>
|
||||||
<Property name="text" type="java.lang.String" value="GUI color style:"/>
|
<Property name="text" type="java.lang.String" value="GUI color style:"/>
|
||||||
<Property name="toolTipText" type="java.lang.String" value=""/>
|
|
||||||
<Property name="horizontalTextPosition" type="int" value="10"/>
|
<Property name="horizontalTextPosition" type="int" value="10"/>
|
||||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
<Dimension value="[110, 16]"/>
|
<Dimension value="[110, 16]"/>
|
||||||
|
|
@ -2184,7 +2183,7 @@
|
||||||
<Component id="panelCardStyles" min="-2" max="-2" attributes="0"/>
|
<Component id="panelCardStyles" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Component id="panelCardImages" min="-2" max="-2" attributes="0"/>
|
<Component id="panelCardImages" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace pref="306" max="32767" attributes="0"/>
|
<EmptySpace pref="309" max="32767" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
</DimensionLayout>
|
</DimensionLayout>
|
||||||
|
|
@ -2225,7 +2224,7 @@
|
||||||
<Component id="cbPreferredImageLanguage" min="-2" pref="153" max="-2" attributes="0"/>
|
<Component id="cbPreferredImageLanguage" min="-2" pref="153" max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
<EmptySpace min="0" pref="480" max="32767" attributes="0"/>
|
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
|
@ -2284,7 +2283,6 @@
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JComboBox" name="cbPreferredImageLanguage">
|
<Component class="javax.swing.JComboBox" name="cbPreferredImageLanguage">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="maximumRowCount" type="int" value="20"/>
|
|
||||||
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
|
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
|
||||||
<StringArray count="4">
|
<StringArray count="4">
|
||||||
<StringItem index="0" value="Item 1"/>
|
<StringItem index="0" value="Item 1"/>
|
||||||
|
|
@ -2319,15 +2317,48 @@
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
|
|
||||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout">
|
<Layout>
|
||||||
<Property name="axis" type="int" value="1"/>
|
<DimensionLayout dim="0">
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Component id="cbCardRenderIconsForAbilities" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="cbCardRenderIconsForPlayable" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="jSeparator1" min="-2" pref="775" max="-2" attributes="0"/>
|
||||||
|
<Component id="cbCardRenderShowReminderText" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="cbCardRenderHideSetSymbol" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="cbCardRenderShowAbilityTextOverlay" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Group type="102" alignment="0" attributes="0">
|
||||||
|
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
|
||||||
|
<Component id="labelRenderMode" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="cbCardRenderImageFallback" min="-2" pref="122" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
</DimensionLayout>
|
||||||
|
<DimensionLayout dim="1">
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Group type="102" attributes="0">
|
||||||
|
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||||
|
<Group type="103" groupAlignment="3" attributes="0">
|
||||||
|
<Component id="labelRenderMode" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="cbCardRenderImageFallback" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||||
|
<Component id="cbCardRenderIconsForAbilities" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||||
|
<Component id="cbCardRenderIconsForPlayable" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||||
|
<Component id="jSeparator1" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||||
|
<Component id="cbCardRenderShowReminderText" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||||
|
<Component id="cbCardRenderHideSetSymbol" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||||
|
<Component id="cbCardRenderShowAbilityTextOverlay" min="-2" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
</DimensionLayout>
|
||||||
</Layout>
|
</Layout>
|
||||||
<SubComponents>
|
<SubComponents>
|
||||||
<Component class="javax.swing.JCheckBox" name="cbCardRenderImageFallback">
|
|
||||||
<Properties>
|
|
||||||
<Property name="text" type="java.lang.String" value="Render mode: MTGO style (off) or IMAGE style (on)"/>
|
|
||||||
</Properties>
|
|
||||||
</Component>
|
|
||||||
<Component class="javax.swing.JCheckBox" name="cbCardRenderIconsForAbilities">
|
<Component class="javax.swing.JCheckBox" name="cbCardRenderIconsForAbilities">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" value="Enable card icons for abilities (example: flying, deathtouch)"/>
|
<Property name="text" type="java.lang.String" value="Enable card icons for abilities (example: flying, deathtouch)"/>
|
||||||
|
|
@ -2355,6 +2386,28 @@
|
||||||
<Property name="text" type="java.lang.String" value="Show ability text as overlay in big card view"/>
|
<Property name="text" type="java.lang.String" value="Show ability text as overlay in big card view"/>
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</Component>
|
||||||
|
<Component class="javax.swing.JLabel" name="labelRenderMode">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" value="Render Mode:"/>
|
||||||
|
<Property name="toolTipText" type="java.lang.String" value="<HTML>Image - Renders card image with text overlay<br> MTGO - Renders card frame around card art<br> Forced M15 - Renders all cards in the modern frame<br> Forced Retro - Renders all cards in the retro frame"/>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JComboBox" name="cbCardRenderImageFallback">
|
||||||
|
<Properties>
|
||||||
|
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
|
||||||
|
<StringArray count="4">
|
||||||
|
<StringItem index="0" value="Item 1"/>
|
||||||
|
<StringItem index="1" value="Item 2"/>
|
||||||
|
<StringItem index="2" value="Item 3"/>
|
||||||
|
<StringItem index="3" value="Item 4"/>
|
||||||
|
</StringArray>
|
||||||
|
</Property>
|
||||||
|
<Property name="toolTipText" type="java.lang.String" value="<HTML>Image - Renders card image with text overlay<br> MTGO - Renders card frame around card art<br> Forced M15 - Renders all cards in the MTGO style with the modern frame<br> Forced Retro - Renders all cards in the MTGO style with the retro frame"/>
|
||||||
|
</Properties>
|
||||||
|
<AuxValues>
|
||||||
|
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<String>"/>
|
||||||
|
</AuxValues>
|
||||||
|
</Component>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
</Container>
|
</Container>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
|
|
@ -2616,29 +2669,25 @@
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="selected" type="boolean" value="true"/>
|
<Property name="selected" type="boolean" value="true"/>
|
||||||
<Property name="text" type="java.lang.String" value="STOP skips on declare attackers if attackers are available"/>
|
<Property name="text" type="java.lang.String" value="STOP skips on declare attackers if attackers are available"/>
|
||||||
<Property name="toolTipText" type="java.lang.String" value=""/>
|
|
||||||
<Property name="actionCommand" type="java.lang.String" value=""/>
|
<Property name="actionCommand" type="java.lang.String" value=""/>
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JCheckBox" name="cbStopBlockWithAny">
|
<Component class="javax.swing.JCheckBox" name="cbStopBlockWithAny">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="selected" type="boolean" value="true"/>
|
<Property name="selected" type="boolean" value="true"/>
|
||||||
<Property name="text" type="java.lang.String" value="STOP skips on declare blockers if ANY blockers are available"/>
|
<Property name="text" type="java.lang.String" value="STOP skips when attacked and on declare blockers if ANY blockers are available"/>
|
||||||
<Property name="toolTipText" type="java.lang.String" value=""/>
|
|
||||||
<Property name="actionCommand" type="java.lang.String" value=""/>
|
<Property name="actionCommand" type="java.lang.String" value=""/>
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JCheckBox" name="cbStopBlockWithZero">
|
<Component class="javax.swing.JCheckBox" name="cbStopBlockWithZero">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" value="STOP skips on declare blockers if ZERO blockers are available"/>
|
<Property name="text" type="java.lang.String" value="STOP skips when attacked if ZERO blockers are available"/>
|
||||||
<Property name="toolTipText" type="java.lang.String" value=""/>
|
|
||||||
<Property name="actionCommand" type="java.lang.String" value=""/>
|
<Property name="actionCommand" type="java.lang.String" value=""/>
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JCheckBox" name="cbStopOnNewStackObjects">
|
<Component class="javax.swing.JCheckBox" name="cbStopOnNewStackObjects">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" value="Skip to STACK resolved (F10): stop on new objects added (on) or stop until empty (off)"/>
|
<Property name="text" type="java.lang.String" value="Skip to STACK resolved (F10): stop on new objects added (on) or stop when stack empty (off)"/>
|
||||||
<Property name="toolTipText" type="java.lang.String" value=""/>
|
|
||||||
<Property name="actionCommand" type="java.lang.String" value=""/>
|
<Property name="actionCommand" type="java.lang.String" value=""/>
|
||||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
<Dimension value="[300, 25]"/>
|
<Dimension value="[300, 25]"/>
|
||||||
|
|
@ -2648,14 +2697,12 @@
|
||||||
<Component class="javax.swing.JCheckBox" name="cbStopOnAllMain">
|
<Component class="javax.swing.JCheckBox" name="cbStopOnAllMain">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" value="Skip to MAIN step (F7): stop on any main steps (on) or stop on your main step (off)"/>
|
<Property name="text" type="java.lang.String" value="Skip to MAIN step (F7): stop on any main steps (on) or stop on your main step (off)"/>
|
||||||
<Property name="toolTipText" type="java.lang.String" value=""/>
|
|
||||||
<Property name="actionCommand" type="java.lang.String" value=""/>
|
<Property name="actionCommand" type="java.lang.String" value=""/>
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JCheckBox" name="cbStopOnAllEnd">
|
<Component class="javax.swing.JCheckBox" name="cbStopOnAllEnd">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" value="Skip to END step (F5): stop on any end steps (on) or stop on opponents end step (off)"/>
|
<Property name="text" type="java.lang.String" value="Skip to END step (F5): stop on any end steps (on) or stop on opponents end step (off)"/>
|
||||||
<Property name="toolTipText" type="java.lang.String" value=""/>
|
|
||||||
<Property name="actionCommand" type="java.lang.String" value=""/>
|
<Property name="actionCommand" type="java.lang.String" value=""/>
|
||||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
<Dimension value="[300, 25]"/>
|
<Dimension value="[300, 25]"/>
|
||||||
|
|
@ -3128,7 +3175,6 @@
|
||||||
<Component class="javax.swing.JLabel" name="jLabel16">
|
<Component class="javax.swing.JLabel" name="jLabel16">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" value="Playing from folder:"/>
|
<Property name="text" type="java.lang.String" value="Playing from folder:"/>
|
||||||
<Property name="toolTipText" type="java.lang.String" value=""/>
|
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JTextField" name="txtBattlefieldIBGMPath">
|
<Component class="javax.swing.JTextField" name="txtBattlefieldIBGMPath">
|
||||||
|
|
@ -3178,7 +3224,7 @@
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||||
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
|
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
|
||||||
<TitledBorder title="Proxy for server connection and images download">
|
<TitledBorder title="Proxy for server connection and images download (DO NOT SUPPORTED)">
|
||||||
<Border PropertyName="innerBorder" info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
|
<Border PropertyName="innerBorder" info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
|
||||||
<EtchetBorder/>
|
<EtchetBorder/>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,7 @@ import mage.client.MageFrame;
|
||||||
import mage.client.SessionHandler;
|
import mage.client.SessionHandler;
|
||||||
import mage.client.components.KeyBindButton;
|
import mage.client.components.KeyBindButton;
|
||||||
import mage.client.themes.ThemeType;
|
import mage.client.themes.ThemeType;
|
||||||
import mage.client.util.CardLanguage;
|
import mage.client.util.*;
|
||||||
import mage.client.util.ClientDefaultSettings;
|
|
||||||
import mage.client.util.GUISizeHelper;
|
|
||||||
import mage.client.util.ImageHelper;
|
|
||||||
import mage.client.util.audio.MusicPlayer;
|
import mage.client.util.audio.MusicPlayer;
|
||||||
import mage.client.util.gui.BufferedImageBuilder;
|
import mage.client.util.gui.BufferedImageBuilder;
|
||||||
import mage.client.util.gui.GuiDisplayUtil;
|
import mage.client.util.gui.GuiDisplayUtil;
|
||||||
|
|
@ -37,7 +34,6 @@ import java.util.concurrent.locks.ReadWriteLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
import java.util.prefs.BackingStoreException;
|
import java.util.prefs.BackingStoreException;
|
||||||
import java.util.prefs.Preferences;
|
import java.util.prefs.Preferences;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import static mage.client.constants.Constants.AUTO_TARGET_NON_FEEL_BAD;
|
import static mage.client.constants.Constants.AUTO_TARGET_NON_FEEL_BAD;
|
||||||
import static mage.constants.Constants.*;
|
import static mage.constants.Constants.*;
|
||||||
|
|
@ -55,6 +51,8 @@ public class PreferencesDialog extends javax.swing.JDialog {
|
||||||
|
|
||||||
private static PreferencesDialog instance; // shared dialog instance
|
private static PreferencesDialog instance; // shared dialog instance
|
||||||
|
|
||||||
|
public static final boolean NETWORK_ENABLE_PROXY_SUPPORT = false; // TODO: delete proxy at all after few releases, 2025-02-09
|
||||||
|
|
||||||
// WARNING, do not change const values - it must be same for compatibility with user's saved settings
|
// WARNING, do not change const values - it must be same for compatibility with user's saved settings
|
||||||
public static final String KEY_SHOW_TOOLTIPS_DELAY = "showTooltipsDelay";
|
public static final String KEY_SHOW_TOOLTIPS_DELAY = "showTooltipsDelay";
|
||||||
public static final String KEY_SHOW_CARD_NAMES = "showCardNames";
|
public static final String KEY_SHOW_CARD_NAMES = "showCardNames";
|
||||||
|
|
@ -87,7 +85,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
|
||||||
public static final String KEY_CARD_IMAGES_SAVE_TO_ZIP = "cardImagesSaveToZip";
|
public static final String KEY_CARD_IMAGES_SAVE_TO_ZIP = "cardImagesSaveToZip";
|
||||||
public static final String KEY_CARD_IMAGES_PREF_LANGUAGE = "cardImagesPreferredImageLaguage";
|
public static final String KEY_CARD_IMAGES_PREF_LANGUAGE = "cardImagesPreferredImageLaguage";
|
||||||
|
|
||||||
public static final String KEY_CARD_RENDERING_IMAGE_MODE = "cardRenderingFallback";
|
public static final String KEY_CARD_RENDERING_IMAGE_MODE = "cardRenderingMode";
|
||||||
public static final String KEY_CARD_RENDERING_ICONS_FOR_ABILITIES = "cardRenderingIconsForAbilities";
|
public static final String KEY_CARD_RENDERING_ICONS_FOR_ABILITIES = "cardRenderingIconsForAbilities";
|
||||||
public static final String KEY_CARD_RENDERING_ICONS_FOR_PLAYABLE = "cardRenderingIconsForPlayable";
|
public static final String KEY_CARD_RENDERING_ICONS_FOR_PLAYABLE = "cardRenderingIconsForPlayable";
|
||||||
public static final String KEY_CARD_RENDERING_REMINDER_TEXT = "cardRenderingReminderText";
|
public static final String KEY_CARD_RENDERING_REMINDER_TEXT = "cardRenderingReminderText";
|
||||||
|
|
@ -246,7 +244,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
|
||||||
public static final String KEY_NEW_TOURNAMENT_PACKS_DRAFT = "newTournamentPacksDraft";
|
public static final String KEY_NEW_TOURNAMENT_PACKS_DRAFT = "newTournamentPacksDraft";
|
||||||
public static final String KEY_NEW_TOURNAMENT_PACKS_RANDOM_DRAFT = "newTournamentPacksRandomDraft";
|
public static final String KEY_NEW_TOURNAMENT_PACKS_RANDOM_DRAFT = "newTournamentPacksRandomDraft";
|
||||||
public static final String KEY_NEW_TOURNAMENT_NUMBER_PLAYERS = "newTournamentNumberPlayers";
|
public static final String KEY_NEW_TOURNAMENT_NUMBER_PLAYERS = "newTournamentNumberPlayers";
|
||||||
public static final String KEY_NEW_TOURNAMENT_NUMBER_SEATS = "newTournamentNumberSeats";
|
public static final String KEY_NEW_TOURNAMENT_SINGLE_MULTIPLAYER_GAME = "newTournamentSingleMultiplayerGame";
|
||||||
public static final String KEY_NEW_TOURNAMENT_PLAYER_TYPES = "newTournamentPlayerTypes";
|
public static final String KEY_NEW_TOURNAMENT_PLAYER_TYPES = "newTournamentPlayerTypes";
|
||||||
public static final String KEY_NEW_TOURNAMENT_PLAYER_SKILLS = "newTournamentPlayerSkills";
|
public static final String KEY_NEW_TOURNAMENT_PLAYER_SKILLS = "newTournamentPlayerSkills";
|
||||||
public static final String KEY_NEW_TOURNAMENT_DRAFT_TIMING = "newTournamentDraftTiming";
|
public static final String KEY_NEW_TOURNAMENT_DRAFT_TIMING = "newTournamentDraftTiming";
|
||||||
|
|
@ -265,12 +263,14 @@ public class PreferencesDialog extends javax.swing.JDialog {
|
||||||
public static final String KEY_AUTO_TARGET_LEVEL = "autoTargetLevel";
|
public static final String KEY_AUTO_TARGET_LEVEL = "autoTargetLevel";
|
||||||
|
|
||||||
// pref setting for deck generator
|
// pref setting for deck generator
|
||||||
|
public static final String KEY_NEW_DECK_GENERATOR_COLORS = "newDeckGeneratorDeckColors";
|
||||||
public static final String KEY_NEW_DECK_GENERATOR_DECK_SIZE = "newDeckGeneratorDeckSize";
|
public static final String KEY_NEW_DECK_GENERATOR_DECK_SIZE = "newDeckGeneratorDeckSize";
|
||||||
public static final String KEY_NEW_DECK_GENERATOR_SET = "newDeckGeneratorSet";
|
public static final String KEY_NEW_DECK_GENERATOR_SET = "newDeckGeneratorSet";
|
||||||
public static final String KEY_NEW_DECK_GENERATOR_SINGLETON = "newDeckGeneratorSingleton";
|
public static final String KEY_NEW_DECK_GENERATOR_SINGLETON = "newDeckGeneratorSingleton";
|
||||||
public static final String KEY_NEW_DECK_GENERATOR_ARTIFACTS = "newDeckGeneratorArtifacts";
|
public static final String KEY_NEW_DECK_GENERATOR_ARTIFACTS = "newDeckGeneratorArtifacts";
|
||||||
public static final String KEY_NEW_DECK_GENERATOR_NON_BASIC_LANDS = "newDeckGeneratorNonBasicLands";
|
public static final String KEY_NEW_DECK_GENERATOR_NON_BASIC_LANDS = "newDeckGeneratorNonBasicLands";
|
||||||
public static final String KEY_NEW_DECK_GENERATOR_COLORLESS = "newDeckGeneratorColorless";
|
public static final String KEY_NEW_DECK_GENERATOR_COLORLESS = "newDeckGeneratorColorless";
|
||||||
|
public static final String KEY_NEW_DECK_GENERATOR_COMMANDER = "newDeckGeneratorCommander";
|
||||||
public static final String KEY_NEW_DECK_GENERATOR_ADVANCED = "newDeckGeneratorAdvanced";
|
public static final String KEY_NEW_DECK_GENERATOR_ADVANCED = "newDeckGeneratorAdvanced";
|
||||||
public static final String KEY_NEW_DECK_GENERATOR_CREATURE_PERCENTAGE = "newDeckGeneratorCreaturePercentage";
|
public static final String KEY_NEW_DECK_GENERATOR_CREATURE_PERCENTAGE = "newDeckGeneratorCreaturePercentage";
|
||||||
public static final String KEY_NEW_DECK_GENERATOR_NON_CREATURE_PERCENTAGE = "newDeckGeneratorNonCreaturePercentage";
|
public static final String KEY_NEW_DECK_GENERATOR_NON_CREATURE_PERCENTAGE = "newDeckGeneratorNonCreaturePercentage";
|
||||||
|
|
@ -758,6 +758,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
|
||||||
}
|
}
|
||||||
|
|
||||||
cbPreferredImageLanguage.setModel(new DefaultComboBoxModel<>(CardLanguage.toList()));
|
cbPreferredImageLanguage.setModel(new DefaultComboBoxModel<>(CardLanguage.toList()));
|
||||||
|
cbCardRenderImageFallback.setModel(new DefaultComboBoxModel<>(CardRenderMode.toList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createSizeSetting(Integer position, String key, Integer defaultValue, boolean useExample, String name, String hint) {
|
private void createSizeSetting(Integer position, String key, Integer defaultValue, boolean useExample, String name, String hint) {
|
||||||
|
|
@ -959,13 +960,14 @@ public class PreferencesDialog extends javax.swing.JDialog {
|
||||||
cbPreferredImageLanguage = new javax.swing.JComboBox<>();
|
cbPreferredImageLanguage = new javax.swing.JComboBox<>();
|
||||||
labelPreferredImageLanguage = new javax.swing.JLabel();
|
labelPreferredImageLanguage = new javax.swing.JLabel();
|
||||||
panelCardStyles = new javax.swing.JPanel();
|
panelCardStyles = new javax.swing.JPanel();
|
||||||
cbCardRenderImageFallback = new javax.swing.JCheckBox();
|
|
||||||
cbCardRenderIconsForAbilities = new javax.swing.JCheckBox();
|
cbCardRenderIconsForAbilities = new javax.swing.JCheckBox();
|
||||||
cbCardRenderIconsForPlayable = new javax.swing.JCheckBox();
|
cbCardRenderIconsForPlayable = new javax.swing.JCheckBox();
|
||||||
jSeparator1 = new javax.swing.JSeparator();
|
jSeparator1 = new javax.swing.JSeparator();
|
||||||
cbCardRenderShowReminderText = new javax.swing.JCheckBox();
|
cbCardRenderShowReminderText = new javax.swing.JCheckBox();
|
||||||
cbCardRenderHideSetSymbol = new javax.swing.JCheckBox();
|
cbCardRenderHideSetSymbol = new javax.swing.JCheckBox();
|
||||||
cbCardRenderShowAbilityTextOverlay = new javax.swing.JCheckBox();
|
cbCardRenderShowAbilityTextOverlay = new javax.swing.JCheckBox();
|
||||||
|
labelRenderMode = new javax.swing.JLabel();
|
||||||
|
cbCardRenderImageFallback = new javax.swing.JComboBox<>();
|
||||||
tabPhases = new javax.swing.JPanel();
|
tabPhases = new javax.swing.JPanel();
|
||||||
jLabelHeadLine = new javax.swing.JLabel();
|
jLabelHeadLine = new javax.swing.JLabel();
|
||||||
jLabelYourTurn = new javax.swing.JLabel();
|
jLabelYourTurn = new javax.swing.JLabel();
|
||||||
|
|
@ -2108,7 +2110,6 @@ public class PreferencesDialog extends javax.swing.JDialog {
|
||||||
|
|
||||||
lbSelectLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
|
lbSelectLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
|
||||||
lbSelectLabel.setText("GUI color style:");
|
lbSelectLabel.setText("GUI color style:");
|
||||||
lbSelectLabel.setToolTipText("");
|
|
||||||
lbSelectLabel.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING);
|
lbSelectLabel.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING);
|
||||||
lbSelectLabel.setPreferredSize(new java.awt.Dimension(110, 16));
|
lbSelectLabel.setPreferredSize(new java.awt.Dimension(110, 16));
|
||||||
lbSelectLabel.setVerticalTextPosition(javax.swing.SwingConstants.TOP);
|
lbSelectLabel.setVerticalTextPosition(javax.swing.SwingConstants.TOP);
|
||||||
|
|
@ -2276,7 +2277,6 @@ public class PreferencesDialog extends javax.swing.JDialog {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
cbPreferredImageLanguage.setMaximumRowCount(20);
|
|
||||||
cbPreferredImageLanguage.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
|
cbPreferredImageLanguage.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
|
||||||
|
|
||||||
labelPreferredImageLanguage.setText("Default images language:");
|
labelPreferredImageLanguage.setText("Default images language:");
|
||||||
|
|
@ -2302,7 +2302,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
|
||||||
.add(labelPreferredImageLanguage)
|
.add(labelPreferredImageLanguage)
|
||||||
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
||||||
.add(cbPreferredImageLanguage, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 153, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))
|
.add(cbPreferredImageLanguage, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 153, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))
|
||||||
.add(0, 480, Short.MAX_VALUE)))
|
.add(0, 0, Short.MAX_VALUE)))
|
||||||
.addContainerGap())
|
.addContainerGap())
|
||||||
);
|
);
|
||||||
panelCardImagesLayout.setVerticalGroup(
|
panelCardImagesLayout.setVerticalGroup(
|
||||||
|
|
@ -2322,26 +2322,59 @@ public class PreferencesDialog extends javax.swing.JDialog {
|
||||||
);
|
);
|
||||||
|
|
||||||
panelCardStyles.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "Card styles (restart xmage to apply new settings)"));
|
panelCardStyles.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "Card styles (restart xmage to apply new settings)"));
|
||||||
panelCardStyles.setLayout(new javax.swing.BoxLayout(panelCardStyles, javax.swing.BoxLayout.Y_AXIS));
|
|
||||||
|
|
||||||
cbCardRenderImageFallback.setText("Render mode: MTGO style (off) or IMAGE style (on)");
|
|
||||||
panelCardStyles.add(cbCardRenderImageFallback);
|
|
||||||
|
|
||||||
cbCardRenderIconsForAbilities.setText("Enable card icons for abilities (example: flying, deathtouch)");
|
cbCardRenderIconsForAbilities.setText("Enable card icons for abilities (example: flying, deathtouch)");
|
||||||
panelCardStyles.add(cbCardRenderIconsForAbilities);
|
|
||||||
|
|
||||||
cbCardRenderIconsForPlayable.setText("Enable card icons for playable abilities (example: if you can activate card's ability then show a special icon in the corner)");
|
cbCardRenderIconsForPlayable.setText("Enable card icons for playable abilities (example: if you can activate card's ability then show a special icon in the corner)");
|
||||||
panelCardStyles.add(cbCardRenderIconsForPlayable);
|
|
||||||
panelCardStyles.add(jSeparator1);
|
|
||||||
|
|
||||||
cbCardRenderShowReminderText.setText("Show reminder text in rendered card textboxes");
|
cbCardRenderShowReminderText.setText("Show reminder text in rendered card textboxes");
|
||||||
panelCardStyles.add(cbCardRenderShowReminderText);
|
|
||||||
|
|
||||||
cbCardRenderHideSetSymbol.setText("Hide set symbols on cards (more space on the type line for card types)");
|
cbCardRenderHideSetSymbol.setText("Hide set symbols on cards (more space on the type line for card types)");
|
||||||
panelCardStyles.add(cbCardRenderHideSetSymbol);
|
|
||||||
|
|
||||||
cbCardRenderShowAbilityTextOverlay.setText("Show ability text as overlay in big card view");
|
cbCardRenderShowAbilityTextOverlay.setText("Show ability text as overlay in big card view");
|
||||||
panelCardStyles.add(cbCardRenderShowAbilityTextOverlay);
|
|
||||||
|
labelRenderMode.setText("Render Mode:");
|
||||||
|
labelRenderMode.setToolTipText("<HTML>Image - Renders card image with text overlay<br> MTGO - Renders card frame around card art<br> Forced M15 - Renders all cards in the modern frame<br> Forced Retro - Renders all cards in the retro frame");
|
||||||
|
|
||||||
|
cbCardRenderImageFallback.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
|
||||||
|
cbCardRenderImageFallback.setToolTipText("<HTML>Image - Renders card image with text overlay<br> MTGO - Renders card frame around card art<br> Forced M15 - Renders all cards in the MTGO style with the modern frame<br> Forced Retro - Renders all cards in the MTGO style with the retro frame");
|
||||||
|
|
||||||
|
org.jdesktop.layout.GroupLayout panelCardStylesLayout = new org.jdesktop.layout.GroupLayout(panelCardStyles);
|
||||||
|
panelCardStyles.setLayout(panelCardStylesLayout);
|
||||||
|
panelCardStylesLayout.setHorizontalGroup(
|
||||||
|
panelCardStylesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
|
||||||
|
.add(cbCardRenderIconsForAbilities)
|
||||||
|
.add(cbCardRenderIconsForPlayable)
|
||||||
|
.add(jSeparator1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 775, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
|
||||||
|
.add(cbCardRenderShowReminderText)
|
||||||
|
.add(cbCardRenderHideSetSymbol)
|
||||||
|
.add(cbCardRenderShowAbilityTextOverlay)
|
||||||
|
.add(panelCardStylesLayout.createSequentialGroup()
|
||||||
|
.add(6, 6, 6)
|
||||||
|
.add(labelRenderMode)
|
||||||
|
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
||||||
|
.add(cbCardRenderImageFallback, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 122, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
|
||||||
|
);
|
||||||
|
panelCardStylesLayout.setVerticalGroup(
|
||||||
|
panelCardStylesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
|
||||||
|
.add(panelCardStylesLayout.createSequentialGroup()
|
||||||
|
.add(0, 0, 0)
|
||||||
|
.add(panelCardStylesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
|
||||||
|
.add(labelRenderMode)
|
||||||
|
.add(cbCardRenderImageFallback, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
|
||||||
|
.add(0, 0, 0)
|
||||||
|
.add(cbCardRenderIconsForAbilities)
|
||||||
|
.add(0, 0, 0)
|
||||||
|
.add(cbCardRenderIconsForPlayable)
|
||||||
|
.add(0, 0, 0)
|
||||||
|
.add(jSeparator1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
|
||||||
|
.add(0, 0, 0)
|
||||||
|
.add(cbCardRenderShowReminderText)
|
||||||
|
.add(0, 0, 0)
|
||||||
|
.add(cbCardRenderHideSetSymbol)
|
||||||
|
.add(0, 0, 0)
|
||||||
|
.add(cbCardRenderShowAbilityTextOverlay))
|
||||||
|
);
|
||||||
|
|
||||||
org.jdesktop.layout.GroupLayout tabGuiImagesLayout = new org.jdesktop.layout.GroupLayout(tabGuiImages);
|
org.jdesktop.layout.GroupLayout tabGuiImagesLayout = new org.jdesktop.layout.GroupLayout(tabGuiImages);
|
||||||
tabGuiImages.setLayout(tabGuiImagesLayout);
|
tabGuiImages.setLayout(tabGuiImagesLayout);
|
||||||
|
|
@ -2361,7 +2394,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
|
||||||
.add(panelCardStyles, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
|
.add(panelCardStyles, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
|
||||||
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
|
||||||
.add(panelCardImages, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
|
.add(panelCardImages, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
|
||||||
.addContainerGap(306, Short.MAX_VALUE))
|
.addContainerGap(309, Short.MAX_VALUE))
|
||||||
);
|
);
|
||||||
|
|
||||||
tabsPanel.addTab("GUI Images", tabGuiImages);
|
tabsPanel.addTab("GUI Images", tabGuiImages);
|
||||||
|
|
@ -2391,34 +2424,28 @@ public class PreferencesDialog extends javax.swing.JDialog {
|
||||||
|
|
||||||
cbStopAttack.setSelected(true);
|
cbStopAttack.setSelected(true);
|
||||||
cbStopAttack.setText("STOP skips on declare attackers if attackers are available");
|
cbStopAttack.setText("STOP skips on declare attackers if attackers are available");
|
||||||
cbStopAttack.setToolTipText("");
|
|
||||||
cbStopAttack.setActionCommand("");
|
cbStopAttack.setActionCommand("");
|
||||||
phases_stopSettings.add(cbStopAttack);
|
phases_stopSettings.add(cbStopAttack);
|
||||||
|
|
||||||
cbStopBlockWithAny.setSelected(true);
|
cbStopBlockWithAny.setSelected(true);
|
||||||
cbStopBlockWithAny.setText("STOP skips on declare blockers if ANY blockers are available");
|
cbStopBlockWithAny.setText("STOP skips when attacked and on declare blockers if ANY blockers are available");
|
||||||
cbStopBlockWithAny.setToolTipText("");
|
|
||||||
cbStopBlockWithAny.setActionCommand("");
|
cbStopBlockWithAny.setActionCommand("");
|
||||||
phases_stopSettings.add(cbStopBlockWithAny);
|
phases_stopSettings.add(cbStopBlockWithAny);
|
||||||
|
|
||||||
cbStopBlockWithZero.setText("STOP skips on declare blockers if ZERO blockers are available");
|
cbStopBlockWithZero.setText("STOP skips when attacked if ZERO blockers are available");
|
||||||
cbStopBlockWithZero.setToolTipText("");
|
|
||||||
cbStopBlockWithZero.setActionCommand("");
|
cbStopBlockWithZero.setActionCommand("");
|
||||||
phases_stopSettings.add(cbStopBlockWithZero);
|
phases_stopSettings.add(cbStopBlockWithZero);
|
||||||
|
|
||||||
cbStopOnNewStackObjects.setText("Skip to STACK resolved (F10): stop on new objects added (on) or stop until empty (off)");
|
cbStopOnNewStackObjects.setText("Skip to STACK resolved (F10): stop on new objects added (on) or stop when stack empty (off)");
|
||||||
cbStopOnNewStackObjects.setToolTipText("");
|
|
||||||
cbStopOnNewStackObjects.setActionCommand("");
|
cbStopOnNewStackObjects.setActionCommand("");
|
||||||
cbStopOnNewStackObjects.setPreferredSize(new java.awt.Dimension(300, 25));
|
cbStopOnNewStackObjects.setPreferredSize(new java.awt.Dimension(300, 25));
|
||||||
phases_stopSettings.add(cbStopOnNewStackObjects);
|
phases_stopSettings.add(cbStopOnNewStackObjects);
|
||||||
|
|
||||||
cbStopOnAllMain.setText("Skip to MAIN step (F7): stop on any main steps (on) or stop on your main step (off)");
|
cbStopOnAllMain.setText("Skip to MAIN step (F7): stop on any main steps (on) or stop on your main step (off)");
|
||||||
cbStopOnAllMain.setToolTipText("");
|
|
||||||
cbStopOnAllMain.setActionCommand("");
|
cbStopOnAllMain.setActionCommand("");
|
||||||
phases_stopSettings.add(cbStopOnAllMain);
|
phases_stopSettings.add(cbStopOnAllMain);
|
||||||
|
|
||||||
cbStopOnAllEnd.setText("Skip to END step (F5): stop on any end steps (on) or stop on opponents end step (off)");
|
cbStopOnAllEnd.setText("Skip to END step (F5): stop on any end steps (on) or stop on opponents end step (off)");
|
||||||
cbStopOnAllEnd.setToolTipText("");
|
|
||||||
cbStopOnAllEnd.setActionCommand("");
|
cbStopOnAllEnd.setActionCommand("");
|
||||||
cbStopOnAllEnd.setPreferredSize(new java.awt.Dimension(300, 25));
|
cbStopOnAllEnd.setPreferredSize(new java.awt.Dimension(300, 25));
|
||||||
phases_stopSettings.add(cbStopOnAllEnd);
|
phases_stopSettings.add(cbStopOnAllEnd);
|
||||||
|
|
@ -2743,7 +2770,6 @@ public class PreferencesDialog extends javax.swing.JDialog {
|
||||||
});
|
});
|
||||||
|
|
||||||
jLabel16.setText("Playing from folder:");
|
jLabel16.setText("Playing from folder:");
|
||||||
jLabel16.setToolTipText("");
|
|
||||||
|
|
||||||
btnBattlefieldBGMBrowse.setText("Browse...");
|
btnBattlefieldBGMBrowse.setText("Browse...");
|
||||||
btnBattlefieldBGMBrowse.addActionListener(new java.awt.event.ActionListener() {
|
btnBattlefieldBGMBrowse.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
|
@ -2803,7 +2829,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
|
||||||
|
|
||||||
tabsPanel.addTab("Sounds", tabSounds);
|
tabsPanel.addTab("Sounds", tabSounds);
|
||||||
|
|
||||||
connection_Proxy.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "Proxy for server connection and images download"));
|
connection_Proxy.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "Proxy for server connection and images download (DO NOT SUPPORTED)"));
|
||||||
|
|
||||||
cbProxyType.addActionListener(new java.awt.event.ActionListener() {
|
cbProxyType.addActionListener(new java.awt.event.ActionListener() {
|
||||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
|
@ -3039,7 +3065,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
|
||||||
save(prefs, dialog.cbUseRandomBattleImage, KEY_BATTLEFIELD_IMAGE_RANDOM, "true", "false");
|
save(prefs, dialog.cbUseRandomBattleImage, KEY_BATTLEFIELD_IMAGE_RANDOM, "true", "false");
|
||||||
|
|
||||||
// rendering
|
// rendering
|
||||||
save(prefs, dialog.cbCardRenderImageFallback, KEY_CARD_RENDERING_IMAGE_MODE, "true", "false");
|
save(prefs, dialog.cbCardRenderImageFallback, KEY_CARD_RENDERING_IMAGE_MODE);
|
||||||
save(prefs, dialog.cbCardRenderIconsForAbilities, KEY_CARD_RENDERING_ICONS_FOR_ABILITIES, "true", "false");
|
save(prefs, dialog.cbCardRenderIconsForAbilities, KEY_CARD_RENDERING_ICONS_FOR_ABILITIES, "true", "false");
|
||||||
save(prefs, dialog.cbCardRenderIconsForPlayable, KEY_CARD_RENDERING_ICONS_FOR_PLAYABLE, "true", "false");
|
save(prefs, dialog.cbCardRenderIconsForPlayable, KEY_CARD_RENDERING_ICONS_FOR_PLAYABLE, "true", "false");
|
||||||
save(prefs, dialog.cbCardRenderHideSetSymbol, KEY_CARD_RENDERING_SET_SYMBOL, "true", "false");
|
save(prefs, dialog.cbCardRenderHideSetSymbol, KEY_CARD_RENDERING_SET_SYMBOL, "true", "false");
|
||||||
|
|
@ -3325,6 +3351,11 @@ public class PreferencesDialog extends javax.swing.JDialog {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!NETWORK_ENABLE_PROXY_SUPPORT) {
|
||||||
|
connection.setProxyType(ProxyType.NONE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
connection.setProxyType(configProxyType);
|
connection.setProxyType(configProxyType);
|
||||||
if (configProxyType != ProxyType.NONE) {
|
if (configProxyType != ProxyType.NONE) {
|
||||||
String host = getCachedValue(KEY_PROXY_ADDRESS, "");
|
String host = getCachedValue(KEY_PROXY_ADDRESS, "");
|
||||||
|
|
@ -3485,7 +3516,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
|
||||||
dialog.cbPreferredImageLanguage.setSelectedItem(MageFrame.getPreferences().get(KEY_CARD_IMAGES_PREF_LANGUAGE, CardLanguage.ENGLISH.getCode()));
|
dialog.cbPreferredImageLanguage.setSelectedItem(MageFrame.getPreferences().get(KEY_CARD_IMAGES_PREF_LANGUAGE, CardLanguage.ENGLISH.getCode()));
|
||||||
|
|
||||||
// rendering settings
|
// rendering settings
|
||||||
load(prefs, dialog.cbCardRenderImageFallback, KEY_CARD_RENDERING_IMAGE_MODE, "true", "false");
|
dialog.cbCardRenderImageFallback.setSelectedItem(MageFrame.getPreferences().get(KEY_CARD_RENDERING_IMAGE_MODE, CardRenderMode.MTGO.toString()));
|
||||||
load(prefs, dialog.cbCardRenderIconsForAbilities, KEY_CARD_RENDERING_ICONS_FOR_ABILITIES, "true", "true");
|
load(prefs, dialog.cbCardRenderIconsForAbilities, KEY_CARD_RENDERING_ICONS_FOR_ABILITIES, "true", "true");
|
||||||
load(prefs, dialog.cbCardRenderIconsForPlayable, KEY_CARD_RENDERING_ICONS_FOR_PLAYABLE, "true", "true");
|
load(prefs, dialog.cbCardRenderIconsForPlayable, KEY_CARD_RENDERING_ICONS_FOR_PLAYABLE, "true", "true");
|
||||||
load(prefs, dialog.cbCardRenderHideSetSymbol, KEY_CARD_RENDERING_SET_SYMBOL, "true");
|
load(prefs, dialog.cbCardRenderHideSetSymbol, KEY_CARD_RENDERING_SET_SYMBOL, "true");
|
||||||
|
|
@ -3809,11 +3840,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getRenderMode() {
|
public static int getRenderMode() {
|
||||||
if (getCachedValue(PreferencesDialog.KEY_CARD_RENDERING_IMAGE_MODE, "false").equals("false")) {
|
return CardRenderMode.fromString(getCachedValue(PreferencesDialog.KEY_CARD_RENDERING_IMAGE_MODE, CardRenderMode.MTGO.toString())).getId();
|
||||||
return 0; // mtgo
|
|
||||||
} else {
|
|
||||||
return 1; // image
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean getRenderIconsForAbilities() {
|
public static boolean getRenderIconsForAbilities() {
|
||||||
|
|
@ -4043,7 +4070,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
|
||||||
private javax.swing.JCheckBox cbCardRenderHideSetSymbol;
|
private javax.swing.JCheckBox cbCardRenderHideSetSymbol;
|
||||||
private javax.swing.JCheckBox cbCardRenderIconsForAbilities;
|
private javax.swing.JCheckBox cbCardRenderIconsForAbilities;
|
||||||
private javax.swing.JCheckBox cbCardRenderIconsForPlayable;
|
private javax.swing.JCheckBox cbCardRenderIconsForPlayable;
|
||||||
private javax.swing.JCheckBox cbCardRenderImageFallback;
|
private javax.swing.JComboBox<String> cbCardRenderImageFallback;
|
||||||
private javax.swing.JCheckBox cbCardRenderShowAbilityTextOverlay;
|
private javax.swing.JCheckBox cbCardRenderShowAbilityTextOverlay;
|
||||||
private javax.swing.JCheckBox cbCardRenderShowReminderText;
|
private javax.swing.JCheckBox cbCardRenderShowReminderText;
|
||||||
private javax.swing.JCheckBox cbConfirmEmptyManaPool;
|
private javax.swing.JCheckBox cbConfirmEmptyManaPool;
|
||||||
|
|
@ -4175,6 +4202,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
|
||||||
private javax.swing.JLabel labelNextTurn;
|
private javax.swing.JLabel labelNextTurn;
|
||||||
private javax.swing.JLabel labelPreferredImageLanguage;
|
private javax.swing.JLabel labelPreferredImageLanguage;
|
||||||
private javax.swing.JLabel labelPriorEnd;
|
private javax.swing.JLabel labelPriorEnd;
|
||||||
|
private javax.swing.JLabel labelRenderMode;
|
||||||
private javax.swing.JLabel labelSizeGroup1;
|
private javax.swing.JLabel labelSizeGroup1;
|
||||||
private javax.swing.JLabel labelSizeGroup2;
|
private javax.swing.JLabel labelSizeGroup2;
|
||||||
private javax.swing.JLabel labelSkipStep;
|
private javax.swing.JLabel labelSkipStep;
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,6 @@
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JLabel" name="lblStatus">
|
<Component class="javax.swing.JLabel" name="lblStatus">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="toolTipText" type="java.lang.String" value=""/>
|
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JTextField" name="txtServer">
|
<Component class="javax.swing.JTextField" name="txtServer">
|
||||||
|
|
@ -212,7 +211,6 @@
|
||||||
<ComponentRef name="txtEmail"/>
|
<ComponentRef name="txtEmail"/>
|
||||||
</Property>
|
</Property>
|
||||||
<Property name="text" type="java.lang.String" value="(used for password reset)"/>
|
<Property name="text" type="java.lang.String" value="(used for password reset)"/>
|
||||||
<Property name="toolTipText" type="java.lang.String" value=""/>
|
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</Component>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
|
|
|
||||||
|
|
@ -87,8 +87,6 @@ public class RegisterUserDialog extends MageDialog {
|
||||||
btnCancel.setText("Cancel");
|
btnCancel.setText("Cancel");
|
||||||
btnCancel.addActionListener(evt -> btnCancelActionPerformed(evt));
|
btnCancel.addActionListener(evt -> btnCancelActionPerformed(evt));
|
||||||
|
|
||||||
lblStatus.setToolTipText("");
|
|
||||||
|
|
||||||
lblPasswordConfirmation.setLabelFor(txtPasswordConfirmation);
|
lblPasswordConfirmation.setLabelFor(txtPasswordConfirmation);
|
||||||
lblPasswordConfirmation.setText("Password:");
|
lblPasswordConfirmation.setText("Password:");
|
||||||
|
|
||||||
|
|
@ -102,7 +100,6 @@ public class RegisterUserDialog extends MageDialog {
|
||||||
lblEmailReasoning.setFont(new java.awt.Font("Lucida Grande", 0, 10)); // NOI18N
|
lblEmailReasoning.setFont(new java.awt.Font("Lucida Grande", 0, 10)); // NOI18N
|
||||||
lblEmailReasoning.setLabelFor(txtEmail);
|
lblEmailReasoning.setLabelFor(txtEmail);
|
||||||
lblEmailReasoning.setText("(used for password reset and sending initial password)");
|
lblEmailReasoning.setText("(used for password reset and sending initial password)");
|
||||||
lblEmailReasoning.setToolTipText("");
|
|
||||||
|
|
||||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
|
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
|
||||||
getContentPane().setLayout(layout);
|
getContentPane().setLayout(layout);
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,6 @@
|
||||||
<Property name="dividerLocation" type="int" value="300"/>
|
<Property name="dividerLocation" type="int" value="300"/>
|
||||||
<Property name="dividerSize" type="int" value="3"/>
|
<Property name="dividerSize" type="int" value="3"/>
|
||||||
<Property name="resizeWeight" type="double" value="1.0"/>
|
<Property name="resizeWeight" type="double" value="1.0"/>
|
||||||
<Property name="toolTipText" type="java.lang.String" value=""/>
|
|
||||||
</Properties>
|
</Properties>
|
||||||
|
|
||||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
|
||||||
|
|
|
||||||
|
|
@ -207,7 +207,6 @@ public class TableWaitingDialog extends MageDialog {
|
||||||
jSplitPane1.setDividerLocation(300);
|
jSplitPane1.setDividerLocation(300);
|
||||||
jSplitPane1.setDividerSize(3);
|
jSplitPane1.setDividerSize(3);
|
||||||
jSplitPane1.setResizeWeight(1.0);
|
jSplitPane1.setResizeWeight(1.0);
|
||||||
jSplitPane1.setToolTipText("");
|
|
||||||
|
|
||||||
jTableSeats.setModel(tableWaitModel);
|
jTableSeats.setModel(tableWaitModel);
|
||||||
jTableSeats.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
|
jTableSeats.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
|
||||||
|
|
|
||||||
|
|
@ -116,11 +116,9 @@
|
||||||
<Component class="javax.swing.JComboBox" name="comboRenderMode">
|
<Component class="javax.swing.JComboBox" name="comboRenderMode">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
|
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
|
||||||
<StringArray count="2">
|
<StringArray count="0"/>
|
||||||
<StringItem index="0" value="MTGO"/>
|
|
||||||
<StringItem index="1" value="Image"/>
|
|
||||||
</StringArray>
|
|
||||||
</Property>
|
</Property>
|
||||||
|
<Property name="toolTipText" type="java.lang.String" value="<HTML>Image - Renders card image with text overlay<br> MTGO - Renders card frame around card art<br> Forced M15 - Renders all cards in the MTGO style with the modern frame<br> Forced Retro - Renders all cards in the MTGO style with the retro frame"/>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Events>
|
<Events>
|
||||||
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="comboRenderModeItemStateChanged"/>
|
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="comboRenderModeItemStateChanged"/>
|
||||||
|
|
@ -300,7 +298,6 @@
|
||||||
<StringItem index="0" value="loading..."/>
|
<StringItem index="0" value="loading..."/>
|
||||||
</StringArray>
|
</StringArray>
|
||||||
</Property>
|
</Property>
|
||||||
<Property name="toolTipText" type="java.lang.String" value=""/>
|
|
||||||
</Properties>
|
</Properties>
|
||||||
<Events>
|
<Events>
|
||||||
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="comboCardColorItemStateChanged"/>
|
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="comboCardColorItemStateChanged"/>
|
||||||
|
|
@ -382,7 +379,6 @@
|
||||||
<StringItem index="2" value="Dead"/>
|
<StringItem index="2" value="Dead"/>
|
||||||
</StringArray>
|
</StringArray>
|
||||||
</Property>
|
</Property>
|
||||||
<Property name="toolTipText" type="java.lang.String" value=""/>
|
|
||||||
<Property name="alignmentX" type="float" value="0.0"/>
|
<Property name="alignmentX" type="float" value="0.0"/>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Events>
|
<Events>
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ import mage.client.cards.BigCard;
|
||||||
import mage.client.game.PlayAreaPanel;
|
import mage.client.game.PlayAreaPanel;
|
||||||
import mage.client.game.PlayerPanelExt;
|
import mage.client.game.PlayerPanelExt;
|
||||||
import mage.client.themes.ThemeType;
|
import mage.client.themes.ThemeType;
|
||||||
import mage.client.util.ClientEventType;
|
import mage.client.util.*;
|
||||||
import mage.client.util.Event;
|
import mage.client.util.Event;
|
||||||
import mage.client.util.GUISizeHelper;
|
import mage.client.util.GUISizeHelper;
|
||||||
import mage.client.util.Listener;
|
import mage.client.util.Listener;
|
||||||
|
|
@ -82,6 +82,7 @@ public class TestCardRenderDialog extends MageDialog {
|
||||||
getRootPane().setDefaultButton(buttonCancel);
|
getRootPane().setDefaultButton(buttonCancel);
|
||||||
|
|
||||||
// init render mode
|
// init render mode
|
||||||
|
this.comboRenderMode.setModel(new DefaultComboBoxModel<>(CardRenderMode.toList()));
|
||||||
this.comboRenderMode.setSelectedIndex(PreferencesDialog.getRenderMode());
|
this.comboRenderMode.setSelectedIndex(PreferencesDialog.getRenderMode());
|
||||||
|
|
||||||
// init themes list
|
// init themes list
|
||||||
|
|
@ -326,6 +327,13 @@ public class TestCardRenderDialog extends MageDialog {
|
||||||
possibleTargets.add(playerYou.getId());
|
possibleTargets.add(playerYou.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// chosen target
|
||||||
|
Set<UUID> chosenTargets = null;
|
||||||
|
if (false) { // TODO: add GUI's checkbox for checkPlayerAsChosen
|
||||||
|
chosenTargets = new LinkedHashSet<>();
|
||||||
|
chosenTargets.add(playerYou.getId());
|
||||||
|
}
|
||||||
|
|
||||||
// player's panel
|
// player's panel
|
||||||
if (this.player == null) {
|
if (this.player == null) {
|
||||||
// create new panel
|
// create new panel
|
||||||
|
|
@ -345,7 +353,7 @@ public class TestCardRenderDialog extends MageDialog {
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
this.player.init(this.game.getId(), playerYou.getId(), isMe, this.bigCard, 0);
|
this.player.init(this.game.getId(), playerYou.getId(), isMe, this.bigCard, 0);
|
||||||
this.player.update(gameView, currentPlayerView, possibleTargets);
|
this.player.update(gameView, currentPlayerView, possibleTargets, chosenTargets);
|
||||||
this.player.sizePlayerPanel(smallMode);
|
this.player.sizePlayerPanel(smallMode);
|
||||||
|
|
||||||
// update CARDS
|
// update CARDS
|
||||||
|
|
@ -424,6 +432,7 @@ public class TestCardRenderDialog extends MageDialog {
|
||||||
cardViews.add(createPermanentCard(game, playerYou.getId(), "RNA", "185", 0, 0, 0, true, false, null)); // Judith, the Scourge Diva
|
cardViews.add(createPermanentCard(game, playerYou.getId(), "RNA", "185", 0, 0, 0, true, false, null)); // Judith, the Scourge Diva
|
||||||
cardViews.add(createHandCard(game, playerYou.getId(), "DIS", "153")); // Odds // Ends (split card)
|
cardViews.add(createHandCard(game, playerYou.getId(), "DIS", "153")); // Odds // Ends (split card)
|
||||||
cardViews.add(createHandCard(game, playerYou.getId(), "ELD", "38")); // Animating Faerie (adventure card)
|
cardViews.add(createHandCard(game, playerYou.getId(), "ELD", "38")); // Animating Faerie (adventure card)
|
||||||
|
cardViews.add(createHandCard(game, playerYou.getId(), "LEA", "278")); // Bayou (retro frame)
|
||||||
cardViews.add(createFaceDownCard(game, playerOpponent.getId(), "ELD", "38", false, false, false)); // face down
|
cardViews.add(createFaceDownCard(game, playerOpponent.getId(), "ELD", "38", false, false, false)); // face down
|
||||||
cardViews.add(createFaceDownCard(game, playerOpponent.getId(), "ELD", "38", true, false, true)); // morphed
|
cardViews.add(createFaceDownCard(game, playerOpponent.getId(), "ELD", "38", true, false, true)); // morphed
|
||||||
cardViews.add(createFaceDownCard(game, playerOpponent.getId(), "ELD", "38", false, true, false)); // manifested
|
cardViews.add(createFaceDownCard(game, playerOpponent.getId(), "ELD", "38", false, true, false)); // manifested
|
||||||
|
|
@ -628,7 +637,7 @@ public class TestCardRenderDialog extends MageDialog {
|
||||||
|
|
||||||
labelRenderMode.setText("Render mode:");
|
labelRenderMode.setText("Render mode:");
|
||||||
|
|
||||||
comboRenderMode.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "MTGO", "Image" }));
|
comboRenderMode.setToolTipText("<HTML>Image - Renders card image with text overlay<br> MTGO - Renders card frame around card art<br> Forced M15 - Renders all cards in the MTGO style with the modern frame<br> Forced Retro - Renders all cards in the MTGO style with the retro frame");
|
||||||
comboRenderMode.addItemListener(new java.awt.event.ItemListener() {
|
comboRenderMode.addItemListener(new java.awt.event.ItemListener() {
|
||||||
public void itemStateChanged(java.awt.event.ItemEvent evt) {
|
public void itemStateChanged(java.awt.event.ItemEvent evt) {
|
||||||
comboRenderModeItemStateChanged(evt);
|
comboRenderModeItemStateChanged(evt);
|
||||||
|
|
@ -736,7 +745,6 @@ public class TestCardRenderDialog extends MageDialog {
|
||||||
labelCardColor.setText("Card color:");
|
labelCardColor.setText("Card color:");
|
||||||
|
|
||||||
comboCardColor.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "loading..." }));
|
comboCardColor.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "loading..." }));
|
||||||
comboCardColor.setToolTipText("");
|
|
||||||
comboCardColor.addItemListener(new java.awt.event.ItemListener() {
|
comboCardColor.addItemListener(new java.awt.event.ItemListener() {
|
||||||
public void itemStateChanged(java.awt.event.ItemEvent evt) {
|
public void itemStateChanged(java.awt.event.ItemEvent evt) {
|
||||||
comboCardColorItemStateChanged(evt);
|
comboCardColorItemStateChanged(evt);
|
||||||
|
|
@ -774,7 +782,6 @@ public class TestCardRenderDialog extends MageDialog {
|
||||||
playerOptions.add(checkPlayerSmallMode);
|
playerOptions.add(checkPlayerSmallMode);
|
||||||
|
|
||||||
comboPlayerStatus.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "Active", "Inactive", "Dead" }));
|
comboPlayerStatus.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "Active", "Inactive", "Dead" }));
|
||||||
comboPlayerStatus.setToolTipText("");
|
|
||||||
comboPlayerStatus.setAlignmentX(0.0F);
|
comboPlayerStatus.setAlignmentX(0.0F);
|
||||||
comboPlayerStatus.addItemListener(new java.awt.event.ItemListener() {
|
comboPlayerStatus.addItemListener(new java.awt.event.ItemListener() {
|
||||||
public void itemStateChanged(java.awt.event.ItemEvent evt) {
|
public void itemStateChanged(java.awt.event.ItemEvent evt) {
|
||||||
|
|
|
||||||
|
|
@ -343,7 +343,6 @@
|
||||||
</Property>
|
</Property>
|
||||||
<Property name="horizontalAlignment" type="int" value="4"/>
|
<Property name="horizontalAlignment" type="int" value="4"/>
|
||||||
<Property name="text" type="java.lang.String" value="player 2"/>
|
<Property name="text" type="java.lang.String" value="player 2"/>
|
||||||
<Property name="toolTipText" type="java.lang.String" value=""/>
|
|
||||||
<Property name="alignmentX" type="float" value="1.0"/>
|
<Property name="alignmentX" type="float" value="1.0"/>
|
||||||
<Property name="alignmentY" type="float" value="0.0"/>
|
<Property name="alignmentY" type="float" value="0.0"/>
|
||||||
<Property name="focusable" type="boolean" value="false"/>
|
<Property name="focusable" type="boolean" value="false"/>
|
||||||
|
|
@ -523,7 +522,6 @@
|
||||||
</Property>
|
</Property>
|
||||||
<Property name="horizontalAlignment" type="int" value="2"/>
|
<Property name="horizontalAlignment" type="int" value="2"/>
|
||||||
<Property name="text" type="java.lang.String" value="player 12"/>
|
<Property name="text" type="java.lang.String" value="player 12"/>
|
||||||
<Property name="toolTipText" type="java.lang.String" value=""/>
|
|
||||||
<Property name="focusable" type="boolean" value="false"/>
|
<Property name="focusable" type="boolean" value="false"/>
|
||||||
<Property name="requestFocusEnabled" type="boolean" value="false"/>
|
<Property name="requestFocusEnabled" type="boolean" value="false"/>
|
||||||
<Property name="verifyInputWhenFocusTarget" type="boolean" value="false"/>
|
<Property name="verifyInputWhenFocusTarget" type="boolean" value="false"/>
|
||||||
|
|
|
||||||
|
|
@ -45,8 +45,9 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ms delay between booster showing up and pick being allowed.
|
* ms delay between booster showing up and pick being allowed.
|
||||||
|
* Will be disabled in test mode
|
||||||
*/
|
*/
|
||||||
private static final int protectionTime = 1500;
|
private static final int PROTECTION_CLICKS_TIMEOUT_MS = 1500;
|
||||||
/**
|
/**
|
||||||
* Timer starting at booster being displayed, to protect from early pick due to clicking
|
* Timer starting at booster being displayed, to protect from early pick due to clicking
|
||||||
* a little too much on the last pick.
|
* a little too much on the last pick.
|
||||||
|
|
@ -138,7 +139,11 @@
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
protectionTimer = new Timer(protectionTime, e -> protectionTimer.stop());
|
int protectionTimeout = PROTECTION_CLICKS_TIMEOUT_MS;
|
||||||
|
if (SessionHandler.isTestMode()) {
|
||||||
|
protectionTimeout = 100;
|
||||||
|
}
|
||||||
|
protectionTimer = new Timer(protectionTimeout, e -> protectionTimer.stop());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void cleanUp() {
|
public void cleanUp() {
|
||||||
|
|
@ -186,15 +191,15 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateDraft(DraftView draftView) {
|
public void updateDraft(DraftView draftView) {
|
||||||
if (draftView.getSets().size() != 3) {
|
if (draftView.getSetNames().size() != 3) {
|
||||||
// Random draft - TODO: can we access the type of draft here?
|
// Random draft - TODO: can we access the type of draft here?
|
||||||
this.editPack1.setText("Random Boosters");
|
this.editPack1.setText("Random Boosters");
|
||||||
this.editPack2.setText("Random Boosters");
|
this.editPack2.setText("Random Boosters");
|
||||||
this.editPack3.setText("Random Boosters");
|
this.editPack3.setText("Random Boosters");
|
||||||
} else {
|
} else {
|
||||||
this.editPack1.setText(String.format("%s - %s", draftView.getSetCodes().get(0), draftView.getSets().get(0)));
|
this.editPack1.setText(draftView.getBoosterInfo(0));
|
||||||
this.editPack2.setText(String.format("%s - %s", draftView.getSetCodes().get(1), draftView.getSets().get(1)));
|
this.editPack2.setText(draftView.getBoosterInfo(1));
|
||||||
this.editPack3.setText(String.format("%s - %s", draftView.getSetCodes().get(2), draftView.getSets().get(2)));
|
this.editPack3.setText(draftView.getBoosterInfo(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
// scroll too long text to the start
|
// scroll too long text to the start
|
||||||
|
|
@ -396,7 +401,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!draftBooster.isEmptyGrid()) {
|
if (!draftBooster.isEmptyGrid()) {
|
||||||
SessionHandler.setBoosterLoaded(draftId); // confirm to the server that the booster has been successfully loaded, otherwise the server will re-send the booster
|
// confirm to the server that the booster has been successfully loaded, otherwise the server will re-send the booster
|
||||||
|
SessionHandler.setBoosterLoaded(draftId);
|
||||||
|
|
||||||
if (pickNo != protectionPickNo && !protectionTimer.isRunning()) {
|
if (pickNo != protectionPickNo && !protectionTimer.isRunning()) {
|
||||||
// Restart the protection timer.
|
// Restart the protection timer.
|
||||||
|
|
@ -773,7 +779,6 @@
|
||||||
labelPlayer02.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N
|
labelPlayer02.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N
|
||||||
labelPlayer02.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
|
labelPlayer02.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
|
||||||
labelPlayer02.setText("player 2");
|
labelPlayer02.setText("player 2");
|
||||||
labelPlayer02.setToolTipText("");
|
|
||||||
labelPlayer02.setAlignmentX(1.0F);
|
labelPlayer02.setAlignmentX(1.0F);
|
||||||
labelPlayer02.setAlignmentY(0.0F);
|
labelPlayer02.setAlignmentY(0.0F);
|
||||||
labelPlayer02.setFocusable(false);
|
labelPlayer02.setFocusable(false);
|
||||||
|
|
@ -887,7 +892,6 @@
|
||||||
labelPlayer12.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N
|
labelPlayer12.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N
|
||||||
labelPlayer12.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
|
labelPlayer12.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
|
||||||
labelPlayer12.setText("player 12");
|
labelPlayer12.setText("player 12");
|
||||||
labelPlayer12.setToolTipText("");
|
|
||||||
labelPlayer12.setFocusable(false);
|
labelPlayer12.setFocusable(false);
|
||||||
labelPlayer12.setRequestFocusEnabled(false);
|
labelPlayer12.setRequestFocusEnabled(false);
|
||||||
labelPlayer12.setVerifyInputWhenFocusTarget(false);
|
labelPlayer12.setVerifyInputWhenFocusTarget(false);
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,10 @@ import mage.constants.*;
|
||||||
import mage.game.events.PlayerQueryEvent;
|
import mage.game.events.PlayerQueryEvent;
|
||||||
import mage.players.PlayableObjectStats;
|
import mage.players.PlayableObjectStats;
|
||||||
import mage.players.PlayableObjectsList;
|
import mage.players.PlayableObjectsList;
|
||||||
|
import mage.util.CardUtil;
|
||||||
import mage.util.DebugUtil;
|
import mage.util.DebugUtil;
|
||||||
import mage.util.MultiAmountMessage;
|
import mage.util.MultiAmountMessage;
|
||||||
|
import mage.util.StreamUtils;
|
||||||
import mage.view.*;
|
import mage.view.*;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.mage.plugins.card.utils.impl.ImageManagerImpl;
|
import org.mage.plugins.card.utils.impl.ImageManagerImpl;
|
||||||
|
|
@ -53,6 +55,7 @@ import java.util.*;
|
||||||
import java.util.concurrent.CancellationException;
|
import java.util.concurrent.CancellationException;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static mage.client.dialog.PreferencesDialog.*;
|
import static mage.client.dialog.PreferencesDialog.*;
|
||||||
import static mage.constants.PlayerAction.*;
|
import static mage.constants.PlayerAction.*;
|
||||||
|
|
@ -213,6 +216,22 @@ public final class GamePanel extends javax.swing.JPanel {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<UUID> getPossibleTargets() {
|
||||||
|
if (options != null && options.containsKey("possibleTargets")) {
|
||||||
|
return (List<UUID>) options.get("possibleTargets");
|
||||||
|
} else {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<UUID> getChosenTargets() {
|
||||||
|
if (options != null && options.containsKey("chosenTargets")) {
|
||||||
|
return new HashSet<>((List<UUID>) options.get("chosenTargets"));
|
||||||
|
} else {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public CardView findCard(UUID id) {
|
public CardView findCard(UUID id) {
|
||||||
return this.allCardsIndex.getOrDefault(id, null);
|
return this.allCardsIndex.getOrDefault(id, null);
|
||||||
}
|
}
|
||||||
|
|
@ -639,7 +658,7 @@ public final class GamePanel extends javax.swing.JPanel {
|
||||||
// see test render dialog for refresh commands order
|
// see test render dialog for refresh commands order
|
||||||
playPanel.getPlayerPanel().fullRefresh(GUISizeHelper.playerPanelGuiScale);
|
playPanel.getPlayerPanel().fullRefresh(GUISizeHelper.playerPanelGuiScale);
|
||||||
playPanel.init(player, bigCard, gameId, player.getPriorityTimeLeftSecs());
|
playPanel.init(player, bigCard, gameId, player.getPriorityTimeLeftSecs());
|
||||||
playPanel.update(lastGameData.game, player, lastGameData.targets);
|
playPanel.update(lastGameData.game, player, lastGameData.targets, lastGameData.getChosenTargets());
|
||||||
playPanel.getPlayerPanel().sizePlayerPanel(false);
|
playPanel.getPlayerPanel().sizePlayerPanel(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -650,6 +669,11 @@ public final class GamePanel extends javax.swing.JPanel {
|
||||||
this.abilityPicker.fullRefresh(GUISizeHelper.dialogGuiScale);
|
this.abilityPicker.fullRefresh(GUISizeHelper.dialogGuiScale);
|
||||||
this.abilityPicker.init(gameId, bigCard);
|
this.abilityPicker.init(gameId, bigCard);
|
||||||
}
|
}
|
||||||
|
if (this.pickMultiNumber != null && !this.pickMultiNumber.isVisible()) {
|
||||||
|
// TODO: add pick number dialogs support here
|
||||||
|
//this.pickMultiNumber.fullRefresh(GUISizeHelper.dialogGuiScale);
|
||||||
|
this.pickMultiNumber.init(gameId, bigCard);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setSkipButtonImage(JButton button, Image image) {
|
private void setSkipButtonImage(JButton button, Image image) {
|
||||||
|
|
@ -819,6 +843,7 @@ public final class GamePanel extends javax.swing.JPanel {
|
||||||
MageFrame.addGame(gameId, this);
|
MageFrame.addGame(gameId, this);
|
||||||
this.feedbackPanel.init(gameId, bigCard);
|
this.feedbackPanel.init(gameId, bigCard);
|
||||||
this.feedbackPanel.clear();
|
this.feedbackPanel.clear();
|
||||||
|
this.pickMultiNumber.init(gameId, bigCard);
|
||||||
this.abilityPicker.init(gameId, bigCard);
|
this.abilityPicker.init(gameId, bigCard);
|
||||||
this.btnConcede.setVisible(true);
|
this.btnConcede.setVisible(true);
|
||||||
this.btnStopWatching.setVisible(false);
|
this.btnStopWatching.setVisible(false);
|
||||||
|
|
@ -1161,7 +1186,7 @@ public final class GamePanel extends javax.swing.JPanel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
players.get(player.getPlayerId()).update(lastGameData.game, player, lastGameData.targets);
|
players.get(player.getPlayerId()).update(lastGameData.game, player, lastGameData.targets, lastGameData.getChosenTargets());
|
||||||
if (player.getPlayerId().equals(playerId)) {
|
if (player.getPlayerId().equals(playerId)) {
|
||||||
skipButtons.updateFromPlayer(player);
|
skipButtons.updateFromPlayer(player);
|
||||||
}
|
}
|
||||||
|
|
@ -1777,12 +1802,7 @@ public final class GamePanel extends javax.swing.JPanel {
|
||||||
needZone = (Zone) lastGameData.options.get("targetZone");
|
needZone = (Zone) lastGameData.options.get("targetZone");
|
||||||
}
|
}
|
||||||
|
|
||||||
List<UUID> needChosen;
|
Set<UUID> needChosen = lastGameData.getChosenTargets();
|
||||||
if (lastGameData.options != null && lastGameData.options.containsKey("chosenTargets")) {
|
|
||||||
needChosen = (List<UUID>) lastGameData.options.get("chosenTargets");
|
|
||||||
} else {
|
|
||||||
needChosen = new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
Set<UUID> needSelectable;
|
Set<UUID> needSelectable;
|
||||||
if (lastGameData.targets != null) {
|
if (lastGameData.targets != null) {
|
||||||
|
|
@ -1804,6 +1824,7 @@ public final class GamePanel extends javax.swing.JPanel {
|
||||||
|
|
||||||
// hand
|
// hand
|
||||||
if (needZone == Zone.HAND || needZone == Zone.ALL) {
|
if (needZone == Zone.HAND || needZone == Zone.ALL) {
|
||||||
|
// my hand
|
||||||
for (CardView card : lastGameData.game.getMyHand().values()) {
|
for (CardView card : lastGameData.game.getMyHand().values()) {
|
||||||
if (needSelectable.contains(card.getId())) {
|
if (needSelectable.contains(card.getId())) {
|
||||||
card.setChoosable(true);
|
card.setChoosable(true);
|
||||||
|
|
@ -1815,6 +1836,34 @@ public final class GamePanel extends javax.swing.JPanel {
|
||||||
card.setPlayableStats(needPlayable.getStats(card.getId()));
|
card.setPlayableStats(needPlayable.getStats(card.getId()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// opponent hands (switching by GUI's button with my hand)
|
||||||
|
List<SimpleCardView> list = lastGameData.game.getOpponentHands().values().stream().flatMap(s -> s.values().stream()).collect(Collectors.toList());
|
||||||
|
for (SimpleCardView card : list) {
|
||||||
|
if (needSelectable.contains(card.getId())) {
|
||||||
|
card.setChoosable(true);
|
||||||
|
}
|
||||||
|
if (needChosen.contains(card.getId())) {
|
||||||
|
card.setSelected(true);
|
||||||
|
}
|
||||||
|
if (needPlayable.containsObject(card.getId())) {
|
||||||
|
card.setPlayableStats(needPlayable.getStats(card.getId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// watched hands (switching by GUI's button with my hand)
|
||||||
|
list = lastGameData.game.getWatchedHands().values().stream().flatMap(s -> s.values().stream()).collect(Collectors.toList());
|
||||||
|
for (SimpleCardView card : list) {
|
||||||
|
if (needSelectable.contains(card.getId())) {
|
||||||
|
card.setChoosable(true);
|
||||||
|
}
|
||||||
|
if (needChosen.contains(card.getId())) {
|
||||||
|
card.setSelected(true);
|
||||||
|
}
|
||||||
|
if (needPlayable.containsObject(card.getId())) {
|
||||||
|
card.setPlayableStats(needPlayable.getStats(card.getId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// stack
|
// stack
|
||||||
|
|
@ -1983,7 +2032,7 @@ public final class GamePanel extends javax.swing.JPanel {
|
||||||
private void prepareSelectableWindows(
|
private void prepareSelectableWindows(
|
||||||
Collection<CardInfoWindowDialog> windows,
|
Collection<CardInfoWindowDialog> windows,
|
||||||
Set<UUID> needSelectable,
|
Set<UUID> needSelectable,
|
||||||
List<UUID> needChosen,
|
Set<UUID> needChosen,
|
||||||
PlayableObjectsList needPlayable
|
PlayableObjectsList needPlayable
|
||||||
) {
|
) {
|
||||||
// lookAt or reveals windows clean up on next priority, so users can see dialogs, but xmage can't restore it
|
// lookAt or reveals windows clean up on next priority, so users can see dialogs, but xmage can't restore it
|
||||||
|
|
@ -2177,6 +2226,7 @@ public final class GamePanel extends javax.swing.JPanel {
|
||||||
hideAll();
|
hideAll();
|
||||||
DialogManager.getManager(gameId).fadeOut();
|
DialogManager.getManager(gameId).fadeOut();
|
||||||
|
|
||||||
|
pickMultiNumber.init(gameId, bigCard);
|
||||||
pickMultiNumber.showDialog(messages, min, max, lastGameData.options, () -> {
|
pickMultiNumber.showDialog(messages, min, max, lastGameData.options, () -> {
|
||||||
if (pickMultiNumber.isCancel()) {
|
if (pickMultiNumber.isCancel()) {
|
||||||
SessionHandler.sendPlayerBoolean(gameId, false);
|
SessionHandler.sendPlayerBoolean(gameId, false);
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ public class PlayAreaPanel extends javax.swing.JPanel {
|
||||||
|
|
||||||
// data init
|
// data init
|
||||||
init(player, bigCard, gameId, priorityTime);
|
init(player, bigCard, gameId, priorityTime);
|
||||||
update(null, player, null);
|
update(null, player, null, null);
|
||||||
playerPanel.sizePlayerPanel(isSmallMode());
|
playerPanel.sizePlayerPanel(isSmallMode());
|
||||||
|
|
||||||
// init popup menu (must run after data init)
|
// init popup menu (must run after data init)
|
||||||
|
|
@ -510,8 +510,8 @@ public class PlayAreaPanel extends javax.swing.JPanel {
|
||||||
this.isMe = player.getControlled();
|
this.isMe = player.getControlled();
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void update(GameView game, PlayerView player, Set<UUID> possibleTargets) {
|
public final void update(GameView game, PlayerView player, Set<UUID> possibleTargets, Set<UUID> chosenTargets) {
|
||||||
this.playerPanel.update(game, player, possibleTargets);
|
this.playerPanel.update(game, player, possibleTargets, chosenTargets);
|
||||||
this.battlefieldPanel.update(player.getBattlefield());
|
this.battlefieldPanel.update(player.getBattlefield());
|
||||||
if (this.allowViewHandCardsMenuItem != null) {
|
if (this.allowViewHandCardsMenuItem != null) {
|
||||||
this.allowViewHandCardsMenuItem.setSelected(player.getUserData().isAllowRequestHandToAll());
|
this.allowViewHandCardsMenuItem.setSelected(player.getUserData().isAllowRequestHandToAll());
|
||||||
|
|
|
||||||
|
|
@ -247,7 +247,7 @@ public class PlayerPanelExt extends javax.swing.JPanel {
|
||||||
.orElse(0);
|
.orElse(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(GameView game, PlayerView player, Set<UUID> possibleTargets) {
|
public void update(GameView game, PlayerView player, Set<UUID> possibleTargets, Set<UUID> chosenTargets) {
|
||||||
this.player = player;
|
this.player = player;
|
||||||
int pastLife = player.getLife();
|
int pastLife = player.getLife();
|
||||||
if (playerLives != null) {
|
if (playerLives != null) {
|
||||||
|
|
@ -427,6 +427,12 @@ public class PlayerPanelExt extends javax.swing.JPanel {
|
||||||
this.btnPlayer.setBorder(YELLOW_BORDER);
|
this.btnPlayer.setBorder(YELLOW_BORDER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// selected targeting (draw as priority)
|
||||||
|
if (chosenTargets != null && chosenTargets.contains(this.playerId)) {
|
||||||
|
this.avatar.setBorder(GREEN_BORDER); // TODO: use diff green color for chosen targeting and current priority?
|
||||||
|
this.btnPlayer.setBorder(GREEN_BORDER);
|
||||||
|
}
|
||||||
|
|
||||||
update(player.getManaPool());
|
update(player.getManaPool());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -687,11 +693,11 @@ public class PlayerPanelExt extends javax.swing.JPanel {
|
||||||
zonesPanel.setLayout(null);
|
zonesPanel.setLayout(null);
|
||||||
zonesPanel.setOpaque(false);
|
zonesPanel.setOpaque(false);
|
||||||
|
|
||||||
// tools button like hints
|
// hints
|
||||||
toolHintsHelper = new JButton();
|
toolHintsHelper = new JButton();
|
||||||
toolHintsHelper.setFont(this.getFont());
|
toolHintsHelper.setFont(this.getFont());
|
||||||
toolHintsHelper.setText("hints");
|
toolHintsHelper.setText("Hints");
|
||||||
toolHintsHelper.setToolTipText("Open new card hints helper window");
|
toolHintsHelper.setToolTipText("Open card hints helper window");
|
||||||
toolHintsHelper.addActionListener(this::btnToolHintsHelperActionPerformed);
|
toolHintsHelper.addActionListener(this::btnToolHintsHelperActionPerformed);
|
||||||
toolHintsHelper.setBounds(sizeMod(3), sizeMod(2 + 21 + 2), sizeMod(73), sizeMod(21));
|
toolHintsHelper.setBounds(sizeMod(3), sizeMod(2 + 21 + 2), sizeMod(73), sizeMod(21));
|
||||||
zonesPanel.add(toolHintsHelper);
|
zonesPanel.add(toolHintsHelper);
|
||||||
|
|
@ -701,7 +707,7 @@ public class PlayerPanelExt extends javax.swing.JPanel {
|
||||||
image = ImageHelper.getImageFromResources("/info/command_zone.png");
|
image = ImageHelper.getImageFromResources("/info/command_zone.png");
|
||||||
resized = ImageHelper.getResizedImage(BufferedImageBuilder.bufferImage(image, BufferedImage.TYPE_INT_ARGB), r);
|
resized = ImageHelper.getResizedImage(BufferedImageBuilder.bufferImage(image, BufferedImage.TYPE_INT_ARGB), r);
|
||||||
commandZone = new HoverButton(null, resized, resized, resized, r, this.guiScaleMod);
|
commandZone = new HoverButton(null, resized, resized, resized, r, this.guiScaleMod);
|
||||||
commandZone.setToolTipText("Command Zone (Commanders, Emblems and Planes)");
|
commandZone.setToolTipText("Command Zone (Commanders, Emblems, and Planes)");
|
||||||
commandZone.setOpaque(false);
|
commandZone.setOpaque(false);
|
||||||
commandZone.setObserver(() -> btnCommandZoneActionPerformed(null));
|
commandZone.setObserver(() -> btnCommandZoneActionPerformed(null));
|
||||||
commandZone.setBounds(sizeMod(3), 0, sizeMod(21), sizeMod(21));
|
commandZone.setBounds(sizeMod(3), 0, sizeMod(21), sizeMod(21));
|
||||||
|
|
|
||||||
|
|
@ -98,8 +98,8 @@ public class MageActionCallback implements ActionCallback {
|
||||||
private MageCard prevCardPanel;
|
private MageCard prevCardPanel;
|
||||||
private boolean startedDragging;
|
private boolean startedDragging;
|
||||||
private boolean isDragging; // TODO: remove drag hand code to the hand panels
|
private boolean isDragging; // TODO: remove drag hand code to the hand panels
|
||||||
private Point initialCardPos;
|
private Point initialCardPos = null;
|
||||||
private Point initialMousePos;
|
private Point initialMousePos = null;
|
||||||
private final Set<MageCard> draggingCards = new HashSet<>();
|
private final Set<MageCard> draggingCards = new HashSet<>();
|
||||||
|
|
||||||
public MageActionCallback() {
|
public MageActionCallback() {
|
||||||
|
|
@ -351,6 +351,11 @@ public class MageActionCallback implements ActionCallback {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.initialMousePos == null || this.initialCardPos == null) {
|
||||||
|
// only allow really mouse pressed, e.g. ignore draft/game update on active card draging/pressing
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Point mouse = new Point(e.getX(), e.getY());
|
Point mouse = new Point(e.getX(), e.getY());
|
||||||
SwingUtilities.convertPointToScreen(mouse, data.getComponent());
|
SwingUtilities.convertPointToScreen(mouse, data.getComponent());
|
||||||
if (!isDragging
|
if (!isDragging
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import mage.client.draft.DraftPanel;
|
||||||
import mage.client.game.GamePanel;
|
import mage.client.game.GamePanel;
|
||||||
import mage.client.plugins.impl.Plugins;
|
import mage.client.plugins.impl.Plugins;
|
||||||
import mage.client.util.DeckUtil;
|
import mage.client.util.DeckUtil;
|
||||||
|
import mage.client.util.GUISizeHelper;
|
||||||
import mage.client.util.IgnoreList;
|
import mage.client.util.IgnoreList;
|
||||||
import mage.client.util.audio.AudioManager;
|
import mage.client.util.audio.AudioManager;
|
||||||
import mage.client.util.object.SaveObjectUtil;
|
import mage.client.util.object.SaveObjectUtil;
|
||||||
|
|
@ -22,9 +23,12 @@ import mage.util.DebugUtil;
|
||||||
import mage.view.*;
|
import mage.view.*;
|
||||||
import mage.view.ChatMessage.MessageType;
|
import mage.view.ChatMessage.MessageType;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
import org.mage.card.arcane.ManaSymbols;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
|
import java.util.List;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -72,7 +76,7 @@ public class CallbackClientImpl implements CallbackClient {
|
||||||
SwingUtilities.invokeLater(() -> {
|
SwingUtilities.invokeLater(() -> {
|
||||||
try {
|
try {
|
||||||
if (DebugUtil.NETWORK_SHOW_CLIENT_CALLBACK_MESSAGES_LOG) {
|
if (DebugUtil.NETWORK_SHOW_CLIENT_CALLBACK_MESSAGES_LOG) {
|
||||||
logger.info("message " + callback.getMessageId() + " - " + callback.getMethod().getType() + " - " + callback.getMethod());
|
logger.info(callback.getInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
// process bad connection (events can income in wrong order, so outdated data must be ignored)
|
// process bad connection (events can income in wrong order, so outdated data must be ignored)
|
||||||
|
|
@ -203,11 +207,7 @@ public class CallbackClientImpl implements CallbackClient {
|
||||||
case SERVER_MESSAGE: {
|
case SERVER_MESSAGE: {
|
||||||
if (callback.getData() != null) {
|
if (callback.getData() != null) {
|
||||||
ChatMessage message = (ChatMessage) callback.getData();
|
ChatMessage message = (ChatMessage) callback.getData();
|
||||||
if (message.getColor() == ChatMessage.MessageColor.RED) {
|
showMessageDialog(null, message.getMessage(), "Server message");
|
||||||
JOptionPane.showMessageDialog(null, message.getMessage(), "Server message", JOptionPane.WARNING_MESSAGE);
|
|
||||||
} else {
|
|
||||||
JOptionPane.showMessageDialog(null, message.getMessage(), "Server message", JOptionPane.INFORMATION_MESSAGE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -401,7 +401,7 @@ public class CallbackClientImpl implements CallbackClient {
|
||||||
case SHOW_USERMESSAGE: {
|
case SHOW_USERMESSAGE: {
|
||||||
List<String> messageData = (List<String>) callback.getData();
|
List<String> messageData = (List<String>) callback.getData();
|
||||||
if (messageData.size() == 2) {
|
if (messageData.size() == 2) {
|
||||||
JOptionPane.showMessageDialog(null, messageData.get(1), messageData.get(0), JOptionPane.WARNING_MESSAGE);
|
showMessageDialog(null, messageData.get(1), messageData.get(0));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -420,8 +420,7 @@ public class CallbackClientImpl implements CallbackClient {
|
||||||
GameClientMessage message = (GameClientMessage) callback.getData();
|
GameClientMessage message = (GameClientMessage) callback.getData();
|
||||||
GamePanel panel = MageFrame.getGame(callback.getObjectId());
|
GamePanel panel = MageFrame.getGame(callback.getObjectId());
|
||||||
if (panel != null) {
|
if (panel != null) {
|
||||||
JOptionPane.showMessageDialog(panel, message.getMessage(), "Game message",
|
showMessageDialog(panel, message.getMessage(), "Game message");
|
||||||
JOptionPane.INFORMATION_MESSAGE);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -510,6 +509,18 @@ public class CallbackClientImpl implements CallbackClient {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show modal message box, so try to use it only for critical errors or global message. As less as possible.
|
||||||
|
*/
|
||||||
|
private void showMessageDialog(Component parentComponent, String message, String title) {
|
||||||
|
// convert to html
|
||||||
|
// message - supported
|
||||||
|
// title - not supported
|
||||||
|
message = ManaSymbols.replaceSymbolsWithHTML(message, ManaSymbols.Type.DIALOG);
|
||||||
|
message = GUISizeHelper.textToHtmlWithSize(message, GUISizeHelper.dialogFont);
|
||||||
|
JOptionPane.showMessageDialog(parentComponent, message, title, JOptionPane.INFORMATION_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
private ActionData appendJsonEvent(String name, UUID gameId, Object value) {
|
private ActionData appendJsonEvent(String name, UUID gameId, Object value) {
|
||||||
Session session = SessionHandler.getSession();
|
Session session = SessionHandler.getSession();
|
||||||
if (session.isJsonLogActive()) {
|
if (session.isJsonLogActive()) {
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,12 @@ public class XmageURLConnection {
|
||||||
private static final AtomicLong debugLastRequestTimeMs = new AtomicLong(0);
|
private static final AtomicLong debugLastRequestTimeMs = new AtomicLong(0);
|
||||||
private static final ReentrantLock debugLogsWriterlock = new ReentrantLock();
|
private static final ReentrantLock debugLogsWriterlock = new ReentrantLock();
|
||||||
|
|
||||||
|
static {
|
||||||
|
// add Authority Information Access (AIA) Extension support for certificates from Windows servers like gatherer website
|
||||||
|
// fix download errors like sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
|
||||||
|
System.setProperty("com.sun.security.enableAIAcaIssuers", "true");
|
||||||
|
}
|
||||||
|
|
||||||
final String url;
|
final String url;
|
||||||
Proxy proxy = null;
|
Proxy proxy = null;
|
||||||
HttpURLConnection connection = null;
|
HttpURLConnection connection = null;
|
||||||
|
|
@ -123,6 +129,10 @@ public class XmageURLConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.proxy = Proxy.NO_PROXY;
|
this.proxy = Proxy.NO_PROXY;
|
||||||
|
if (!PreferencesDialog.NETWORK_ENABLE_PROXY_SUPPORT) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (type != Proxy.Type.DIRECT) {
|
if (type != Proxy.Type.DIRECT) {
|
||||||
try {
|
try {
|
||||||
String address = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_PROXY_ADDRESS, "");
|
String address = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_PROXY_ADDRESS, "");
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,10 @@ public class TablePlayerPanel extends javax.swing.JPanel {
|
||||||
this.newPlayerPanel.setSkillLevel(playerSkill);
|
this.newPlayerPanel.setSkillLevel(playerSkill);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String extractAiPlayerNumberFromLabel(String label) {
|
||||||
|
return ClientDefaultSettings.computerName + " " + label.substring(Math.max(0, label.length() - 2)).trim();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean joinTable(UUID roomId, UUID tableId) throws IOException, ClassNotFoundException {
|
public boolean joinTable(UUID roomId, UUID tableId) throws IOException, ClassNotFoundException {
|
||||||
if (this.cbPlayerType.getSelectedItem() != PlayerType.HUMAN) {
|
if (this.cbPlayerType.getSelectedItem() != PlayerType.HUMAN) {
|
||||||
return SessionHandler.joinTable(roomId, tableId, this.newPlayerPanel.getPlayerName(), (PlayerType) this.cbPlayerType.getSelectedItem(), this.newPlayerPanel.getSkillLevel(), DeckImporter.importDeckFromFile(this.newPlayerPanel.getDeckFile(), true), "");
|
return SessionHandler.joinTable(roomId, tableId, this.newPlayerPanel.getPlayerName(), (PlayerType) this.cbPlayerType.getSelectedItem(), this.newPlayerPanel.getSkillLevel(), DeckImporter.importDeckFromFile(this.newPlayerPanel.getDeckFile(), true), "");
|
||||||
|
|
@ -124,7 +128,7 @@ public class TablePlayerPanel extends javax.swing.JPanel {
|
||||||
private void cbPlayerTypeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbPlayerTypeActionPerformed
|
private void cbPlayerTypeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbPlayerTypeActionPerformed
|
||||||
if (getPlayerType() != PlayerType.HUMAN) {
|
if (getPlayerType() != PlayerType.HUMAN) {
|
||||||
this.newPlayerPanel.setVisible(true);
|
this.newPlayerPanel.setVisible(true);
|
||||||
this.newPlayerPanel.setPlayerName(ClientDefaultSettings.computerName + " " + this.lblPlayerNum.getText().charAt(this.lblPlayerNum.getText().length() - 1));
|
this.newPlayerPanel.setPlayerName(extractAiPlayerNumberFromLabel(this.lblPlayerNum.getText()));
|
||||||
} else {
|
} else {
|
||||||
this.newPlayerPanel.setVisible(false);
|
this.newPlayerPanel.setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -201,7 +201,7 @@
|
||||||
<Component class="javax.swing.JToggleButton" name="btnTypeTourneyConstructed">
|
<Component class="javax.swing.JToggleButton" name="btnTypeTourneyConstructed">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="selected" type="boolean" value="true"/>
|
<Property name="selected" type="boolean" value="true"/>
|
||||||
<Property name="text" type="java.lang.String" value="Constructed tourn."/>
|
<Property name="text" type="java.lang.String" value="Constructed tourney"/>
|
||||||
<Property name="toolTipText" type="java.lang.String" value="Shows all constructed tournament tables."/>
|
<Property name="toolTipText" type="java.lang.String" value="Shows all constructed tournament tables."/>
|
||||||
<Property name="actionCommand" type="java.lang.String" value="typeTourneyConstructed"/>
|
<Property name="actionCommand" type="java.lang.String" value="typeTourneyConstructed"/>
|
||||||
<Property name="focusPainted" type="boolean" value="false"/>
|
<Property name="focusPainted" type="boolean" value="false"/>
|
||||||
|
|
@ -216,7 +216,7 @@
|
||||||
<Component class="javax.swing.JToggleButton" name="btnTypeTourneyLimited">
|
<Component class="javax.swing.JToggleButton" name="btnTypeTourneyLimited">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="selected" type="boolean" value="true"/>
|
<Property name="selected" type="boolean" value="true"/>
|
||||||
<Property name="text" type="java.lang.String" value="Limited tourn."/>
|
<Property name="text" type="java.lang.String" value="Limited tourney"/>
|
||||||
<Property name="toolTipText" type="java.lang.String" value="Shows all limited tournament tables."/>
|
<Property name="toolTipText" type="java.lang.String" value="Shows all limited tournament tables."/>
|
||||||
<Property name="actionCommand" type="java.lang.String" value="typeTourneyLimited"/>
|
<Property name="actionCommand" type="java.lang.String" value="typeTourneyLimited"/>
|
||||||
<Property name="focusPainted" type="boolean" value="false"/>
|
<Property name="focusPainted" type="boolean" value="false"/>
|
||||||
|
|
|
||||||
|
|
@ -1163,7 +1163,7 @@ public class TablesPanel extends javax.swing.JPanel {
|
||||||
filterBar1.add(btnTypeMatch);
|
filterBar1.add(btnTypeMatch);
|
||||||
|
|
||||||
btnTypeTourneyConstructed.setSelected(true);
|
btnTypeTourneyConstructed.setSelected(true);
|
||||||
btnTypeTourneyConstructed.setText("Constructed tourn.");
|
btnTypeTourneyConstructed.setText("Constructed tourney");
|
||||||
btnTypeTourneyConstructed.setToolTipText("Shows all constructed tournament tables.");
|
btnTypeTourneyConstructed.setToolTipText("Shows all constructed tournament tables.");
|
||||||
btnTypeTourneyConstructed.setActionCommand("typeTourneyConstructed");
|
btnTypeTourneyConstructed.setActionCommand("typeTourneyConstructed");
|
||||||
btnTypeTourneyConstructed.setFocusPainted(false);
|
btnTypeTourneyConstructed.setFocusPainted(false);
|
||||||
|
|
@ -1178,7 +1178,7 @@ public class TablesPanel extends javax.swing.JPanel {
|
||||||
filterBar1.add(btnTypeTourneyConstructed);
|
filterBar1.add(btnTypeTourneyConstructed);
|
||||||
|
|
||||||
btnTypeTourneyLimited.setSelected(true);
|
btnTypeTourneyLimited.setSelected(true);
|
||||||
btnTypeTourneyLimited.setText("Limited tourn.");
|
btnTypeTourneyLimited.setText("Limited tourney");
|
||||||
btnTypeTourneyLimited.setToolTipText("Shows all limited tournament tables.");
|
btnTypeTourneyLimited.setToolTipText("Shows all limited tournament tables.");
|
||||||
btnTypeTourneyLimited.setActionCommand("typeTourneyLimited");
|
btnTypeTourneyLimited.setActionCommand("typeTourneyLimited");
|
||||||
btnTypeTourneyLimited.setFocusPainted(false);
|
btnTypeTourneyLimited.setFocusPainted(false);
|
||||||
|
|
@ -1694,13 +1694,13 @@ public class TablesPanel extends javax.swing.JPanel {
|
||||||
DeckCardLists testDeck = DeckImporter.importDeckFromFile(testDeckFile, false);
|
DeckCardLists testDeck = DeckImporter.importDeckFromFile(testDeckFile, false);
|
||||||
|
|
||||||
PlayerType aiType = useMonteCarloAI ? PlayerType.COMPUTER_MONTE_CARLO : PlayerType.COMPUTER_MAD;
|
PlayerType aiType = useMonteCarloAI ? PlayerType.COMPUTER_MONTE_CARLO : PlayerType.COMPUTER_MAD;
|
||||||
int numSeats = gameName.contains("2") || gameName.contains("Monte Carlo") ? 2 : 4;
|
int numPlayers = gameName.contains("2") || gameName.contains("Monte Carlo") ? 2 : 4;
|
||||||
boolean multiPlayer = numSeats > 2;
|
boolean multiPlayer = numPlayers > 2;
|
||||||
|
|
||||||
MatchOptions options = new MatchOptions(gameName, gameType, multiPlayer, numSeats);
|
MatchOptions options = new MatchOptions(gameName, gameType, multiPlayer);
|
||||||
options.getPlayerTypes().add(PlayerType.HUMAN);
|
options.getPlayerTypes().add(PlayerType.HUMAN);
|
||||||
options.getPlayerTypes().add(aiType);
|
options.getPlayerTypes().add(aiType);
|
||||||
for (int i=2 ; i < numSeats ; i++) {
|
for (int i=2 ; i < numPlayers ; i++) {
|
||||||
options.getPlayerTypes().add(aiType);
|
options.getPlayerTypes().add(aiType);
|
||||||
}
|
}
|
||||||
options.setDeckType("Variant Magic - Freeform Commander");
|
options.setDeckType("Variant Magic - Freeform Commander");
|
||||||
|
|
@ -1720,7 +1720,7 @@ public class TablesPanel extends javax.swing.JPanel {
|
||||||
|
|
||||||
SessionHandler.joinTable(roomId, table.getTableId(), "Human", PlayerType.HUMAN, 1, testDeck, "");
|
SessionHandler.joinTable(roomId, table.getTableId(), "Human", PlayerType.HUMAN, 1, testDeck, "");
|
||||||
SessionHandler.joinTable(roomId, table.getTableId(), "Computer", aiType, 1, testDeck, "");
|
SessionHandler.joinTable(roomId, table.getTableId(), "Computer", aiType, 1, testDeck, "");
|
||||||
for (int i=2 ; i < numSeats ; i++) {
|
for (int i=2 ; i < numPlayers ; i++) {
|
||||||
SessionHandler.joinTable(roomId, table.getTableId(), "Computer" + i, aiType, 1, testDeck, "");
|
SessionHandler.joinTable(roomId, table.getTableId(), "Computer" + i, aiType, 1, testDeck, "");
|
||||||
}
|
}
|
||||||
SessionHandler.startMatch(roomId, table.getTableId());
|
SessionHandler.startMatch(roomId, table.getTableId());
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ public class TournamentPlayerPanel extends javax.swing.JPanel {
|
||||||
private void cbPlayerTypeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbPlayerTypeActionPerformed
|
private void cbPlayerTypeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbPlayerTypeActionPerformed
|
||||||
if (this.cbPlayerType.getSelectedItem() != PlayerType.HUMAN) {
|
if (this.cbPlayerType.getSelectedItem() != PlayerType.HUMAN) {
|
||||||
this.pnlPlayerName.setVisible(true);
|
this.pnlPlayerName.setVisible(true);
|
||||||
this.txtPlayerName.setText(ClientDefaultSettings.computerName + " " + this.lblPlayerNum.getText().charAt(this.lblPlayerNum.getText().length() - 1));
|
this.txtPlayerName.setText(TablePlayerPanel.extractAiPlayerNumberFromLabel(this.lblPlayerNum.getText()));
|
||||||
this.txtPlayerName.setEditable(false);
|
this.txtPlayerName.setEditable(false);
|
||||||
this.txtPlayerName.setEnabled(false);
|
this.txtPlayerName.setEnabled(false);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -273,7 +273,6 @@
|
||||||
<Container class="javax.swing.JSplitPane" name="jSplitPane2">
|
<Container class="javax.swing.JSplitPane" name="jSplitPane2">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="resizeWeight" type="double" value="1.0"/>
|
<Property name="resizeWeight" type="double" value="1.0"/>
|
||||||
<Property name="toolTipText" type="java.lang.String" value=""/>
|
|
||||||
</Properties>
|
</Properties>
|
||||||
|
|
||||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
|
||||||
|
|
|
||||||
|
|
@ -234,12 +234,15 @@ public class TournamentPanel extends javax.swing.JPanel {
|
||||||
if (tournament.getStepStartTime() != null) {
|
if (tournament.getStepStartTime() != null) {
|
||||||
usedTime = Format.getDuration((tournament.getServerTime().getTime() - tournament.getStepStartTime().getTime()) / 1000);
|
usedTime = Format.getDuration((tournament.getServerTime().getTime() - tournament.getStepStartTime().getTime()) / 1000);
|
||||||
}
|
}
|
||||||
txtTournamentState.setText(tournament.getTournamentState() + " (" + usedTime + ") " + tournament.getRunningInfo());
|
txtTournamentState.setText(tournament.getTournamentState() + " (" + usedTime + ")");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
txtTournamentState.setText(tournament.getTournamentState());
|
txtTournamentState.setText(tournament.getTournamentState());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (!tournament.getRunningInfo().isEmpty()) {
|
||||||
|
txtTournamentState.setText(txtTournamentState.getText() + ", " + tournament.getRunningInfo());
|
||||||
|
}
|
||||||
|
|
||||||
if (txtEndTime == null) {
|
if (txtEndTime == null) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -444,7 +447,6 @@ public class TournamentPanel extends javax.swing.JPanel {
|
||||||
);
|
);
|
||||||
|
|
||||||
jSplitPane2.setResizeWeight(1.0);
|
jSplitPane2.setResizeWeight(1.0);
|
||||||
jSplitPane2.setToolTipText("");
|
|
||||||
|
|
||||||
jSplitPane1.setDividerLocation(230);
|
jSplitPane1.setDividerLocation(230);
|
||||||
jSplitPane1.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
|
jSplitPane1.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
package mage.client.util;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public enum CardRenderMode {
|
||||||
|
|
||||||
|
MTGO("MTGO", 0),
|
||||||
|
IMAGE("Image", 1),
|
||||||
|
FORCED_M15("Forced M15", 2),
|
||||||
|
FORCED_RETRO("Forced Retro", 3);
|
||||||
|
|
||||||
|
private final String text;
|
||||||
|
private final int id;
|
||||||
|
|
||||||
|
CardRenderMode(String text, int id) {
|
||||||
|
this.text = text;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getText() {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String[] toList() {
|
||||||
|
List<String> list = new ArrayList<>();
|
||||||
|
for (CardRenderMode mode : CardRenderMode.values()) {
|
||||||
|
list.add(mode.toString());
|
||||||
|
}
|
||||||
|
return list.toArray(new String[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CardRenderMode fromId(int id) {
|
||||||
|
for (CardRenderMode mode : CardRenderMode.values()) {
|
||||||
|
if (mode.getId() == id) {
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return MTGO;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CardRenderMode fromString(String text) {
|
||||||
|
for (CardRenderMode mode : CardRenderMode.values()) {
|
||||||
|
if (mode.text.equals(text)) {
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return MTGO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,6 +6,7 @@ import mage.client.util.gui.GuiDisplayUtil;
|
||||||
import org.mage.card.arcane.CardRenderer;
|
import org.mage.card.arcane.CardRenderer;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
import javax.swing.plaf.FontUIResource;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
@ -108,7 +109,7 @@ public final class GUISizeHelper {
|
||||||
|
|
||||||
// app - frame/window title
|
// app - frame/window title
|
||||||
// nimbus's LaF limited to static title size, so font can't be too big (related code in SynthInternalFrameTitlePane, BasicInternalFrameTitlePane)
|
// nimbus's LaF limited to static title size, so font can't be too big (related code in SynthInternalFrameTitlePane, BasicInternalFrameTitlePane)
|
||||||
UIManager.put("InternalFrame.titleFont", dialogFont.deriveFont(Font.BOLD, Math.min(17, 0.8f * dialogFont.getSize())));
|
UIManager.put("InternalFrame.titleFont", new FontUIResource(dialogFont.deriveFont(Font.BOLD, Math.min(17, 0.8f * dialogFont.getSize()))));
|
||||||
|
|
||||||
// app - tables
|
// app - tables
|
||||||
tableFont = new java.awt.Font("Arial", 0, dialogFontSize);
|
tableFont = new java.awt.Font("Arial", 0, dialogFontSize);
|
||||||
|
|
@ -150,7 +151,11 @@ public final class GUISizeHelper {
|
||||||
cardTooltipLargeImageHeight = 30 * tooltipFontSize;
|
cardTooltipLargeImageHeight = 30 * tooltipFontSize;
|
||||||
cardTooltipLargeTextWidth = Math.max(150, 20 * tooltipFontSize - 50);
|
cardTooltipLargeTextWidth = Math.max(150, 20 * tooltipFontSize - 50);
|
||||||
cardTooltipLargeTextHeight = Math.max(100, 12 * tooltipFontSize - 20);
|
cardTooltipLargeTextHeight = Math.max(100, 12 * tooltipFontSize - 20);
|
||||||
UIManager.put("ToolTip.font", cardTooltipFont);
|
UIManager.put("ToolTip.font", new FontUIResource(cardTooltipFont));
|
||||||
|
|
||||||
|
// app - information boxes (only title, text controls by content)
|
||||||
|
// TODO: doesn't work
|
||||||
|
//UIManager.put("OptionPane.titleFont", new FontUIResource(dialogFont.deriveFont(Font.BOLD, Math.min(17, 1.3f * dialogFont.getSize()))));
|
||||||
|
|
||||||
// game - player panel
|
// game - player panel
|
||||||
playerPanelGuiScale = (float) (PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GUI_PLAYER_PANEL_SIZE, 14) / 14.0);
|
playerPanelGuiScale = (float) (PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GUI_PLAYER_PANEL_SIZE, 14) / 14.0);
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ public class CardViewEDHPowerLevelComparator implements CardViewComparator {
|
||||||
return "EDH: " + getPowerLevel(sample);
|
return "EDH: " + getPowerLevel(sample);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: it's outdated code, must migrate to shared code from AbstractCommander
|
||||||
private int getPowerLevel(CardView card) {
|
private int getPowerLevel(CardView card) {
|
||||||
|
|
||||||
int thisMaxPower = 0;
|
int thisMaxPower = 0;
|
||||||
|
|
@ -322,7 +323,6 @@ public class CardViewEDHPowerLevelComparator implements CardViewComparator {
|
||||||
if (cn.equals("acid rain")
|
if (cn.equals("acid rain")
|
||||||
|| cn.equals("agent of treachery")
|
|| cn.equals("agent of treachery")
|
||||||
|| cn.equals("anafenza, the foremost")
|
|| cn.equals("anafenza, the foremost")
|
||||||
|| cn.equals("ancient tomb")
|
|
||||||
|| cn.equals("animar, soul of element")
|
|| cn.equals("animar, soul of element")
|
||||||
|| cn.equals("animate artifact")
|
|| cn.equals("animate artifact")
|
||||||
|| cn.equals("apocalypse")
|
|| cn.equals("apocalypse")
|
||||||
|
|
@ -352,7 +352,6 @@ public class CardViewEDHPowerLevelComparator implements CardViewComparator {
|
||||||
|| cn.equals("cabal coffers")
|
|| cn.equals("cabal coffers")
|
||||||
|| cn.equals("candelabra of tawnos")
|
|| cn.equals("candelabra of tawnos")
|
||||||
|| cn.equals("captain sisay")
|
|| cn.equals("captain sisay")
|
||||||
|| cn.equals("card view")
|
|
||||||
|| cn.equals("cataclysm")
|
|| cn.equals("cataclysm")
|
||||||
|| cn.equals("catastrophe")
|
|| cn.equals("catastrophe")
|
||||||
|| cn.equals("celestial dawn")
|
|| cn.equals("celestial dawn")
|
||||||
|
|
@ -368,7 +367,6 @@ public class CardViewEDHPowerLevelComparator implements CardViewComparator {
|
||||||
|| cn.equals("contamination")
|
|| cn.equals("contamination")
|
||||||
|| cn.equals("craterhoof behemoth")
|
|| cn.equals("craterhoof behemoth")
|
||||||
|| cn.equals("cryptic gateway")
|
|| cn.equals("cryptic gateway")
|
||||||
|| cn.equals("cyclonic rift")
|
|
||||||
|| cn.equals("deadeye navigator")
|
|| cn.equals("deadeye navigator")
|
||||||
|| cn.equals("death cloud")
|
|| cn.equals("death cloud")
|
||||||
|| cn.equals("decree of annihilation")
|
|| cn.equals("decree of annihilation")
|
||||||
|
|
@ -377,6 +375,7 @@ public class CardViewEDHPowerLevelComparator implements CardViewComparator {
|
||||||
|| cn.equals("demonic consultation")
|
|| cn.equals("demonic consultation")
|
||||||
|| cn.equals("derevi, empyrial tactician")
|
|| cn.equals("derevi, empyrial tactician")
|
||||||
|| cn.equals("devastation")
|
|| cn.equals("devastation")
|
||||||
|
|| cn.equals("dictate of erebos")
|
||||||
|| cn.equals("dig through time")
|
|| cn.equals("dig through time")
|
||||||
|| cn.equals("divine intervention")
|
|| cn.equals("divine intervention")
|
||||||
|| cn.equals("dockside extortionist")
|
|| cn.equals("dockside extortionist")
|
||||||
|
|
@ -385,34 +384,35 @@ public class CardViewEDHPowerLevelComparator implements CardViewComparator {
|
||||||
|| cn.equals("drannith magistrate")
|
|| cn.equals("drannith magistrate")
|
||||||
|| cn.equals("dross scorpion")
|
|| cn.equals("dross scorpion")
|
||||||
|| cn.equals("earthcraft")
|
|| cn.equals("earthcraft")
|
||||||
|
|| cn.equals("edgar markov")
|
||||||
|| cn.equals("edric, spymaster of trest")
|
|| cn.equals("edric, spymaster of trest")
|
||||||
|| cn.equals("elesh norn, grand cenobite")
|
|| cn.equals("elesh norn, grand cenobite")
|
||||||
|
|| cn.equals("elesh norn, mother of machines")
|
||||||
|| cn.equals("embargo")
|
|| cn.equals("embargo")
|
||||||
|| cn.equals("emrakul, the promised end")
|
|| cn.equals("emrakul, the promised end")
|
||||||
|| cn.equals("enter the infinite")
|
|| cn.equals("enter the infinite")
|
||||||
|| cn.equals("entomb")
|
|| cn.equals("entomb")
|
||||||
|| cn.equals("epicenter")
|
|| cn.equals("epicenter")
|
||||||
|| cn.equals("erratic portal")
|
|| cn.equals("erratic portal")
|
||||||
|| cn.equals("expropriate")
|
|
||||||
|| cn.equals("exquisite blood")
|
|| cn.equals("exquisite blood")
|
||||||
|| cn.equals("fall of the thran")
|
|| cn.equals("fall of the thran")
|
||||||
|| cn.equals("fierce guardianship")
|
|| cn.equals("farewell")
|
||||||
|
|| cn.equals("flashfires")
|
||||||
|| cn.equals("food chain")
|
|| cn.equals("food chain")
|
||||||
|| cn.equals("force of negation")
|
|| cn.equals("force of negation")
|
||||||
|| cn.equals("force of will")
|
|
||||||
|| cn.equals("future sight")
|
|| cn.equals("future sight")
|
||||||
|| cn.equals("gaddock teeg")
|
|| cn.equals("gaddock teeg")
|
||||||
|| cn.equals("gaea's cradle")
|
|
||||||
|| cn.equals("genesis chamber")
|
|| cn.equals("genesis chamber")
|
||||||
|| cn.equals("ghave, guru of spores")
|
|| cn.equals("ghave, guru of spores")
|
||||||
|| cn.equals("gilded drake")
|
|| cn.equals("gilded drake")
|
||||||
|| cn.equals("glenn, the voice of calm")
|
|| cn.equals("glenn, the voice of calm")
|
||||||
|| cn.equals("global ruin")
|
|| cn.equals("global ruin")
|
||||||
|| cn.equals("golos, tireless pilgrim")
|
|| cn.equals("golos, tireless pilgrim")
|
||||||
|| cn.equals("grand arbiter augustin iv")
|
|
||||||
|| cn.equals("grave pact")
|
|| cn.equals("grave pact")
|
||||||
|| cn.equals("grave titan")
|
|| cn.equals("grave titan")
|
||||||
|| cn.equals("great whale")
|
|| cn.equals("great whale")
|
||||||
|
|| cn.equals("gregor, shrewd magistrate")
|
||||||
|
|| cn.equals("greymond, avacyn's stalwart")
|
||||||
|| cn.equals("grim monolith")
|
|| cn.equals("grim monolith")
|
||||||
|| cn.equals("grip of chaos")
|
|| cn.equals("grip of chaos")
|
||||||
|| cn.equals("gush")
|
|| cn.equals("gush")
|
||||||
|
|
@ -421,21 +421,23 @@ public class CardViewEDHPowerLevelComparator implements CardViewComparator {
|
||||||
|| cn.equals("hokori, dust drinker")
|
|| cn.equals("hokori, dust drinker")
|
||||||
|| cn.equals("humility")
|
|| cn.equals("humility")
|
||||||
|| cn.equals("impending disaster")
|
|| cn.equals("impending disaster")
|
||||||
|| cn.equals("imperial seal")
|
|
||||||
|| cn.equals("intruder alarm")
|
|| cn.equals("intruder alarm")
|
||||||
|| cn.equals("invoke prejudice")
|
|| cn.equals("invoke prejudice")
|
||||||
|| cn.equals("iona, shield of emeria")
|
|| cn.equals("iona, shield of emeria")
|
||||||
|| cn.equals("jin-gitaxias, core augur")
|
|| cn.equals("jeweled lotus")
|
||||||
|
|| cn.equals("jin-gitaxias, progress tyrant")
|
||||||
|| cn.equals("jokulhaups")
|
|| cn.equals("jokulhaups")
|
||||||
|| cn.equals("kaalia of the vast")
|
|| cn.equals("kaalia of the vast")
|
||||||
|| cn.equals("karador, ghost chieftain")
|
|| cn.equals("karador, ghost chieftain")
|
||||||
|| cn.equals("karakas")
|
|| cn.equals("karakas")
|
||||||
|| cn.equals("karn, silver golem")
|
|| cn.equals("karn, silver golem")
|
||||||
|
|| cn.equals("karn, the great creator")
|
||||||
|| cn.equals("kataki, war's wage")
|
|| cn.equals("kataki, war's wage")
|
||||||
|| cn.equals("keldon firebombers")
|
|| cn.equals("keldon firebombers")
|
||||||
|| cn.equals("kiki-jiki, mirror breaker")
|
|| cn.equals("kiki-jiki, mirror breaker")
|
||||||
|| cn.equals("kinnan, bonder prodigy")
|
|
||||||
|| cn.equals("knowledge pool")
|
|| cn.equals("knowledge pool")
|
||||||
|
|| cn.equals("koma, cosmos serpent")
|
||||||
|
|| cn.equals("korvold, fae-cursed king")
|
||||||
|| cn.equals("kozilek, butcher of truth")
|
|| cn.equals("kozilek, butcher of truth")
|
||||||
|| cn.equals("krark-clan ironworks")
|
|| cn.equals("krark-clan ironworks")
|
||||||
|| cn.equals("krenko, mob boss")
|
|| cn.equals("krenko, mob boss")
|
||||||
|
|
@ -452,10 +454,10 @@ public class CardViewEDHPowerLevelComparator implements CardViewComparator {
|
||||||
|| cn.equals("maelstrom wanderer")
|
|| cn.equals("maelstrom wanderer")
|
||||||
|| cn.equals("magister sphinx")
|
|| cn.equals("magister sphinx")
|
||||||
|| cn.equals("malfegor")
|
|| cn.equals("malfegor")
|
||||||
|
|| cn.equals("malik, grim manipulator")
|
||||||
|| cn.equals("mana breach")
|
|| cn.equals("mana breach")
|
||||||
|| cn.equals("mana crypt")
|
|| cn.equals("mana crypt")
|
||||||
|| cn.equals("mana drain")
|
|| cn.equals("mana drain")
|
||||||
|| cn.equals("mana vault")
|
|
||||||
|| cn.equals("mana vortex")
|
|| cn.equals("mana vortex")
|
||||||
|| cn.equals("master of cruelties")
|
|| cn.equals("master of cruelties")
|
||||||
|| cn.equals("memnarch")
|
|| cn.equals("memnarch")
|
||||||
|
|
@ -468,6 +470,7 @@ public class CardViewEDHPowerLevelComparator implements CardViewComparator {
|
||||||
|| cn.equals("minion reflector")
|
|| cn.equals("minion reflector")
|
||||||
|| cn.equals("mycosynth lattice")
|
|| cn.equals("mycosynth lattice")
|
||||||
|| cn.equals("myr turbine")
|
|| cn.equals("myr turbine")
|
||||||
|
|| cn.equals("nadu, winged wisdom")
|
||||||
|| cn.equals("narset, enlightened master")
|
|| cn.equals("narset, enlightened master")
|
||||||
|| cn.equals("narset, parter of veils")
|
|| cn.equals("narset, parter of veils")
|
||||||
|| cn.equals("nath of the gilt-leaf")
|
|| cn.equals("nath of the gilt-leaf")
|
||||||
|
|
@ -487,8 +490,8 @@ public class CardViewEDHPowerLevelComparator implements CardViewComparator {
|
||||||
|| cn.equals("oloro, ageless ascetic")
|
|| cn.equals("oloro, ageless ascetic")
|
||||||
|| cn.equals("omniscience")
|
|| cn.equals("omniscience")
|
||||||
|| cn.equals("opalescence")
|
|| cn.equals("opalescence")
|
||||||
|| cn.equals("opposition agent")
|
|
||||||
|| cn.equals("oppression")
|
|| cn.equals("oppression")
|
||||||
|
|| cn.equals("orcish bowmasters")
|
||||||
|| cn.equals("ornithopter")
|
|| cn.equals("ornithopter")
|
||||||
|| cn.equals("overwhelming splendor")
|
|| cn.equals("overwhelming splendor")
|
||||||
|| cn.equals("palinchron")
|
|| cn.equals("palinchron")
|
||||||
|
|
@ -504,7 +507,6 @@ public class CardViewEDHPowerLevelComparator implements CardViewComparator {
|
||||||
|| cn.equals("purphoros, god of the forge")
|
|| cn.equals("purphoros, god of the forge")
|
||||||
|| cn.equals("ravages of war")
|
|| cn.equals("ravages of war")
|
||||||
|| cn.equals("reclamation sage")
|
|| cn.equals("reclamation sage")
|
||||||
|| cn.equals("rhystic study")
|
|
||||||
|| cn.equals("rick, steadfast leader")
|
|| cn.equals("rick, steadfast leader")
|
||||||
|| cn.equals("rings of brighthearth")
|
|| cn.equals("rings of brighthearth")
|
||||||
|| cn.equals("rising waters")
|
|| cn.equals("rising waters")
|
||||||
|
|
@ -515,12 +517,11 @@ public class CardViewEDHPowerLevelComparator implements CardViewComparator {
|
||||||
|| cn.equals("seedborn muse")
|
|| cn.equals("seedborn muse")
|
||||||
|| cn.equals("sen triplets")
|
|| cn.equals("sen triplets")
|
||||||
|| cn.equals("sensei's divining top")
|
|| cn.equals("sensei's divining top")
|
||||||
|| cn.equals("serra's sanctum")
|
|| cn.equals("sheoldred, the apocalypse")
|
||||||
|| cn.equals("sheoldred, whispering one")
|
|| cn.equals("sheoldred, whispering one")
|
||||||
|| cn.equals("sire of insanity")
|
|| cn.equals("sire of insanity")
|
||||||
|| cn.equals("skithiryx, the blight dragon")
|
|| cn.equals("skithiryx, the blight dragon")
|
||||||
|| cn.equals("smokestack")
|
|| cn.equals("smokestack")
|
||||||
|| cn.equals("smothering tithe")
|
|
||||||
|| cn.equals("sol ring")
|
|| cn.equals("sol ring")
|
||||||
|| cn.equals("sorin markov")
|
|| cn.equals("sorin markov")
|
||||||
|| cn.equals("splinter twin")
|
|| cn.equals("splinter twin")
|
||||||
|
|
@ -532,8 +533,6 @@ public class CardViewEDHPowerLevelComparator implements CardViewComparator {
|
||||||
|| cn.equals("storm cauldron")
|
|| cn.equals("storm cauldron")
|
||||||
|| cn.equals("strip mine")
|
|| cn.equals("strip mine")
|
||||||
|| cn.equals("sunder")
|
|| cn.equals("sunder")
|
||||||
|| cn.equals("survival of the fittest")
|
|
||||||
|| cn.equals("table view")
|
|
||||||
|| cn.equals("tainted aether")
|
|| cn.equals("tainted aether")
|
||||||
|| cn.equals("tangle wire")
|
|| cn.equals("tangle wire")
|
||||||
|| cn.equals("tectonic break")
|
|| cn.equals("tectonic break")
|
||||||
|
|
@ -543,21 +542,19 @@ public class CardViewEDHPowerLevelComparator implements CardViewComparator {
|
||||||
|| cn.equals("teferi, master of time")
|
|| cn.equals("teferi, master of time")
|
||||||
|| cn.equals("teferi, time raveler")
|
|| cn.equals("teferi, time raveler")
|
||||||
|| cn.equals("temporal manipulation")
|
|| cn.equals("temporal manipulation")
|
||||||
|| cn.equals("tergrid, god of fright")
|
|
||||||
|| cn.equals("text view")
|
|
||||||
|| cn.equals("tezzeret the seeker")
|
|| cn.equals("tezzeret the seeker")
|
||||||
|| cn.equals("thassa's oracle")
|
|
||||||
|| cn.equals("the chain veil")
|
|| cn.equals("the chain veil")
|
||||||
|| cn.equals("the tabernacle at pendrell vale")
|
|
||||||
|| cn.equals("thieves' auction")
|
|| cn.equals("thieves' auction")
|
||||||
|| cn.equals("thoughts of ruin")
|
|| cn.equals("thoughts of ruin")
|
||||||
|| cn.equals("thrasios, triton hero")
|
|| cn.equals("thrasios, triton hero")
|
||||||
|
|| cn.equals("time sieve")
|
||||||
|| cn.equals("time stretch")
|
|| cn.equals("time stretch")
|
||||||
|| cn.equals("time warp")
|
|| cn.equals("time warp")
|
||||||
|| cn.equals("tinker")
|
|| cn.equals("tinker")
|
||||||
|| cn.equals("tooth and nail")
|
|| cn.equals("tooth and nail")
|
||||||
|| cn.equals("torment of hailfire")
|
|| cn.equals("torment of hailfire")
|
||||||
|| cn.equals("torpor orb")
|
|| cn.equals("torpor orb")
|
||||||
|
|| cn.equals("toxrill, the corrosive")
|
||||||
|| cn.equals("training grounds")
|
|| cn.equals("training grounds")
|
||||||
|| cn.equals("treasure cruise")
|
|| cn.equals("treasure cruise")
|
||||||
|| cn.equals("triskelavus")
|
|| cn.equals("triskelavus")
|
||||||
|
|
@ -566,18 +563,20 @@ public class CardViewEDHPowerLevelComparator implements CardViewComparator {
|
||||||
|| cn.equals("turnabout")
|
|| cn.equals("turnabout")
|
||||||
|| cn.equals("ugin, the spirit dragon")
|
|| cn.equals("ugin, the spirit dragon")
|
||||||
|| cn.equals("ulamog, the ceaseless hunger")
|
|| cn.equals("ulamog, the ceaseless hunger")
|
||||||
|
|| cn.equals("ulamog, the defiler")
|
||||||
|| cn.equals("ulamog, the infinite gyre")
|
|| cn.equals("ulamog, the infinite gyre")
|
||||||
|| cn.equals("umbral mantle")
|
|| cn.equals("umbral mantle")
|
||||||
|| cn.equals("urabrask the hidden")
|
|| cn.equals("urabrask the hidden")
|
||||||
|| cn.equals("urza, lord high artificer")
|
|
||||||
|| cn.equals("uyo, silent prophet")
|
|| cn.equals("uyo, silent prophet")
|
||||||
|| cn.equals("void winnower")
|
|| cn.equals("void winnower")
|
||||||
|| cn.equals("voltaic key")
|
|| cn.equals("voltaic key")
|
||||||
|| cn.equals("vorinclex, voice of hunger")
|
|| cn.equals("vorinclex, monstrous raider")
|
||||||
|| cn.equals("wake of destruction")
|
|| cn.equals("wake of destruction")
|
||||||
|| cn.equals("warp world")
|
|| cn.equals("warp world")
|
||||||
|
|| cn.equals("winter moon")
|
||||||
|| cn.equals("winter orb")
|
|| cn.equals("winter orb")
|
||||||
|| cn.equals("workhorse")
|
|| cn.equals("workhorse")
|
||||||
|
|| cn.equals("worldfire")
|
||||||
|| cn.equals("worldgorger dragon")
|
|| cn.equals("worldgorger dragon")
|
||||||
|| cn.equals("worthy cause")
|
|| cn.equals("worthy cause")
|
||||||
|| cn.equals("xanathar, guild kingpin")
|
|| cn.equals("xanathar, guild kingpin")
|
||||||
|
|
@ -586,6 +585,111 @@ public class CardViewEDHPowerLevelComparator implements CardViewComparator {
|
||||||
|| cn.equals("zur the enchanter")) {
|
|| cn.equals("zur the enchanter")) {
|
||||||
thisMaxPower = Math.max(thisMaxPower, 12);
|
thisMaxPower = Math.max(thisMaxPower, 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parts of infinite combos
|
||||||
|
if (cn.equals("animate artifact") || cn.equals("animar, soul of element")
|
||||||
|
|| cn.equals("archaeomancer")
|
||||||
|
|| cn.equals("ashnod's altar") || cn.equals("azami, lady of scrolls")
|
||||||
|
|| cn.equals("aura flux")
|
||||||
|
|| cn.equals("basalt monolith") || cn.equals("brago, king eternal")
|
||||||
|
|| cn.equals("candelabra of tawnos") || cn.equals("cephalid aristocrat")
|
||||||
|
|| cn.equals("cephalid illusionist") || cn.equals("changeling berserker")
|
||||||
|
|| cn.equals("consecrated sphinx")
|
||||||
|
|| cn.equals("cyclonic rift")
|
||||||
|
|| cn.equals("the chain veil")
|
||||||
|
|| cn.equals("cinderhaze wretch") || cn.equals("cryptic gateway")
|
||||||
|
|| cn.equals("deadeye navigator") || cn.equals("derevi, empyrial tactician")
|
||||||
|
|| cn.equals("doubling season") || cn.equals("dross scorpion")
|
||||||
|
|| cn.equals("earthcraft") || cn.equals("erratic portal")
|
||||||
|
|| cn.equals("enter the infinite") || cn.equals("omniscience")
|
||||||
|
|| cn.equals("exquisite blood") || cn.equals("future sight")
|
||||||
|
|| cn.equals("genesis chamber")
|
||||||
|
|| cn.equals("ghave, guru of spores")
|
||||||
|
|| cn.equals("grave pact")
|
||||||
|
|| cn.equals("grave titan") || cn.equals("great whale")
|
||||||
|
|| cn.equals("grim monolith") || cn.equals("gush")
|
||||||
|
|| cn.equals("hellkite charger") || cn.equals("intruder alarm")
|
||||||
|
|| cn.equals("helm of obedience")
|
||||||
|
|| cn.equals("hermit druid")
|
||||||
|
|| cn.equals("humility")
|
||||||
|
|| cn.equals("iona, shield of emeria")
|
||||||
|
|| cn.equals("karn, silver golem") || cn.equals("kiki-jiki, mirror breaker")
|
||||||
|
|| cn.equals("krark-clan ironworks") || cn.equals("krenko, mob boss")
|
||||||
|
|| cn.equals("krosan restorer") || cn.equals("laboratory maniac")
|
||||||
|
|| cn.equals("leonin relic-warder") || cn.equals("leyline of the void")
|
||||||
|
|| cn.equals("memnarch")
|
||||||
|
|| cn.equals("meren of clan nel toth") || cn.equals("mikaeus, the unhallowed")
|
||||||
|
|| cn.equals("mindcrank") || cn.equals("mindslaver")
|
||||||
|
|| cn.equals("minion reflector") || cn.equals("mycosynth lattice")
|
||||||
|
|| cn.equals("myr turbine") || cn.equals("narset, enlightened master")
|
||||||
|
|| cn.equals("nekusar, the mindrazer") || cn.equals("norin the wary")
|
||||||
|
|| cn.equals("notion thief")
|
||||||
|
|| cn.equals("opalescence") || cn.equals("ornithopter")
|
||||||
|
|| cn.equals("paradox engine")
|
||||||
|
|| cn.equals("purphoros, god of the forge")
|
||||||
|
|| cn.equals("peregrine drake") || cn.equals("palinchron")
|
||||||
|
|| cn.equals("planar portal") || cn.equals("power artifact")
|
||||||
|
|| cn.equals("rings of brighthearth") || cn.equals("rite of replication")
|
||||||
|
|| cn.equals("sanguine bond") || cn.equals("sensei's divining top")
|
||||||
|
|| cn.equals("splinter twin") || cn.equals("stony silence")
|
||||||
|
|| cn.equals("sunder")
|
||||||
|
|| cn.equals("storm cauldron") || cn.equals("teferi's puzzle box")
|
||||||
|
|| cn.equals("tangle wire")
|
||||||
|
|| cn.equals("teferi, mage of zhalfir")
|
||||||
|
|| cn.equals("tezzeret the seeker") || cn.equals("time stretch")
|
||||||
|
|| cn.equals("time warp") || cn.equals("training grounds")
|
||||||
|
|| cn.equals("triskelavus") || cn.equals("triskelion")
|
||||||
|
|| cn.equals("turnabout") || cn.equals("umbral mantle")
|
||||||
|
|| cn.equals("uyo, silent prophet") || cn.equals("voltaic key")
|
||||||
|
|| cn.equals("workhorse") || cn.equals("worldgorger dragon")
|
||||||
|
|| cn.equals("worthy cause") || cn.equals("yawgmoth's will")
|
||||||
|
|| cn.equals("zealous conscripts")) {
|
||||||
|
thisMaxPower = Math.max(thisMaxPower, 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Game changers
|
||||||
|
if (cn.equals("ad nauseam")
|
||||||
|
|| cn.equals("ancient tomb")
|
||||||
|
|| cn.equals("bolas's citadel")
|
||||||
|
|| cn.equals("chrome mox")
|
||||||
|
|| cn.equals("cyclonic rift")
|
||||||
|
|| cn.equals("demonic tutor")
|
||||||
|
|| cn.equals("drannith magistrate")
|
||||||
|
|| cn.equals("enlightened tutor")
|
||||||
|
|| cn.equals("expropriate")
|
||||||
|
|| cn.equals("fierce guardianship")
|
||||||
|
|| cn.equals("force of will")
|
||||||
|
|| cn.equals("gaea's cradle")
|
||||||
|
|| cn.equals("glacial chasm")
|
||||||
|
|| cn.equals("grand arbiter augustin iv")
|
||||||
|
|| cn.equals("grim monolith")
|
||||||
|
|| cn.equals("imperial seal")
|
||||||
|
|| cn.equals("jeska's will")
|
||||||
|
|| cn.equals("jin-gitaxias, core augur")
|
||||||
|
|| cn.equals("kinnan, bonder prodigy")
|
||||||
|
|| cn.equals("lion's eye diamond")
|
||||||
|
|| cn.equals("mana vault")
|
||||||
|
|| cn.equals("mox diamond")
|
||||||
|
|| cn.equals("mystical tutor")
|
||||||
|
|| cn.equals("opposition agent")
|
||||||
|
|| cn.equals("rhystic study")
|
||||||
|
|| cn.equals("serra's sanctum")
|
||||||
|
|| cn.equals("smothering tithe")
|
||||||
|
|| cn.equals("survival of the fittest")
|
||||||
|
|| cn.equals("tergrid, god of fright")
|
||||||
|
|| cn.equals("thassa's oracle")
|
||||||
|
|| cn.equals("the one ring")
|
||||||
|
|| cn.equals("the tabernacle at pendrell vale")
|
||||||
|
|| cn.equals("trinisphere")
|
||||||
|
|| cn.equals("trouble in pairs")
|
||||||
|
|| cn.equals("underworld breach")
|
||||||
|
|| cn.equals("urza, lord high artificer")
|
||||||
|
|| cn.equals("vampiric tutor")
|
||||||
|
|| cn.equals("vorinclex, voice of hunger")
|
||||||
|
|| cn.equals("winota, joiner of forces")
|
||||||
|
|| cn.equals("yuriko, the tiger's shadow")) {
|
||||||
|
thisMaxPower = Math.max(thisMaxPower, 20);
|
||||||
|
}
|
||||||
return thisMaxPower;
|
return thisMaxPower;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -474,7 +474,7 @@ public final class GuiDisplayUtil {
|
||||||
public static void refreshThemeSettings() {
|
public static void refreshThemeSettings() {
|
||||||
// apply Nimbus's look and fill
|
// apply Nimbus's look and fill
|
||||||
// possible settings:
|
// possible settings:
|
||||||
// https://docs.oracle.com/en%2Fjava%2Fjavase%2F17%2Fdocs%2Fapi%2F%2F/java.desktop/javax/swing/plaf/nimbus/doc-files/properties.html
|
// https://docs.oracle.com/en/java/javase/23/docs/api/java.desktop/javax/swing/plaf/nimbus/doc-files/properties.html
|
||||||
|
|
||||||
// enable nimbus
|
// enable nimbus
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ public class CardPanelRenderModeMTGO extends CardPanel {
|
||||||
private CardRenderer cardRenderer;
|
private CardRenderer cardRenderer;
|
||||||
|
|
||||||
private int updateArtImageStamp;
|
private int updateArtImageStamp;
|
||||||
|
private final int cardRenderMode;
|
||||||
|
|
||||||
private static class ImageKey {
|
private static class ImageKey {
|
||||||
final BufferedImage artImage;
|
final BufferedImage artImage;
|
||||||
|
|
@ -84,7 +85,7 @@ public class CardPanelRenderModeMTGO extends CardPanel {
|
||||||
sb.append((char) (this.view.isCanAttack() ? 1 : 0));
|
sb.append((char) (this.view.isCanAttack() ? 1 : 0));
|
||||||
sb.append((char) (this.view.isCanBlock() ? 1 : 0));
|
sb.append((char) (this.view.isCanBlock() ? 1 : 0));
|
||||||
sb.append((char) (this.view.isFaceDown() ? 1 : 0));
|
sb.append((char) (this.view.isFaceDown() ? 1 : 0));
|
||||||
sb.append((char) this.view.getFrameStyle().ordinal());
|
sb.append((char) (this.view.getFrameStyle() != null ? this.view.getFrameStyle().ordinal() : -1));
|
||||||
if (this.view instanceof PermanentView) {
|
if (this.view instanceof PermanentView) {
|
||||||
sb.append((char) (((PermanentView) this.view).hasSummoningSickness() ? 1 : 0));
|
sb.append((char) (((PermanentView) this.view).hasSummoningSickness() ? 1 : 0));
|
||||||
sb.append((char) (((PermanentView) this.view).getDamage()));
|
sb.append((char) (((PermanentView) this.view).getDamage()));
|
||||||
|
|
@ -143,12 +144,13 @@ public class CardPanelRenderModeMTGO extends CardPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
public CardPanelRenderModeMTGO(CardView newGameCard, UUID gameId, final boolean loadImage, ActionCallback callback,
|
public CardPanelRenderModeMTGO(CardView newGameCard, UUID gameId, final boolean loadImage, ActionCallback callback,
|
||||||
final boolean foil, Dimension dimension, boolean needFullPermanentRender) {
|
final boolean foil, Dimension dimension, boolean needFullPermanentRender, int renderMode) {
|
||||||
// Call to super
|
// Call to super
|
||||||
super(newGameCard, gameId, loadImage, callback, foil, dimension, needFullPermanentRender);
|
super(newGameCard, gameId, loadImage, callback, foil, dimension, needFullPermanentRender);
|
||||||
|
|
||||||
// Renderer
|
// Renderer
|
||||||
cardRenderer = cardRendererFactory.create(getGameCard());
|
cardRenderMode = renderMode;
|
||||||
|
cardRenderer = cardRendererFactory.create(getGameCard(), cardRenderMode);
|
||||||
|
|
||||||
// Draw the parts
|
// Draw the parts
|
||||||
initialDraw();
|
initialDraw();
|
||||||
|
|
@ -265,7 +267,7 @@ public class CardPanelRenderModeMTGO extends CardPanel {
|
||||||
|
|
||||||
// Update renderer
|
// Update renderer
|
||||||
cardImage = null;
|
cardImage = null;
|
||||||
cardRenderer = cardRendererFactory.create(getGameCard());
|
cardRenderer = cardRendererFactory.create(getGameCard(), cardRenderMode);
|
||||||
cardRenderer.setArtImage(artImage);
|
cardRenderer.setArtImage(artImage);
|
||||||
|
|
||||||
// Repaint
|
// Repaint
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
package org.mage.card.arcane;
|
package org.mage.card.arcane;
|
||||||
|
|
||||||
|
import mage.cards.FrameStyle;
|
||||||
|
import mage.client.dialog.PreferencesDialog;
|
||||||
|
import mage.client.util.CardRenderMode;
|
||||||
import mage.view.CardView;
|
import mage.view.CardView;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -11,10 +14,27 @@ public class CardRendererFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
public CardRenderer create(CardView card) {
|
public CardRenderer create(CardView card) {
|
||||||
|
return create(card, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CardRenderer create(CardView card, int renderModeOverride) {
|
||||||
if (card.isSplitCard()) {
|
if (card.isSplitCard()) {
|
||||||
return new ModernSplitCardRenderer(card);
|
return new ModernSplitCardRenderer(card);
|
||||||
|
} else if (shouldRenderRetro(card, renderModeOverride)) {
|
||||||
|
// TODO: implement split card renderer for retro cards
|
||||||
|
return new RetroCardRenderer(card);
|
||||||
} else {
|
} else {
|
||||||
return new ModernCardRenderer(card);
|
return new ModernCardRenderer(card);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean shouldRenderRetro(CardView card, int renderModeOverride) {
|
||||||
|
int renderMode = PreferencesDialog.getRenderMode();
|
||||||
|
if (renderModeOverride != -1) {
|
||||||
|
renderMode = renderModeOverride;
|
||||||
|
}
|
||||||
|
boolean renderMTGO = (card.getFrameStyle().equals(FrameStyle.RETRO) || card.getFrameStyle().equals(FrameStyle.LEA_ORIGINAL_DUAL_LAND_ART_BASIC)) && renderMode == CardRenderMode.MTGO.ordinal();
|
||||||
|
boolean forcedRetro = renderMode == CardRenderMode.FORCED_RETRO.ordinal();
|
||||||
|
return renderMTGO || forcedRetro;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -123,6 +123,7 @@ public class ModernCardRenderer extends CardRenderer {
|
||||||
public static final Color ERROR_COLOR = new Color(255, 0, 255);
|
public static final Color ERROR_COLOR = new Color(255, 0, 255);
|
||||||
|
|
||||||
static String SUB_TYPE_ADVENTURE = "Adventure";
|
static String SUB_TYPE_ADVENTURE = "Adventure";
|
||||||
|
static String SUB_TYPE_OMEN = "Omen";
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Layout metrics for modern border cards
|
// Layout metrics for modern border cards
|
||||||
|
|
@ -168,8 +169,8 @@ public class ModernCardRenderer extends CardRenderer {
|
||||||
// Processed mana cost string
|
// Processed mana cost string
|
||||||
protected String manaCostString;
|
protected String manaCostString;
|
||||||
|
|
||||||
// Is an adventure
|
// Is an adventure or omen
|
||||||
protected boolean isAdventure = false;
|
protected boolean isCardWithSpellOption = false;
|
||||||
|
|
||||||
public ModernCardRenderer(CardView card) {
|
public ModernCardRenderer(CardView card) {
|
||||||
// Pass off to parent
|
// Pass off to parent
|
||||||
|
|
@ -179,12 +180,13 @@ public class ModernCardRenderer extends CardRenderer {
|
||||||
manaCostString = ManaSymbols.getClearManaCost(cardView.getManaCostStr());
|
manaCostString = ManaSymbols.getClearManaCost(cardView.getManaCostStr());
|
||||||
|
|
||||||
if (cardView.isSplitCard()) {
|
if (cardView.isSplitCard()) {
|
||||||
isAdventure = cardView.getRightSplitTypeLine().contains(SUB_TYPE_ADVENTURE);
|
isCardWithSpellOption = cardView.getRightSplitTypeLine().contains(SUB_TYPE_ADVENTURE)
|
||||||
|
|| cardView.getRightSplitTypeLine().contains(SUB_TYPE_OMEN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isAdventure() {
|
protected boolean isCardWithSpellOption() {
|
||||||
return isAdventure;
|
return isCardWithSpellOption;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -316,7 +318,8 @@ public class ModernCardRenderer extends CardRenderer {
|
||||||
} else if (isUnstableFullArtLand()) {
|
} else if (isUnstableFullArtLand()) {
|
||||||
rect = new Rectangle2D.Float(.0f, .0f, 1.0f, 1.0f);
|
rect = new Rectangle2D.Float(.0f, .0f, 1.0f, 1.0f);
|
||||||
} else if (cardView.getArtRect() == ArtRect.FULL_LENGTH_LEFT ||
|
} else if (cardView.getArtRect() == ArtRect.FULL_LENGTH_LEFT ||
|
||||||
cardView.getArtRect() == ArtRect.FULL_LENGTH_RIGHT) {
|
cardView.getArtRect() == ArtRect.FULL_LENGTH_RIGHT ||
|
||||||
|
cardView.getArtRect() == ArtRect.RETRO) {
|
||||||
rect = cardView.getArtRect().rect;
|
rect = cardView.getArtRect().rect;
|
||||||
} else if (cardView.getFrameStyle().isFullArt() || (cardView.isToken())) {
|
} else if (cardView.getFrameStyle().isFullArt() || (cardView.isToken())) {
|
||||||
rect = new Rectangle2D.Float(.079f, .11f, .84f, .63f);
|
rect = new Rectangle2D.Float(.079f, .11f, .84f, .63f);
|
||||||
|
|
@ -660,7 +663,7 @@ public class ModernCardRenderer extends CardRenderer {
|
||||||
drawRulesText(g, textboxKeywords, textboxRules,
|
drawRulesText(g, textboxKeywords, textboxRules,
|
||||||
contentWidth / 2 + totalContentInset + 4, totalContentInset + boxHeight + 2,
|
contentWidth / 2 + totalContentInset + 4, totalContentInset + boxHeight + 2,
|
||||||
contentWidth / 2 - 8, typeLineY - totalContentInset - boxHeight - 6, false);
|
contentWidth / 2 - 8, typeLineY - totalContentInset - boxHeight - 6, false);
|
||||||
} else if (isAdventure) {
|
} else if (isCardWithSpellOption) {
|
||||||
drawRulesText(g, textboxKeywords, textboxRules,
|
drawRulesText(g, textboxKeywords, textboxRules,
|
||||||
contentWidth / 2 + totalContentInset + 4, typeLineY + boxHeight + 2,
|
contentWidth / 2 + totalContentInset + 4, typeLineY + boxHeight + 2,
|
||||||
contentWidth / 2 - 8, cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3, false);
|
contentWidth / 2 - 8, cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3, false);
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
|
||||||
private boolean isAftermath = false;
|
private boolean isAftermath = false;
|
||||||
|
|
||||||
private static String trimAdventure(String rule) {
|
private static String trimAdventure(String rule) {
|
||||||
if (rule.startsWith("Adventure")) {
|
if (rule.startsWith("Adventure") || rule.startsWith("Omen")) {
|
||||||
return rule.substring(rule.lastIndexOf("—") + 8);
|
return rule.substring(rule.lastIndexOf("—") + 8);
|
||||||
}
|
}
|
||||||
return rule;
|
return rule;
|
||||||
|
|
@ -71,7 +71,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
|
||||||
rightHalf.color = new ObjectColor(cardView.getRightSplitCostsStr());
|
rightHalf.color = new ObjectColor(cardView.getRightSplitCostsStr());
|
||||||
leftHalf.color = new ObjectColor(cardView.getLeftSplitCostsStr());
|
leftHalf.color = new ObjectColor(cardView.getLeftSplitCostsStr());
|
||||||
|
|
||||||
if (isAdventure()) {
|
if (isCardWithSpellOption()) {
|
||||||
List<String> trimmedRules = new ArrayList<>();
|
List<String> trimmedRules = new ArrayList<>();
|
||||||
for (String rule : view.getRightSplitRules()) {
|
for (String rule : view.getRightSplitRules()) {
|
||||||
trimmedRules.add(trimAdventure(rule));
|
trimmedRules.add(trimAdventure(rule));
|
||||||
|
|
@ -95,7 +95,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
|
||||||
// they "rotate" in opposite directions making consquence and normal split cards
|
// they "rotate" in opposite directions making consquence and normal split cards
|
||||||
// have the "right" vs "left" as the top half.
|
// have the "right" vs "left" as the top half.
|
||||||
// Adventures are treated differently and not rotated at all.
|
// Adventures are treated differently and not rotated at all.
|
||||||
if (isAdventure()) {
|
if (isCardWithSpellOption()) {
|
||||||
manaCostString = leftHalf.manaCostString;
|
manaCostString = leftHalf.manaCostString;
|
||||||
textboxKeywords = leftHalf.keywords;
|
textboxKeywords = leftHalf.keywords;
|
||||||
textboxRules = leftHalf.rules;
|
textboxRules = leftHalf.rules;
|
||||||
|
|
@ -159,7 +159,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
|
||||||
protected void drawBackground(Graphics2D g) {
|
protected void drawBackground(Graphics2D g) {
|
||||||
if (cardView.isFaceDown()) {
|
if (cardView.isFaceDown()) {
|
||||||
drawCardBackTexture(g);
|
drawCardBackTexture(g);
|
||||||
} if (isAdventure()) {
|
} if (isCardWithSpellOption()) {
|
||||||
super.drawBackground(g);
|
super.drawBackground(g);
|
||||||
} else {
|
} else {
|
||||||
{ // Left half background (top of the card)
|
{ // Left half background (top of the card)
|
||||||
|
|
@ -204,7 +204,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void drawArt(Graphics2D g) {
|
protected void drawArt(Graphics2D g) {
|
||||||
if (isAdventure) {
|
if (isCardWithSpellOption) {
|
||||||
super.drawArt(g);
|
super.drawArt(g);
|
||||||
} else if (artImage != null) {
|
} else if (artImage != null) {
|
||||||
if (isAftermath()) {
|
if (isAftermath()) {
|
||||||
|
|
@ -318,7 +318,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void drawFrame(Graphics2D g, CardPanelAttributes attribs, BufferedImage image, boolean lessOpaqueRulesTextBox) {
|
protected void drawFrame(Graphics2D g, CardPanelAttributes attribs, BufferedImage image, boolean lessOpaqueRulesTextBox) {
|
||||||
if (isAdventure()) {
|
if (isCardWithSpellOption()) {
|
||||||
super.drawFrame(g, attribs, image, lessOpaqueRulesTextBox);
|
super.drawFrame(g, attribs, image, lessOpaqueRulesTextBox);
|
||||||
|
|
||||||
CardPanelAttributes adventureAttribs = new CardPanelAttributes(
|
CardPanelAttributes adventureAttribs = new CardPanelAttributes(
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,7 @@ public final class TextboxRuleParser {
|
||||||
index += 5;
|
index += 5;
|
||||||
++outputIndex;
|
++outputIndex;
|
||||||
} else {
|
} else {
|
||||||
LOGGER.error("Bad &...; sequence `" + rule.substring(index + 1, index + 10) + "` in rule.");
|
LOGGER.error("Bad &...; sequence `" + rule.substring(index, Math.min(rule.length(), index + 10)) + "` in rule.");
|
||||||
build.append('&');
|
build.append('&');
|
||||||
++index;
|
++index;
|
||||||
++outputIndex;
|
++outputIndex;
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package org.mage.plugins.card;
|
||||||
import mage.cards.MageCard;
|
import mage.cards.MageCard;
|
||||||
import mage.cards.MagePermanent;
|
import mage.cards.MagePermanent;
|
||||||
import mage.cards.action.ActionCallback;
|
import mage.cards.action.ActionCallback;
|
||||||
import mage.client.util.GUISizeHelper;
|
import mage.client.util.*;
|
||||||
import mage.interfaces.plugin.CardPlugin;
|
import mage.interfaces.plugin.CardPlugin;
|
||||||
import mage.view.CardView;
|
import mage.view.CardView;
|
||||||
import mage.view.CounterView;
|
import mage.view.CounterView;
|
||||||
|
|
@ -35,6 +35,8 @@ import java.util.List;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import static mage.client.util.CardRenderMode.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link CardPlugin} implementation.
|
* {@link CardPlugin} implementation.
|
||||||
*
|
*
|
||||||
|
|
@ -102,16 +104,19 @@ public class CardPluginImpl implements CardPlugin {
|
||||||
* yet, so use old component based rendering for the split cards.
|
* yet, so use old component based rendering for the split cards.
|
||||||
*/
|
*/
|
||||||
private CardPanel makeCardPanel(CardView view, UUID gameId, boolean loadImage, ActionCallback callback,
|
private CardPanel makeCardPanel(CardView view, UUID gameId, boolean loadImage, ActionCallback callback,
|
||||||
boolean isFoil, Dimension dimension, int renderMode, boolean needFullPermanentRender) {
|
boolean isFoil, Dimension dimension, int renderModeId, boolean needFullPermanentRender) {
|
||||||
switch (renderMode) {
|
CardRenderMode cardRenderMode = CardRenderMode.fromId(renderModeId);
|
||||||
case 0:
|
switch (cardRenderMode) {
|
||||||
|
case MTGO:
|
||||||
|
case FORCED_M15:
|
||||||
|
case FORCED_RETRO:
|
||||||
return new CardPanelRenderModeMTGO(view, gameId, loadImage, callback, isFoil, dimension,
|
return new CardPanelRenderModeMTGO(view, gameId, loadImage, callback, isFoil, dimension,
|
||||||
needFullPermanentRender);
|
needFullPermanentRender, renderModeId);
|
||||||
case 1:
|
case IMAGE:
|
||||||
return new CardPanelRenderModeImage(view, gameId, loadImage, callback, isFoil, dimension,
|
return new CardPanelRenderModeImage(view, gameId, loadImage, callback, isFoil, dimension,
|
||||||
needFullPermanentRender);
|
needFullPermanentRender);
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException("Unknown render mode " + renderMode);
|
throw new IllegalStateException("Unknown render mode " + cardRenderMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -204,7 +204,7 @@ public enum GrabbagImageSource implements CardImageSource {
|
||||||
singleLinks.put("SWS/Hazard Trooper", "ZOutamG.jpeg");
|
singleLinks.put("SWS/Hazard Trooper", "ZOutamG.jpeg");
|
||||||
singleLinks.put("SWS/Head Hunting", "7OT1bGZ.jpeg");
|
singleLinks.put("SWS/Head Hunting", "7OT1bGZ.jpeg");
|
||||||
singleLinks.put("SWS/Heavy Trooper", "HhZWs2N.jpeg");
|
singleLinks.put("SWS/Heavy Trooper", "HhZWs2N.jpeg");
|
||||||
singleLinks.put("SWS/Hot Pursuit", "ih1GT5Z.jpeg");
|
singleLinks.put("SWS/Hot Pursuit (Star Wars)", "ih1GT5Z.jpeg");
|
||||||
singleLinks.put("SWS/Hungry Dragonsnake", "23v7RTm.jpeg");
|
singleLinks.put("SWS/Hungry Dragonsnake", "23v7RTm.jpeg");
|
||||||
singleLinks.put("SWS/Hunt to Extinction", "3eJyfzZ.jpeg");
|
singleLinks.put("SWS/Hunt to Extinction", "3eJyfzZ.jpeg");
|
||||||
singleLinks.put("SWS/Hutt Crime Lord", "NAzK7Hp.jpeg");
|
singleLinks.put("SWS/Hutt Crime Lord", "NAzK7Hp.jpeg");
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ public class ScryfallApiCard {
|
||||||
//public String watermark; // background watermark image for some cards
|
//public String watermark; // background watermark image for some cards
|
||||||
|
|
||||||
public void prepareCompatibleData() {
|
public void prepareCompatibleData() {
|
||||||
|
// take images from main card
|
||||||
if (this.image_uris != null) {
|
if (this.image_uris != null) {
|
||||||
this.imageSmall = this.image_uris.getOrDefault("small", "");
|
this.imageSmall = this.image_uris.getOrDefault("small", "");
|
||||||
this.imageNormal = this.image_uris.getOrDefault("normal", "");
|
this.imageNormal = this.image_uris.getOrDefault("normal", "");
|
||||||
|
|
@ -48,11 +49,12 @@ public class ScryfallApiCard {
|
||||||
this.image_uris = null;
|
this.image_uris = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// take first available images from one of the faces
|
||||||
if (this.card_faces != null) {
|
if (this.card_faces != null) {
|
||||||
this.card_faces.forEach(ScryfallApiCardFace::prepareCompatibleData);
|
this.card_faces.forEach(ScryfallApiCardFace::prepareCompatibleData);
|
||||||
}
|
}
|
||||||
|
|
||||||
// workaround for adventure card name fix:
|
// workaround for adventure/omen card name fix:
|
||||||
// - scryfall: Ondu Knotmaster // Throw a Line
|
// - scryfall: Ondu Knotmaster // Throw a Line
|
||||||
// - xmage: Ondu Knotmaster
|
// - xmage: Ondu Knotmaster
|
||||||
if (this.layout.equals("adventure")) {
|
if (this.layout.equals("adventure")) {
|
||||||
|
|
@ -88,11 +90,50 @@ public class ScryfallApiCard {
|
||||||
// - scryfall: Command Tower // Command Tower
|
// - scryfall: Command Tower // Command Tower
|
||||||
// - xmage: Command Tower (second side as diff card and direct link image), example: https://scryfall.com/card/rex/26/command-tower-command-tower
|
// - xmage: Command Tower (second side as diff card and direct link image), example: https://scryfall.com/card/rex/26/command-tower-command-tower
|
||||||
if (this.layout.equals("reversible_card")) {
|
if (this.layout.equals("reversible_card")) {
|
||||||
if (!this.card_faces.get(0).name.equals(this.card_faces.get(1).name)) {
|
if (false) {
|
||||||
throw new IllegalArgumentException("Scryfall: unsupported data type, reversible_card has diff faces "
|
// ignore
|
||||||
+ this.set + " - " + this.collector_number + " - " + this.name);
|
} else if (this.card_faces == null) {
|
||||||
|
// TODO: temporary fix, delete after scryfall site update
|
||||||
|
// broken adventure/omen card (scryfall changed it for some reason)
|
||||||
|
// Scavenger Regent // Exude Toxin
|
||||||
|
// https://scryfall.com/card/tdm/90/scavenger-regent-exude-toxin
|
||||||
|
if (this.name.contains("//")) {
|
||||||
|
throw new IllegalArgumentException("Scryfall: unsupported data type, broken reversible_card must have same simple name"
|
||||||
|
+ this.set + " - " + this.collector_number + " - " + this.name);
|
||||||
|
}
|
||||||
|
} else if (this.card_faces.get(0).layout.equals("reversible_card")) {
|
||||||
|
// TODO: temporary fix, delete after scryfall site update
|
||||||
|
// broken adventure/omen card (scryfall changed it for some reason)
|
||||||
|
// Bloomvine Regent // Claim Territory
|
||||||
|
// https://scryfall.com/card/tdm/381/bloomvine-regent-claim-territory-bloomvine-regent
|
||||||
|
this.name = this.card_faces.get(0).name;
|
||||||
|
} else if (this.card_faces.get(0).layout == null || this.card_faces.get(0).layout.equals("normal")) {
|
||||||
|
// simple card
|
||||||
|
// Command Tower // Command Tower
|
||||||
|
// https://scryfall.com/card/rex/26/command-tower-command-tower
|
||||||
|
if (!this.card_faces.get(0).name.equals(this.card_faces.get(1).name)) {
|
||||||
|
throw new IllegalArgumentException("Scryfall: unsupported data type, normal reversible_card must have same name in faces"
|
||||||
|
+ this.set + " - " + this.collector_number + " - " + this.name);
|
||||||
|
}
|
||||||
|
this.name = this.card_faces.get(0).name;
|
||||||
|
} else if (this.card_faces.get(0).layout.equals("adventure")) {
|
||||||
|
// adventure/omen card
|
||||||
|
// Bloomvine Regent // Claim Territory
|
||||||
|
// https://scryfall.com/card/tdm/381/bloomvine-regent-claim-territory-bloomvine-regent
|
||||||
|
this.name = this.card_faces.get(0).name;
|
||||||
|
if (this.card_faces.get(0).name.equals(this.card_faces.get(1).name)) {
|
||||||
|
throw new IllegalArgumentException("Scryfall: unsupported data type, adventure/omen's reversible_card must have diff names in faces "
|
||||||
|
+ this.set + " - " + this.collector_number + " - " + this.name);
|
||||||
|
}
|
||||||
|
} else if (this.card_faces.get(0).layout.equals("token")) {
|
||||||
|
// token (it's not used for xmage's tokens, but must pass checks here anyway)
|
||||||
|
// Mechtitan // Mechtitan
|
||||||
|
// https://scryfall.com/card/sld/1969/mechtitan-mechtitan
|
||||||
|
this.name = this.card_faces.get(0).name;
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Scryfall: unsupported layout type in reversible_card - "
|
||||||
|
+ this.card_faces.get(0).layout + " - " + this.set + " - " + this.collector_number + " - " + this.name);
|
||||||
}
|
}
|
||||||
this.name = this.card_faces.get(0).name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// workaround for non ascii names
|
// workaround for non ascii names
|
||||||
|
|
@ -104,7 +145,6 @@ public class ScryfallApiCard {
|
||||||
// - scryfall uses unicode numbers for reprints like Chandra Nalaar - dd2 - 34★ https://scryfall.com/card/dd2/34%E2%98%85/
|
// - scryfall uses unicode numbers for reprints like Chandra Nalaar - dd2 - 34★ https://scryfall.com/card/dd2/34%E2%98%85/
|
||||||
// - xmage uses ascii alternative Chandra Nalaar - dd2 - 34*
|
// - xmage uses ascii alternative Chandra Nalaar - dd2 - 34*
|
||||||
this.collector_number = transformCardNumberFromScryfallToXmage(this.collector_number);
|
this.collector_number = transformCardNumberFromScryfallToXmage(this.collector_number);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String transformCardNumberFromXmageToScryfall(String cardNumber) {
|
public static String transformCardNumberFromXmageToScryfall(String cardNumber) {
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import java.util.Map;
|
||||||
*/
|
*/
|
||||||
public class ScryfallApiCardFace {
|
public class ScryfallApiCardFace {
|
||||||
public String name;
|
public String name;
|
||||||
|
public String layout;
|
||||||
public Map<String, String> image_uris;
|
public Map<String, String> image_uris;
|
||||||
|
|
||||||
// fast access fields, fills on loading
|
// fast access fields, fills on loading
|
||||||
|
|
|
||||||
|
|
@ -504,7 +504,7 @@ public class ScryfallImageSource implements CardImageSource {
|
||||||
jsonReader.close();
|
jsonReader.close();
|
||||||
return bulkCardsDatabaseAll.size() > 0;
|
return bulkCardsDatabaseAll.size() > 0;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("Can't read bulk file (possible reason: broken format)");
|
logger.error("Can't read bulk file (possible reason: broken scryfall format), details: " + e, e);
|
||||||
try {
|
try {
|
||||||
// clean up
|
// clean up
|
||||||
if (!SCRYFALL_BULK_FILES_DEBUG_READ_ONLY_MODE) {
|
if (!SCRYFALL_BULK_FILES_DEBUG_READ_ONLY_MODE) {
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ public class ScryfallImageSupportCards {
|
||||||
add("PAL06"); // Arena League 2006
|
add("PAL06"); // Arena League 2006
|
||||||
//add("PMPS06"); // Magic Premiere Shop 2006
|
//add("PMPS06"); // Magic Premiere Shop 2006
|
||||||
add("PHUK"); // Hachette UK
|
add("PHUK"); // Hachette UK
|
||||||
add("PDCI"); // DCI Promos
|
add("DCI"); // DCI Promos
|
||||||
add("P06"); // Magic Player Rewards 2006
|
add("P06"); // Magic Player Rewards 2006
|
||||||
add("G06"); // Judge Gift Cards 2006
|
add("G06"); // Judge Gift Cards 2006
|
||||||
add("F06"); // Friday Night Magic 2006
|
add("F06"); // Friday Night Magic 2006
|
||||||
|
|
@ -190,7 +190,6 @@ public class ScryfallImageSupportCards {
|
||||||
add("P09"); // Magic Player Rewards 2009
|
add("P09"); // Magic Player Rewards 2009
|
||||||
add("G09"); // Judge Gift Cards 2009
|
add("G09"); // Judge Gift Cards 2009
|
||||||
add("F09"); // Friday Night Magic 2009
|
add("F09"); // Friday Night Magic 2009
|
||||||
add("PBOOK"); // Miscellaneous Book Promos
|
|
||||||
add("CON"); // Conflux
|
add("CON"); // Conflux
|
||||||
add("DDC"); // Duel Decks: Divine vs. Demonic
|
add("DDC"); // Duel Decks: Divine vs. Demonic
|
||||||
add("ARB"); // Alara Reborn
|
add("ARB"); // Alara Reborn
|
||||||
|
|
@ -405,7 +404,7 @@ public class ScryfallImageSupportCards {
|
||||||
add("XANA"); // Arena New Player Experience Extras
|
add("XANA"); // Arena New Player Experience Extras
|
||||||
add("OANA"); // Arena New Player Experience Cards
|
add("OANA"); // Arena New Player Experience Cards
|
||||||
add("PS18"); // San Diego Comic-Con 2018
|
add("PS18"); // San Diego Comic-Con 2018
|
||||||
add("PH17"); // Heroes of the Realm 2017
|
add("PH17"); // 2017 Heroes of the Realm
|
||||||
add("C18"); // Commander 2018
|
add("C18"); // Commander 2018
|
||||||
add("PGRN"); // Guilds of Ravnica Promos
|
add("PGRN"); // Guilds of Ravnica Promos
|
||||||
add("PRWK"); // GRN Ravnica Weekend
|
add("PRWK"); // GRN Ravnica Weekend
|
||||||
|
|
@ -440,7 +439,7 @@ public class ScryfallImageSupportCards {
|
||||||
add("ELD"); // Throne of Eldraine
|
add("ELD"); // Throne of Eldraine
|
||||||
//add("PTG"); // Ponies: The Galloping
|
//add("PTG"); // Ponies: The Galloping
|
||||||
add("CMB1"); // Mystery Booster Playtest Cards 2019
|
add("CMB1"); // Mystery Booster Playtest Cards 2019
|
||||||
//add("MB1"); // Mystery Booster
|
add("MB1"); // Mystery Booster
|
||||||
add("GN2"); // Game Night 2019
|
add("GN2"); // Game Night 2019
|
||||||
add("HA1"); // Historic Anthology 1
|
add("HA1"); // Historic Anthology 1
|
||||||
//add("HHO"); // Happy Holidays
|
//add("HHO"); // Happy Holidays
|
||||||
|
|
@ -457,7 +456,7 @@ public class ScryfallImageSupportCards {
|
||||||
//add("FMB1"); // Mystery Booster Retail Edition Foils
|
//add("FMB1"); // Mystery Booster Retail Edition Foils
|
||||||
add("HA2"); // Historic Anthology 2
|
add("HA2"); // Historic Anthology 2
|
||||||
add("SLD"); // Secret Lair Drop
|
add("SLD"); // Secret Lair Drop
|
||||||
add("PMEI"); // Magazine Inserts
|
add("PMEI"); // Media and Collaboration Promos
|
||||||
add("SLU"); // Secret Lair: Ultimate Edition
|
add("SLU"); // Secret Lair: Ultimate Edition
|
||||||
add("SS3"); // Signature Spellbook: Chandra
|
add("SS3"); // Signature Spellbook: Chandra
|
||||||
add("HA3"); // Historic Anthology 3
|
add("HA3"); // Historic Anthology 3
|
||||||
|
|
@ -467,7 +466,7 @@ public class ScryfallImageSupportCards {
|
||||||
// add("DD3"); // Duel Decks Anthology
|
// add("DD3"); // Duel Decks Anthology
|
||||||
// add("PZ1"); // Legendary Cube
|
// add("PZ1"); // Legendary Cube
|
||||||
add("IKO"); // Ikoria: Lair of Behemoths
|
add("IKO"); // Ikoria: Lair of Behemoths
|
||||||
add("C20"); // Commander 2020 Edition
|
add("C20"); // Commander 2020
|
||||||
add("M21"); // Core Set 2021
|
add("M21"); // Core Set 2021
|
||||||
add("JMP"); // Jumpstart
|
add("JMP"); // Jumpstart
|
||||||
add("PH19"); // 2019 Heroes of the Realm
|
add("PH19"); // 2019 Heroes of the Realm
|
||||||
|
|
@ -480,6 +479,7 @@ public class ScryfallImageSupportCards {
|
||||||
add("KLR"); // Kaladesh Remastered
|
add("KLR"); // Kaladesh Remastered
|
||||||
add("CMR"); // Commander Legends
|
add("CMR"); // Commander Legends
|
||||||
add("CC1"); // Commander Collection: Green
|
add("CC1"); // Commander Collection: Green
|
||||||
|
add("PJ21"); // Judge Gift Cards 2021
|
||||||
add("PL21"); // Year of the Ox 2021
|
add("PL21"); // Year of the Ox 2021
|
||||||
add("KHM"); // Kaldheim
|
add("KHM"); // Kaldheim
|
||||||
add("KHC"); // Kaldheim Commander
|
add("KHC"); // Kaldheim Commander
|
||||||
|
|
@ -488,9 +488,10 @@ public class ScryfallImageSupportCards {
|
||||||
add("STA"); // Strixhaven Mystical Archive
|
add("STA"); // Strixhaven Mystical Archive
|
||||||
add("HA4"); // Historic Anthology 4
|
add("HA4"); // Historic Anthology 4
|
||||||
add("HA5"); // Historic Anthology 5
|
add("HA5"); // Historic Anthology 5
|
||||||
add("C21"); // Commander 2021 Edition
|
add("C21"); // Commander 2021
|
||||||
add("MH2"); // Modern Horizons 2
|
add("MH2"); // Modern Horizons 2
|
||||||
add("H1R"); // Modern Horizons 1 Timeshifts
|
add("H1R"); // Modern Horizons 1 Timeshifts
|
||||||
|
add("PW21"); // Wizards Play Network 2021
|
||||||
add("PLG21"); // Love Your LGS 2021
|
add("PLG21"); // Love Your LGS 2021
|
||||||
add("AFR"); // Adventures in the Forgotten Realms
|
add("AFR"); // Adventures in the Forgotten Realms
|
||||||
add("AFC"); // Forgotten Realms Commander
|
add("AFC"); // Forgotten Realms Commander
|
||||||
|
|
@ -500,12 +501,15 @@ public class ScryfallImageSupportCards {
|
||||||
add("VOW"); // Innistrad: Crimson Vow
|
add("VOW"); // Innistrad: Crimson Vow
|
||||||
add("VOC"); // Crimson Vow Commander
|
add("VOC"); // Crimson Vow Commander
|
||||||
add("YMID"); // Alchemy: Innistrad
|
add("YMID"); // Alchemy: Innistrad
|
||||||
|
add("P22"); // Judge Gift Cards 2022
|
||||||
add("DBL"); // Innistrad: Double Feature
|
add("DBL"); // Innistrad: Double Feature
|
||||||
add("CC2"); // Commander Collection: Black
|
add("CC2"); // Commander Collection: Black
|
||||||
add("NEO"); // Kamigawa: Neon Dynasty
|
add("NEO"); // Kamigawa: Neon Dynasty
|
||||||
add("YNEO"); // Alchemy: Kamigawa
|
add("YNEO"); // Alchemy: Kamigawa
|
||||||
add("NEC"); // Neon Dynasty Commander
|
add("NEC"); // Neon Dynasty Commander
|
||||||
add("PL22"); // Year of the Tiger 2022
|
add("PL22"); // Year of the Tiger 2022
|
||||||
|
add("PW22"); // Wizards Play Network 2022
|
||||||
|
add("GDY"); // Game Day Promos
|
||||||
add("SNC"); // Streets of New Capenna
|
add("SNC"); // Streets of New Capenna
|
||||||
add("NCC"); // New Capenna Commander
|
add("NCC"); // New Capenna Commander
|
||||||
add("SLX"); // Universes Within
|
add("SLX"); // Universes Within
|
||||||
|
|
@ -514,7 +518,7 @@ public class ScryfallImageSupportCards {
|
||||||
add("DMU"); // Dominaria United
|
add("DMU"); // Dominaria United
|
||||||
add("DMC"); // Dominaria United Commander
|
add("DMC"); // Dominaria United Commander
|
||||||
add("YDMU"); // Alchemy: Dominaria
|
add("YDMU"); // Alchemy: Dominaria
|
||||||
add("40K"); // Warhammer 40,000
|
add("40K"); // Warhammer 40,000 Commander
|
||||||
add("UNF"); // Unfinity
|
add("UNF"); // Unfinity
|
||||||
add("GN3"); // Game Night: Free-for-All
|
add("GN3"); // Game Night: Free-for-All
|
||||||
add("BRO"); // The Brothers' War
|
add("BRO"); // The Brothers' War
|
||||||
|
|
@ -523,17 +527,25 @@ public class ScryfallImageSupportCards {
|
||||||
add("BOT"); // Transformers
|
add("BOT"); // Transformers
|
||||||
add("J22"); // Jumpstart 2022
|
add("J22"); // Jumpstart 2022
|
||||||
add("SCD"); // Starter Commander Decks
|
add("SCD"); // Starter Commander Decks
|
||||||
|
add("PW23"); // Wizards Play Network 2023
|
||||||
|
add("P23"); // Judge Gift Cards 2023
|
||||||
add("SLC"); // Secret Lair 30th Anniversary Countdown Kit
|
add("SLC"); // Secret Lair 30th Anniversary Countdown Kit
|
||||||
add("DMR"); // Dominaria Remastered
|
add("DMR"); // Dominaria Remastered
|
||||||
add("ONE"); // Phyrexia: All Will Be One
|
add("ONE"); // Phyrexia: All Will Be One
|
||||||
add("ONC"); // Phyrexia: All Will Be One Commander
|
add("ONC"); // Phyrexia: All Will Be One Commander
|
||||||
add("PL23"); // Year of the Rabbit 2023
|
add("PL23"); // Year of the Rabbit 2023
|
||||||
|
add("UNK"); // Unknown Event
|
||||||
|
add("SIS"); // Shadows of the Past
|
||||||
|
add("SIR"); // Shadows over Innistrad Remastered
|
||||||
add("SLP"); // Secret Lair Showdown
|
add("SLP"); // Secret Lair Showdown
|
||||||
add("MOM"); // March of the Machine
|
add("MOM"); // March of the Machine
|
||||||
add("MOC"); // March of the Machine Commander
|
add("MOC"); // March of the Machine Commander
|
||||||
add("MAT"); // March of the Machine: The Aftermath
|
add("MAT"); // March of the Machine: The Aftermath
|
||||||
add("MUL"); // Multiverse Legends
|
add("MUL"); // Multiverse Legends
|
||||||
add("30A"); // Thirtieth Anniversary Edition
|
add("30A"); // 30th Anniversary Edition
|
||||||
|
add("P30A"); // 30th Anniversary Play Promos
|
||||||
|
add("P30M"); // 30th Anniversary Misc Promos
|
||||||
|
add("PEWK"); // Eternal Weekend
|
||||||
add("LTR"); // The Lord of the Rings: Tales of Middle-Earth
|
add("LTR"); // The Lord of the Rings: Tales of Middle-Earth
|
||||||
add("LTC"); // Tales of Middle-Earth Commander
|
add("LTC"); // Tales of Middle-Earth Commander
|
||||||
add("CMM"); // Commander Masters
|
add("CMM"); // Commander Masters
|
||||||
|
|
@ -542,9 +554,10 @@ public class ScryfallImageSupportCards {
|
||||||
add("WOT"); // Wilds of Eldraine: Enchanting Tales
|
add("WOT"); // Wilds of Eldraine: Enchanting Tales
|
||||||
add("WOC"); // Wilds of Eldraine Commander
|
add("WOC"); // Wilds of Eldraine Commander
|
||||||
add("LCI"); // The Lost Caverns of Ixalan
|
add("LCI"); // The Lost Caverns of Ixalan
|
||||||
add("LCC"); // The Lost Caverns of Ixalan Commander
|
add("LCC"); // The The Lost Caverns of Ixalan Commander
|
||||||
add("REX"); // Jurassic World Collection
|
add("REX"); // Jurassic World Collection
|
||||||
add("SPG"); // Special Guests
|
add("SPG"); // Special Guests
|
||||||
|
add("PW24"); // Wizards Play Network 2024
|
||||||
add("RVR"); // Ravnica Remastered
|
add("RVR"); // Ravnica Remastered
|
||||||
add("PIP"); // Fallout
|
add("PIP"); // Fallout
|
||||||
add("MKM"); // Murders at Karlov Manor
|
add("MKM"); // Murders at Karlov Manor
|
||||||
|
|
@ -563,6 +576,19 @@ public class ScryfallImageSupportCards {
|
||||||
add("DSK"); // Duskmourn: House of Horror
|
add("DSK"); // Duskmourn: House of Horror
|
||||||
add("DSC"); // Duskmourn: House of Horror Commander
|
add("DSC"); // Duskmourn: House of Horror Commander
|
||||||
add("FDN"); // Foundations
|
add("FDN"); // Foundations
|
||||||
|
add("J25"); // Foundations Jumpstart
|
||||||
|
add("PIO"); // Pioneer Masters
|
||||||
|
add("PW25"); // Wizards Play Network 2025
|
||||||
|
add("INR"); // Innistrad Remastered
|
||||||
|
add("PF25"); // MagicFest 2025
|
||||||
|
add("DFT"); // Aetherdrift
|
||||||
|
add("DRC"); // Aetherdrift Commander
|
||||||
|
add("TDM"); // Tarkir: Dragonstorm
|
||||||
|
add("TDC"); // Tarkir: Dragonstorm Commander
|
||||||
|
add("FIN"); // Final Fantasy
|
||||||
|
add("FIC"); // Final Fantasy Commander
|
||||||
|
add("FCA"); // Final Fantasy: Through the Ages
|
||||||
|
add("SPE"); // Marvel's Spider-Man Eternal
|
||||||
|
|
||||||
// Custom sets using Scryfall images - must provide a direct link for each card in directDownloadLinks
|
// Custom sets using Scryfall images - must provide a direct link for each card in directDownloadLinks
|
||||||
add("CALC"); // Custom Alchemized versions of existing cards
|
add("CALC"); // Custom Alchemized versions of existing cards
|
||||||
|
|
@ -609,46 +635,85 @@ public class ScryfallImageSupportCards {
|
||||||
// SLD
|
// SLD
|
||||||
// fake double faced cards
|
// fake double faced cards
|
||||||
put("SLD/Adrix and Nev, Twincasters/1544b", "https://api.scryfall.com/cards/sld/1544/en?format=image&face=back");
|
put("SLD/Adrix and Nev, Twincasters/1544b", "https://api.scryfall.com/cards/sld/1544/en?format=image&face=back");
|
||||||
|
put("SLD/Aesi, Tyrant of Gyre Strait/1873b", "https://api.scryfall.com/cards/sld/1873/en?format=image&face=back");
|
||||||
|
put("SLD/Ajani Goldmane/745b", "https://api.scryfall.com/cards/sld/745/en?format=image&face=back");
|
||||||
put("SLD/Ajani Goldmane/1453b", "https://api.scryfall.com/cards/sld/1453/en?format=image&face=back");
|
put("SLD/Ajani Goldmane/1453b", "https://api.scryfall.com/cards/sld/1453/en?format=image&face=back");
|
||||||
put("SLD/Anointed Procession/1511b", "https://api.scryfall.com/cards/sld/1453/en?format=image&face=back");
|
put("SLD/Anje Falkenrath/1874b", "https://api.scryfall.com/cards/sld/1874/en?format=image&face=back");
|
||||||
|
put("SLD/Anointed Procession/1511b", "https://api.scryfall.com/cards/sld/1511/en?format=image&face=back");
|
||||||
|
put("SLD/Birds of Paradise/1675b", "https://api.scryfall.com/cards/sld/1675/en?format=image&face=back");
|
||||||
put("SLD/Blightsteel Colossus/1079b", "https://api.scryfall.com/cards/sld/1079/en?format=image&face=back");
|
put("SLD/Blightsteel Colossus/1079b", "https://api.scryfall.com/cards/sld/1079/en?format=image&face=back");
|
||||||
|
put("SLD/Chandra Nalaar/748b", "https://api.scryfall.com/cards/sld/748/en?format=image&face=back");
|
||||||
put("SLD/Chandra Nalaar/1456b", "https://api.scryfall.com/cards/sld/1456/en?format=image&face=back");
|
put("SLD/Chandra Nalaar/1456b", "https://api.scryfall.com/cards/sld/1456/en?format=image&face=back");
|
||||||
|
put("SLD/Chulane, Teller of Tales/1875b", "https://api.scryfall.com/cards/sld/1875/en?format=image&face=back");
|
||||||
put("SLD/Darksteel Colossus/1081b", "https://api.scryfall.com/cards/sld/1081/en?format=image&face=back");
|
put("SLD/Darksteel Colossus/1081b", "https://api.scryfall.com/cards/sld/1081/en?format=image&face=back");
|
||||||
put("SLD/Death Baron/1458b", "https://api.scryfall.com/cards/sld/1458/en?format=image&face=back");
|
put("SLD/Death Baron/1458b", "https://api.scryfall.com/cards/sld/1458/en?format=image&face=back");
|
||||||
put("SLD/Doubling Cube/1080b", "https://api.scryfall.com/cards/sld/1080/en?format=image&face=back");
|
put("SLD/Doubling Cube/1080b", "https://api.scryfall.com/cards/sld/1080/en?format=image&face=back");
|
||||||
|
put("SLD/Dragonlord Atarka/1970b", "https://api.scryfall.com/cards/sld/1970/en?format=image&face=back");
|
||||||
|
put("SLD/Dragonlord Dromoka/1971b", "https://api.scryfall.com/cards/sld/1971/en?format=image&face=back");
|
||||||
|
put("SLD/Dragonlord Kolaghan/1972b", "https://api.scryfall.com/cards/sld/1972/en?format=image&face=back");
|
||||||
|
put("SLD/Dragonlord Ojutai/1973b", "https://api.scryfall.com/cards/sld/1973/en?format=image&face=back");
|
||||||
|
put("SLD/Dragonlord Silumgar/1974b", "https://api.scryfall.com/cards/sld/1974/en?format=image&face=back");
|
||||||
|
put("SLD/Estrid's Invocation/1325b", "https://api.scryfall.com/cards/sld/1325/en?format=image&face=back");
|
||||||
|
put("SLD/Estrid, the Masked/1327b", "https://api.scryfall.com/cards/sld/1327/en?format=image&face=back");
|
||||||
put("SLD/Etali, Primal Storm/1123b", "https://api.scryfall.com/cards/sld/1123/en?format=image&face=back");
|
put("SLD/Etali, Primal Storm/1123b", "https://api.scryfall.com/cards/sld/1123/en?format=image&face=back");
|
||||||
|
put("SLD/Garruk Wildspeaker/749b", "https://api.scryfall.com/cards/sld/749/en?format=image&face=back");
|
||||||
put("SLD/Garruk Wildspeaker/1457b", "https://api.scryfall.com/cards/sld/1457/en?format=image&face=back");
|
put("SLD/Garruk Wildspeaker/1457b", "https://api.scryfall.com/cards/sld/1457/en?format=image&face=back");
|
||||||
put("SLD/Ghalta, Primal Hunger/1124b", "https://api.scryfall.com/cards/sld/1124/en?format=image&face=back");
|
put("SLD/Ghalta, Primal Hunger/1124b", "https://api.scryfall.com/cards/sld/1124/en?format=image&face=back");
|
||||||
put("SLD/Grimgrin, Corpse-Born/1461b", "https://api.scryfall.com/cards/sld/1461/en?format=image&face=back");
|
put("SLD/Grimgrin, Corpse-Born/1461b", "https://api.scryfall.com/cards/sld/1461/en?format=image&face=back");
|
||||||
|
put("SLD/Jace Beleren/746b", "https://api.scryfall.com/cards/sld/746/en?format=image&face=back");
|
||||||
put("SLD/Jace Beleren/1454b", "https://api.scryfall.com/cards/sld/1454/en?format=image&face=back");
|
put("SLD/Jace Beleren/1454b", "https://api.scryfall.com/cards/sld/1454/en?format=image&face=back");
|
||||||
put("SLD/Jetmir, Nexus of Revels/1509b", "https://api.scryfall.com/cards/sld/1509/en?format=image&face=back");
|
put("SLD/Jetmir, Nexus of Revels/1509b", "https://api.scryfall.com/cards/sld/1509/en?format=image&face=back");
|
||||||
|
put("SLD/Jetmir, Nexus of Revels/1555b", "https://api.scryfall.com/cards/sld/1555/en?format=image&face=back");
|
||||||
put("SLD/Jinnie Fay, Jetmir's Second/1510b", "https://api.scryfall.com/cards/sld/1510/en?format=image&face=back");
|
put("SLD/Jinnie Fay, Jetmir's Second/1510b", "https://api.scryfall.com/cards/sld/1510/en?format=image&face=back");
|
||||||
|
put("SLD/Jinnie Fay, Jetmir's Second/1556b", "https://api.scryfall.com/cards/sld/1556/en?format=image&face=back");
|
||||||
|
put("SLD/Kardur, Doomscourge/1807b", "https://api.scryfall.com/cards/sld/1807/en?format=image&face=back");
|
||||||
put("SLD/Krark's Thumb/383b", "https://api.scryfall.com/cards/sld/383/en?format=image&face=back");
|
put("SLD/Krark's Thumb/383b", "https://api.scryfall.com/cards/sld/383/en?format=image&face=back");
|
||||||
put("SLD/Krark, the Thumbless/1543b", "https://api.scryfall.com/cards/sld/1543/en?format=image&face=back");
|
put("SLD/Krark, the Thumbless/1543b", "https://api.scryfall.com/cards/sld/1543/en?format=image&face=back");
|
||||||
|
put("SLD/Liliana Vess/747b", "https://api.scryfall.com/cards/sld/747/en?format=image&face=back");
|
||||||
put("SLD/Liliana Vess/1455b", "https://api.scryfall.com/cards/sld/1455/en?format=image&face=back");
|
put("SLD/Liliana Vess/1455b", "https://api.scryfall.com/cards/sld/1455/en?format=image&face=back");
|
||||||
|
put("SLD/Mechtitan Core/1969b", "https://api.scryfall.com/cards/sld/1969/en?format=image&face=back");
|
||||||
|
put("SLD/Mechtitan Core/1965b", "https://api.scryfall.com/cards/sld/1965/en?format=image&face=back");
|
||||||
|
put("SLD/Norin the Wary/827b", "https://api.scryfall.com/cards/sld/827/en?format=image&face=back");
|
||||||
put("SLD/Noxious Ghoul/1459b", "https://api.scryfall.com/cards/sld/1459/en?format=image&face=back");
|
put("SLD/Noxious Ghoul/1459b", "https://api.scryfall.com/cards/sld/1459/en?format=image&face=back");
|
||||||
put("SLD/Okaun, Eye of Chaos/380b", "https://api.scryfall.com/cards/sld/380/en?format=image&face=back");
|
put("SLD/Okaun, Eye of Chaos/380b", "https://api.scryfall.com/cards/sld/380/en?format=image&face=back");
|
||||||
put("SLD/Okaun, Eye of Chaos/380b*", "https://api.scryfall.com/cards/sld/380★/en?format=image&face=back");
|
put("SLD/Okaun, Eye of Chaos/380*b", "https://api.scryfall.com/cards/sld/380★/en?format=image&face=back");
|
||||||
|
put("SLD/Parhelion II/1964b", "https://api.scryfall.com/cards/sld/1964/en?format=image&face=back");
|
||||||
|
put("SLD/Peacewalker Colossus/1966b", "https://api.scryfall.com/cards/sld/1966/en?format=image&face=back");
|
||||||
put("SLD/Propaganda/381b", "https://api.scryfall.com/cards/sld/381/en?format=image&face=back");
|
put("SLD/Propaganda/381b", "https://api.scryfall.com/cards/sld/381/en?format=image&face=back");
|
||||||
|
put("SLD/Radha, Heart of Keld/1876b", "https://api.scryfall.com/cards/sld/1876/en?format=image&face=back");
|
||||||
|
put("SLD/Reckoner Bankbuster/1967b", "https://api.scryfall.com/cards/sld/1967/en?format=image&face=back");
|
||||||
put("SLD/Rin and Seri, Inseparable/1508b", "https://api.scryfall.com/cards/sld/1508/en?format=image&face=back");
|
put("SLD/Rin and Seri, Inseparable/1508b", "https://api.scryfall.com/cards/sld/1508/en?format=image&face=back");
|
||||||
|
put("SLD/Rin and Seri, Inseparable/1554b", "https://api.scryfall.com/cards/sld/1554/en?format=image&face=back");
|
||||||
put("SLD/Sakashima of a Thousand Faces/1541b", "https://api.scryfall.com/cards/sld/1541/en?format=image&face=back");
|
put("SLD/Sakashima of a Thousand Faces/1541b", "https://api.scryfall.com/cards/sld/1541/en?format=image&face=back");
|
||||||
|
put("SLD/Smuggler's Copter/1968b", "https://api.scryfall.com/cards/sld/1968/en?format=image&face=back");
|
||||||
put("SLD/Sol Ring/1512b", "https://api.scryfall.com/cards/sld/1512/en?format=image&face=back");
|
put("SLD/Sol Ring/1512b", "https://api.scryfall.com/cards/sld/1512/en?format=image&face=back");
|
||||||
|
put("SLD/Steely Resolve/1326b", "https://api.scryfall.com/cards/sld/1326/en?format=image&face=back");
|
||||||
put("SLD/Stitch in Time/382b", "https://api.scryfall.com/cards/sld/382/en?format=image&face=back");
|
put("SLD/Stitch in Time/382b", "https://api.scryfall.com/cards/sld/382/en?format=image&face=back");
|
||||||
put("SLD/Terror/750b", "https://api.scryfall.com/cards/sld/750/en?format=image&face=back");
|
put("SLD/Terror/750b", "https://api.scryfall.com/cards/sld/750/en?format=image&face=back");
|
||||||
|
put("SLD/Tuvasa the Sunlit/1328b", "https://api.scryfall.com/cards/sld/1328/en?format=image&face=back");
|
||||||
put("SLD/Ulamog, the Ceaseless Hunger/1122b", "https://api.scryfall.com/cards/sld/1122/en?format=image&face=back");
|
put("SLD/Ulamog, the Ceaseless Hunger/1122b", "https://api.scryfall.com/cards/sld/1122/en?format=image&face=back");
|
||||||
put("SLD/Unholy Grotto/1462b", "https://api.scryfall.com/cards/sld/1462/en?format=image&face=back");
|
put("SLD/Unholy Grotto/1462b", "https://api.scryfall.com/cards/sld/1462/en?format=image&face=back");
|
||||||
put("SLD/Yargle, Glutton of Urborg/1542b", "https://api.scryfall.com/cards/sld/1542/en?format=image&face=back");
|
put("SLD/Yargle, Glutton of Urborg/1542b", "https://api.scryfall.com/cards/sld/1542/en?format=image&face=back");
|
||||||
put("SLD/Zndrsplt, Eye of Wisdom/379b", "https://api.scryfall.com/cards/sld/379/en?format=image&face=back");
|
put("SLD/Zndrsplt, Eye of Wisdom/379b", "https://api.scryfall.com/cards/sld/379/en?format=image&face=back");
|
||||||
put("SLD/Zndrsplt, Eye of Wisdom/379b*", "https://api.scryfall.com/cards/sld/379★/en?format=image&face=back");
|
put("SLD/Zndrsplt, Eye of Wisdom/379*b", "https://api.scryfall.com/cards/sld/379★/en?format=image&face=back");
|
||||||
put("SLD/Zombie Master/1460b", "https://api.scryfall.com/cards/sld/1460/en?format=image&face=back");
|
put("SLD/Zombie Master/1460b", "https://api.scryfall.com/cards/sld/1460/en?format=image&face=back");
|
||||||
// normal cards
|
// normal cards
|
||||||
|
put("SLD/Counterspell/99999SCTLR", "https://api.scryfall.com/cards/sld/SCTLR/"); // see issue 11157
|
||||||
put("SLD/Viscera Seer/99999VS", "https://api.scryfall.com/cards/sld/VS/"); // see issue 11157
|
put("SLD/Viscera Seer/99999VS", "https://api.scryfall.com/cards/sld/VS/"); // see issue 11157
|
||||||
|
|
||||||
// CALC - custom alchemy version of cards.
|
// CALC - custom alchemy version of cards.
|
||||||
put("CALC/C-Pillar of the Paruns", "https://api.scryfall.com/cards/dis/176/");
|
put("CALC/C-Pillar of the Paruns", "https://api.scryfall.com/cards/dis/176/");
|
||||||
|
|
||||||
|
// MB1
|
||||||
|
put("MB1/Goblin Trenches", "https://api.scryfall.com/cards/plst/EMA-203/");
|
||||||
|
put("MB1/Prophetic Bolt", "https://api.scryfall.com/cards/plst/C15-231/");
|
||||||
|
|
||||||
// LTR - 0 number for tokens only
|
// LTR - 0 number for tokens only
|
||||||
put("LTR/The One Ring/001", "https://api.scryfall.com/cards/ltr/0/");
|
// Scryfall has a bug, for some reason this link doesn't work with ?format=image even though it works with ?format=json
|
||||||
|
// and ?format=text. Base url fails because language is qya and not en and alternate url fails because of this bug
|
||||||
|
// TODO: This should be reverted when Scryfall fixes the bug
|
||||||
|
// put("LTR/The One Ring/001", "https://api.scryfall.com/cards/ltr/0/");
|
||||||
|
put("LTR/The One Ring/001", "https://api.scryfall.com/cards/ltr/0/qya?format=image");
|
||||||
|
|
||||||
// REX - double faced lands (xmage uses two diff lands for it)
|
// REX - double faced lands (xmage uses two diff lands for it)
|
||||||
put("REX/Command Tower/26b", "https://api.scryfall.com/cards/rex/26/en?format=image&face=back");
|
put("REX/Command Tower/26b", "https://api.scryfall.com/cards/rex/26/en?format=image&face=back");
|
||||||
|
|
@ -657,6 +722,15 @@ public class ScryfallImageSupportCards {
|
||||||
put("REX/Mountain/24b", "https://api.scryfall.com/cards/rex/24/en?format=image&face=back");
|
put("REX/Mountain/24b", "https://api.scryfall.com/cards/rex/24/en?format=image&face=back");
|
||||||
put("REX/Plains/21b", "https://api.scryfall.com/cards/rex/21/en?format=image&face=back");
|
put("REX/Plains/21b", "https://api.scryfall.com/cards/rex/21/en?format=image&face=back");
|
||||||
put("REX/Swamp/23b", "https://api.scryfall.com/cards/rex/23/en?format=image&face=back");
|
put("REX/Swamp/23b", "https://api.scryfall.com/cards/rex/23/en?format=image&face=back");
|
||||||
|
|
||||||
|
// TDM - fake double faced cards
|
||||||
|
put("TDM/Bloomvine Regent/381b", "https://api.scryfall.com/cards/tdm/381/en?format=image&face=back");
|
||||||
|
put("TDM/Clarion Conqueror/377b", "https://api.scryfall.com/cards/tdm/377/en?format=image&face=back");
|
||||||
|
put("TDM/Magmatic Hellkite/380b", "https://api.scryfall.com/cards/tdm/380/en?format=image&face=back");
|
||||||
|
put("TDM/Marang River Regent/378b", "https://api.scryfall.com/cards/tdm/378/en?format=image&face=back");
|
||||||
|
put("TDM/Scavenger Regent/379b", "https://api.scryfall.com/cards/tdm/379/en?format=image&face=back");
|
||||||
|
put("TDM/Ugin, Eye of the Storms/382b", "https://api.scryfall.com/cards/tdm/382/en?format=image&face=back");
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,8 @@ public class ScryfallImageSupportTokens {
|
||||||
putAll(TokenRepository.instance.prepareScryfallDownloadList());
|
putAll(TokenRepository.instance.prepareScryfallDownloadList());
|
||||||
|
|
||||||
// RIX
|
// RIX
|
||||||
put("RIX/City's Blessing", "https://api.scryfall.com/cards/trix/6/en?format=image"); // TODO: missing from tokens data
|
// TODO: this should be readded when condition tokens are implemented
|
||||||
|
// put("RIX/City's Blessing", "https://api.scryfall.com/cards/trix/6/en?format=image");
|
||||||
put("RIX/Elemental/1", "https://api.scryfall.com/cards/trix/1/en?format=image");
|
put("RIX/Elemental/1", "https://api.scryfall.com/cards/trix/1/en?format=image");
|
||||||
put("RIX/Elemental/2", "https://api.scryfall.com/cards/trix/2/en?format=image");
|
put("RIX/Elemental/2", "https://api.scryfall.com/cards/trix/2/en?format=image");
|
||||||
put("RIX/Golem", "https://api.scryfall.com/cards/trix/4/en?format=image");
|
put("RIX/Golem", "https://api.scryfall.com/cards/trix/4/en?format=image");
|
||||||
|
|
@ -61,7 +62,7 @@ public class ScryfallImageSupportTokens {
|
||||||
put("RNA/Treasure", "https://api.scryfall.com/cards/trna/12/en?format=image");
|
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");
|
put("RNA/Zombie", "https://api.scryfall.com/cards/trna/3/en?format=image");
|
||||||
|
|
||||||
//GRN
|
// GRN
|
||||||
put("GRN/Angel", "https://api.scryfall.com/cards/tgrn/1/en?format=image");
|
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/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/Elf Knight", "https://api.scryfall.com/cards/tgrn/6/en?format=image");
|
||||||
|
|
@ -71,7 +72,7 @@ public class ScryfallImageSupportTokens {
|
||||||
put("GRN/Soldier", "https://api.scryfall.com/cards/tgrn/2/en?format=image");
|
put("GRN/Soldier", "https://api.scryfall.com/cards/tgrn/2/en?format=image");
|
||||||
put("GRN/Emblem Vraska", "https://api.scryfall.com/cards/tgrn/8/en?format=image");
|
put("GRN/Emblem Vraska", "https://api.scryfall.com/cards/tgrn/8/en?format=image");
|
||||||
|
|
||||||
//DOM
|
// DOM
|
||||||
put("DOM/Cleric", "https://api.scryfall.com/cards/tdom/4/en?format=image");
|
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/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/Demon", "https://api.scryfall.com/cards/tdom/7/en?format=image");
|
||||||
|
|
@ -89,7 +90,7 @@ public class ScryfallImageSupportTokens {
|
||||||
put("DOM/Emblem Teferi", "https://api.scryfall.com/cards/tdom/16/en?format=image");
|
put("DOM/Emblem Teferi", "https://api.scryfall.com/cards/tdom/16/en?format=image");
|
||||||
put("DOM/Zombie Knight", "https://api.scryfall.com/cards/tdom/5/en?format=image");
|
put("DOM/Zombie Knight", "https://api.scryfall.com/cards/tdom/5/en?format=image");
|
||||||
|
|
||||||
//XLN
|
// XLN
|
||||||
put("XLN/Dinosaur", "https://api.scryfall.com/cards/txln/5/en?format=image");
|
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/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/Merfolk", "https://api.scryfall.com/cards/txln/3/en?format=image");
|
||||||
|
|
@ -101,12 +102,12 @@ public class ScryfallImageSupportTokens {
|
||||||
put("XLN/Treasure/4", "https://api.scryfall.com/cards/txln/10/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");
|
put("XLN/Vampire", "https://api.scryfall.com/cards/txln/1/en?format=image");
|
||||||
|
|
||||||
//HOU
|
// HOU
|
||||||
put("HOU/Horse", "https://api.scryfall.com/cards/thou/10/en?format=image");
|
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/Insect", "https://api.scryfall.com/cards/thou/12/en?format=image");
|
||||||
put("HOU/Snake", "https://api.scryfall.com/cards/thou/11/en?format=image");
|
put("HOU/Snake", "https://api.scryfall.com/cards/thou/11/en?format=image");
|
||||||
|
|
||||||
//AKH - tokens
|
// AKH - tokens
|
||||||
put("AKH/Beast", "https://api.scryfall.com/cards/takh/21/en?format=image");
|
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/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/Drake", "https://api.scryfall.com/cards/takh/18/en?format=image");
|
||||||
|
|
@ -117,30 +118,14 @@ public class ScryfallImageSupportTokens {
|
||||||
put("AKH/Warrior", "https://api.scryfall.com/cards/takh/17/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/Wurm", "https://api.scryfall.com/cards/takh/24/en?format=image");
|
||||||
put("AKH/Zombie", "https://api.scryfall.com/cards/takh/20/en?format=image");
|
put("AKH/Zombie", "https://api.scryfall.com/cards/takh/20/en?format=image");
|
||||||
//AKH - embalm ability (token from card)
|
|
||||||
put("AKH/Angel of Sanctions", "https://api.scryfall.com/cards/takh/1/en?format=image");
|
|
||||||
put("AKH/Anointer Priest", "https://api.scryfall.com/cards/takh/2/en?format=image");
|
|
||||||
put("AKH/Aven Initiate", "https://api.scryfall.com/cards/takh/3/en?format=image");
|
|
||||||
put("AKH/Aven Wind Guide", "https://api.scryfall.com/cards/takh/4/en?format=image");
|
|
||||||
put("AKH/Glyph Keeper", "https://api.scryfall.com/cards/takh/5/en?format=image");
|
|
||||||
put("AKH/Heart-Piercer Manticore", "https://api.scryfall.com/cards/takh/6/en?format=image");
|
|
||||||
put("AKH/Honored Hydra", "https://api.scryfall.com/cards/takh/7/en?format=image");
|
|
||||||
put("AKH/Labyrinth Guardian", "https://api.scryfall.com/cards/takh/8/en?format=image");
|
|
||||||
put("AKH/Oketra's Attendant", "https://api.scryfall.com/cards/takh/9/en?format=image");
|
|
||||||
put("AKH/Sacred Cat", "https://api.scryfall.com/cards/takh/10/en?format=image");
|
|
||||||
put("AKH/Tah-Crop Skirmisher", "https://api.scryfall.com/cards/takh/11/en?format=image");
|
|
||||||
put("AKH/Temmet, Vizier of Naktamun", "https://api.scryfall.com/cards/takh/12/en?format=image");
|
|
||||||
put("AKH/Trueheart Duelist", "https://api.scryfall.com/cards/takh/13/en?format=image");
|
|
||||||
put("AKH/Unwavering Initiate", "https://api.scryfall.com/cards/takh/14/en?format=image");
|
|
||||||
put("AKH/Vizier of Many Faces", "https://api.scryfall.com/cards/takh/15/en?format=image");
|
|
||||||
|
|
||||||
//AER
|
// AER
|
||||||
put("AER/Etherium Cell", "https://api.scryfall.com/cards/taer/3/en?format=image");
|
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/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/Ragavan", "https://api.scryfall.com/cards/taer/2/en?format=image");
|
||||||
put("AER/Emblem Tezzeret", "https://api.scryfall.com/cards/taer/4/en?format=image");
|
put("AER/Emblem Tezzeret", "https://api.scryfall.com/cards/taer/4/en?format=image");
|
||||||
|
|
||||||
//KLD
|
// KLD
|
||||||
put("KLD/Beast", "https://api.scryfall.com/cards/tkld/1/en?format=image");
|
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/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/1", "https://api.scryfall.com/cards/tkld/2/en?format=image");
|
||||||
|
|
@ -154,7 +139,7 @@ public class ScryfallImageSupportTokens {
|
||||||
put("KLD/Thopter/2", "https://api.scryfall.com/cards/tkld/8/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");
|
put("KLD/Thopter/3", "https://api.scryfall.com/cards/tkld/9/en?format=image");
|
||||||
|
|
||||||
//EMN
|
// EMN
|
||||||
put("EMN/Eldrazi Horror", "https://api.scryfall.com/cards/temn/1/en?format=image");
|
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", "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/Human Wizard", "https://api.scryfall.com/cards/temn/2/en?format=image");
|
||||||
|
|
@ -166,7 +151,7 @@ public class ScryfallImageSupportTokens {
|
||||||
put("EMN/Zombie/3", "https://api.scryfall.com/cards/temn/5/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");
|
put("EMN/Zombie/4", "https://api.scryfall.com/cards/temn/6/en?format=image");
|
||||||
|
|
||||||
//SOI
|
// SOI
|
||||||
put("SOI/Angel", "https://api.scryfall.com/cards/tsoi/1/en?format=image");
|
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/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/1", "https://api.scryfall.com/cards/tsoi/11/en?format=image");
|
||||||
|
|
@ -186,7 +171,7 @@ public class ScryfallImageSupportTokens {
|
||||||
put("SOI/Wolf", "https://api.scryfall.com/cards/tsoi/9/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");
|
put("SOI/Zombie", "https://api.scryfall.com/cards/tsoi/5/en?format=image");
|
||||||
|
|
||||||
//OGW
|
// OGW
|
||||||
put("OGW/Angel", "https://api.scryfall.com/cards/togw/7/en?format=image");
|
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/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/2", "https://api.scryfall.com/cards/togw/2/en?format=image");
|
||||||
|
|
@ -199,7 +184,7 @@ public class ScryfallImageSupportTokens {
|
||||||
put("OGW/Plant", "https://api.scryfall.com/cards/togw/11/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");
|
put("OGW/Zombie", "https://api.scryfall.com/cards/togw/8/en?format=image");
|
||||||
|
|
||||||
//BFZ
|
// BFZ
|
||||||
put("BFZ/Dragon", "https://api.scryfall.com/cards/tbfz/8/en?format=image");
|
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", "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/1", "https://api.scryfall.com/cards/tbfz/2/en?format=image");
|
||||||
|
|
@ -319,7 +304,7 @@ public class ScryfallImageSupportTokens {
|
||||||
put("C18/Worm", "https://api.scryfall.com/cards/tc18/18/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");
|
put("C18/Zombie", "https://api.scryfall.com/cards/tc18/9/en?format=image");
|
||||||
|
|
||||||
//C19
|
// C19
|
||||||
put("C19/Assassin", "https://api.scryfall.com/cards/tc19/9/en?format=image");
|
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/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/Beast/2", "https://api.scryfall.com/cards/tc19/14/en?format=image");
|
||||||
|
|
@ -501,7 +486,7 @@ public class ScryfallImageSupportTokens {
|
||||||
put("ZNC/Elemental/1", "https://api.scryfall.com/cards/tznc/10/en?format=image"); // 5/5
|
put("ZNC/Elemental/1", "https://api.scryfall.com/cards/tznc/10/en?format=image"); // 5/5
|
||||||
put("ZNC/Elemental/2", "https://api.scryfall.com/cards/tznc/8/en?format=image"); // 2/2
|
put("ZNC/Elemental/2", "https://api.scryfall.com/cards/tznc/8/en?format=image"); // 2/2
|
||||||
put("ZNC/Faerie Rogue", "https://api.scryfall.com/cards/tznc/3/en?format=image");
|
put("ZNC/Faerie Rogue", "https://api.scryfall.com/cards/tznc/3/en?format=image");
|
||||||
put("ZNC/Germ", "https://api.scryfall.com/cards/tznc/4/en?format=image"); // must be in chest or antology
|
put("ZNC/Phyrexian Germ", "https://api.scryfall.com/cards/tznc/4/en?format=image"); // must be in chest or antology
|
||||||
put("ZNC/Goblin Rogue", "https://api.scryfall.com/cards/tznc/5/en?format=image");
|
put("ZNC/Goblin Rogue", "https://api.scryfall.com/cards/tznc/5/en?format=image");
|
||||||
put("ZNC/Kor Ally", "https://api.scryfall.com/cards/tznc/2/en?format=image");
|
put("ZNC/Kor Ally", "https://api.scryfall.com/cards/tznc/2/en?format=image");
|
||||||
put("ZNC/Rat", "https://api.scryfall.com/cards/tznc/6/en?format=image");
|
put("ZNC/Rat", "https://api.scryfall.com/cards/tznc/6/en?format=image");
|
||||||
|
|
@ -596,7 +581,6 @@ public class ScryfallImageSupportTokens {
|
||||||
put("C21/Beast/1", "https://api.scryfall.com/cards/tc21/10/en?format=image"); // 3/3
|
put("C21/Beast/1", "https://api.scryfall.com/cards/tc21/10/en?format=image"); // 3/3
|
||||||
put("C21/Beast/2", "https://api.scryfall.com/cards/tc21/11/en?format=image"); // 4/4
|
put("C21/Beast/2", "https://api.scryfall.com/cards/tc21/11/en?format=image"); // 4/4
|
||||||
put("C21/Boar", "https://api.scryfall.com/cards/tc21/12/en?format=image");
|
put("C21/Boar", "https://api.scryfall.com/cards/tc21/12/en?format=image");
|
||||||
put("C21/Champion of Wits", "https://api.scryfall.com/cards/tc21/6/en?format=image");
|
|
||||||
put("C21/Construct/1", "https://api.scryfall.com/cards/tc21/22/en?format=image"); // x/x
|
put("C21/Construct/1", "https://api.scryfall.com/cards/tc21/22/en?format=image"); // x/x
|
||||||
put("C21/Construct/2", "https://api.scryfall.com/cards/tc21/23/en?format=image"); // 0/0
|
put("C21/Construct/2", "https://api.scryfall.com/cards/tc21/23/en?format=image"); // 0/0
|
||||||
put("C21/Demon", "https://api.scryfall.com/cards/tc21/7/en?format=image");
|
put("C21/Demon", "https://api.scryfall.com/cards/tc21/7/en?format=image");
|
||||||
|
|
@ -829,17 +813,45 @@ public class ScryfallImageSupportTokens {
|
||||||
put("NEC/Thopter", "https://api.scryfall.com/cards/tnec/12/en?format=image");
|
put("NEC/Thopter", "https://api.scryfall.com/cards/tnec/12/en?format=image");
|
||||||
|
|
||||||
// SLD
|
// SLD
|
||||||
|
put("SLD/Angel", "https://api.scryfall.com/cards/sld/1340?format=image");
|
||||||
|
put("SLD/Cat/1", "https://api.scryfall.com/cards/sld/1517?format=image");
|
||||||
|
put("SLD/Cat/2", "https://api.scryfall.com/cards/sld/27?format=image");
|
||||||
|
put("SLD/Cat/3", "https://api.scryfall.com/cards/sld/28?format=image");
|
||||||
put("SLD/Clue", "https://api.scryfall.com/cards/sld/348/en?format=image");
|
put("SLD/Clue", "https://api.scryfall.com/cards/sld/348/en?format=image");
|
||||||
|
put("SLD/Dog", "https://api.scryfall.com/cards/sld/1516?format=image");
|
||||||
|
put("SLD/Egg", "https://api.scryfall.com/cards/sld/1398?format=image");
|
||||||
put("SLD/Faerie Rogue/1", "https://api.scryfall.com/cards/sld/13/en?format=image");
|
put("SLD/Faerie Rogue/1", "https://api.scryfall.com/cards/sld/13/en?format=image");
|
||||||
put("SLD/Faerie Rogue/2", "https://api.scryfall.com/cards/sld/14/en?format=image");
|
put("SLD/Faerie Rogue/2", "https://api.scryfall.com/cards/sld/14/en?format=image");
|
||||||
put("SLD/Faerie Rogue/3", "https://api.scryfall.com/cards/sld/15/en?format=image");
|
put("SLD/Faerie Rogue/3", "https://api.scryfall.com/cards/sld/15/en?format=image");
|
||||||
put("SLD/Faerie Rogue/4", "https://api.scryfall.com/cards/sld/16/en?format=image");
|
put("SLD/Faerie Rogue/4", "https://api.scryfall.com/cards/sld/16/en?format=image");
|
||||||
put("SLD/Treasure", "https://api.scryfall.com/cards/sld/153/en?format=image");
|
put("SLD/Food/1", "https://api.scryfall.com/cards/sld/1938?format=image");
|
||||||
|
put("SLD/Food/2", "https://api.scryfall.com/cards/sld/2010?format=image");
|
||||||
|
put("SLD/Food/3", "https://api.scryfall.com/cards/sld/2011?format=image");
|
||||||
|
put("SLD/Food/4", "https://api.scryfall.com/cards/sld/2012?format=image");
|
||||||
|
put("SLD/Food/5", "https://api.scryfall.com/cards/sld/2013?format=image");
|
||||||
|
put("SLD/Goblin", "https://api.scryfall.com/cards/sld/219?format=image");
|
||||||
|
put("SLD/Hydra", "https://api.scryfall.com/cards/sld/1334?format=image");
|
||||||
|
put("SLD/Icingdeath, Frost Tongue", "https://api.scryfall.com/cards/sld/1018?format=image");
|
||||||
|
put("SLD/Marit Lage", "https://api.scryfall.com/cards/sld/1681?format=image");
|
||||||
|
put("SLD/Mechtitan", "https://api.scryfall.com/cards/sld/1969?format=image");
|
||||||
|
put("SLD/Saproling", "https://api.scryfall.com/cards/sld/1139?format=image");
|
||||||
|
put("SLD/Shrine", "https://api.scryfall.com/cards/sld/1835?format=image");
|
||||||
|
put("SLD/Spirit/1", "https://api.scryfall.com/cards/sld/1341?format=image");
|
||||||
|
put("SLD/Spirit/2", "https://api.scryfall.com/cards/sld/1852?format=image");
|
||||||
|
put("SLD/Squirrel", "https://api.scryfall.com/cards/sld/200?format=image");
|
||||||
|
put("SLD/Treasure/1", "https://api.scryfall.com/cards/sld/1432/en?format=image");
|
||||||
|
put("SLD/Treasure/2", "https://api.scryfall.com/cards/sld/1736/en?format=image");
|
||||||
|
put("SLD/Treasure/3", "https://api.scryfall.com/cards/sld/1507/en?format=image");
|
||||||
|
put("SLD/Treasure/4", "https://api.scryfall.com/cards/sld/153/en?format=image");
|
||||||
put("SLD/Walker/1", "https://api.scryfall.com/cards/sld/148/en?format=image");
|
put("SLD/Walker/1", "https://api.scryfall.com/cards/sld/148/en?format=image");
|
||||||
put("SLD/Walker/2", "https://api.scryfall.com/cards/sld/149/en?format=image");
|
put("SLD/Walker/2", "https://api.scryfall.com/cards/sld/149/en?format=image");
|
||||||
put("SLD/Walker/3", "https://api.scryfall.com/cards/sld/150/en?format=image");
|
put("SLD/Walker/3", "https://api.scryfall.com/cards/sld/150/en?format=image");
|
||||||
put("SLD/Walker/4", "https://api.scryfall.com/cards/sld/151/en?format=image");
|
put("SLD/Walker/4", "https://api.scryfall.com/cards/sld/151/en?format=image");
|
||||||
put("SLD/Walker/5", "https://api.scryfall.com/cards/sld/152/en?format=image");
|
put("SLD/Walker/5", "https://api.scryfall.com/cards/sld/152/en?format=image");
|
||||||
|
put("SLD/Warrior", "https://api.scryfall.com/cards/sld/1752?format=image");
|
||||||
|
put("SLD/Wolf", "https://api.scryfall.com/cards/sld/1613?format=image");
|
||||||
|
put("SLD/Wurm", "https://api.scryfall.com/cards/sld/1306?format=image");
|
||||||
|
put("SLD/Zombie", "https://api.scryfall.com/cards/sld/1357?format=image");
|
||||||
|
|
||||||
// 2XM
|
// 2XM
|
||||||
put("2XM/Angel", "https://api.scryfall.com/cards/t2xm/3/en?format=image");
|
put("2XM/Angel", "https://api.scryfall.com/cards/t2xm/3/en?format=image");
|
||||||
|
|
@ -1707,6 +1719,7 @@ public class ScryfallImageSupportTokens {
|
||||||
put("CLB/Squid", "https://api.scryfall.com/cards/tclb/29/en?format=image");
|
put("CLB/Squid", "https://api.scryfall.com/cards/tclb/29/en?format=image");
|
||||||
put("CLB/Squirrel", "https://api.scryfall.com/cards/tclb/15/en?format=image");
|
put("CLB/Squirrel", "https://api.scryfall.com/cards/tclb/15/en?format=image");
|
||||||
put("CLB/Treasure", "https://api.scryfall.com/cards/tclb/17/en?format=image");
|
put("CLB/Treasure", "https://api.scryfall.com/cards/tclb/17/en?format=image");
|
||||||
|
put("CLB/Undercity", "https://api.scryfall.com/cards/tclb/20/en?format=image");
|
||||||
put("CLB/Volo's Journal", "https://api.scryfall.com/cards/tclb/18/en?format=image");
|
put("CLB/Volo's Journal", "https://api.scryfall.com/cards/tclb/18/en?format=image");
|
||||||
put("CLB/Warrior", "https://api.scryfall.com/cards/tclb/32/en?format=image");
|
put("CLB/Warrior", "https://api.scryfall.com/cards/tclb/32/en?format=image");
|
||||||
put("CLB/Emblem Will Kenrith", "https://api.scryfall.com/cards/tclb/50/en?format=image");
|
put("CLB/Emblem Will Kenrith", "https://api.scryfall.com/cards/tclb/50/en?format=image");
|
||||||
|
|
@ -2167,11 +2180,36 @@ public class ScryfallImageSupportTokens {
|
||||||
put("WOC/Spirit", "https://api.scryfall.com/cards/twoc/17/en?format=image");
|
put("WOC/Spirit", "https://api.scryfall.com/cards/twoc/17/en?format=image");
|
||||||
put("WOC/Virtuous", "https://api.scryfall.com/cards/twoc/3/en?format=image");
|
put("WOC/Virtuous", "https://api.scryfall.com/cards/twoc/3/en?format=image");
|
||||||
|
|
||||||
//WHO
|
// WHO
|
||||||
|
put("WHO/Alien", "https://api.scryfall.com/cards/twho/2?format=image");
|
||||||
put("WHO/Alien Insect", "https://api.scryfall.com/cards/twho/19/en?format=image");
|
put("WHO/Alien Insect", "https://api.scryfall.com/cards/twho/19/en?format=image");
|
||||||
|
put("WHO/Alien Rhino", "https://api.scryfall.com/cards/twho/3/en?format=image");
|
||||||
|
put("WHO/Alien Salamander", "https://api.scryfall.com/cards/twho/16?format=image");
|
||||||
|
put("WHO/Alien Warrior", "https://api.scryfall.com/cards/twho/14?format=image");
|
||||||
|
put("WHO/Beast", "https://api.scryfall.com/cards/twho/17?format=image");
|
||||||
|
put("WHO/Clue/1", "https://api.scryfall.com/cards/twho/21?format=image");
|
||||||
|
put("WHO/Clue/2", "https://api.scryfall.com/cards/twho/22?format=image");
|
||||||
|
put("WHO/Clue/3", "https://api.scryfall.com/cards/twho/23?format=image");
|
||||||
|
put("WHO/Dalek", "https://api.scryfall.com/cards/twho/12?format=image");
|
||||||
|
put("WHO/Dinosaur", "https://api.scryfall.com/cards/twho/20?format=image");
|
||||||
|
put("WHO/Fish", "https://api.scryfall.com/cards/twho/10?format=image");
|
||||||
|
put("WHO/Food/1", "https://api.scryfall.com/cards/twho/25?format=image");
|
||||||
|
put("WHO/Food/2", "https://api.scryfall.com/cards/twho/26?format=image");
|
||||||
|
put("WHO/Food/3", "https://api.scryfall.com/cards/twho/27?format=image");
|
||||||
|
put("WHO/Horse", "https://api.scryfall.com/cards/twho/4/en?format=image");
|
||||||
|
put("WHO/Human/1", "https://api.scryfall.com/cards/twho/6/en?format=image");
|
||||||
|
put("WHO/Human/2", "https://api.scryfall.com/cards/twho/5/en?format=image");
|
||||||
|
put("WHO/Human Noble", "https://api.scryfall.com/cards/twho/7/en?format=image");
|
||||||
|
put("WHO/Mark of the Rani", "https://api.scryfall.com/cards/twho/15?format=image");
|
||||||
|
put("WHO/Soldier", "https://api.scryfall.com/cards/twho/8?format=image");
|
||||||
|
put("WHO/Treasure/1", "https://api.scryfall.com/cards/twho/28?format=image");
|
||||||
|
put("WHO/Treasure/2", "https://api.scryfall.com/cards/twho/29?format=image");
|
||||||
|
put("WHO/Treasure/3", "https://api.scryfall.com/cards/twho/30?format=image");
|
||||||
|
put("WHO/Treasure/4", "https://api.scryfall.com/cards/twho/31?format=image");
|
||||||
|
put("WHO/Warrior", "https://api.scryfall.com/cards/twho/9?format=image");
|
||||||
|
|
||||||
// 8ED
|
// 8ED
|
||||||
put("8ED/Rukh", "https://api.scryfall.com/cards/p03/7/en?format=image");
|
put("8ED/Bird", "https://api.scryfall.com/cards/p03/7/en?format=image");
|
||||||
|
|
||||||
// LCI
|
// LCI
|
||||||
put("LCI/Angel", "https://api.scryfall.com/cards/tlci/2/en?format=image");
|
put("LCI/Angel", "https://api.scryfall.com/cards/tlci/2/en?format=image");
|
||||||
|
|
@ -2455,7 +2493,348 @@ public class ScryfallImageSupportTokens {
|
||||||
put("BLB/Wall", "https://api.scryfall.com/cards/tblb/4/en?format=image");
|
put("BLB/Wall", "https://api.scryfall.com/cards/tblb/4/en?format=image");
|
||||||
|
|
||||||
// BLC
|
// BLC
|
||||||
|
put("BLC/Beast/1", "https://api.scryfall.com/cards/tblc/24/en?format=image");
|
||||||
|
put("BLC/Beast/2", "https://api.scryfall.com/cards/tblc/25/en?format=image");
|
||||||
|
put("BLC/Bird/1", "https://api.scryfall.com/cards/tblc/11/en?format=image");
|
||||||
|
put("BLC/Bird/2", "https://api.scryfall.com/cards/tblc/3/en?format=image");
|
||||||
|
put("BLC/Blood", "https://api.scryfall.com/cards/tblc/36/en?format=image");
|
||||||
|
put("BLC/Cat", "https://api.scryfall.com/cards/tblc/26/en?format=image");
|
||||||
|
put("BLC/Citizen", "https://api.scryfall.com/cards/tblc/33/en?format=image");
|
||||||
|
put("BLC/Clue", "https://api.scryfall.com/cards/tblc/37/en?format=image");
|
||||||
|
put("BLC/Eldrazi", "https://api.scryfall.com/cards/tblc/2/en?format=image");
|
||||||
|
put("BLC/Elemental", "https://api.scryfall.com/cards/tblc/4/en?format=image");
|
||||||
|
put("BLC/Elephant", "https://api.scryfall.com/cards/tblc/27/en?format=image");
|
||||||
|
put("BLC/Faerie", "https://api.scryfall.com/cards/tblc/12/en?format=image");
|
||||||
|
put("BLC/Frog Lizard", "https://api.scryfall.com/cards/tblc/28/en?format=image");
|
||||||
|
put("BLC/Goat", "https://api.scryfall.com/cards/tblc/5/en?format=image");
|
||||||
|
put("BLC/Goblin", "https://api.scryfall.com/cards/tblc/21/en?format=image");
|
||||||
|
put("BLC/Hamster", "https://api.scryfall.com/cards/tblc/22/en?format=image");
|
||||||
|
put("BLC/Human", "https://api.scryfall.com/cards/tblc/6/en?format=image");
|
||||||
|
put("BLC/Human Soldier", "https://api.scryfall.com/cards/tblc/7/en?format=image");
|
||||||
|
put("BLC/Illusion", "https://api.scryfall.com/cards/tblc/13/en?format=image");
|
||||||
|
put("BLC/Octopus", "https://api.scryfall.com/cards/tblc/14/en?format=image");
|
||||||
|
put("BLC/Pest", "https://api.scryfall.com/cards/tblc/34/en?format=image");
|
||||||
|
put("BLC/Phyrexian Golem", "https://api.scryfall.com/cards/tblc/38/en?format=image");
|
||||||
put("BLC/Raccoon", "https://api.scryfall.com/cards/tblc/29/en?format=image");
|
put("BLC/Raccoon", "https://api.scryfall.com/cards/tblc/29/en?format=image");
|
||||||
|
put("BLC/Rat", "https://api.scryfall.com/cards/tblc/19/en?format=image");
|
||||||
|
put("BLC/Saproling", "https://api.scryfall.com/cards/tblc/30/en?format=image");
|
||||||
|
put("BLC/Shapeshifter", "https://api.scryfall.com/cards/tblc/15/en?format=image");
|
||||||
|
put("BLC/Shark", "https://api.scryfall.com/cards/tblc/16/en?format=image");
|
||||||
|
put("BLC/Soldier", "https://api.scryfall.com/cards/tblc/8/en?format=image");
|
||||||
|
put("BLC/Spider", "https://api.scryfall.com/cards/tblc/31/en?format=image");
|
||||||
|
put("BLC/Spirit", "https://api.scryfall.com/cards/tblc/9/en?format=image");
|
||||||
|
put("BLC/Squid", "https://api.scryfall.com/cards/tblc/17/en?format=image");
|
||||||
|
put("BLC/Storm Crow", "https://api.scryfall.com/cards/tblc/18/en?format=image");
|
||||||
|
put("BLC/Thopter", "https://api.scryfall.com/cards/tblc/39/en?format=image");
|
||||||
|
put("BLC/Wolf/1", "https://api.scryfall.com/cards/tblc/35/en?format=image");
|
||||||
|
put("BLC/Wolf/2", "https://api.scryfall.com/cards/tblc/32/en?format=image");
|
||||||
|
|
||||||
|
// DSK
|
||||||
|
put("DSK/Beast", "https://api.scryfall.com/cards/tdsk/3?format=image");
|
||||||
|
put("DSK/Emblem Kaito", "https://api.scryfall.com/cards/tdsk/17/en?format=image");
|
||||||
|
put("DSK/Everywhere", "https://api.scryfall.com/cards/tdsk/16?format=image");
|
||||||
|
put("DSK/Glimmer", "https://api.scryfall.com/cards/tdsk/4?format=image");
|
||||||
|
put("DSK/Gremlin", "https://api.scryfall.com/cards/tdsk/11?format=image");
|
||||||
|
put("DSK/Insect/1", "https://api.scryfall.com/cards/tdsk/13?format=image");
|
||||||
|
put("DSK/Insect/2", "https://api.scryfall.com/cards/tdsk/5?format=image");
|
||||||
|
put("DSK/Primo, the Indivisible", "https://api.scryfall.com/cards/tdsk/14?format=image");
|
||||||
|
put("DSK/Shard", "https://api.scryfall.com/cards/tdsk/2?format=image");
|
||||||
|
put("DSK/Spider", "https://api.scryfall.com/cards/tdsk/12?format=image");
|
||||||
|
put("DSK/Spirit", "https://api.scryfall.com/cards/tdsk/8?format=image");
|
||||||
|
put("DSK/Treasure", "https://api.scryfall.com/cards/tdsk/15?format=image");
|
||||||
|
|
||||||
|
// DSC
|
||||||
|
put("DSC/Angel", "https://api.scryfall.com/cards/tdsc/2/en?format=image");
|
||||||
|
put("DSC/Beast", "https://api.scryfall.com/cards/tdsc/8/en?format=image");
|
||||||
|
put("DSC/Bird", "https://api.scryfall.com/cards/tdsc/5/en?format=image");
|
||||||
|
put("DSC/Demon", "https://api.scryfall.com/cards/tdsc/6/en?format=image");
|
||||||
|
put("DSC/Devil", "https://api.scryfall.com/cards/tdsc/7/en?format=image");
|
||||||
|
put("DSC/Elemental", "https://api.scryfall.com/cards/tdsc/9/en?format=image");
|
||||||
|
put("DSC/Fractal", "https://api.scryfall.com/cards/tdsc/20/en?format=image");
|
||||||
|
put("DSC/Human Soldier", "https://api.scryfall.com/cards/tdsc/3/en?format=image");
|
||||||
|
put("DSC/Inkling", "https://api.scryfall.com/cards/tdsc/21/en?format=image");
|
||||||
|
put("DSC/Insect/1", "https://api.scryfall.com/cards/tdsc/22/en?format=image");
|
||||||
|
put("DSC/Insect/2", "https://api.scryfall.com/cards/tdsc/10/en?format=image");
|
||||||
|
put("DSC/Insect/3", "https://api.scryfall.com/cards/tdsc/11/en?format=image");
|
||||||
|
put("DSC/Insect/4", "https://api.scryfall.com/cards/tdsc/12/en?format=image");
|
||||||
|
put("DSC/Ooze/1", "https://api.scryfall.com/cards/tdsc/14/en?format=image");
|
||||||
|
put("DSC/Ooze/2", "https://api.scryfall.com/cards/tdsc/13/en?format=image");
|
||||||
|
put("DSC/Phyrexian Beast", "https://api.scryfall.com/cards/tdsc/15/en?format=image");
|
||||||
|
put("DSC/Shapeshifter", "https://api.scryfall.com/cards/tdsc/1/en?format=image");
|
||||||
|
put("DSC/Shark", "https://api.scryfall.com/cards/tdsc/4/en?format=image");
|
||||||
|
put("DSC/Spider", "https://api.scryfall.com/cards/tdsc/16/en?format=image");
|
||||||
|
put("DSC/Treefolk", "https://api.scryfall.com/cards/tdsc/17/en?format=image");
|
||||||
|
put("DSC/Wurm/1", "https://api.scryfall.com/cards/tdsc/18/en?format=image");
|
||||||
|
put("DSC/Wurm/2", "https://api.scryfall.com/cards/tdsc/19/en?format=image");
|
||||||
|
|
||||||
|
// FDN
|
||||||
|
put("FDN/Beast/1", "https://api.scryfall.com/cards/tfdn/32/en?format=image");
|
||||||
|
put("FDN/Beast/2", "https://api.scryfall.com/cards/tfdn/33/en?format=image");
|
||||||
|
put("FDN/Cat/1", "https://api.scryfall.com/cards/tfdn/1/en?format=image");
|
||||||
|
put("FDN/Cat/2", "https://api.scryfall.com/cards/tfdn/27/en?format=image");
|
||||||
|
put("FDN/Cat/3", "https://api.scryfall.com/cards/tfdn/2/en?format=image");
|
||||||
|
put("FDN/Cat Beast", "https://api.scryfall.com/cards/tfdn/28/en?format=image");
|
||||||
|
put("FDN/Dog", "https://api.scryfall.com/cards/tfdn/29/en?format=image");
|
||||||
|
put("FDN/Dragon/1", "https://api.scryfall.com/cards/tfdn/16/en?format=image");
|
||||||
|
put("FDN/Dragon/2", "https://api.scryfall.com/cards/tfdn/17/en?format=image");
|
||||||
|
put("FDN/Drake", "https://api.scryfall.com/cards/tfdn/8/en?format=image");
|
||||||
|
put("FDN/Elf Warrior", "https://api.scryfall.com/cards/tfdn/19/en?format=image");
|
||||||
|
put("FDN/Faerie", "https://api.scryfall.com/cards/tfdn/9/en?format=image");
|
||||||
|
put("FDN/Fish", "https://api.scryfall.com/cards/tfdn/10/en?format=image");
|
||||||
|
put("FDN/Food", "https://api.scryfall.com/cards/tfdn/22/en?format=image");
|
||||||
|
put("FDN/Goblin", "https://api.scryfall.com/cards/tfdn/18/en?format=image");
|
||||||
|
put("FDN/Human", "https://api.scryfall.com/cards/tfdn/3/en?format=image");
|
||||||
|
put("FDN/Insect", "https://api.scryfall.com/cards/tfdn/21/en?format=image");
|
||||||
|
put("FDN/Emblem Kaito", "https://api.scryfall.com/cards/tfdn/24/en?format=image");
|
||||||
|
put("FDN/Knight", "https://api.scryfall.com/cards/tfdn/4/en?format=image");
|
||||||
|
put("FDN/Koma's Coil", "https://api.scryfall.com/cards/tfdn/11/en?format=image");
|
||||||
|
put("FDN/Ninja", "https://api.scryfall.com/cards/tfdn/12/en?format=image");
|
||||||
|
put("FDN/Phyrexian Goblin", "https://api.scryfall.com/cards/tfdn/31/en?format=image");
|
||||||
|
put("FDN/Rabbit", "https://api.scryfall.com/cards/tfdn/5/en?format=image");
|
||||||
|
put("FDN/Raccoon", "https://api.scryfall.com/cards/tfdn/20/en?format=image");
|
||||||
|
put("FDN/Rat/1", "https://api.scryfall.com/cards/tfdn/14/en?format=image");
|
||||||
|
put("FDN/Rat/2", "https://api.scryfall.com/cards/tfdn/30/en?format=image");
|
||||||
|
put("FDN/Scion of the Deep", "https://api.scryfall.com/cards/tfdn/13/en?format=image");
|
||||||
|
put("FDN/Soldier", "https://api.scryfall.com/cards/tfdn/6/en?format=image");
|
||||||
|
put("FDN/Spirit", "https://api.scryfall.com/cards/tfdn/7/en?format=image");
|
||||||
|
put("FDN/Treasure", "https://api.scryfall.com/cards/tfdn/23/en?format=image");
|
||||||
|
put("FDN/Emblem Vivien", "https://api.scryfall.com/cards/tfdn/25/en?format=image");
|
||||||
|
put("FDN/Zombie", "https://api.scryfall.com/cards/tfdn/15/en?format=image");
|
||||||
|
|
||||||
|
// H17
|
||||||
|
put("H17/Dragon", "https://api.scryfall.com/cards/h17/4/en?format=image");
|
||||||
|
|
||||||
|
// INR
|
||||||
|
put("INR/Emblem Arlinn", "https://api.scryfall.com/cards/tinr/23/en?format=image");
|
||||||
|
put("INR/Blood", "https://api.scryfall.com/cards/tinr/21/en?format=image");
|
||||||
|
put("INR/Emblem Chandra", "https://api.scryfall.com/cards/tinr/24/en?format=image");
|
||||||
|
put("INR/Clue", "https://api.scryfall.com/cards/tinr/22/en?format=image");
|
||||||
|
put("INR/Demon", "https://api.scryfall.com/cards/tinr/6/en?format=image");
|
||||||
|
put("INR/Eldrazi Horror", "https://api.scryfall.com/cards/tinr/1/en?format=image");
|
||||||
|
put("INR/Elemental", "https://api.scryfall.com/cards/tinr/13/en?format=image");
|
||||||
|
put("INR/Human/1", "https://api.scryfall.com/cards/tinr/14/en?format=image");
|
||||||
|
put("INR/Human/2", "https://api.scryfall.com/cards/tinr/2/en?format=image");
|
||||||
|
put("INR/Human Cleric", "https://api.scryfall.com/cards/tinr/19/en?format=image");
|
||||||
|
put("INR/Human Soldier/1", "https://api.scryfall.com/cards/tinr/3/en?format=image");
|
||||||
|
put("INR/Human Soldier/2", "https://api.scryfall.com/cards/tinr/20/en?format=image");
|
||||||
|
put("INR/Human Wizard", "https://api.scryfall.com/cards/tinr/5/en?format=image");
|
||||||
|
put("INR/Insect", "https://api.scryfall.com/cards/tinr/15/en?format=image");
|
||||||
|
put("INR/Emblem Jace", "https://api.scryfall.com/cards/tinr/25/en?format=image");
|
||||||
|
put("INR/Spider", "https://api.scryfall.com/cards/tinr/16/en?format=image");
|
||||||
|
put("INR/Spirit", "https://api.scryfall.com/cards/tinr/4/en?format=image");
|
||||||
|
put("INR/Emblem Tamiyo", "https://api.scryfall.com/cards/tinr/26/en?format=image");
|
||||||
|
put("INR/Treefolk", "https://api.scryfall.com/cards/tinr/17/en?format=image");
|
||||||
|
put("INR/Vampire/1", "https://api.scryfall.com/cards/tinr/7/en?format=image");
|
||||||
|
put("INR/Vampire/2", "https://api.scryfall.com/cards/tinr/8/en?format=image");
|
||||||
|
put("INR/Wolf/1", "https://api.scryfall.com/cards/tinr/9/en?format=image");
|
||||||
|
put("INR/Wolf/2", "https://api.scryfall.com/cards/tinr/18/en?format=image");
|
||||||
|
put("INR/Emblem Wrenn", "https://api.scryfall.com/cards/tinr/27/en?format=image");
|
||||||
|
put("INR/Zombie/1", "https://api.scryfall.com/cards/tinr/12/en?format=image");
|
||||||
|
put("INR/Zombie/2", "https://api.scryfall.com/cards/tinr/10/en?format=image");
|
||||||
|
put("INR/Zombie/3", "https://api.scryfall.com/cards/tinr/11/en?format=image");
|
||||||
|
|
||||||
|
// DFT
|
||||||
|
put("DFT/Cat", "https://api.scryfall.com/cards/tdft/2/en?format=image");
|
||||||
|
put("DFT/Emblem Chandra", "https://api.scryfall.com/cards/tdft/13/en?format=image");
|
||||||
|
put("DFT/Dinosaur Dragon", "https://api.scryfall.com/cards/tdft/4/en?format=image");
|
||||||
|
put("DFT/Elephant", "https://api.scryfall.com/cards/tdft/6/en?format=image");
|
||||||
|
put("DFT/Goblin", "https://api.scryfall.com/cards/tdft/5/en?format=image");
|
||||||
|
put("DFT/Insect", "https://api.scryfall.com/cards/tdft/7/en?format=image");
|
||||||
|
put("DFT/Pilot", "https://api.scryfall.com/cards/tdft/1/en?format=image");
|
||||||
|
put("DFT/Servo", "https://api.scryfall.com/cards/tdft/8/en?format=image");
|
||||||
|
put("DFT/Thopter/1", "https://api.scryfall.com/cards/tdft/9/en?format=image");
|
||||||
|
put("DFT/Thopter/2", "https://api.scryfall.com/cards/tdft/10/en?format=image");
|
||||||
|
put("DFT/Treasure", "https://api.scryfall.com/cards/tdft/11/en?format=image");
|
||||||
|
put("DFT/Vehicle", "https://api.scryfall.com/cards/tdft/12/en?format=image");
|
||||||
|
put("DFT/Zombie", "https://api.scryfall.com/cards/tdft/3/en?format=image");
|
||||||
|
|
||||||
|
// DRC
|
||||||
|
put("DRC/Beast/1", "https://api.scryfall.com/cards/tdrc/10/en?format=image");
|
||||||
|
put("DRC/Beast/2", "https://api.scryfall.com/cards/tdrc/11/en?format=image");
|
||||||
|
put("DRC/Construct", "https://api.scryfall.com/cards/tdrc/12/en?format=image");
|
||||||
|
put("DRC/Golem/1", "https://api.scryfall.com/cards/tdrc/13/en?format=image");
|
||||||
|
put("DRC/Golem/2", "https://api.scryfall.com/cards/tdrc/14/en?format=image");
|
||||||
|
put("DRC/Golem/3", "https://api.scryfall.com/cards/tdrc/15/en?format=image");
|
||||||
|
put("DRC/Nalaar Aetherjet", "https://api.scryfall.com/cards/tdrc/16/en?format=image");
|
||||||
|
put("DRC/Shapeshifter", "https://api.scryfall.com/cards/tdrc/4/en?format=image");
|
||||||
|
put("DRC/Zombie/1", "https://api.scryfall.com/cards/tdrc/3/en?format=image");
|
||||||
|
put("DRC/Zombie/2", "https://api.scryfall.com/cards/tdrc/7/en?format=image");
|
||||||
|
put("DRC/Zombie Army", "https://api.scryfall.com/cards/tdrc/8/en?format=image");
|
||||||
|
put("DRC/Zombie Warrior", "https://api.scryfall.com/cards/tdrc/9/en?format=image");
|
||||||
|
|
||||||
|
// TDM
|
||||||
|
put("TDM/Bird", "https://api.scryfall.com/cards/ttdm/2/en?format=image");
|
||||||
|
put("TDM/Dragon", "https://api.scryfall.com/cards/ttdm/11/en?format=image");
|
||||||
|
put("TDM/Elephant", "https://api.scryfall.com/cards/ttdm/14/en?format=image");
|
||||||
|
put("TDM/Goblin", "https://api.scryfall.com/cards/ttdm/12/en?format=image");
|
||||||
|
put("TDM/Monk", "https://api.scryfall.com/cards/ttdm/3/en?format=image");
|
||||||
|
put("TDM/Reliquary Dragon", "https://api.scryfall.com/cards/ttdm/15/en?format=image");
|
||||||
|
put("TDM/Soldier/1", "https://api.scryfall.com/cards/ttdm/4/en?format=image");
|
||||||
|
put("TDM/Soldier/2", "https://api.scryfall.com/cards/ttdm/5/en?format=image");
|
||||||
|
put("TDM/Spirit/1", "https://api.scryfall.com/cards/ttdm/9/en?format=image");
|
||||||
|
put("TDM/Spirit/2", "https://api.scryfall.com/cards/ttdm/6/en?format=image");
|
||||||
|
// TODO: 2/2 and 3/3 Spirit tokens (no relevant cards revealed, token not implemented)
|
||||||
|
put("TDM/Treasure", "https://api.scryfall.com/cards/ttdm/16/en?format=image");
|
||||||
|
put("TDM/Warrior", "https://api.scryfall.com/cards/ttdm/13/en?format=image");
|
||||||
|
put("TDM/Zombie Druid", "https://api.scryfall.com/cards/ttdm/10/en?format=image");
|
||||||
|
|
||||||
|
// TDC
|
||||||
|
put("TDC/Angel", "https://api.scryfall.com/cards/ttdc/2/en?format=image");
|
||||||
|
put("TDC/Beast", "https://api.scryfall.com/cards/ttdc/20?format=image");
|
||||||
|
put("TDC/Citizen", "https://api.scryfall.com/cards/ttdc/26/en?format=image");
|
||||||
|
put("TDC/Dog", "https://api.scryfall.com/cards/ttdc/3/en?format=image");
|
||||||
|
put("TDC/Dragon/1", "https://api.scryfall.com/cards/ttdc/13?format=image");
|
||||||
|
put("TDC/Dragon/2", "https://api.scryfall.com/cards/ttdc/14?format=image");
|
||||||
|
put("TDC/Dragon Egg", "https://api.scryfall.com/cards/ttdc/12?format=image");
|
||||||
|
put("TDC/Dragon Illusion", "https://api.scryfall.com/cards/ttdc/15/en?format=image");
|
||||||
|
put("TDC/Eldrazi", "https://api.scryfall.com/cards/ttdc/1/en?format=image");
|
||||||
|
put("TDC/Elemental/1", "https://api.scryfall.com/cards/ttdc/16/en?format=image");
|
||||||
|
put("TDC/Elemental/2", "https://api.scryfall.com/cards/ttdc/17/en?format=image");
|
||||||
|
put("TDC/Elemental/3", "https://api.scryfall.com/cards/ttdc/27/en?format=image");
|
||||||
|
put("TDC/First Mate Ragavan", "https://api.scryfall.com/cards/ttdc/18/en?format=image");
|
||||||
|
put("TDC/Frog Lizard", "https://api.scryfall.com/cards/ttdc/21?format=image");
|
||||||
|
put("TDC/Goat", "https://api.scryfall.com/cards/ttdc/4/en?format=image");
|
||||||
|
put("TDC/Gold", "https://api.scryfall.com/cards/ttdc/29/en?format=image");
|
||||||
|
put("TDC/Human", "https://api.scryfall.com/cards/ttdc/5/en?format=image");
|
||||||
|
put("TDC/Inkling", "https://api.scryfall.com/cards/ttdc/28?format=image");
|
||||||
|
put("TDC/Insect", "https://api.scryfall.com/cards/ttdc/22/en?format=image");
|
||||||
|
put("TDC/Karox Bladewing", "https://api.scryfall.com/cards/ttdc/19?format=image");
|
||||||
|
put("TDC/Myr", "https://api.scryfall.com/cards/ttdc/30/en?format=image");
|
||||||
|
put("TDC/Plant", "https://api.scryfall.com/cards/ttdc/24/en?format=image");
|
||||||
|
put("TDC/Rat", "https://api.scryfall.com/cards/ttdc/9/en?format=image");
|
||||||
|
put("TDC/Salamander Warrior", "https://api.scryfall.com/cards/ttdc/8/en?format=image");
|
||||||
|
put("TDC/Servo", "https://api.scryfall.com/cards/ttdc/31/en?format=image");
|
||||||
|
put("TDC/Snake", "https://api.scryfall.com/cards/ttdc/10/en?format=image");
|
||||||
|
put("TDC/Soldier", "https://api.scryfall.com/cards/ttdc/32/en?format=image");
|
||||||
|
put("TDC/Spider", "https://api.scryfall.com/cards/ttdc/25?format=image");
|
||||||
|
put("TDC/Spirit", "https://api.scryfall.com/cards/ttdc/6/en?format=image");
|
||||||
|
put("TDC/Thopter", "https://api.scryfall.com/cards/ttdc/33/en?format=image");
|
||||||
|
|
||||||
|
// ACR
|
||||||
|
put("ACR/Assassin", "https://api.scryfall.com/cards/tacr/4?format=image");
|
||||||
|
put("ACR/Emblem Capitoline Triad", "https://api.scryfall.com/cards/tacr/7/en?format=image");
|
||||||
|
put("ACR/Human Rogue", "https://api.scryfall.com/cards/tacr/3?format=image");
|
||||||
|
put("ACR/Phobos", "https://api.scryfall.com/cards/tacr/5?format=image");
|
||||||
|
put("ACR/Shapeshifter", "https://api.scryfall.com/cards/tacr/2?format=image");
|
||||||
|
put("ACR/Treasure", "https://api.scryfall.com/cards/tacr/6?format=image");
|
||||||
|
|
||||||
|
// DD2
|
||||||
|
put("DD2/Elemental Shaman", "https://api.scryfall.com/cards/tdd2/1?format=image");
|
||||||
|
|
||||||
|
// FIN
|
||||||
|
put("FIN/Food", "https://api.scryfall.com/cards/tfin/22?format=image");
|
||||||
|
|
||||||
|
// JVC
|
||||||
|
put("JVC/Elemental Shaman", "https://api.scryfall.com/cards/tjvc/4?format=image");
|
||||||
|
|
||||||
|
// PIP
|
||||||
|
put("PIP/Alien", "https://api.scryfall.com/cards/tpip/6?format=image");
|
||||||
|
put("PIP/Clue", "https://api.scryfall.com/cards/tpip/11?format=image");
|
||||||
|
put("PIP/Food/1", "https://api.scryfall.com/cards/tpip/12?format=image");
|
||||||
|
put("PIP/Food/2", "https://api.scryfall.com/cards/tpip/13?format=image");
|
||||||
|
put("PIP/Food/3", "https://api.scryfall.com/cards/tpip/14?format=image");
|
||||||
|
put("PIP/Human Knight", "https://api.scryfall.com/cards/tpip/2?format=image");
|
||||||
|
put("PIP/Human Soldier", "https://api.scryfall.com/cards/tpip/3?format=image");
|
||||||
|
put("PIP/Junk", "https://api.scryfall.com/cards/tpip/15?format=image");
|
||||||
|
put("PIP/Robot", "https://api.scryfall.com/cards/tpip/16?format=image");
|
||||||
|
put("PIP/Settlement", "https://api.scryfall.com/cards/tpip/8?format=image");
|
||||||
|
put("PIP/Soldier/1", "https://api.scryfall.com/cards/tpip/10?format=image");
|
||||||
|
put("PIP/Soldier/2", "https://api.scryfall.com/cards/tpip/4?format=image");
|
||||||
|
put("PIP/Squirrel", "https://api.scryfall.com/cards/tpip/9?format=image");
|
||||||
|
put("PIP/Thopter", "https://api.scryfall.com/cards/tpip/17?format=image");
|
||||||
|
put("PIP/Treasure/1", "https://api.scryfall.com/cards/tpip/18?format=image");
|
||||||
|
put("PIP/Treasure/2", "https://api.scryfall.com/cards/tpip/19?format=image");
|
||||||
|
put("PIP/Warrior", "https://api.scryfall.com/cards/tpip/5?format=image");
|
||||||
|
put("PIP/Wasteland Survival Guide", "https://api.scryfall.com/cards/tpip/20?format=image");
|
||||||
|
put("PIP/Zombie Mutant", "https://api.scryfall.com/cards/tpip/7?format=image");
|
||||||
|
|
||||||
|
// REX
|
||||||
|
put("REX/Dinosaur", "https://api.scryfall.com/cards/trex/1?format=image");
|
||||||
|
put("REX/Treasure", "https://api.scryfall.com/cards/trex/2?format=image");
|
||||||
|
|
||||||
|
// UGL
|
||||||
|
put("UGL/Goblin", "https://api.scryfall.com/cards/tugl/4?format=image");
|
||||||
|
put("UGL/Pegasus", "https://api.scryfall.com/cards/tugl/1?format=image");
|
||||||
|
put("UGL/Soldier", "https://api.scryfall.com/cards/tugl/2?format=image");
|
||||||
|
put("UGL/Squirrel", "https://api.scryfall.com/cards/tugl/6?format=image");
|
||||||
|
put("UGL/Zombie", "https://api.scryfall.com/cards/tugl/3?format=image");
|
||||||
|
|
||||||
|
// UST
|
||||||
|
put("UST/Angel", "https://api.scryfall.com/cards/tust/1?format=image");
|
||||||
|
put("UST/Beast", "https://api.scryfall.com/cards/tust/13?format=image");
|
||||||
|
put("UST/Brainiac", "https://api.scryfall.com/cards/tust/10?format=image");
|
||||||
|
put("UST/Clue", "https://api.scryfall.com/cards/tust/18?format=image");
|
||||||
|
put("UST/Dragon", "https://api.scryfall.com/cards/tust/16?format=image");
|
||||||
|
put("UST/Elemental/1", "https://api.scryfall.com/cards/tust/11?format=image");
|
||||||
|
put("UST/Elemental/2", "https://api.scryfall.com/cards/tust/17?format=image");
|
||||||
|
put("UST/Gnome", "https://api.scryfall.com/cards/tust/20?format=image");
|
||||||
|
put("UST/Goat", "https://api.scryfall.com/cards/tust/2?format=image");
|
||||||
|
put("UST/Goblin", "https://api.scryfall.com/cards/tust/12?format=image");
|
||||||
|
put("UST/Saproling", "https://api.scryfall.com/cards/tust/14?format=image");
|
||||||
|
put("UST/Spirit", "https://api.scryfall.com/cards/tust/3?format=image");
|
||||||
|
put("UST/Squirrel", "https://api.scryfall.com/cards/tust/15?format=image");
|
||||||
|
put("UST/Storm Crow", "https://api.scryfall.com/cards/tust/5?format=image");
|
||||||
|
put("UST/Thopter", "https://api.scryfall.com/cards/tust/6?format=image");
|
||||||
|
put("UST/Vampire", "https://api.scryfall.com/cards/tust/8?format=image");
|
||||||
|
put("UST/Zombie", "https://api.scryfall.com/cards/tust/9?format=image");
|
||||||
|
|
||||||
|
// F12
|
||||||
|
put("F12/Human", "https://api.scryfall.com/cards/f12/1a?format=image");
|
||||||
|
put("F12/Wolf", "https://api.scryfall.com/cards/f12/1a?format=image&face=back");
|
||||||
|
|
||||||
|
// F17
|
||||||
|
put("F17/Dinosaur", "https://api.scryfall.com/cards/f17/11?format=image");
|
||||||
|
put("F17/Pirate", "https://api.scryfall.com/cards/f17/12?format=image");
|
||||||
|
put("F17/Vampire", "https://api.scryfall.com/cards/f17/10?format=image");
|
||||||
|
put("F17/Treasure/1", "https://api.scryfall.com/cards/f17/11?format=image&face=back");
|
||||||
|
put("F17/Treasure/2", "https://api.scryfall.com/cards/f17/12?format=image&face=back");
|
||||||
|
put("F17/Treasure/3", "https://api.scryfall.com/cards/f17/10?format=image&face=back");
|
||||||
|
|
||||||
|
// HHO
|
||||||
|
put("HHO/Treasure", "https://api.scryfall.com/cards/hho/21★?format=image");
|
||||||
|
|
||||||
|
// J12
|
||||||
|
put("J12/Centaur", "https://api.scryfall.com/cards/j12/9?format=image");
|
||||||
|
|
||||||
|
// J13
|
||||||
|
put("J13/Golem", "https://api.scryfall.com/cards/j13/9?format=image");
|
||||||
|
|
||||||
|
// MPR
|
||||||
|
put("MPR/Bear", "https://api.scryfall.com/cards/mpr/7?format=image");
|
||||||
|
put("MPR/Beast", "https://api.scryfall.com/cards/mpr/8?format=image");
|
||||||
|
put("MPR/Bird", "https://api.scryfall.com/cards/mpr/4?format=image");
|
||||||
|
put("MPR/Elephant", "https://api.scryfall.com/cards/mpr/3?format=image");
|
||||||
|
put("MPR/Goblin Soldier", "https://api.scryfall.com/cards/mpr/6?format=image");
|
||||||
|
put("MPR/Saproling", "https://api.scryfall.com/cards/mpr/2?format=image");
|
||||||
|
put("MPR/Spirit", "https://api.scryfall.com/cards/mpr/5?format=image");
|
||||||
|
|
||||||
|
// P03
|
||||||
|
put("P03/Bear", "https://api.scryfall.com/cards/p03/4?format=image");
|
||||||
|
put("P03/Demon", "https://api.scryfall.com/cards/p03/6?format=image");
|
||||||
|
put("P03/Goblin", "https://api.scryfall.com/cards/p03/5?format=image");
|
||||||
|
put("P03/Insect", "https://api.scryfall.com/cards/p03/2?format=image");
|
||||||
|
put("P03/Bird", "https://api.scryfall.com/cards/p03/7?format=image");
|
||||||
|
put("P03/Sliver", "https://api.scryfall.com/cards/p03/3?format=image");
|
||||||
|
|
||||||
|
// P04
|
||||||
|
put("P04/Angel", "https://api.scryfall.com/cards/p04/2?format=image");
|
||||||
|
put("P04/Beast", "https://api.scryfall.com/cards/p04/5?format=image");
|
||||||
|
put("P04/Myr", "https://api.scryfall.com/cards/p04/4?format=image");
|
||||||
|
put("P04/Pentavite", "https://api.scryfall.com/cards/p04/3?format=image");
|
||||||
|
put("P04/Spirit", "https://api.scryfall.com/cards/p04/6?format=image");
|
||||||
|
|
||||||
|
// PEMN
|
||||||
|
put("PEMN/Zombie/1", "https://api.scryfall.com/cards/pemn/1Z?format=image");
|
||||||
|
put("PEMN/Zombie/2", "https://api.scryfall.com/cards/pemn/1Z?format=image&face=back");
|
||||||
|
|
||||||
|
// PHEL
|
||||||
|
put("PHEL/Angel", "https://api.scryfall.com/cards/phel/1★?format=image");
|
||||||
|
|
||||||
|
// PL21
|
||||||
|
put("PL21/Minotaur", "https://api.scryfall.com/cards/pl21/2★?format=image");
|
||||||
|
|
||||||
|
// PL23
|
||||||
|
put("PL23/Food", "https://api.scryfall.com/cards/pl23/2?format=image");
|
||||||
|
|
||||||
// generate supported sets
|
// generate supported sets
|
||||||
supportedSets.clear();
|
supportedSets.clear();
|
||||||
|
|
|
||||||
|
|
@ -282,7 +282,7 @@ public enum WizardCardsImageSource implements CardImageSource {
|
||||||
setsAliases.put("BOK", "Betrayers of Kamigawa");
|
setsAliases.put("BOK", "Betrayers of Kamigawa");
|
||||||
setsAliases.put("BRB", "Battle Royale Box Set");
|
setsAliases.put("BRB", "Battle Royale Box Set");
|
||||||
setsAliases.put("BTD", "Beatdown Box Set");
|
setsAliases.put("BTD", "Beatdown Box Set");
|
||||||
setsAliases.put("C13", "Commander 2013 Edition");
|
setsAliases.put("C13", "Commander 2013");
|
||||||
setsAliases.put("C14", "Commander 2014");
|
setsAliases.put("C14", "Commander 2014");
|
||||||
setsAliases.put("C15", "Commander 2015");
|
setsAliases.put("C15", "Commander 2015");
|
||||||
setsAliases.put("C16", "Commander 2016");
|
setsAliases.put("C16", "Commander 2016");
|
||||||
|
|
@ -365,7 +365,7 @@ public enum WizardCardsImageSource implements CardImageSource {
|
||||||
setsAliases.put("M13", "Magic 2013");
|
setsAliases.put("M13", "Magic 2013");
|
||||||
setsAliases.put("M14", "Magic 2014");
|
setsAliases.put("M14", "Magic 2014");
|
||||||
setsAliases.put("M15", "Magic 2015");
|
setsAliases.put("M15", "Magic 2015");
|
||||||
setsAliases.put("PMEI", "Media Inserts");
|
setsAliases.put("PMEI", "Media and Collaboration Promos");
|
||||||
setsAliases.put("MBS", "Mirrodin Besieged");
|
setsAliases.put("MBS", "Mirrodin Besieged");
|
||||||
setsAliases.put("ME2", "Masters Edition II");
|
setsAliases.put("ME2", "Masters Edition II");
|
||||||
setsAliases.put("ME3", "Masters Edition III");
|
setsAliases.put("ME3", "Masters Edition III");
|
||||||
|
|
@ -386,7 +386,7 @@ public enum WizardCardsImageSource implements CardImageSource {
|
||||||
setsAliases.put("ODY", "Odyssey");
|
setsAliases.put("ODY", "Odyssey");
|
||||||
setsAliases.put("ONS", "Onslaught");
|
setsAliases.put("ONS", "Onslaught");
|
||||||
setsAliases.put("ORI", "Magic Origins");
|
setsAliases.put("ORI", "Magic Origins");
|
||||||
setsAliases.put("PC2", "Planechase 2012 Edition");
|
setsAliases.put("PC2", "Planechase 2012");
|
||||||
setsAliases.put("PCY", "Prophecy");
|
setsAliases.put("PCY", "Prophecy");
|
||||||
setsAliases.put("PD2", "Premium Deck Series: Fire and Lightning");
|
setsAliases.put("PD2", "Premium Deck Series: Fire and Lightning");
|
||||||
setsAliases.put("PLC", "Planar Chaos");
|
setsAliases.put("PLC", "Planar Chaos");
|
||||||
|
|
@ -409,7 +409,7 @@ public enum WizardCardsImageSource implements CardImageSource {
|
||||||
setsAliases.put("TMP", "Tempest");
|
setsAliases.put("TMP", "Tempest");
|
||||||
setsAliases.put("TOR", "Torment");
|
setsAliases.put("TOR", "Torment");
|
||||||
setsAliases.put("TPR", "Tempest Remastered");
|
setsAliases.put("TPR", "Tempest Remastered");
|
||||||
setsAliases.put("TSB", "Time Spiral \"Timeshifted\"");
|
setsAliases.put("TSB", "Time Spiral Timeshifted");
|
||||||
setsAliases.put("TSP", "Time Spiral");
|
setsAliases.put("TSP", "Time Spiral");
|
||||||
setsAliases.put("UDS", "Urza's Destiny");
|
setsAliases.put("UDS", "Urza's Destiny");
|
||||||
setsAliases.put("UGL", "Unglued");
|
setsAliases.put("UGL", "Unglued");
|
||||||
|
|
|
||||||
|
|
@ -725,8 +725,8 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
|
||||||
try {
|
try {
|
||||||
TVFS.umount();
|
TVFS.umount();
|
||||||
} catch (FsSyncException e) {
|
} catch (FsSyncException e) {
|
||||||
logger.fatal("Couldn't unmount zip files " + e, e);
|
logger.error("Couldn't unmount zip files " + e, e);
|
||||||
MageFrame.getInstance().showErrorDialog("Couldn't unmount zip files " + e, e);
|
// this is not a critical error - just need to run it again - see issue #12833
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -940,14 +940,13 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
|
||||||
logger.warn(err);
|
logger.warn(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (AccessDeniedException e) {
|
} catch (AccessDeniedException e) {
|
||||||
incErrorCount();
|
incErrorCount();
|
||||||
logger.error("Can't access to files: " + card.getName() + "(" + card.getSet() + "). Try rebooting your system to remove the file lock.");
|
logger.error("Can't access to files: " + card.getName() + "(" + card.getSet() + "). Try rebooting your system to remove the file lock.");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
incErrorCount();
|
incErrorCount();
|
||||||
logger.error("Unknown error: " + e.getMessage(), e);
|
String sampleUrl = (urls == null ? "null" : urls.getDownloadList().stream().findFirst().orElse(null));
|
||||||
} finally {
|
logger.error("Unknown error: " + e.getMessage() + ", sample url: " + sampleUrl, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized (sync) {
|
synchronized (sync) {
|
||||||
|
|
|
||||||
|
|
@ -185,7 +185,7 @@ public final class CardImageUtils {
|
||||||
try {
|
try {
|
||||||
TVFS.umount();
|
TVFS.umount();
|
||||||
} catch (FsSyncException e) {
|
} catch (FsSyncException e) {
|
||||||
LOGGER.fatal("Couldn't unmount zip files on searching broken images " + e, e);
|
LOGGER.error("Couldn't unmount zip files on searching broken images " + e, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// real images check is slow, so it used on images download only (not here)
|
// real images check is slow, so it used on images download only (not here)
|
||||||
|
|
|
||||||
|
After Width: | Height: | Size: 125 KiB |
|
After Width: | Height: | Size: 407 KiB |
|
After Width: | Height: | Size: 389 KiB |
|
After Width: | Height: | Size: 244 KiB |
|
After Width: | Height: | Size: 178 KiB |
|
After Width: | Height: | Size: 387 KiB |
|
After Width: | Height: | Size: 403 KiB |
|
After Width: | Height: | Size: 422 KiB |
|
After Width: | Height: | Size: 221 KiB |
|
|
@ -43,7 +43,7 @@ public class ScryfallImagesDownloadTest {
|
||||||
.anyMatch(c -> c.getCardNumber().equals("001"))
|
.anyMatch(c -> c.getCardNumber().equals("001"))
|
||||||
);
|
);
|
||||||
urls = imageSource.generateCardUrl(new CardDownloadData("The One Ring", "LTR", "001", false, 0));
|
urls = imageSource.generateCardUrl(new CardDownloadData("The One Ring", "LTR", "001", false, 0));
|
||||||
Assert.assertEquals("https://api.scryfall.com/cards/ltr/0/en?format=image", urls.getBaseUrl());
|
Assert.assertEquals("https://api.scryfall.com/cards/ltr/0/qya?format=image", urls.getBaseUrl());
|
||||||
|
|
||||||
|
|
||||||
// added same tests for small images
|
// added same tests for small images
|
||||||
|
|
@ -74,6 +74,6 @@ public class ScryfallImagesDownloadTest {
|
||||||
.anyMatch(c -> c.getCardNumber().equals("001"))
|
.anyMatch(c -> c.getCardNumber().equals("001"))
|
||||||
);
|
);
|
||||||
urls = imageSourceSmall.generateCardUrl(new CardDownloadData("The One Ring", "LTR", "001", false, 0));
|
urls = imageSourceSmall.generateCardUrl(new CardDownloadData("The One Ring", "LTR", "001", false, 0));
|
||||||
Assert.assertEquals("https://api.scryfall.com/cards/ltr/0/en?format=image&version=small", urls.getBaseUrl());
|
Assert.assertEquals("https://api.scryfall.com/cards/ltr/0/qya?format=image&version=small", urls.getBaseUrl());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package mage.client.util;
|
||||||
|
|
||||||
import mage.client.remote.XmageURLConnection;
|
import mage.client.remote.XmageURLConnection;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
|
|
@ -12,24 +13,40 @@ import java.io.InputStream;
|
||||||
/**
|
/**
|
||||||
* @author JayDi85
|
* @author JayDi85
|
||||||
*/
|
*/
|
||||||
|
@Ignore // TODO: too many fails due third party servers downtime, migrate to more stable resources or just run it manually
|
||||||
public class DownloaderTest {
|
public class DownloaderTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_DownloadText_ByHttp() {
|
public void test_DownloadText_ByHttp() {
|
||||||
String s = XmageURLConnection.downloadText("http://google.com");
|
String s = XmageURLConnection.downloadText("http://example.com");
|
||||||
Assert.assertTrue("must have text data", s.contains("<head>"));
|
Assert.assertTrue("must have text data", s.contains("<head>"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_DownloadText_ByHttps() {
|
public void test_DownloadText_ByHttps() {
|
||||||
String s = XmageURLConnection.downloadText("https://google.com");
|
String s = XmageURLConnection.downloadText("https://example.com");
|
||||||
Assert.assertTrue("must have text data", s.contains("<head>"));
|
Assert.assertTrue("must have text data", s.contains("<head>"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_DownloadText_ByRedirectProtocol() {
|
||||||
|
// http to https restricted by design, see https://stackoverflow.com/a/1884427/1276632
|
||||||
|
// it's not critical for a client (e.g. for images download), so no needs in custom implementation
|
||||||
|
// like xmage launcher does
|
||||||
|
String s = XmageURLConnection.downloadText("http://github.com");
|
||||||
|
Assert.assertTrue("must have fail on https redirect (301 result)", s.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_DownloadText_ByRedirectUri() {
|
||||||
|
String s = XmageURLConnection.downloadText("https://github.com/magefree/mage/issues/new");
|
||||||
|
Assert.assertTrue("must have text data (redirect to login page)", s.contains("Sign in to GitHub"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_DownloadFile_ByHttp() throws IOException {
|
public void test_DownloadFile_ByHttp() throws IOException {
|
||||||
// use any public image here
|
// use any public image here
|
||||||
InputStream stream = XmageURLConnection.downloadBinary("http://www.google.com/tia/tia.png");
|
InputStream stream = XmageURLConnection.downloadBinary("http://xmage.today/images/xmage-logo.png");
|
||||||
Assert.assertNotNull(stream);
|
Assert.assertNotNull(stream);
|
||||||
BufferedImage image = ImageIO.read(stream);
|
BufferedImage image = ImageIO.read(stream);
|
||||||
Assert.assertNotNull(stream);
|
Assert.assertNotNull(stream);
|
||||||
|
|
@ -39,10 +56,28 @@ public class DownloaderTest {
|
||||||
@Test
|
@Test
|
||||||
public void test_DownloadFile_ByHttps() throws IOException {
|
public void test_DownloadFile_ByHttps() throws IOException {
|
||||||
// use any public image here
|
// use any public image here
|
||||||
InputStream stream = XmageURLConnection.downloadBinary("https://www.google.com/tia/tia.png");
|
InputStream stream = XmageURLConnection.downloadBinary("https://xmage.today/images/xmage-logo.png");
|
||||||
Assert.assertNotNull(stream);
|
Assert.assertNotNull(stream);
|
||||||
BufferedImage image = ImageIO.read(stream);
|
BufferedImage image = ImageIO.read(stream);
|
||||||
Assert.assertNotNull(stream);
|
Assert.assertNotNull(stream);
|
||||||
Assert.assertTrue("must have image data", image.getWidth() > 0);
|
Assert.assertTrue("must have image data", image.getWidth() > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Ignore // TODO: enable after gatherer server maintenance done
|
||||||
|
public void test_DownloadFromWindowsServers() throws IOException {
|
||||||
|
// symbols download from gatherer website
|
||||||
|
// error example: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
|
||||||
|
InputStream stream = XmageURLConnection.downloadBinary("https://gatherer.wizards.com/Handlers/Image.ashx?type=symbol&set=BIG&size=small&rarity=C");
|
||||||
|
Assert.assertNotNull(stream);
|
||||||
|
BufferedImage image = null;
|
||||||
|
try {
|
||||||
|
image = ImageIO.read(stream);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Assert.fail("Can't download image file due error: " + e);
|
||||||
|
}
|
||||||
|
Assert.assertNotNull(stream);
|
||||||
|
Assert.assertNotNull(image);
|
||||||
|
Assert.assertTrue("must have image data", image.getWidth() > 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.mage</groupId>
|
<groupId>org.mage</groupId>
|
||||||
<artifactId>mage-root</artifactId>
|
<artifactId>mage-root</artifactId>
|
||||||
<version>1.4.54</version>
|
<version>1.4.57</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>mage-common</artifactId>
|
<artifactId>mage-common</artifactId>
|
||||||
|
|
|
||||||
|
|
@ -64,10 +64,10 @@ public class MageTable extends JTable {
|
||||||
// html tooltip
|
// html tooltip
|
||||||
java.awt.Point p = e.getPoint();
|
java.awt.Point p = e.getPoint();
|
||||||
int colIndex = columnModel.getColumnIndexAtX(p.x);
|
int colIndex = columnModel.getColumnIndexAtX(p.x);
|
||||||
TableColumn col = columnModel.getColumn(colIndex);
|
|
||||||
if (colIndex < 0) {
|
if (colIndex < 0) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
TableColumn col = columnModel.getColumn(colIndex);
|
||||||
int realIndex = col.getModelIndex();
|
int realIndex = col.getModelIndex();
|
||||||
|
|
||||||
String tip;
|
String tip;
|
||||||
|
|
|
||||||
|
|
@ -99,4 +99,7 @@ public class ClientCallback implements Serializable {
|
||||||
return messageId;
|
return messageId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getInfo() {
|
||||||
|
return String.format("message %d - %s - %s", this.getMessageId(), this.getMethod().getType(), this.getMethod());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,13 +13,12 @@ import mage.interfaces.ServerState;
|
||||||
import mage.interfaces.callback.ClientCallback;
|
import mage.interfaces.callback.ClientCallback;
|
||||||
import mage.players.PlayerType;
|
import mage.players.PlayerType;
|
||||||
import mage.players.net.UserData;
|
import mage.players.net.UserData;
|
||||||
import mage.utils.CompressUtil;
|
|
||||||
import mage.util.ThreadUtils;
|
import mage.util.ThreadUtils;
|
||||||
|
import mage.utils.CompressUtil;
|
||||||
import mage.view.*;
|
import mage.view.*;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.jboss.remoting.*;
|
import org.jboss.remoting.*;
|
||||||
import org.jboss.remoting.callback.Callback;
|
import org.jboss.remoting.callback.Callback;
|
||||||
import org.jboss.remoting.callback.HandleCallbackException;
|
|
||||||
import org.jboss.remoting.callback.InvokerCallbackHandler;
|
import org.jboss.remoting.callback.InvokerCallbackHandler;
|
||||||
import org.jboss.remoting.transport.bisocket.Bisocket;
|
import org.jboss.remoting.transport.bisocket.Bisocket;
|
||||||
import org.jboss.remoting.transport.socket.SocketWrapper;
|
import org.jboss.remoting.transport.socket.SocketWrapper;
|
||||||
|
|
@ -31,6 +30,7 @@ import java.lang.reflect.UndeclaredThrowableException;
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.CancellationException;
|
import java.util.concurrent.CancellationException;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -47,6 +47,8 @@ public class SessionImpl implements Session {
|
||||||
private static final int SESSION_VALIDATOR_PING_PERIOD_SECS = 4;
|
private static final int SESSION_VALIDATOR_PING_PERIOD_SECS = 4;
|
||||||
private static final int SESSION_VALIDATOR_PING_TIMEOUT_SECS = 3;
|
private static final int SESSION_VALIDATOR_PING_TIMEOUT_SECS = 3;
|
||||||
|
|
||||||
|
private static final int CONNECT_WAIT_BEFORE_PROCESS_ANY_CALLBACKS_SECS = 3;
|
||||||
|
|
||||||
public static final String ADMIN_NAME = "Admin"; // if you change here then change in User too
|
public static final String ADMIN_NAME = "Admin"; // if you change here then change in User too
|
||||||
public static final String KEEP_MY_OLD_SESSION = "keep_my_old_session"; // for disconnects without active session lose (keep tables/games)
|
public static final String KEEP_MY_OLD_SESSION = "keep_my_old_session"; // for disconnects without active session lose (keep tables/games)
|
||||||
|
|
||||||
|
|
@ -269,6 +271,7 @@ public class SessionImpl implements Session {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
|
// server state used in client side to setup game panels and dialogs, e.g. test mode info or available game types
|
||||||
serverState = server.getServerState();
|
serverState = server.getServerState();
|
||||||
if (serverState == null) {
|
if (serverState == null) {
|
||||||
throw new MageVersionException(client.getVersion(), null);
|
throw new MageVersionException(client.getVersion(), null);
|
||||||
|
|
@ -597,14 +600,43 @@ public class SessionImpl implements Session {
|
||||||
|
|
||||||
class CallbackHandler implements InvokerCallbackHandler {
|
class CallbackHandler implements InvokerCallbackHandler {
|
||||||
|
|
||||||
|
final CopyOnWriteArrayList<ClientCallback> waitingCallbacks = new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleCallback(Callback callback) throws HandleCallbackException {
|
public void handleCallback(Callback callback) {
|
||||||
|
// keep callbacks
|
||||||
|
ClientCallback clientCallback = (ClientCallback) callback.getCallbackObject();
|
||||||
|
waitingCallbacks.add(clientCallback);
|
||||||
|
|
||||||
|
// wait for client ready
|
||||||
|
// on connection client will receive all waiting callbacks from a server, e.g. started table, draft pick, etc
|
||||||
|
// but it's require to get server settings first (server state), e.g. for test mode
|
||||||
|
// possible bugs:
|
||||||
|
// - hidden cheat button or enabled clicks protection in draft
|
||||||
|
// - miss dialogs like draft or game panels
|
||||||
|
// so wait for server state some time
|
||||||
|
if (serverState == null) {
|
||||||
|
ThreadUtils.sleep(CONNECT_WAIT_BEFORE_PROCESS_ANY_CALLBACKS_SECS * 1000);
|
||||||
|
if (serverState == null) {
|
||||||
|
logger.error("Can't receive server state before other data (possible reason: unstable network): "
|
||||||
|
+ clientCallback.getInfo());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// execute waiting queue
|
||||||
|
// client.onCallback must process and ignore outdated data inside
|
||||||
|
List<ClientCallback> executingCallbacks;
|
||||||
|
synchronized (waitingCallbacks) {
|
||||||
|
executingCallbacks = new ArrayList<>(waitingCallbacks);
|
||||||
|
executingCallbacks.sort(Comparator.comparingInt(ClientCallback::getMessageId));
|
||||||
|
waitingCallbacks.clear();
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
client.onCallback((ClientCallback) callback.getCallbackObject());
|
executingCallbacks.forEach(client::onCallback);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
logger.error("handleCallback error", ex);
|
logger.error("handleCallback error", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,8 @@ public class MageVersion implements Serializable, Comparable<MageVersion> {
|
||||||
// * launcher gives priority to 1.4.48 instead 1.4.48-any-text, so don't use empty release info
|
// * launcher gives priority to 1.4.48 instead 1.4.48-any-text, so don't use empty release info
|
||||||
public static final int MAGE_VERSION_MAJOR = 1;
|
public static final int MAGE_VERSION_MAJOR = 1;
|
||||||
public static final int MAGE_VERSION_MINOR = 4;
|
public static final int MAGE_VERSION_MINOR = 4;
|
||||||
public static final int MAGE_VERSION_RELEASE = 54;
|
public static final int MAGE_VERSION_RELEASE = 57;
|
||||||
public static final String MAGE_VERSION_RELEASE_INFO = "V3"; // V1, V1a, V1b for releases; V1-beta3, V1-beta4 for betas
|
public static final String MAGE_VERSION_RELEASE_INFO = "V2"; // V1, V1a, V1b for releases; V1-beta3, V1-beta4 for betas
|
||||||
|
|
||||||
// strict mode
|
// strict mode
|
||||||
// Each update requires a strict version
|
// Each update requires a strict version
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
package mage.utils;
|
package mage.utils;
|
||||||
|
|
||||||
import mage.MageObject;
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.ActivatedAbility;
|
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.effects.ContinuousEffect;
|
import mage.abilities.effects.ContinuousEffect;
|
||||||
import mage.abilities.effects.Effect;
|
import mage.abilities.effects.Effect;
|
||||||
|
|
@ -24,9 +22,13 @@ import mage.game.command.Plane;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
import mage.game.permanent.token.Token;
|
import mage.game.permanent.token.Token;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
|
import mage.target.Target;
|
||||||
|
import mage.target.TargetPlayer;
|
||||||
|
import mage.target.common.TargetOpponent;
|
||||||
import mage.util.CardUtil;
|
import mage.util.CardUtil;
|
||||||
import mage.util.MultiAmountMessage;
|
import mage.util.MultiAmountMessage;
|
||||||
import mage.util.RandomUtil;
|
import mage.util.RandomUtil;
|
||||||
|
import mage.utils.testers.TestableDialogsRunner;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
|
|
@ -66,26 +68,31 @@ public final class SystemUtil {
|
||||||
// [@mana add] -> MANA ADD
|
// [@mana add] -> MANA ADD
|
||||||
private static final String COMMAND_CARDS_ADD_TO_HAND = "@card add to hand";
|
private static final String COMMAND_CARDS_ADD_TO_HAND = "@card add to hand";
|
||||||
private static final String COMMAND_LANDS_ADD_TO_BATTLEFIELD = "@lands add";
|
private static final String COMMAND_LANDS_ADD_TO_BATTLEFIELD = "@lands add";
|
||||||
|
private static final String COMMAND_UNDER_CONTROL_TAKE = "@under control take";
|
||||||
|
private static final String COMMAND_UNDER_CONTROL_GIVE = "@under control give";
|
||||||
|
private static final String COMMAND_SHOW_TEST_DIALOGS = "@show dialog";
|
||||||
private static final String COMMAND_MANA_ADD = "@mana add"; // TODO: not implemented
|
private static final String COMMAND_MANA_ADD = "@mana add"; // TODO: not implemented
|
||||||
private static final String COMMAND_RUN_CUSTOM_CODE = "@run custom code"; // TODO: not implemented
|
private static final String COMMAND_RUN_CUSTOM_CODE = "@run custom code"; // TODO: not implemented
|
||||||
private static final String COMMAND_SHOW_OPPONENT_HAND = "@show opponent hand";
|
private static final String COMMAND_SHOW_OPPONENT_HAND = "@show opponent hand";
|
||||||
private static final String COMMAND_SHOW_OPPONENT_LIBRARY = "@show opponent library";
|
private static final String COMMAND_SHOW_OPPONENT_LIBRARY = "@show opponent library";
|
||||||
private static final String COMMAND_SHOW_MY_HAND = "@show my hand";
|
private static final String COMMAND_SHOW_MY_HAND = "@show my hand";
|
||||||
private static final String COMMAND_SHOW_MY_LIBRARY = "@show my library";
|
private static final String COMMAND_SHOW_MY_LIBRARY = "@show my library";
|
||||||
private static final String COMMAND_ACTIVATE_OPPONENT_ABILITY = "@activate opponent ability";
|
|
||||||
private static final Map<String, String> supportedCommands = new HashMap<>();
|
private static final Map<String, String> supportedCommands = new HashMap<>();
|
||||||
|
private static final TestableDialogsRunner testableDialogsRunner = new TestableDialogsRunner(); // for tests
|
||||||
|
|
||||||
static {
|
static {
|
||||||
// special commands names in choose dialog
|
// special commands names in choose dialog
|
||||||
supportedCommands.put(COMMAND_CARDS_ADD_TO_HAND, "CARDS: ADD TO HAND");
|
supportedCommands.put(COMMAND_CARDS_ADD_TO_HAND, "CARDS: ADD TO HAND");
|
||||||
supportedCommands.put(COMMAND_MANA_ADD, "MANA ADD");
|
supportedCommands.put(COMMAND_MANA_ADD, "MANA ADD");
|
||||||
supportedCommands.put(COMMAND_LANDS_ADD_TO_BATTLEFIELD, "LANDS: ADD TO BATTLEFIELD");
|
supportedCommands.put(COMMAND_LANDS_ADD_TO_BATTLEFIELD, "LANDS: ADD TO BATTLEFIELD");
|
||||||
|
supportedCommands.put(COMMAND_UNDER_CONTROL_TAKE, "UNDER CONTROL: TAKE");
|
||||||
|
supportedCommands.put(COMMAND_UNDER_CONTROL_GIVE, "UNDER CONTROL: GIVE");
|
||||||
supportedCommands.put(COMMAND_RUN_CUSTOM_CODE, "RUN CUSTOM CODE");
|
supportedCommands.put(COMMAND_RUN_CUSTOM_CODE, "RUN CUSTOM CODE");
|
||||||
supportedCommands.put(COMMAND_SHOW_OPPONENT_HAND, "SHOW OPPONENT HAND");
|
supportedCommands.put(COMMAND_SHOW_OPPONENT_HAND, "SHOW OPPONENT HAND");
|
||||||
supportedCommands.put(COMMAND_SHOW_OPPONENT_LIBRARY, "SHOW OPPONENT LIBRARY");
|
supportedCommands.put(COMMAND_SHOW_OPPONENT_LIBRARY, "SHOW OPPONENT LIBRARY");
|
||||||
supportedCommands.put(COMMAND_SHOW_MY_HAND, "SHOW MY HAND");
|
supportedCommands.put(COMMAND_SHOW_MY_HAND, "SHOW MY HAND");
|
||||||
supportedCommands.put(COMMAND_SHOW_MY_LIBRARY, "SHOW MY LIBRARY");
|
supportedCommands.put(COMMAND_SHOW_MY_LIBRARY, "SHOW MY LIBRARY");
|
||||||
supportedCommands.put(COMMAND_ACTIVATE_OPPONENT_ABILITY, "ACTIVATE OPPONENT ABILITY");
|
supportedCommands.put(COMMAND_SHOW_TEST_DIALOGS, "SHOW TEST DIALOGS");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Pattern patternGroup = Pattern.compile("\\[(.+)\\]"); // [test new card]
|
private static final Pattern patternGroup = Pattern.compile("\\[(.+)\\]"); // [test new card]
|
||||||
|
|
@ -255,13 +262,18 @@ public final class SystemUtil {
|
||||||
*
|
*
|
||||||
* @param game
|
* @param game
|
||||||
* @param commandsFilePath file path with commands in init.txt format
|
* @param commandsFilePath file path with commands in init.txt format
|
||||||
* @param feedbackPlayer player to execute that cheats (will see choose dialogs)
|
* @param feedbackPlayer player to execute that cheats (will see choose dialogs)
|
||||||
*/
|
*/
|
||||||
public static void executeCheatCommands(Game game, String commandsFilePath, Player feedbackPlayer) {
|
public static void executeCheatCommands(Game game, String commandsFilePath, Player feedbackPlayer) {
|
||||||
|
|
||||||
// fake test ability for triggers and events
|
// fake test ability for triggers and events
|
||||||
Ability fakeSourceAbilityTemplate = new SimpleStaticAbility(Zone.OUTSIDE, new InfoEffect("adding testing cards"));
|
Ability fakeSourceAbilityTemplate = new SimpleStaticAbility(Zone.OUTSIDE, new InfoEffect("fake ability"));
|
||||||
fakeSourceAbilityTemplate.setControllerId(feedbackPlayer.getId());
|
fakeSourceAbilityTemplate.setControllerId(feedbackPlayer.getId());
|
||||||
|
Card fakeSourceCard = feedbackPlayer.getLibrary().getFromTop(game);
|
||||||
|
if (fakeSourceCard != null) {
|
||||||
|
// set any existing card as source, so dialogs will show all GUI elements, including source and workable popup info
|
||||||
|
fakeSourceAbilityTemplate.setSourceId(fakeSourceCard.getId());
|
||||||
|
}
|
||||||
|
|
||||||
List<String> errorsList = new ArrayList<>();
|
List<String> errorsList = new ArrayList<>();
|
||||||
try {
|
try {
|
||||||
|
|
@ -301,6 +313,9 @@ public final class SystemUtil {
|
||||||
// add default commands
|
// add default commands
|
||||||
initLines.add(0, String.format("[%s]", COMMAND_LANDS_ADD_TO_BATTLEFIELD));
|
initLines.add(0, String.format("[%s]", COMMAND_LANDS_ADD_TO_BATTLEFIELD));
|
||||||
initLines.add(1, String.format("[%s]", COMMAND_CARDS_ADD_TO_HAND));
|
initLines.add(1, String.format("[%s]", COMMAND_CARDS_ADD_TO_HAND));
|
||||||
|
initLines.add(2, String.format("[%s]", COMMAND_SHOW_TEST_DIALOGS));
|
||||||
|
initLines.add(3, String.format("[%s]", COMMAND_UNDER_CONTROL_TAKE));
|
||||||
|
initLines.add(4, String.format("[%s]", COMMAND_UNDER_CONTROL_GIVE));
|
||||||
|
|
||||||
// collect all commands
|
// collect all commands
|
||||||
CommandGroup currentGroup = null;
|
CommandGroup currentGroup = null;
|
||||||
|
|
@ -386,7 +401,7 @@ public final class SystemUtil {
|
||||||
// 3. system commands
|
// 3. system commands
|
||||||
if (runGroup.isSpecialCommand) {
|
if (runGroup.isSpecialCommand) {
|
||||||
|
|
||||||
Player opponent = game.getPlayer(game.getOpponents(feedbackPlayer.getId()).stream().findFirst().orElse(null));
|
Player opponent = game.getPlayer(game.getOpponents(feedbackPlayer.getId(), true).stream().findFirst().orElse(null));
|
||||||
|
|
||||||
String info;
|
String info;
|
||||||
switch (runGroup.name) {
|
switch (runGroup.name) {
|
||||||
|
|
@ -419,53 +434,6 @@ public final class SystemUtil {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case COMMAND_ACTIVATE_OPPONENT_ABILITY: {
|
|
||||||
// WARNING, maybe very bugged if called in wrong priority
|
|
||||||
// uses choose triggered ability dialog to select it
|
|
||||||
UUID savedPriorityPlayer = null;
|
|
||||||
if (game.getActivePlayerId() != opponent.getId()) {
|
|
||||||
savedPriorityPlayer = game.getActivePlayerId();
|
|
||||||
}
|
|
||||||
|
|
||||||
// change active player to find and play selected abilities (it's danger and buggy code)
|
|
||||||
if (savedPriorityPlayer != null) {
|
|
||||||
game.getState().setPriorityPlayerId(opponent.getId());
|
|
||||||
game.firePriorityEvent(opponent.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
List<ActivatedAbility> abilities = opponent.getPlayable(game, true);
|
|
||||||
Map<String, String> choices = new HashMap<>();
|
|
||||||
abilities.forEach(ability -> {
|
|
||||||
MageObject object = ability.getSourceObject(game);
|
|
||||||
choices.put(ability.getId().toString(), object.getName() + ": " + ability.toString());
|
|
||||||
});
|
|
||||||
// TODO: set priority for us?
|
|
||||||
Choice choice = new ChoiceImpl(false);
|
|
||||||
choice.setMessage("Choose playable ability to activate by opponent " + opponent.getName());
|
|
||||||
choice.setKeyChoices(choices);
|
|
||||||
if (feedbackPlayer.choose(Outcome.Detriment, choice, game) && choice.getChoiceKey() != null) {
|
|
||||||
String needId = choice.getChoiceKey();
|
|
||||||
Optional<ActivatedAbility> ability = abilities.stream().filter(a -> a.getId().toString().equals(needId)).findFirst();
|
|
||||||
if (ability.isPresent()) {
|
|
||||||
// TODO: set priority for player?
|
|
||||||
ActivatedAbility activatedAbility = ability.get();
|
|
||||||
game.informPlayers(feedbackPlayer.getLogName() + " as another player " + opponent.getLogName()
|
|
||||||
+ " trying to force an activate ability: " + activatedAbility.getGameLogMessage(game));
|
|
||||||
if (opponent.activateAbility(activatedAbility, game)) {
|
|
||||||
game.informPlayers("Force to activate ability: DONE");
|
|
||||||
} else {
|
|
||||||
game.informPlayers("Force to activate ability: FAIL");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// restore original priority player
|
|
||||||
if (savedPriorityPlayer != null) {
|
|
||||||
game.getState().setPriorityPlayerId(savedPriorityPlayer);
|
|
||||||
game.firePriorityEvent(savedPriorityPlayer);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case COMMAND_CARDS_ADD_TO_HAND: {
|
case COMMAND_CARDS_ADD_TO_HAND: {
|
||||||
|
|
||||||
// card
|
// card
|
||||||
|
|
@ -480,7 +448,7 @@ public final class SystemUtil {
|
||||||
cardName = cardChoice.getChoice();
|
cardName = cardChoice.getChoice();
|
||||||
|
|
||||||
// amount
|
// amount
|
||||||
int cardAmount = feedbackPlayer.getAmount(1, 100, "How many [" + cardName + "] to add?", game);
|
int cardAmount = feedbackPlayer.getAmount(1, 100, "How many [" + cardName + "] to add?", null, game);
|
||||||
if (cardAmount == 0) {
|
if (cardAmount == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -544,6 +512,47 @@ public final class SystemUtil {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case COMMAND_UNDER_CONTROL_TAKE: {
|
||||||
|
Target target = new TargetOpponent().withNotTarget(true).withChooseHint("to take under your control");
|
||||||
|
Ability fakeSourceAbility = fakeSourceAbilityTemplate.copy();
|
||||||
|
if (feedbackPlayer.chooseTarget(Outcome.GainControl, target, fakeSourceAbility, game)) {
|
||||||
|
Player targetPlayer = game.getPlayer(target.getFirstTarget());
|
||||||
|
if (!targetPlayer.getId().equals(feedbackPlayer.getId())) {
|
||||||
|
CardUtil.takeControlUnderPlayerStart(game, fakeSourceAbility, feedbackPlayer, targetPlayer, false);
|
||||||
|
// allow priority play again in same step (for better cheat UX)
|
||||||
|
targetPlayer.resetPassed();
|
||||||
|
}
|
||||||
|
// workaround for refresh priority dialog like avatar click (cheats called from priority in 99%)
|
||||||
|
game.firePriorityEvent(feedbackPlayer.getId());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case COMMAND_UNDER_CONTROL_GIVE: {
|
||||||
|
Target target = new TargetPlayer().withNotTarget(true).withChooseHint("to give control of your player");
|
||||||
|
Ability fakeSourceAbility = fakeSourceAbilityTemplate.copy();
|
||||||
|
if (feedbackPlayer.chooseTarget(Outcome.GainControl, target, fakeSourceAbility, game)) {
|
||||||
|
Player targetPlayer = game.getPlayer(target.getFirstTarget());
|
||||||
|
if (targetPlayer != null) {
|
||||||
|
if (!targetPlayer.getId().equals(feedbackPlayer.getId())) {
|
||||||
|
// give control to another player
|
||||||
|
CardUtil.takeControlUnderPlayerStart(game, fakeSourceAbility, targetPlayer, feedbackPlayer, false);
|
||||||
|
} else {
|
||||||
|
// return control to itself
|
||||||
|
CardUtil.takeControlUnderPlayerEnd(game, fakeSourceAbility, feedbackPlayer, targetPlayer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// workaround for refresh priority dialog like avatar click (cheats called from priority in 99%)
|
||||||
|
game.firePriorityEvent(feedbackPlayer.getId());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case COMMAND_SHOW_TEST_DIALOGS: {
|
||||||
|
testableDialogsRunner.selectAndShowTestableDialog(feedbackPlayer, fakeSourceAbilityTemplate.copy(), game, opponent);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
String mes = String.format("Unknown system command: %s", runGroup.name);
|
String mes = String.format("Unknown system command: %s", runGroup.name);
|
||||||
errorsList.add(mes);
|
errorsList.add(mes);
|
||||||
|
|
@ -551,7 +560,6 @@ public final class SystemUtil {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sendCheatCommandsFeedback(game, feedbackPlayer, errorsList);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
package mage.utils.testers;
|
||||||
|
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.players.Player;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Part of testable game dialogs
|
||||||
|
* <p>
|
||||||
|
* Supported methods:
|
||||||
|
* - player.announceX()
|
||||||
|
*
|
||||||
|
* @author JayDi85
|
||||||
|
*/
|
||||||
|
class AnnounceXTestableDialog extends BaseTestableDialog {
|
||||||
|
|
||||||
|
boolean isYou; // who choose - you or opponent
|
||||||
|
boolean isMana; // reason - for mana payment or another value
|
||||||
|
int min;
|
||||||
|
int max;
|
||||||
|
|
||||||
|
public AnnounceXTestableDialog(boolean isYou, boolean isMana, int min, int max) {
|
||||||
|
super(String.format("player.announceX(%s)", isYou ? "you" : "AI"),
|
||||||
|
String.format("%s from %d to %d", isMana ? "mana" : "cost", min, max), "");
|
||||||
|
this.isYou = isYou;
|
||||||
|
this.isMana = isMana;
|
||||||
|
this.min = min;
|
||||||
|
this.max = max;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> showDialog(Player player, Ability source, Game game, Player opponent) {
|
||||||
|
Player choosingPlayer = this.isYou ? player : opponent;
|
||||||
|
String message = "<font color=green>message</font> with html";
|
||||||
|
int chooseRes;
|
||||||
|
chooseRes = choosingPlayer.announceX(this.min, this.max, message, game, source, this.isMana);
|
||||||
|
List<String> result = new ArrayList<>();
|
||||||
|
result.add(getGroup() + " - " + this.getName() + " selected " + chooseRes);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static public void register(TestableDialogsRunner runner) {
|
||||||
|
List<Boolean> isYous = Arrays.asList(false, true);
|
||||||
|
List<Boolean> isManas = Arrays.asList(false, true);
|
||||||
|
for (boolean isYou : isYous) {
|
||||||
|
for (boolean isMana : isManas) {
|
||||||
|
runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 0, 0));
|
||||||
|
runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 0, 1));
|
||||||
|
runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 0, 3));
|
||||||
|
runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 0, 50));
|
||||||
|
runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 0, 500));
|
||||||
|
runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 1, 1));
|
||||||
|
runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 1, 3));
|
||||||
|
runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 1, 50));
|
||||||
|
runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 3, 3));
|
||||||
|
runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 3, 10));
|
||||||
|
runner.registerDialog(new AnnounceXTestableDialog(isYou, isMana, 10, 10));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
package mage.utils.testers;
|
||||||
|
|
||||||
|
import mage.constants.SubType;
|
||||||
|
import mage.filter.common.FilterCreaturePermanent;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.players.Player;
|
||||||
|
import mage.target.Target;
|
||||||
|
import mage.target.common.TargetCreaturePermanent;
|
||||||
|
import mage.target.common.TargetPermanentOrPlayer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Part of testable game dialogs
|
||||||
|
*
|
||||||
|
* @author JayDi85
|
||||||
|
*/
|
||||||
|
abstract class BaseTestableDialog implements TestableDialog {
|
||||||
|
|
||||||
|
private final String group;
|
||||||
|
private final String name;
|
||||||
|
private final String description;
|
||||||
|
|
||||||
|
public BaseTestableDialog(String group, String name, String description) {
|
||||||
|
this.group = group;
|
||||||
|
this.name = name;
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
final public String getGroup() {
|
||||||
|
return this.group;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
final public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
final public String getDescription() {
|
||||||
|
return this.description;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
final public void showResult(Player player, Game game, String result) {
|
||||||
|
// show message with result
|
||||||
|
game.informPlayer(player, result);
|
||||||
|
// reset game and gui (in most use cases it must return to player's priority)
|
||||||
|
game.firePriorityEvent(player.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
static Target createAnyTarget(int min, int max) {
|
||||||
|
return createAnyTarget(min, max, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Target createAnyTarget(int min, int max, boolean notTarget) {
|
||||||
|
return new TargetPermanentOrPlayer(min, max).withNotTarget(notTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Target createCreatureTarget(int min, int max) {
|
||||||
|
return createCreatureTarget(min, max, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Target createCreatureTarget(int min, int max, boolean notTarget) {
|
||||||
|
return new TargetCreaturePermanent(min, max).withNotTarget(notTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Target createImpossibleTarget(int min, int max) {
|
||||||
|
return createImpossibleTarget(min, max, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Target createImpossibleTarget(int min, int max, boolean notTarget) {
|
||||||
|
return new TargetCreaturePermanent(min, max, new FilterCreaturePermanent(SubType.TROOPER, "rare type"), notTarget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,111 @@
|
||||||
|
package mage.utils.testers;
|
||||||
|
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.constants.Outcome;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.players.Player;
|
||||||
|
import mage.target.TargetAmount;
|
||||||
|
import mage.target.Targets;
|
||||||
|
import mage.target.common.TargetAnyTargetAmount;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Part of testable game dialogs
|
||||||
|
* <p>
|
||||||
|
* Supported methods:
|
||||||
|
* - player.chooseTarget(amount)
|
||||||
|
*
|
||||||
|
* @author JayDi85
|
||||||
|
*/
|
||||||
|
class ChooseAmountTestableDialog extends BaseTestableDialog {
|
||||||
|
|
||||||
|
boolean isYou; // who choose - you or opponent
|
||||||
|
int distributeAmount;
|
||||||
|
int targetsMin;
|
||||||
|
int targetsMax;
|
||||||
|
|
||||||
|
public ChooseAmountTestableDialog(boolean isYou, String name, int distributeAmount, int targetsMin, int targetsMax) {
|
||||||
|
super(String.format("player.chooseTarget(%s, amount)", isYou ? "you" : "AI"),
|
||||||
|
name,
|
||||||
|
String.format("%d between %d-%d targets", distributeAmount, targetsMin, targetsMax));
|
||||||
|
this.isYou = isYou;
|
||||||
|
this.distributeAmount = distributeAmount;
|
||||||
|
this.targetsMin = targetsMin;
|
||||||
|
this.targetsMax = targetsMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> showDialog(Player player, Ability source, Game game, Player opponent) {
|
||||||
|
TargetAmount choosingTarget = new TargetAnyTargetAmount(this.distributeAmount, this.targetsMin, this.targetsMax);
|
||||||
|
Player choosingPlayer = this.isYou ? player : opponent;
|
||||||
|
|
||||||
|
// TODO: add "damage" word in ability text, so chooseTargetAmount an show diff dialog (due inner logic - distribute damage or 1/1)
|
||||||
|
boolean chooseRes = choosingPlayer.chooseTargetAmount(Outcome.Benefit, choosingTarget, source, game);
|
||||||
|
List<String> result = new ArrayList<>();
|
||||||
|
if (chooseRes) {
|
||||||
|
Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "TRUE", new Targets(choosingTarget), source, game, result);
|
||||||
|
} else {
|
||||||
|
Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "FALSE", new Targets(choosingTarget), source, game, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static public void register(TestableDialogsRunner runner) {
|
||||||
|
// test game started with 2 players and 1 land on battlefield
|
||||||
|
// so it's better to use target limits like 0, 1, 3, 5, max
|
||||||
|
|
||||||
|
List<Boolean> isYous = Arrays.asList(false, true);
|
||||||
|
|
||||||
|
for (boolean isYou : isYous) {
|
||||||
|
// up to
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 0, 0, 0));
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 0, 0, 1));
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 0, 0, 3));
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 0, 0, 5));
|
||||||
|
//
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to, invalid", 1, 0, 0));
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 1, 0, 1));
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 1, 0, 3));
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 1, 0, 5));
|
||||||
|
//
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to, invalid", 2, 0, 0));
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 2, 0, 1));
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 2, 0, 3));
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 2, 0, 5));
|
||||||
|
//
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to, invalid", 3, 0, 0));
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 3, 0, 1));
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 3, 0, 3));
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 3, 0, 5));
|
||||||
|
//
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to, invalid", 5, 0, 0));
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 5, 0, 1));
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 5, 0, 3));
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "up to", 5, 0, 5));
|
||||||
|
|
||||||
|
// need target
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 0, 1, 1));
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 0, 1, 3));
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 0, 1, 5));
|
||||||
|
//
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 1, 1, 1));
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 1, 1, 3));
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 1, 1, 5));
|
||||||
|
//
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 2, 1, 1));
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 2, 1, 3));
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 2, 1, 5));
|
||||||
|
//
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 3, 1, 1));
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 3, 1, 3));
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 3, 1, 5));
|
||||||
|
//
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 5, 1, 1));
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 5, 1, 3));
|
||||||
|
runner.registerDialog(new ChooseAmountTestableDialog(isYou, "need", 5, 1, 5));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,111 @@
|
||||||
|
package mage.utils.testers;
|
||||||
|
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.cards.Card;
|
||||||
|
import mage.cards.Cards;
|
||||||
|
import mage.cards.CardsImpl;
|
||||||
|
import mage.constants.Outcome;
|
||||||
|
import mage.constants.SubType;
|
||||||
|
import mage.filter.FilterCard;
|
||||||
|
import mage.filter.StaticFilters;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.players.Player;
|
||||||
|
import mage.target.TargetCard;
|
||||||
|
import mage.target.Targets;
|
||||||
|
import mage.target.common.TargetCardInHand;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Part of testable game dialogs
|
||||||
|
* <p>
|
||||||
|
* Supported methods:
|
||||||
|
* - player.choose(cards)
|
||||||
|
* - player.chooseTarget(cards)
|
||||||
|
*
|
||||||
|
* @author JayDi85
|
||||||
|
*/
|
||||||
|
class ChooseCardsTestableDialog extends BaseTestableDialog {
|
||||||
|
|
||||||
|
TargetCard target;
|
||||||
|
boolean isTargetChoice; // how to choose - by xxx.choose or xxx.chooseTarget
|
||||||
|
boolean isYou; // who choose - you or opponent
|
||||||
|
|
||||||
|
public ChooseCardsTestableDialog(boolean isTargetChoice, boolean notTarget, boolean isYou, String name, TargetCard target) {
|
||||||
|
super(String.format("%s(%s, %s, cards)",
|
||||||
|
isTargetChoice ? "player.chooseTarget" : "player.choose",
|
||||||
|
isYou ? "you" : "AI",
|
||||||
|
notTarget ? "not target" : "target"), name, target.toString());
|
||||||
|
this.isTargetChoice = isTargetChoice;
|
||||||
|
this.target = target.withNotTarget(notTarget);
|
||||||
|
this.isYou = isYou;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> showDialog(Player player, Ability source, Game game, Player opponent) {
|
||||||
|
TargetCard choosingTarget = this.target.copy();
|
||||||
|
Player choosingPlayer = this.isYou ? player : opponent;
|
||||||
|
|
||||||
|
// make sure hand go first, so user can test diff type of targets
|
||||||
|
List<Card> all = new ArrayList<>();
|
||||||
|
all.addAll(choosingPlayer.getHand().getCards(game));
|
||||||
|
//all.addAll(choosingPlayer.getLibrary().getCards(game));
|
||||||
|
Cards choosingCards = new CardsImpl(all.stream().limit(100).collect(Collectors.toList()));
|
||||||
|
|
||||||
|
boolean chooseRes;
|
||||||
|
if (this.isTargetChoice) {
|
||||||
|
chooseRes = choosingPlayer.chooseTarget(Outcome.Benefit, choosingCards, choosingTarget, source, game);
|
||||||
|
} else {
|
||||||
|
chooseRes = choosingPlayer.choose(Outcome.Benefit, choosingCards, choosingTarget, source, game);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> result = new ArrayList<>();
|
||||||
|
if (chooseRes) {
|
||||||
|
Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "TRUE", new Targets(choosingTarget), source, game, result);
|
||||||
|
} else {
|
||||||
|
Targets.printDebugTargets(getGroup() + " - " + this.getName() + " - " + "FALSE", new Targets(choosingTarget), source, game, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static public void register(TestableDialogsRunner runner) {
|
||||||
|
// test game started with 2 players and 7 cards in hand and 1 draw
|
||||||
|
// so it's better to use target limits like 0, 1, 3, 9, max
|
||||||
|
|
||||||
|
FilterCard anyCard = StaticFilters.FILTER_CARD;
|
||||||
|
FilterCard impossibleCard = new FilterCard();
|
||||||
|
impossibleCard.add(SubType.TROOPER.getPredicate());
|
||||||
|
|
||||||
|
List<Boolean> notTargets = Arrays.asList(false, true);
|
||||||
|
List<Boolean> isYous = Arrays.asList(false, true);
|
||||||
|
List<Boolean> isTargetChoices = Arrays.asList(false, true);
|
||||||
|
for (boolean notTarget : notTargets) {
|
||||||
|
for (boolean isYou : isYous) {
|
||||||
|
for (boolean isTargetChoice : isTargetChoices) {
|
||||||
|
runner.registerDialog(new ChooseCardsTestableDialog(isTargetChoice, notTarget, isYou, "hand 0, X=0", new TargetCardInHand(0, 0, anyCard)));
|
||||||
|
runner.registerDialog(new ChooseCardsTestableDialog(isTargetChoice, notTarget, isYou, "hand 1", new TargetCardInHand(1, anyCard)));
|
||||||
|
runner.registerDialog(new ChooseCardsTestableDialog(isTargetChoice, notTarget, isYou, "hand 3", new TargetCardInHand(3, anyCard)));
|
||||||
|
runner.registerDialog(new ChooseCardsTestableDialog(isTargetChoice, notTarget, isYou, "hand 9", new TargetCardInHand(9, anyCard)));
|
||||||
|
runner.registerDialog(new ChooseCardsTestableDialog(isTargetChoice, notTarget, isYou, "hand 0-1", new TargetCardInHand(0, 1, anyCard)));
|
||||||
|
runner.registerDialog(new ChooseCardsTestableDialog(isTargetChoice, notTarget, isYou, "hand 0-3", new TargetCardInHand(0, 3, anyCard)));
|
||||||
|
runner.registerDialog(new ChooseCardsTestableDialog(isTargetChoice, notTarget, isYou, "hand 0-9", new TargetCardInHand(0, 9, anyCard)));
|
||||||
|
runner.registerDialog(new ChooseCardsTestableDialog(isTargetChoice, notTarget, isYou, "hand any", new TargetCardInHand(0, Integer.MAX_VALUE, anyCard)));
|
||||||
|
runner.registerDialog(new ChooseCardsTestableDialog(isTargetChoice, notTarget, isYou, "hand 1-3", new TargetCardInHand(1, 3, anyCard)));
|
||||||
|
runner.registerDialog(new ChooseCardsTestableDialog(isTargetChoice, notTarget, isYou, "hand 2-3", new TargetCardInHand(2, 3, anyCard)));
|
||||||
|
runner.registerDialog(new ChooseCardsTestableDialog(isTargetChoice, notTarget, isYou, "hand 2-9", new TargetCardInHand(2, 9, anyCard)));
|
||||||
|
runner.registerDialog(new ChooseCardsTestableDialog(isTargetChoice, notTarget, isYou, "hand 8-9", new TargetCardInHand(8, 9, anyCard)));
|
||||||
|
//
|
||||||
|
runner.registerDialog(new ChooseCardsTestableDialog(isTargetChoice, notTarget, isYou, "impossible 0, X=0", new TargetCardInHand(0, impossibleCard)));
|
||||||
|
runner.registerDialog(new ChooseCardsTestableDialog(isTargetChoice, notTarget, isYou, "impossible 1", new TargetCardInHand(1, impossibleCard)));
|
||||||
|
runner.registerDialog(new ChooseCardsTestableDialog(isTargetChoice, notTarget, isYou, "impossible 3", new TargetCardInHand(3, impossibleCard)));
|
||||||
|
runner.registerDialog(new ChooseCardsTestableDialog(isTargetChoice, notTarget, isYou, "impossible 0-1", new TargetCardInHand(0, 1, impossibleCard)));
|
||||||
|
runner.registerDialog(new ChooseCardsTestableDialog(isTargetChoice, notTarget, isYou, "impossible 0-3", new TargetCardInHand(0, 3, impossibleCard)));
|
||||||
|
runner.registerDialog(new ChooseCardsTestableDialog(isTargetChoice, notTarget, isYou, "impossible any", new TargetCardInHand(0, Integer.MAX_VALUE, impossibleCard)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
package mage.utils.testers;
|
||||||
|
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.choices.*;
|
||||||
|
import mage.constants.Outcome;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.players.Player;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Part of testable game dialogs
|
||||||
|
* <p>
|
||||||
|
* Supported methods:
|
||||||
|
* - player.choose(choice)
|
||||||
|
*
|
||||||
|
* @author JayDi85
|
||||||
|
*/
|
||||||
|
class ChooseChoiceTestableDialog extends BaseTestableDialog {
|
||||||
|
|
||||||
|
boolean isYou; // who choose - you or opponent
|
||||||
|
Choice choice;
|
||||||
|
|
||||||
|
public ChooseChoiceTestableDialog(boolean isYou, String name, Choice choice) {
|
||||||
|
super(String.format("player.choose(%s, choice)", isYou ? "you" : "AI"), name, choice.getClass().getSimpleName());
|
||||||
|
this.isYou = isYou;
|
||||||
|
this.choice = choice;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> showDialog(Player player, Ability source, Game game, Player opponent) {
|
||||||
|
Player choosingPlayer = this.isYou ? player : opponent;
|
||||||
|
Choice dialog = this.choice.copy();
|
||||||
|
boolean chooseRes = choosingPlayer.choose(Outcome.Benefit, dialog, game);
|
||||||
|
|
||||||
|
List<String> result = new ArrayList<>();
|
||||||
|
result.add(getGroup() + " - " + this.getName() + " - " + (chooseRes ? "TRUE" : "FALSE"));
|
||||||
|
result.add("");
|
||||||
|
if (dialog.isKeyChoice()) {
|
||||||
|
String key = dialog.getChoiceKey();
|
||||||
|
result.add(String.format("* selected key: %s (%s)", key, dialog.getKeyChoices().getOrDefault(key, null)));
|
||||||
|
} else {
|
||||||
|
result.add(String.format("* selected value: %s", dialog.getChoice()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static public void register(TestableDialogsRunner runner) {
|
||||||
|
// TODO: add require option
|
||||||
|
// TODO: add ChoiceImpl with diff popup hints
|
||||||
|
List<Boolean> isYous = Arrays.asList(false, true);
|
||||||
|
for (boolean isYou : isYous) {
|
||||||
|
runner.registerDialog(new ChooseChoiceTestableDialog(isYou, "", new ChoiceBasicLandType()));
|
||||||
|
runner.registerDialog(new ChooseChoiceTestableDialog(isYou, "", new ChoiceCardType()));
|
||||||
|
runner.registerDialog(new ChooseChoiceTestableDialog(isYou, "", new ChoiceColor()));
|
||||||
|
runner.registerDialog(new ChooseChoiceTestableDialog(isYou, "", new ChoiceColorOrArtifact()));
|
||||||
|
runner.registerDialog(new ChooseChoiceTestableDialog(isYou, "", new ChoiceCreatureType(null, null))); // TODO: must be dynamic to pass game/source
|
||||||
|
runner.registerDialog(new ChooseChoiceTestableDialog(isYou, "", new ChoiceLandType()));
|
||||||
|
runner.registerDialog(new ChooseChoiceTestableDialog(isYou, "", new ChoiceLeftOrRight()));
|
||||||
|
runner.registerDialog(new ChooseChoiceTestableDialog(isYou, "", new ChoicePlaneswalkerType())); // TODO: must be dynamic to pass game/source
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
package mage.utils.testers;
|
||||||
|
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.cards.Card;
|
||||||
|
import mage.constants.Outcome;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.players.Player;
|
||||||
|
import mage.util.CardUtil;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Part of testable game dialogs
|
||||||
|
* <p>
|
||||||
|
* Supported methods:
|
||||||
|
* - player.choosePile()
|
||||||
|
*
|
||||||
|
* @author JayDi85
|
||||||
|
*/
|
||||||
|
class ChoosePileTestableDialog extends BaseTestableDialog {
|
||||||
|
|
||||||
|
boolean isYou; // who choose - you or opponent
|
||||||
|
int pileSize1;
|
||||||
|
int pileSize2;
|
||||||
|
|
||||||
|
public ChoosePileTestableDialog(boolean isYou, int pileSize1, int pileSize2) {
|
||||||
|
super(String.format("player.choosePile(%s)", isYou ? "you" : "AI"), "pile sizes: " + pileSize1 + " and " + pileSize2, "");
|
||||||
|
this.isYou = isYou;
|
||||||
|
this.pileSize1 = pileSize1;
|
||||||
|
this.pileSize2 = pileSize2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> showDialog(Player player, Ability source, Game game, Player opponent) {
|
||||||
|
// TODO: it's ok to show broken title - must add html support in windows's title someday
|
||||||
|
String mainMessage = "main <font color=green>message</font> with html" + CardUtil.getSourceLogName(game, source);
|
||||||
|
|
||||||
|
// random piles (make sure it contain good amount of cards)
|
||||||
|
List<Card> all = new ArrayList<>(game.getCards());
|
||||||
|
Collections.shuffle(all);
|
||||||
|
List<Card> pile1 = all.stream().limit(this.pileSize1).collect(Collectors.toList());
|
||||||
|
Collections.shuffle(all);
|
||||||
|
List<Card> pile2 = all.stream().limit(this.pileSize2).collect(Collectors.toList());
|
||||||
|
|
||||||
|
Player choosingPlayer = this.isYou ? player : opponent;
|
||||||
|
boolean chooseRes = choosingPlayer.choosePile(Outcome.Benefit, mainMessage, pile1, pile2, game);
|
||||||
|
List<String> result = new ArrayList<>();
|
||||||
|
result.add(getGroup() + " - " + this.getName() + " - " + (chooseRes ? "TRUE" : "FALSE"));
|
||||||
|
result.add(" * selected pile: " + (chooseRes ? "pile 1" : "pile 2"));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static public void register(TestableDialogsRunner runner) {
|
||||||
|
List<Boolean> isYous = Arrays.asList(false, true);
|
||||||
|
for (boolean isYou : isYous) {
|
||||||
|
runner.registerDialog(new ChoosePileTestableDialog(isYou, 3, 5));
|
||||||
|
runner.registerDialog(new ChoosePileTestableDialog(isYou, 10, 10));
|
||||||
|
runner.registerDialog(new ChoosePileTestableDialog(isYou, 30, 30));
|
||||||
|
runner.registerDialog(new ChoosePileTestableDialog(isYou, 90, 90));
|
||||||
|
runner.registerDialog(new ChoosePileTestableDialog(isYou, 0, 10));
|
||||||
|
runner.registerDialog(new ChoosePileTestableDialog(isYou, 10, 0));
|
||||||
|
runner.registerDialog(new ChoosePileTestableDialog(isYou, 0, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||