diff --git a/Mage.Client/manifest.mf b/Mage.Client/manifest.mf deleted file mode 100644 index 3ccfa98e1d8..00000000000 --- a/Mage.Client/manifest.mf +++ /dev/null @@ -1,3 +0,0 @@ -Manifest-Version: 1.0 -X-COMMENT: Main-Class will be added automatically by build -SplashScreen-Image: splash.jpg diff --git a/Mage.Client/pom.xml b/Mage.Client/pom.xml index 35baf24109c..776034c3ba5 100644 --- a/Mage.Client/pom.xml +++ b/Mage.Client/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.31 + 1.4.32 org.mage @@ -194,11 +194,13 @@ maven-jar-plugin - ${manifest.file} true mage.client.MageFrame + + splash.jpg + diff --git a/Mage.Client/src/main/java/mage/client/MageFrame.java b/Mage.Client/src/main/java/mage/client/MageFrame.java index 34377722947..d0f3ebde883 100644 --- a/Mage.Client/src/main/java/mage/client/MageFrame.java +++ b/Mage.Client/src/main/java/mage/client/MageFrame.java @@ -1,21 +1,5 @@ - package mage.client; -import java.awt.*; -import java.awt.event.*; -import java.awt.image.BufferedImage; -import java.io.IOException; -import java.io.InputStream; -import java.net.SocketException; -import java.util.*; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.prefs.Preferences; -import javax.imageio.ImageIO; -import javax.swing.*; -import javax.swing.event.PopupMenuEvent; -import javax.swing.event.PopupMenuListener; import mage.cards.action.ActionCallback; import mage.cards.decks.Deck; import mage.cards.repository.CardRepository; @@ -63,10 +47,26 @@ import net.java.truevfs.access.TConfig; import net.java.truevfs.kernel.spec.FsAccessOption; import org.apache.log4j.Logger; import org.mage.card.arcane.ManaSymbols; -import org.mage.plugins.card.images.DownloadPictures; +import org.mage.plugins.card.images.DownloadPicturesService; import org.mage.plugins.card.info.CardInfoPaneImpl; import org.mage.plugins.card.utils.impl.ImageManagerImpl; +import javax.imageio.ImageIO; +import javax.swing.*; +import javax.swing.event.PopupMenuEvent; +import javax.swing.event.PopupMenuListener; +import java.awt.*; +import java.awt.event.*; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.InputStream; +import java.net.SocketException; +import java.util.*; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.prefs.Preferences; + /** * @author BetaSteward_at_googlemail.com */ @@ -93,7 +93,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { private static final Preferences PREFS = Preferences.userNodeForPackage(MageFrame.class); private JLabel title; private Rectangle titleRectangle; - private static final MageVersion VERSION = new MageVersion(MageVersion.MAGE_VERSION_MAJOR, MageVersion.MAGE_VERSION_MINOR, MageVersion.MAGE_VERSION_PATCH, MageVersion.MAGE_VERSION_MINOR_PATCH, MageVersion.MAGE_VERSION_INFO); + private static final MageVersion VERSION = new MageVersion(MageFrame.class); private Connection currentConnection; private static MagePane activeFrame; private static boolean liteMode = false; @@ -136,7 +136,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { public static boolean isGray() { return grayMode; } - + public static boolean isSkipSmallSymbolGenerationForExisting() { return skipSmallSymbolGenerationForExisting; } @@ -760,7 +760,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { prepareAndShowTablesPane(); return true; } else { - showMessage("Unable to connect to server"); + showMessage("Unable connect to server"); } } finally { setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); @@ -934,16 +934,16 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(desktopPane, javax.swing.GroupLayout.DEFAULT_SIZE, 769, Short.MAX_VALUE) - .addComponent(mageToolbar, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(desktopPane, javax.swing.GroupLayout.DEFAULT_SIZE, 769, Short.MAX_VALUE) + .addComponent(mageToolbar, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(mageToolbar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(2, 2, 2) - .addComponent(desktopPane, javax.swing.GroupLayout.DEFAULT_SIZE, 145, Short.MAX_VALUE)) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(mageToolbar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(2, 2, 2) + .addComponent(desktopPane, javax.swing.GroupLayout.DEFAULT_SIZE, 145, Short.MAX_VALUE)) ); pack(); @@ -1010,7 +1010,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { }//GEN-LAST:event_btnImagesActionPerformed public void downloadImages() { - DownloadPictures.startDownload(); + DownloadPicturesService.startDownload(); } public void exitApp() { @@ -1168,7 +1168,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { startTime = System.currentTimeMillis(); Thread.setDefaultUncaughtExceptionHandler((t, e) -> LOGGER.fatal(null, e)); - + SwingUtilities.invokeLater(() -> { for (int i = 0; i < args.length; i++) { String arg = args[i]; @@ -1184,20 +1184,20 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { if (arg.startsWith(SKIP_DONE_SYMBOLS)) { skipSmallSymbolGenerationForExisting = true; } - if (arg.startsWith(USER_ARG)){ - startUser = args[i+1]; + if (arg.startsWith(USER_ARG)) { + startUser = args[i + 1]; i++; } - if (arg.startsWith(PASSWORD_ARG)){ - startPassword = args[i+1]; + if (arg.startsWith(PASSWORD_ARG)) { + startPassword = args[i + 1]; i++; } - if (arg.startsWith(SERVER_ARG)){ - startServer = args[i+1]; + if (arg.startsWith(SERVER_ARG)) { + startServer = args[i + 1]; i++; } - if (arg.startsWith(PORT_ARG)){ - startPort = Integer.valueOf(args[i+1]); + if (arg.startsWith(PORT_ARG)) { + startPort = Integer.valueOf(args[i + 1]); i++; } } @@ -1212,14 +1212,14 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { } } instance = new MageFrame(); - - if( startUser != null){ + + if (startUser != null) { instance.currentConnection = new Connection(); instance.currentConnection.setUsername(startUser); instance.currentConnection.setHost(startServer); - if (startPort > 0){ + if (startPort > 0) { instance.currentConnection.setPort(startPort); - }else { + } else { instance.currentConnection.setPort(MagePreferences.getServerPortWithDefault(Config.port)); } PreferencesDialog.setProxyInformation(instance.currentConnection); @@ -1339,18 +1339,18 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { } else { LOGGER.info("DISCONNECTED (NO Event Dispatch Thread)"); SwingUtilities.invokeLater(() -> { - setConnectButtonText(NOT_CONNECTED_TEXT); - disableButtons(); - hideGames(); - hideTables(); - SessionHandler.disconnect(false); - if (errorCall) { - UserRequestMessage message = new UserRequestMessage("Connection lost", "The connection to server was lost. Reconnect?"); - message.setButton1("No", null); - message.setButton2("Yes", PlayerAction.CLIENT_RECONNECT); - showUserRequestDialog(message); - } - } + setConnectButtonText(NOT_CONNECTED_TEXT); + disableButtons(); + hideGames(); + hideTables(); + SessionHandler.disconnect(false); + if (errorCall) { + UserRequestMessage message = new UserRequestMessage("Connection lost", "The connection to server was lost. Reconnect?"); + message.setButton1("No", null); + message.setButton2("Yes", PlayerAction.CLIENT_RECONNECT); + showUserRequestDialog(message); + } + } ); } } @@ -1380,7 +1380,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { Plugins.instance.downloadSymbols(); break; case CLIENT_DOWNLOAD_CARD_IMAGES: - DownloadPictures.startDownload(); + DownloadPicturesService.startDownload(); break; case CLIENT_DISCONNECT: if (SessionHandler.isConnected()) { diff --git a/Mage.Client/src/main/java/mage/client/components/ability/AbilityPicker.java b/Mage.Client/src/main/java/mage/client/components/ability/AbilityPicker.java index 98881758dbb..90eff9c8ec5 100644 --- a/Mage.Client/src/main/java/mage/client/components/ability/AbilityPicker.java +++ b/Mage.Client/src/main/java/mage/client/components/ability/AbilityPicker.java @@ -1,9 +1,8 @@ package mage.client.components.ability; import mage.client.SessionHandler; +import mage.client.dialog.MageDialog; import mage.client.util.ImageHelper; -import mage.client.util.SettingsManager; -import mage.client.util.gui.GuiDisplayUtil; import mage.remote.Session; import mage.view.AbilityPickerView; import org.apache.log4j.Logger; @@ -17,8 +16,8 @@ import org.mage.card.arcane.UI; import javax.swing.*; import java.awt.*; import java.awt.event.*; -import java.util.*; import java.util.List; +import java.util.*; /** * Dialog for choosing abilities. @@ -112,10 +111,7 @@ public class AbilityPicker extends JXPanel implements MouseWheelListener { this.selected = false; // back to false - waiting for selection setVisible(true); - Point centered = SettingsManager.instance.getComponentPosition(DIALOG_WIDTH, DIALOG_HEIGHT); - this.setLocation(centered.x, centered.y); - GuiDisplayUtil.keepComponentInsideScreen(centered.x, centered.y, this); - + MageDialog.makeWindowCentered(this, DIALOG_WIDTH, DIALOG_HEIGHT); //startModal(); } @@ -188,28 +184,28 @@ public class AbilityPicker extends JXPanel implements MouseWheelListener { GroupLayout.TRAILING, layout.createSequentialGroup().addContainerGap().add( layout.createParallelGroup(GroupLayout.TRAILING).add(GroupLayout.LEADING, jScrollPane2, GroupLayout.DEFAULT_SIZE, 422, Short.MAX_VALUE).add(GroupLayout.LEADING, - layout.createSequentialGroup().add(jLabel1).addPreferredGap(LayoutStyle.RELATED, 175, Short.MAX_VALUE).add(1, 1, 1)).add( - GroupLayout.LEADING, - layout.createSequentialGroup().add(layout.createParallelGroup(GroupLayout.LEADING) - ) - .addPreferredGap(LayoutStyle.RELATED) - .add( - layout.createParallelGroup(GroupLayout.TRAILING) - .add( - GroupLayout.LEADING, layout.createParallelGroup(GroupLayout.LEADING))))).add(10, 10, 10))); + layout.createSequentialGroup().add(jLabel1).addPreferredGap(LayoutStyle.RELATED, 175, Short.MAX_VALUE).add(1, 1, 1)).add( + GroupLayout.LEADING, + layout.createSequentialGroup().add(layout.createParallelGroup(GroupLayout.LEADING) + ) + .addPreferredGap(LayoutStyle.RELATED) + .add( + layout.createParallelGroup(GroupLayout.TRAILING) + .add( + GroupLayout.LEADING, layout.createParallelGroup(GroupLayout.LEADING))))).add(10, 10, 10))); layout.setVerticalGroup(layout.createParallelGroup(GroupLayout.LEADING).add( layout.createSequentialGroup().add( layout.createParallelGroup(GroupLayout.LEADING).add( - layout.createSequentialGroup().add(jLabel1, GroupLayout.PREFERRED_SIZE, 36, GroupLayout.PREFERRED_SIZE) - .add(5, 5, 5) - .add( - layout.createParallelGroup(GroupLayout.BASELINE) - ) - ).add(layout.createSequentialGroup().add(8, 8, 8))) - .addPreferredGap(LayoutStyle.RELATED).add(layout.createParallelGroup(GroupLayout.BASELINE)).addPreferredGap(LayoutStyle.RELATED).add( - layout.createParallelGroup(GroupLayout.BASELINE)).addPreferredGap(LayoutStyle.RELATED).add(layout.createParallelGroup(GroupLayout.LEADING)).addPreferredGap( - LayoutStyle.RELATED).add(jScrollPane2, GroupLayout.PREFERRED_SIZE, 180, GroupLayout.PREFERRED_SIZE).addContainerGap(23, Short.MAX_VALUE))); + layout.createSequentialGroup().add(jLabel1, GroupLayout.PREFERRED_SIZE, 36, GroupLayout.PREFERRED_SIZE) + .add(5, 5, 5) + .add( + layout.createParallelGroup(GroupLayout.BASELINE) + ) + ).add(layout.createSequentialGroup().add(8, 8, 8))) + .addPreferredGap(LayoutStyle.RELATED).add(layout.createParallelGroup(GroupLayout.BASELINE)).addPreferredGap(LayoutStyle.RELATED).add( + layout.createParallelGroup(GroupLayout.BASELINE)).addPreferredGap(LayoutStyle.RELATED).add(layout.createParallelGroup(GroupLayout.LEADING)).addPreferredGap( + LayoutStyle.RELATED).add(jScrollPane2, GroupLayout.PREFERRED_SIZE, 180, GroupLayout.PREFERRED_SIZE).addContainerGap(23, Short.MAX_VALUE))); } @Override diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/MageBook.java b/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/MageBook.java index fd53051191c..7749b95c800 100644 --- a/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/MageBook.java +++ b/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/MageBook.java @@ -41,7 +41,7 @@ import mage.view.PlaneView; import org.apache.log4j.Logger; import org.mage.card.arcane.ManaSymbols; import org.mage.plugins.card.images.CardDownloadData; -import static org.mage.plugins.card.images.DownloadPictures.getTokenCardUrls; +import static org.mage.plugins.card.images.DownloadPicturesService.getTokenCardUrls; /** * Mage book with cards and page flipping. diff --git a/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java b/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java index 10e188e3336..981d34781e2 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java @@ -34,6 +34,8 @@ import javax.swing.DefaultComboBoxModel; import javax.swing.JLayeredPane; import javax.swing.JOptionPane; import javax.swing.SwingWorker; + +import mage.cards.repository.CardRepository; import mage.choices.Choice; import mage.choices.ChoiceImpl; import mage.client.MageFrame; @@ -454,7 +456,8 @@ public class ConnectDialog extends MageDialog { connection.setPort(Integer.valueOf(this.txtPort.getText().trim())); connection.setUsername(this.txtUserName.getText().trim()); connection.setPassword(this.txtPassword.getText().trim()); - connection.setForceDBComparison(this.chkForceUpdateDB.isSelected()); + boolean redownloadDatabase = CardRepository.instance.findCard("Island") == null; + connection.setForceDBComparison(this.chkForceUpdateDB.isSelected() || redownloadDatabase); String allMAC = ""; try { allMAC = connection.getMAC(); diff --git a/Mage.Client/src/main/java/mage/client/dialog/DownloadImagesDialog.form b/Mage.Client/src/main/java/mage/client/dialog/DownloadImagesDialog.form new file mode 100644 index 00000000000..2ab6699220e --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/dialog/DownloadImagesDialog.form @@ -0,0 +1,560 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Mage.Client/src/main/java/mage/client/dialog/DownloadImagesDialog.java b/Mage.Client/src/main/java/mage/client/dialog/DownloadImagesDialog.java new file mode 100644 index 00000000000..35124e322f5 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/dialog/DownloadImagesDialog.java @@ -0,0 +1,470 @@ +package mage.client.dialog; + +import mage.client.MageFrame; +import mage.client.util.gui.FastSearchUtil; +import mage.client.util.gui.MageDialogState; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import java.util.HashMap; +import java.util.Map; + +/** + * @author JayDi85 + */ +public class DownloadImagesDialog extends MageDialog { + + public static final int RET_CANCEL = 0; + public static final int RET_OK = 1; + + private Dimension sizeModeMessageOnly; + private Dimension sizeModeMessageAndControls; + private Map actionsControlStates = new HashMap<>(); + + + /** + * Creates new form DownloadImagesDialog + */ + public DownloadImagesDialog() { + initComponents(); + this.setModal(true); + + // fix for panelInfo (it's resets aligmentX after netbeans designer opened) + panelInfo.setAlignmentX(CENTER_ALIGNMENT); + + // save default sizes + // + this.sizeModeMessageAndControls = new Dimension(580, 330); // dialog -> properties -> designer size + // + this.sizeModeMessageOnly = new Dimension(this.sizeModeMessageAndControls.getSize()); + sizeModeMessageOnly.height = 25 * 4; + sizeModeMessageOnly.width = sizeModeMessageOnly.width / 2; + + // Close the dialog when Esc is pressed + String cancelName = "cancel"; + InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelName); + ActionMap actionMap = getRootPane().getActionMap(); + actionMap.put(cancelName, new AbstractAction() { + public void actionPerformed(ActionEvent e) { + doClose(RET_CANCEL); + } + }); + } + + public void setWindowSize(int width, int heigth) { + this.setSize(new Dimension(width, heigth)); + } + + public void showDialog() { + showDialog(null); + } + + public void showDialog(MageDialogState mageDialogState) { + showDownloadControls(false); // call to change window size + + // window settings + if (this.isModal()) { + MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER); + } else { + MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER); + } + if (mageDialogState != null) { + mageDialogState.setStateToDialog(this); + } else { + this.makeWindowCentered(); + } + this.setVisible(true); + } + + public void setGlobalInfo(String info) { + this.labelGlobal.setText(info); + } + + public void setCurrentInfo(String info) { + this.labelInfo.setText(info); + } + + public JComboBox getSourcesCombo() { + return this.comboSource; + } + + public JComboBox getLaunguagesCombo() { + return this.comboLanguage; + } + + public JComboBox getSetsCombo() { + return this.comboSets; + } + + public JButton getStartButton() { + return this.buttonOK; + } + + public JButton getCancelButton() { + return this.buttonCancel; + } + + public JButton getStopButton() { + return this.buttonStop; + } + + public JProgressBar getProgressBar() { + return this.progress; + } + + public JCheckBox getRedownloadCheckbox() { + return this.checkboxRedownload; + } + + public void showLanguagesSupport(boolean haveSupport) { + labelLanguage.setEnabled(haveSupport); + comboLanguage.setEnabled(haveSupport); + } + + private void enableActionControl(boolean enable, Component comp) { + if (enable) { + // restore last enable state + comp.setEnabled(actionsControlStates.getOrDefault(comp, true)); + } else { + // save enable state and disable it + actionsControlStates.putIfAbsent(comp, comp.isEnabled()); + comp.setEnabled(false); + } + } + + public void enableActionControls(boolean enable) { + // restrict user actions while downloading/processing (all buttons, comboboxes and edits) + enableActionControl(enable, tabsList); + enableActionControl(enable, comboSource); + enableActionControl(enable, comboSets); + enableActionControl(enable, buttonSearchSet); + enableActionControl(enable, comboLanguage); + enableActionControl(enable, checkboxRedownload); + } + + private void setTabTitle(int tabIndex, String title, String iconResourceName) { + // tab caption with left sided icon + // https://stackoverflow.com/questions/1782224/jtabbedpane-icon-on-left-side-of-tabs + JLabel lbl = new JLabel(title); + Icon icon = new ImageIcon(getClass().getResource(iconResourceName)); + lbl.setIcon(icon); + lbl.setIconTextGap(5); + lbl.setHorizontalTextPosition(SwingConstants.RIGHT); + tabsList.setTabComponentAt(tabIndex, lbl); + } + + public void showDownloadControls(boolean needToShow) { + // 2 modes: + // - only message; + // - message + download controls and buttons + this.panelGlobal.setVisible(true); + this.buttonStop.setVisible(!needToShow); // stop button only for loading mode + this.tabsList.setVisible(needToShow); + this.panelCommands.setVisible(needToShow); + + // auto-size form + if (needToShow) { + this.setWindowSize(this.sizeModeMessageAndControls.width, this.sizeModeMessageAndControls.height); + } else { + this.setWindowSize(this.sizeModeMessageOnly.width, this.sizeModeMessageOnly.height); + } + this.makeWindowCentered(); + //this.setLocationRelativeTo(null); // center screen //FIX + + // icons on tabs left side + setTabTitle(0, "Standard download", "/buttons/card_panel.png"); + setTabTitle(1, "Custom download", "/buttons/list_panel.png"); + + // TODO: add manual mode as tab + this.tabsList.getTabComponentAt(1).setEnabled(false); + this.tabsList.setEnabledAt(1, false); + } + + /** + * @return the return status of this dialog - one of RET_OK or RET_CANCEL + */ + public int getReturnStatus() { + return returnStatus; + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + panelGlobal = new javax.swing.JPanel(); + fillerGlobal1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 5), new java.awt.Dimension(0, 5), new java.awt.Dimension(32767, 5)); + labelGlobal = new javax.swing.JLabel(); + buttonStop = new javax.swing.JButton(); + fillerglobal2 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 5), new java.awt.Dimension(0, 5), new java.awt.Dimension(32767, 5)); + tabsList = new javax.swing.JTabbedPane(); + tabMain = new javax.swing.JPanel(); + panelInfo = new javax.swing.JPanel(); + fillerInfo1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 5), new java.awt.Dimension(0, 5), new java.awt.Dimension(32767, 5)); + labelInfo = new javax.swing.JLabel(); + fillerInfo2 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 5), new java.awt.Dimension(0, 5), new java.awt.Dimension(32767, 5)); + panelSource = new javax.swing.JPanel(); + panelSourceLeft = new javax.swing.JPanel(); + labelSource = new javax.swing.JLabel(); + comboSource = new javax.swing.JComboBox<>(); + panelSourceRight = new javax.swing.JPanel(); + labelLanguage = new javax.swing.JLabel(); + comboLanguage = new javax.swing.JComboBox<>(); + panelMode = new javax.swing.JPanel(); + panelModeInner = new javax.swing.JPanel(); + labelMode = new javax.swing.JLabel(); + panelModeSelect = new javax.swing.JPanel(); + comboSets = new javax.swing.JComboBox<>(); + fillerMode1 = new javax.swing.Box.Filler(new java.awt.Dimension(5, 0), new java.awt.Dimension(5, 0), new java.awt.Dimension(5, 32767)); + buttonSearchSet = new javax.swing.JButton(); + panelRedownload = new javax.swing.JPanel(); + checkboxRedownload = new javax.swing.JCheckBox(); + filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 5), new java.awt.Dimension(0, 3), new java.awt.Dimension(32767, 5)); + fillerMain1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 10), new java.awt.Dimension(0, 10), new java.awt.Dimension(32767, 10)); + panelProgress = new javax.swing.JPanel(); + fillerProgress1 = new javax.swing.Box.Filler(new java.awt.Dimension(5, 0), new java.awt.Dimension(5, 0), new java.awt.Dimension(5, 32767)); + progress = new javax.swing.JProgressBar(); + fillerProgress2 = new javax.swing.Box.Filler(new java.awt.Dimension(5, 0), new java.awt.Dimension(5, 0), new java.awt.Dimension(5, 32767)); + fillerMain2 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 32767)); + tabCustom = new javax.swing.JPanel(); + panelCommands = new javax.swing.JPanel(); + buttonOK = new javax.swing.JButton(); + buttonCancel = new javax.swing.JButton(); + + setTitle("Downloading images"); + setPreferredSize(new java.awt.Dimension(600, 400)); + getContentPane().setLayout(new java.awt.BorderLayout()); + + panelGlobal.setLayout(new javax.swing.BoxLayout(panelGlobal, javax.swing.BoxLayout.Y_AXIS)); + panelGlobal.add(fillerGlobal1); + + labelGlobal.setText("Initializing image download..."); + labelGlobal.setAlignmentX(0.5F); + panelGlobal.add(labelGlobal); + + buttonStop.setText("Cancel"); + buttonStop.setAlignmentX(0.5F); + buttonStop.setPreferredSize(new java.awt.Dimension(65, 30)); + buttonStop.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonStopActionPerformed(evt); + } + }); + panelGlobal.add(buttonStop); + panelGlobal.add(fillerglobal2); + + getContentPane().add(panelGlobal, java.awt.BorderLayout.NORTH); + + tabsList.setTabLayoutPolicy(javax.swing.JTabbedPane.SCROLL_TAB_LAYOUT); + + tabMain.setLayout(new javax.swing.BoxLayout(tabMain, javax.swing.BoxLayout.Y_AXIS)); + + panelInfo.setLayout(new javax.swing.BoxLayout(panelInfo, javax.swing.BoxLayout.Y_AXIS)); + panelInfo.add(fillerInfo1); + + labelInfo.setText("Missing stats: 12345 card images / 789 token images"); + labelInfo.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 7, 0, 0)); + panelInfo.add(labelInfo); + panelInfo.add(fillerInfo2); + + tabMain.add(panelInfo); + + panelSource.setMaximumSize(new java.awt.Dimension(65536, 55)); + panelSource.setMinimumSize(new java.awt.Dimension(352, 55)); + panelSource.setPreferredSize(new java.awt.Dimension(593, 55)); + panelSource.setLayout(new javax.swing.BoxLayout(panelSource, javax.swing.BoxLayout.X_AXIS)); + + panelSourceLeft.setMinimumSize(new java.awt.Dimension(430, 30)); + panelSourceLeft.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEADING)); + + labelSource.setText("Images source to download:"); + panelSourceLeft.add(labelSource); + + comboSource.setMaximumRowCount(15); + comboSource.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" })); + comboSource.setMinimumSize(new java.awt.Dimension(300, 20)); + comboSource.setPreferredSize(new java.awt.Dimension(400, 25)); + panelSourceLeft.add(comboSource); + + panelSource.add(panelSourceLeft); + + panelSourceRight.setAlignmentX(0.0F); + panelSourceRight.setMaximumSize(new java.awt.Dimension(130, 32767)); + panelSourceRight.setMinimumSize(new java.awt.Dimension(130, 30)); + panelSourceRight.setPreferredSize(new java.awt.Dimension(130, 100)); + panelSourceRight.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEADING)); + + labelLanguage.setText("Language:"); + panelSourceRight.add(labelLanguage); + + comboLanguage.setMaximumRowCount(15); + comboLanguage.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" })); + comboLanguage.setPreferredSize(new java.awt.Dimension(90, 25)); + panelSourceRight.add(comboLanguage); + + panelSource.add(panelSourceRight); + + tabMain.add(panelSource); + + panelMode.setMaximumSize(new java.awt.Dimension(32869, 55)); + panelMode.setMinimumSize(new java.awt.Dimension(322, 55)); + panelMode.setPreferredSize(new java.awt.Dimension(100, 55)); + panelMode.setLayout(new javax.swing.BoxLayout(panelMode, javax.swing.BoxLayout.LINE_AXIS)); + + panelModeInner.setMinimumSize(new java.awt.Dimension(430, 43)); + panelModeInner.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT)); + + labelMode.setText("Sets to download:"); + labelMode.setAlignmentY(0.0F); + panelModeInner.add(labelMode); + + panelModeSelect.setLayout(new javax.swing.BoxLayout(panelModeSelect, javax.swing.BoxLayout.X_AXIS)); + + comboSets.setMaximumRowCount(15); + comboSets.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" })); + comboSets.setPreferredSize(new java.awt.Dimension(373, 25)); + panelModeSelect.add(comboSets); + panelModeSelect.add(fillerMode1); + + buttonSearchSet.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/search_24.png"))); // NOI18N + buttonSearchSet.setToolTipText("Fast search your flag"); + buttonSearchSet.setAlignmentX(1.0F); + buttonSearchSet.setPreferredSize(new java.awt.Dimension(25, 25)); + buttonSearchSet.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonSearchSetActionPerformed(evt); + } + }); + panelModeSelect.add(buttonSearchSet); + + panelModeInner.add(panelModeSelect); + + panelMode.add(panelModeInner); + + panelRedownload.setAlignmentX(0.0F); + panelRedownload.setMaximumSize(new java.awt.Dimension(130, 32767)); + panelRedownload.setMinimumSize(new java.awt.Dimension(130, 30)); + panelRedownload.setPreferredSize(new java.awt.Dimension(130, 100)); + panelRedownload.setLayout(new java.awt.BorderLayout()); + + checkboxRedownload.setText("Re-download selected images"); + checkboxRedownload.setVerticalAlignment(javax.swing.SwingConstants.BOTTOM); + panelRedownload.add(checkboxRedownload, java.awt.BorderLayout.CENTER); + panelRedownload.add(filler1, java.awt.BorderLayout.PAGE_END); + + panelMode.add(panelRedownload); + + tabMain.add(panelMode); + tabMain.add(fillerMain1); + + panelProgress.setMaximumSize(new java.awt.Dimension(32777, 30)); + panelProgress.setMinimumSize(new java.awt.Dimension(20, 30)); + panelProgress.setPreferredSize(new java.awt.Dimension(564, 30)); + panelProgress.setLayout(new javax.swing.BoxLayout(panelProgress, javax.swing.BoxLayout.X_AXIS)); + panelProgress.add(fillerProgress1); + + progress.setValue(75); + progress.setMaximumSize(new java.awt.Dimension(32767, 25)); + progress.setString("123 of 12313 (120 cards/546 tokens) image downloads finished! Please wait! [123 Mb]"); + progress.setStringPainted(true); + panelProgress.add(progress); + panelProgress.add(fillerProgress2); + + tabMain.add(panelProgress); + tabMain.add(fillerMain2); + + tabsList.addTab("Standard download", new javax.swing.ImageIcon(getClass().getResource("/buttons/card_panel.png")), tabMain); // NOI18N + + tabCustom.setLayout(new javax.swing.BoxLayout(tabCustom, javax.swing.BoxLayout.Y_AXIS)); + tabsList.addTab("Custom download", new javax.swing.ImageIcon(getClass().getResource("/buttons/list_panel.png")), tabCustom); // NOI18N + + getContentPane().add(tabsList, java.awt.BorderLayout.CENTER); + + panelCommands.setAlignmentX(0.0F); + panelCommands.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.TRAILING)); + + buttonOK.setText("Start download"); + buttonOK.setPreferredSize(new java.awt.Dimension(120, 30)); + panelCommands.add(buttonOK); + getRootPane().setDefaultButton(buttonOK); + + buttonCancel.setText("Cancel"); + buttonCancel.setPreferredSize(new java.awt.Dimension(80, 30)); + panelCommands.add(buttonCancel); + + getContentPane().add(panelCommands, java.awt.BorderLayout.SOUTH); + + pack(); + }// //GEN-END:initComponents + + /** + * Closes the dialog + */ + private void closeDialog(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_closeDialog + doClose(RET_CANCEL); + }//GEN-LAST:event_closeDialog + + private void buttonSearchSetActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonSearchSetActionPerformed + FastSearchUtil.showFastSearchForStringComboBox(comboSets, FastSearchUtil.DEFAULT_EXPANSION_SEARCH_MESSAGE, 400, 500); + }//GEN-LAST:event_buttonSearchSetActionPerformed + + private void buttonStopActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonStopActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_buttonStopActionPerformed + + private void doClose(int retStatus) { + returnStatus = retStatus; + setVisible(false); + dispose(); + } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton buttonCancel; + private javax.swing.JButton buttonOK; + private javax.swing.JButton buttonSearchSet; + private javax.swing.JButton buttonStop; + private javax.swing.JCheckBox checkboxRedownload; + private javax.swing.JComboBox comboLanguage; + private javax.swing.JComboBox comboSets; + private javax.swing.JComboBox comboSource; + private javax.swing.Box.Filler filler1; + private javax.swing.Box.Filler fillerGlobal1; + private javax.swing.Box.Filler fillerInfo1; + private javax.swing.Box.Filler fillerInfo2; + private javax.swing.Box.Filler fillerMain1; + private javax.swing.Box.Filler fillerMain2; + private javax.swing.Box.Filler fillerMode1; + private javax.swing.Box.Filler fillerProgress1; + private javax.swing.Box.Filler fillerProgress2; + private javax.swing.Box.Filler fillerglobal2; + private javax.swing.JLabel labelGlobal; + private javax.swing.JLabel labelInfo; + private javax.swing.JLabel labelLanguage; + private javax.swing.JLabel labelMode; + private javax.swing.JLabel labelSource; + private javax.swing.JPanel panelCommands; + private javax.swing.JPanel panelGlobal; + private javax.swing.JPanel panelInfo; + private javax.swing.JPanel panelMode; + private javax.swing.JPanel panelModeInner; + private javax.swing.JPanel panelModeSelect; + private javax.swing.JPanel panelProgress; + private javax.swing.JPanel panelRedownload; + private javax.swing.JPanel panelSource; + private javax.swing.JPanel panelSourceLeft; + private javax.swing.JPanel panelSourceRight; + private javax.swing.JProgressBar progress; + private javax.swing.JPanel tabCustom; + private javax.swing.JPanel tabMain; + private javax.swing.JTabbedPane tabsList; + // End of variables declaration//GEN-END:variables + + private int returnStatus = RET_CANCEL; +} diff --git a/Mage.Client/src/main/java/mage/client/dialog/MageDialog.java b/Mage.Client/src/main/java/mage/client/dialog/MageDialog.java index 513f4ede22c..334422f1bbb 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/MageDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/MageDialog.java @@ -1,31 +1,19 @@ - - - /* - * MageDialog.java - * - * Created on 15-Dec-2009, 10:28:27 PM - */ package mage.client.dialog; -import java.awt.AWTEvent; -import java.awt.ActiveEvent; -import java.awt.Component; -import java.awt.EventQueue; -import java.awt.KeyboardFocusManager; -import java.awt.MenuComponent; -import java.awt.TrayIcon; +import mage.client.MageFrame; +import mage.client.util.SettingsManager; +import mage.client.util.gui.GuiDisplayUtil; +import org.apache.log4j.Logger; + +import javax.swing.*; +import java.awt.*; import java.awt.event.InvocationEvent; import java.awt.event.MouseEvent; import java.beans.PropertyVetoException; import java.lang.reflect.InvocationTargetException; import java.util.logging.Level; -import javax.swing.*; - -import mage.client.MageFrame; -import org.apache.log4j.Logger; /** - * * @author BetaSteward_at_googlemail.com */ public class MageDialog extends javax.swing.JInternalFrame { @@ -75,7 +63,7 @@ public class MageDialog extends javax.swing.JInternalFrame { this.toFront(); - if (modal){ + if (modal) { startModal(); } } @@ -105,6 +93,7 @@ public class MageDialog extends javax.swing.JInternalFrame { } private synchronized void startModal() { + // modal loop -- all mouse events must be ignored by other windows try { if (SwingUtilities.isEventDispatchThread()) { EventQueue theQueue = getToolkit().getSystemEventQueue(); @@ -115,18 +104,46 @@ public class MageDialog extends javax.swing.JInternalFrame { // https://github.com/magefree/mage/issues/584 - Let's hope this will fix the Linux window problem if (event.getSource() != null && event.getSource() instanceof TrayIcon && !(event instanceof InvocationEvent)) { - return; + dispatch = false; + //return; // JayDi85: users can move mouse over try icon to disable modal mode (it's a bug but can be used in the future) } + + // ignore mouse events outside from panel, only drag and move allowed -- as example: + // combobox's popup will be selectable outside + // cards and button hints will be works + Component popupComponent = null; + MouseEvent popupEvent = null; if (event instanceof MouseEvent && event.getSource() instanceof Component) { MouseEvent e = (MouseEvent) event; MouseEvent m = SwingUtilities.convertMouseEvent((Component) e.getSource(), e, this); - if (!this.contains(m.getPoint()) && e.getID() != MouseEvent.MOUSE_DRAGGED) { - dispatch = false; + + // disable all outer events (except some actions) + if (!this.contains(m.getPoint())) { + boolean allowedEvent = false; + + // need any mouse move (for hints) + if (e.getID() == MouseEvent.MOUSE_DRAGGED || e.getID() == MouseEvent.MOUSE_MOVED) { + allowedEvent = true; + } + + // need popup clicks and mouse wheel (for out of bound actions) + if (!allowedEvent) { + popupComponent = SwingUtilities.getDeepestComponentAt(e.getComponent(), e.getX(), e.getY()); // show root component (popups creates at root) + if (popupComponent != null && popupComponent.getClass().getName().contains("BasicComboPopup")) { + popupEvent = SwingUtilities.convertMouseEvent((Component) e.getSource(), e, popupComponent); + allowedEvent = true; + } + } + + dispatch = allowedEvent; } } if (dispatch) { - if (event instanceof ActiveEvent) { + if (popupEvent != null) { + // process outer popup events, it's must be FIRST check + popupComponent.dispatchEvent(popupEvent); + } else if (event instanceof ActiveEvent) { ((ActiveEvent) event).dispatch(); } else if (source instanceof Component) { ((Component) source).dispatchEvent(event); @@ -174,14 +191,21 @@ public class MageDialog extends javax.swing.JInternalFrame { java.util.logging.Logger.getLogger(MageDialog.class.getName()).log(Level.SEVERE, "setClosed(false) failed", ex); } MageFrame.getDesktop().remove(this); + } + public void makeWindowCentered() { + makeWindowCentered(this, getWidth(), getHeight()); + } + + public static void makeWindowCentered(Component component, int width, int height) { + Point centered = SettingsManager.instance.getComponentPosition(width, height); + component.setLocation(centered.x, centered.y); + GuiDisplayUtil.keepComponentInsideScreen(centered.x, centered.y, component); } /** * Used to set a tooltip text on icon and titel bar * - * used in {@link ExileZoneDialog} and {@link ShowCardsDialog} - * * @param text */ public void setTitelBarToolTip(final String text) { @@ -209,12 +233,12 @@ public class MageDialog extends javax.swing.JInternalFrame { javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 394, Short.MAX_VALUE) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 394, Short.MAX_VALUE) ); layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 274, Short.MAX_VALUE) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 274, Short.MAX_VALUE) ); pack(); diff --git a/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java b/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java index 0e3121f61d9..c47059ed798 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java @@ -51,6 +51,7 @@ public class NewTableDialog extends MageDialog { this.spnNumWins.setModel(new SpinnerNumberModel(1, 1, 5, 1)); this.spnFreeMulligans.setModel(new SpinnerNumberModel(0, 0, 5, 1)); this.spnQuitRatio.setModel(new SpinnerNumberModel(100, 0, 100, 5)); + this.spnMinimumRating.setModel(new SpinnerNumberModel(0, 0, 3000, 10)); this.spnEdhPowerLevel.setModel(new SpinnerNumberModel(100, 0, 100, 5)); MageFrame.getUI().addButton(MageComponents.NEW_TABLE_OK_BUTTON, btnOK); } @@ -102,8 +103,10 @@ public class NewTableDialog extends MageDialog { btnPreviousConfiguration2 = new javax.swing.JButton(); btnCancel = new javax.swing.JButton(); lblQuitRatio = new javax.swing.JLabel(); + lblMinimumRating = new javax.swing.JLabel(); lblEdhPowerLevel = new javax.swing.JLabel(); spnQuitRatio = new javax.swing.JSpinner(); + spnMinimumRating = new javax.swing.JSpinner(); spnEdhPowerLevel = new javax.swing.JSpinner(); setTitle("New Table"); @@ -186,9 +189,11 @@ public class NewTableDialog extends MageDialog { btnCancel.addActionListener(evt -> btnCancelActionPerformed(evt)); lblQuitRatio.setText("Allowed quit %"); + lblMinimumRating.setText("Minimum rating"); lblEdhPowerLevel.setText("EDH power level"); spnQuitRatio.setToolTipText("Players with quit % more than this value can't join this table"); + spnMinimumRating.setToolTipText("Players with rating less than this value can't join this table"); spnEdhPowerLevel.setToolTipText("Players with decks with a higher power level can't join this table"); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); @@ -239,9 +244,10 @@ public class NewTableDialog extends MageDialog { .addComponent(lblQuitRatio) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(spnQuitRatio, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblEdhPowerLevel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(lblMinimumRating) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(spnEdhPowerLevel, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE)))) + .addComponent(spnMinimumRating, javax.swing.GroupLayout.PREFERRED_SIZE, 80, javax.swing.GroupLayout.PREFERRED_SIZE)))) .addComponent(jLabel1, javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jLabel2, javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() @@ -270,7 +276,11 @@ public class NewTableDialog extends MageDialog { .addGap(18, 18, 18) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(lblNumWins) - .addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lblEdhPowerLevel) + .addComponent(spnEdhPowerLevel, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE))) .addComponent(jSeparator2) .addComponent(player1Panel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(pnlOtherPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) @@ -297,14 +307,13 @@ public class NewTableDialog extends MageDialog { .addComponent(cbTimeLimit, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(cbDeckType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(lbDeckType) + .addComponent(cbDeckType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(chkRated) .addComponent(lblQuitRatio) - .addComponent(chkRated) .addComponent(spnQuitRatio, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblEdhPowerLevel) - .addComponent(chkRated) - .addComponent(spnEdhPowerLevel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(lblMinimumRating) + .addComponent(spnMinimumRating, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) @@ -326,6 +335,7 @@ public class NewTableDialog extends MageDialog { .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(lblSkillLevel) .addComponent(lblNumWins) + .addComponent(lblEdhPowerLevel) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(lblRange) .addComponent(lblAttack))) @@ -334,7 +344,8 @@ public class NewTableDialog extends MageDialog { .addComponent(cbRange, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(cbAttackOption, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(cbSkillLevel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))) + .addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(spnEdhPowerLevel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jSeparator2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) @@ -394,6 +405,7 @@ public class NewTableDialog extends MageDialog { options.setFreeMulligans((Integer) this.spnFreeMulligans.getValue()); options.setPassword(this.txtPassword.getText()); options.setQuitRatio((Integer) this.spnQuitRatio.getValue()); + options.setMinimumRating((Integer) this.spnMinimumRating.getValue()); options.setEdhPowerLevel((Integer) this.spnEdhPowerLevel.getValue()); String serverAddress = SessionHandler.getSession().getServerHostname().orElseGet(() -> ""); options.setBannedUsers(IgnoreList.ignoreList(serverAddress)); @@ -695,6 +707,7 @@ public class NewTableDialog extends MageDialog { } this.spnQuitRatio.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_QUIT_RATIO, "100"))); + this.spnMinimumRating.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_MINIMUM_RATING + versionStr, "0"))); this.spnEdhPowerLevel.setValue(0); } @@ -729,6 +742,7 @@ public class NewTableDialog extends MageDialog { PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_SPECTATORS_ALLOWED + versionStr, options.isSpectatorsAllowed() ? "Yes" : "No"); PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_PLANECHASE + versionStr, options.isPlaneChase() ? "Yes" : "No"); PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_QUIT_RATIO + versionStr, Integer.toString(options.getQuitRatio())); + PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_MINIMUM_RATING + versionStr, Integer.toString(options.getMinimumRating())); StringBuilder playerTypesString = new StringBuilder(); for (Object player : players) { if (playerTypesString.length() > 0) { @@ -770,6 +784,7 @@ public class NewTableDialog extends MageDialog { private javax.swing.JLabel lblNumWins; private javax.swing.JLabel lblPassword; private javax.swing.JLabel lblQuitRatio; + private javax.swing.JLabel lblMinimumRating; private javax.swing.JLabel lblEdhPowerLevel; private javax.swing.JLabel lblRange; private javax.swing.JLabel lblSkillLevel; @@ -779,6 +794,7 @@ public class NewTableDialog extends MageDialog { private javax.swing.JSpinner spnNumPlayers; private javax.swing.JSpinner spnNumWins; private javax.swing.JSpinner spnQuitRatio; + private javax.swing.JSpinner spnMinimumRating; private javax.swing.JSpinner spnEdhPowerLevel; private javax.swing.JTextField txtName; private javax.swing.JTextField txtPassword; diff --git a/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.java b/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.java index ee0d5aded56..fef9bdab407 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.java @@ -75,6 +75,7 @@ public class NewTournamentDialog extends MageDialog { this.spnConstructTime.setModel(new SpinnerNumberModel(10, CONSTRUCTION_TIME_MIN, CONSTRUCTION_TIME_MAX, 2)); this.spnNumRounds.setModel(new SpinnerNumberModel(2, 2, 10, 1)); this.spnQuitRatio.setModel(new SpinnerNumberModel(100, 0, 100, 5)); + this.spnMinimumRating.setModel(new SpinnerNumberModel(0, 0, 3000, 10)); } public void showDialog(UUID roomId) { @@ -165,6 +166,8 @@ public class NewTournamentDialog extends MageDialog { pnlRandomPacks = new javax.swing.JPanel(); lblQuitRatio = new javax.swing.JLabel(); spnQuitRatio = new javax.swing.JSpinner(); + lblMinimumRating = new javax.swing.JLabel(); + spnMinimumRating = new javax.swing.JSpinner(); setTitle("New Tournament"); @@ -315,8 +318,10 @@ public class NewTournamentDialog extends MageDialog { pnlRandomPacks.setLayout(new javax.swing.BoxLayout(pnlRandomPacks, javax.swing.BoxLayout.Y_AXIS)); lblQuitRatio.setText("Allowed quit %:"); + lblMinimumRating.setText("Minimum rating:"); spnQuitRatio.setToolTipText("Players with quit % more than this value can't join this table"); + spnMinimumRating.setToolTipText("Players with rating less than this value can't join this table"); spnNumSeats.setToolTipText("The number of seats for each duel. If more than 2, will set number of wins to 1"); spnNumPlayers.setToolTipText("The total number of players who will draft"); @@ -386,11 +391,15 @@ public class NewTournamentDialog extends MageDialog { .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) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(lblQuitRatio) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(spnQuitRatio, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(lblMinimumRating) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(spnMinimumRating, javax.swing.GroupLayout.PREFERRED_SIZE, 80, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(chkRated)) .addComponent(cbTournamentType, javax.swing.GroupLayout.PREFERRED_SIZE, 290, javax.swing.GroupLayout.PREFERRED_SIZE))) .addGroup(layout.createSequentialGroup() @@ -444,6 +453,8 @@ public class NewTournamentDialog extends MageDialog { .addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(lblQuitRatio) .addComponent(spnQuitRatio, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblMinimumRating) + .addComponent(spnMinimumRating, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(chkRated)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) @@ -522,6 +533,7 @@ public class NewTournamentDialog extends MageDialog { tOptions.setWatchingAllowed(cbAllowSpectators.isSelected()); tOptions.setPlaneChase(cbPlaneChase.isSelected()); tOptions.setQuitRatio((Integer) spnQuitRatio.getValue()); + tOptions.setMinimumRating((Integer) spnMinimumRating.getValue()); for (TournamentPlayerPanel player : players) { tOptions.getPlayerTypes().add((PlayerType) player.getPlayerType().getSelectedItem()); } @@ -1065,6 +1077,7 @@ public class NewTournamentDialog extends MageDialog { this.spnFreeMulligans.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_NUMBER_OF_FREE_MULLIGANS + versionStr, "0"))); 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.spnMinimumRating.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_MINIMUM_RATING + versionStr, "0"))); TournamentTypeView tournamentType = (TournamentTypeView) cbTournamentType.getSelectedItem(); activatePanelElements(tournamentType); @@ -1150,6 +1163,7 @@ public class NewTournamentDialog extends MageDialog { PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TOURNAMENT_NUMBER_OF_FREE_MULLIGANS + versionStr, Integer.toString(tOptions.getMatchOptions().getFreeMulligans())); PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TOURNAMENT_NUMBER_OF_WINS + versionStr, Integer.toString(tOptions.getMatchOptions().getWinsNeeded())); PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TOURNAMENT_QUIT_RATIO + versionStr, Integer.toString(tOptions.getQuitRatio())); + PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TOURNAMENT_MINIMUM_RATING + versionStr, Integer.toString(tOptions.getMinimumRating())); if (tOptions.getTournamentType().startsWith("Sealed")) { PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TOURNAMENT_PACKS_SEALED + versionStr, tOptions.getLimitedOptions().getSetCodes().toString()); @@ -1221,6 +1235,7 @@ public class NewTournamentDialog extends MageDialog { private javax.swing.JLabel lblPassword; private javax.swing.JLabel lblPlayer1; private javax.swing.JLabel lblQuitRatio; + private javax.swing.JLabel lblMinimumRating; private javax.swing.JLabel lblTournamentType; private mage.client.table.NewPlayerPanel player1Panel; private javax.swing.JPanel pnlDraftOptions; @@ -1235,6 +1250,7 @@ public class NewTournamentDialog extends MageDialog { private javax.swing.JSpinner spnNumRounds; private javax.swing.JSpinner spnNumWins; private javax.swing.JSpinner spnQuitRatio; + private javax.swing.JSpinner spnMinimumRating; private javax.swing.JTextField txtName; private javax.swing.JTextField txtPassword; private org.jdesktop.beansbinding.BindingGroup bindingGroup; diff --git a/Mage.Client/src/main/java/mage/client/dialog/PickCheckBoxDialog.java b/Mage.Client/src/main/java/mage/client/dialog/PickCheckBoxDialog.java index a9d86c20444..1fccfa75335 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PickCheckBoxDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/PickCheckBoxDialog.java @@ -1,37 +1,17 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ package mage.client.dialog; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Point; -import java.awt.event.ActionEvent; -import java.awt.event.KeyEvent; -import java.awt.event.KeyListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.util.*; -import javax.swing.AbstractAction; -import javax.swing.ActionMap; -import javax.swing.DefaultListModel; -import javax.swing.InputMap; -import javax.swing.JComponent; -import javax.swing.JLabel; -import javax.swing.JLayeredPane; -import javax.swing.KeyStroke; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; import mage.choices.Choice; import mage.client.MageFrame; -import mage.client.util.SettingsManager; -import mage.client.util.gui.GuiDisplayUtil; import mage.client.util.gui.MageDialogState; +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import java.awt.*; +import java.awt.event.*; +import java.util.*; + /** - * * @author JayDi85 * @author Salco */ @@ -42,28 +22,29 @@ public class PickCheckBoxDialog extends MageDialog { ArrayList allItems = new ArrayList<>(); DefaultListModel dataModel = new DefaultListModel(); CheckBoxList.CheckBoxListModel m_dataModel; - + CheckBoxList tList; - + final private static String HTML_TEMPLATE = "
%s
"; - private void setFocus(CheckBoxList obj){ - + private void setFocus(CheckBoxList obj) { + if (!(obj instanceof java.awt.Component)) { throw new IllegalArgumentException("Must be a java.awt.Component!"); } - this.scrollList.setViewportView((java.awt.Component)obj); - } - private javax.swing.JList get_a_Jlist_from_ScrollListView(){ - return ((javax.swing.JList)this.scrollList.getViewport().getView()); + this.scrollList.setViewportView((java.awt.Component) obj); } - private void restoreData(Object dataFrom){ + private javax.swing.JList get_a_Jlist_from_ScrollListView() { + return ((javax.swing.JList) this.scrollList.getViewport().getView()); + } + + private void restoreData(Object dataFrom) { this.allItems.forEach((item) -> { - ((CheckBoxList.CheckBoxListModel)dataFrom).addElement(item.getObjectValue()); + ((CheckBoxList.CheckBoxListModel) dataFrom).addElement(item.getObjectValue()); }); } - + public void showDialog(Choice choice) { showDialog(choice, null, null, null); } @@ -75,47 +56,45 @@ public class PickCheckBoxDialog extends MageDialog { public void showDialog(Choice choice, UUID objectId, MageDialogState mageDialogState) { showDialog(choice, objectId, mageDialogState, null); } - + public void showDialog(Choice choice, UUID objectId, MageDialogState mageDialogState, String startSelectionValue) { this.choice = choice; KeyValueItem tempKeyValue; int indexInTList; - + setLabelText(this.labelMessage, choice.getMessage()); setLabelText(this.labelSubMessage, choice.getSubMessage()); - + btCancel.setEnabled(!choice.isRequired()); - + // 2 modes: string or key-values // sore data in allItems for inremental filtering // http://logicbig.com/tutorials/core-java-tutorial/swing/list-filter/ this.allItems.clear(); - if (choice.isKeyChoice()){ - for (Map.Entry entry: choice.getKeyChoices().entrySet()) { - if(tList != null){ + if (choice.isKeyChoice()) { + for (Map.Entry entry : choice.getKeyChoices().entrySet()) { + if (tList != null) { indexInTList = m_dataModel.indexOf(entry.getKey()); - tempKeyValue=new KeyValueItem(entry.getKey(), entry.getValue(),(CheckBoxList.CheckBoxListItem) this.tList.getModel().getElementAt(indexInTList)); - } - else{ - tempKeyValue=new KeyValueItem(entry.getKey(), entry.getValue()); + tempKeyValue = new KeyValueItem(entry.getKey(), entry.getValue(), (CheckBoxList.CheckBoxListItem) this.tList.getModel().getElementAt(indexInTList)); + } else { + tempKeyValue = new KeyValueItem(entry.getKey(), entry.getValue()); } this.allItems.add(tempKeyValue); } } else { - for (String value: choice.getChoices()){ - if(tList != null){ + for (String value : choice.getChoices()) { + if (tList != null) { indexInTList = m_dataModel.indexOf(value); - tempKeyValue=new KeyValueItem(value, value,(CheckBoxList.CheckBoxListItem) tList.getModel().getElementAt(indexInTList)); - } - else{ - tempKeyValue=new KeyValueItem(value, value); + tempKeyValue = new KeyValueItem(value, value, (CheckBoxList.CheckBoxListItem) tList.getModel().getElementAt(indexInTList)); + } else { + tempKeyValue = new KeyValueItem(value, value); } this.allItems.add(tempKeyValue); } } // sorting - if(choice.isSortEnabled()){ + if (choice.isSortEnabled()) { Collections.sort(this.allItems, new Comparator() { @Override public int compare(KeyValueItem o1, KeyValueItem o2) { @@ -125,38 +104,37 @@ public class PickCheckBoxDialog extends MageDialog { } }); } - + // search - if(choice.isSearchEnabled()) - { + if (choice.isSearchEnabled()) { panelSearch.setVisible(true); this.editSearch.setText(choice.getSearchText()); - }else{ + } else { panelSearch.setVisible(false); this.editSearch.setText(""); } - + // listeners for inremental filtering editSearch.getDocument().addDocumentListener(new DocumentListener() { - @Override - public void insertUpdate(DocumentEvent e) { - choice.setSearchText(editSearch.getText()); - loadData(); - } + @Override + public void insertUpdate(DocumentEvent e) { + choice.setSearchText(editSearch.getText()); + loadData(); + } - @Override - public void removeUpdate(DocumentEvent e) { - choice.setSearchText(editSearch.getText()); - loadData(); - } + @Override + public void removeUpdate(DocumentEvent e) { + choice.setSearchText(editSearch.getText()); + loadData(); + } - @Override - public void changedUpdate(DocumentEvent e) { - choice.setSearchText(editSearch.getText()); - loadData(); - } + @Override + public void changedUpdate(DocumentEvent e) { + choice.setSearchText(editSearch.getText()); + loadData(); + } }); - + // listeners for select up and down without edit focus lost editSearch.addKeyListener(new KeyListener() { @Override @@ -165,10 +143,10 @@ public class PickCheckBoxDialog extends MageDialog { } @Override - public void keyPressed(KeyEvent e) { - if(e.getKeyCode() == KeyEvent.VK_UP){ + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_UP) { doPrevSelect(); - }else if(e.getKeyCode() == KeyEvent.VK_DOWN){ + } else if (e.getKeyCode() == KeyEvent.VK_DOWN) { doNextSelect(); } } @@ -178,19 +156,19 @@ public class PickCheckBoxDialog extends MageDialog { //System.out.println("released"); } }); - + // listeners double click choose listChoices.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { - if(e.getClickCount() == 2){ + if (e.getClickCount() == 2) { doChoose(); } } }); - + // listeners for ESC close - if(!choice.isRequired()){ + if (!choice.isRequired()) { String cancelName = "cancel"; InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelName); @@ -201,107 +179,106 @@ public class PickCheckBoxDialog extends MageDialog { } }); } - + // window settings - if (this.isModal()){ + if (this.isModal()) { MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER); - }else{ + } else { MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER); } if (mageDialogState != null) { mageDialogState.setStateToDialog(this); - } else { - Point centered = SettingsManager.instance.getComponentPosition(getWidth(), getHeight()); - this.setLocation(centered.x, centered.y); - GuiDisplayUtil.keepComponentInsideScreen(centered.x, centered.y, this); + this.makeWindowCentered(); } // final load loadData(); // start selection - if((startSelectionValue != null)){ + if ((startSelectionValue != null)) { javax.swing.JList currentlistChoices;// = new javax.swing.JList(); - currentlistChoices=this.get_a_Jlist_from_ScrollListView(); + currentlistChoices = this.get_a_Jlist_from_ScrollListView(); /*currentlistChoices = this.listChoices;*/ int selectIndex = -1; - for(int i = 0; i < this.listChoices.getModel().getSize(); i++){ + for (int i = 0; i < this.listChoices.getModel().getSize(); i++) { //KeyValueItem listItem = (KeyValueItem)currentlistChoices.getModel().getElementAt(i); String elementOfList = currentlistChoices.getModel().getElementAt(i).toString(); - if (elementOfList.equals(startSelectionValue)){ + if (elementOfList.equals(startSelectionValue)) { selectIndex = i; break; } } - if(selectIndex >= 0){ - // currentlistChoices=this.get_a_Jlist_from_ScrollListView(); + if (selectIndex >= 0) { + // currentlistChoices=this.get_a_Jlist_from_ScrollListView(); /*currentlistChoices = this.listChoices;*/ - currentlistChoices.setSelectedIndex(selectIndex); - currentlistChoices.ensureIndexIsVisible(selectIndex); + currentlistChoices.setSelectedIndex(selectIndex); + currentlistChoices.ensureIndexIsVisible(selectIndex); } } this.setVisible(true); } - - public void setWindowSize(int width, int heigth){ + + public void setWindowSize(int width, int heigth) { this.setSize(new Dimension(width, heigth)); } - - private void loadData(){ + + private void loadData() { // load data to datamodel after filter or on startup - String filter = choice.getSearchText(); - if (filter == null){ filter = ""; } + String filter = choice.getSearchText(); + if (filter == null) { + filter = ""; + } filter = filter.toLowerCase(); - + this.dataModel.clear(); this.m_dataModel.clear(); - for(KeyValueItem item: this.allItems){ - if(!choice.isSearchEnabled() || item.Value.toLowerCase().contains(filter)){ + for (KeyValueItem item : this.allItems) { + if (!choice.isSearchEnabled() || item.Value.toLowerCase().contains(filter)) { this.dataModel.addElement(item); this.m_dataModel.addElement(item.getObjectValue()); } } } - - private void setLabelText(JLabel label, String text){ - if ((text != null) && !text.equals("")){ + + private void setLabelText(JLabel label, String text) { + if ((text != null) && !text.equals("")) { label.setText(String.format(HTML_TEMPLATE, text)); label.setVisible(true); - }else{ + } else { label.setText(""); label.setVisible(false); - } - } - - private void doNextSelect(){ - int newSel = this.listChoices.getSelectedIndex() + 1; - int maxSel = this.listChoices.getModel().getSize() - 1; - if(newSel <= maxSel){ - this.listChoices.setSelectedIndex(newSel); - this.listChoices.ensureIndexIsVisible(newSel); } } - - private void doPrevSelect(){ - int newSel = this.listChoices.getSelectedIndex() - 1; - if(newSel >= 0){ + + private void doNextSelect() { + int newSel = this.listChoices.getSelectedIndex() + 1; + int maxSel = this.listChoices.getModel().getSize() - 1; + if (newSel <= maxSel) { this.listChoices.setSelectedIndex(newSel); this.listChoices.ensureIndexIsVisible(newSel); } } - private void doChoose(){ - if((tList != null)||(setChoice())){ + private void doPrevSelect() { + int newSel = this.listChoices.getSelectedIndex() - 1; + if (newSel >= 0) { + this.listChoices.setSelectedIndex(newSel); + this.listChoices.ensureIndexIsVisible(newSel); + } + } + + private void doChoose() { + if ((tList != null) || (setChoice())) { this.m_dataModel.clear(); restoreData(this.m_dataModel); this.hideDialog(); } } - - private void doCancel(){ + + private void doCancel() { this.listChoices.clearSelection(); this.choice.clearChoice(); hideDialog(); @@ -309,91 +286,93 @@ public class PickCheckBoxDialog extends MageDialog { /** * Creates new form PickChoiceDialog - * @param list + * + * @param list */ public PickCheckBoxDialog(CheckBoxList list) { initComponents(); - tList=list; - + tList = list; + this.listChoices.setModel(dataModel); this.setModal(true); - if(tList != null) - { + if (tList != null) { this.listChoices.setVisible(false); - - m_dataModel= ( CheckBoxList.CheckBoxListModel )tList.getModel(); + + m_dataModel = (CheckBoxList.CheckBoxListModel) tList.getModel(); tList.setSelectionForeground(Color.BLUE); - - if(this.tList instanceof javax.swing.JList){ - setFocus(tList); - } - + + if (this.tList instanceof javax.swing.JList) { + setFocus(tList); + } + } } + /** * Creates new form PickChoiceDialog */ public PickCheckBoxDialog() { this(null); } - + public boolean setChoice() { - KeyValueItem item = (KeyValueItem)this.listChoices.getSelectedValue(); - + KeyValueItem item = (KeyValueItem) this.listChoices.getSelectedValue(); + // auto select one item (after incemental filtering) - if((item == null) && (this.listChoices.getModel().getSize() == 1)){ + if ((item == null) && (this.listChoices.getModel().getSize() == 1)) { this.listChoices.setSelectedIndex(0); - item = (KeyValueItem)this.listChoices.getSelectedValue(); + item = (KeyValueItem) this.listChoices.getSelectedValue(); } - - if(item != null){ - if(choice.isKeyChoice()){ + + if (item != null) { + if (choice.isKeyChoice()) { choice.setChoiceByKey(item.getKey()); - }else{ + } else { choice.setChoice(item.getKey()); } return true; - }else{ + } else { choice.clearChoice(); return false; } } - - class KeyValueItem - { + + class KeyValueItem { private final String Key; private final String Value; private final CheckBoxList.CheckBoxListItem objectValue; - - public KeyValueItem(String value) { - this(value,null,null); - } - public KeyValueItem(String value, String label) { - this(value,label,null); + + public KeyValueItem(String value) { + this(value, null, null); } - public KeyValueItem(String value, String label,CheckBoxList.CheckBoxListItem object) { + + public KeyValueItem(String value, String label) { + this(value, label, null); + } + + public KeyValueItem(String value, String label, CheckBoxList.CheckBoxListItem object) { this.Key = value; this.Value = label; - this.objectValue = object; + this.objectValue = object; } public String getKey() { return this.Key; - } + } public String getValue() { return this.Value; } - - public Object getObjectValue(){ - return (CheckBoxList.CheckBoxListItem)this.objectValue; + + public Object getObjectValue() { + return (CheckBoxList.CheckBoxListItem) this.objectValue; } @Override public String toString() { return this.Value; - } + } } /** @@ -428,20 +407,20 @@ public class PickCheckBoxDialog extends MageDialog { javax.swing.GroupLayout panelHeaderLayout = new javax.swing.GroupLayout(panelHeader); panelHeader.setLayout(panelHeaderLayout); panelHeaderLayout.setHorizontalGroup( - panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelHeaderLayout.createSequentialGroup() - .addGroup(panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(labelMessage, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) - .addComponent(labelSubMessage, javax.swing.GroupLayout.Alignment.TRAILING)) - .addGap(0, 0, 0)) + panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelHeaderLayout.createSequentialGroup() + .addGroup(panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(labelMessage, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addComponent(labelSubMessage, javax.swing.GroupLayout.Alignment.TRAILING)) + .addGap(0, 0, 0)) ); panelHeaderLayout.setVerticalGroup( - panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelHeaderLayout.createSequentialGroup() - .addGap(0, 0, Short.MAX_VALUE) - .addComponent(labelMessage) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(labelSubMessage, javax.swing.GroupLayout.DEFAULT_SIZE, 30, Short.MAX_VALUE)) + panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelHeaderLayout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addComponent(labelMessage) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(labelSubMessage, javax.swing.GroupLayout.DEFAULT_SIZE, 30, Short.MAX_VALUE)) ); labelSearch.setText("Search:"); @@ -451,28 +430,34 @@ public class PickCheckBoxDialog extends MageDialog { javax.swing.GroupLayout panelSearchLayout = new javax.swing.GroupLayout(panelSearch); panelSearch.setLayout(panelSearchLayout); panelSearchLayout.setHorizontalGroup( - panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelSearchLayout.createSequentialGroup() - .addGap(0, 0, 0) - .addComponent(labelSearch) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(editSearch) - .addGap(0, 0, 0)) + panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelSearchLayout.createSequentialGroup() + .addGap(0, 0, 0) + .addComponent(labelSearch) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(editSearch) + .addGap(0, 0, 0)) ); panelSearchLayout.setVerticalGroup( - panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelSearchLayout.createSequentialGroup() - .addGap(3, 3, 3) - .addGroup(panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(labelSearch) - .addComponent(editSearch, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(3, 3, 3)) + panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelSearchLayout.createSequentialGroup() + .addGap(3, 3, 3) + .addGroup(panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(labelSearch) + .addComponent(editSearch, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(3, 3, 3)) ); listChoices.setModel(new javax.swing.AbstractListModel() { - String[] strings = { "item1", "item2", "item3" }; - public int getSize() { return strings.length; } - public Object getElementAt(int i) { return strings[i]; } + String[] strings = {"item1", "item2", "item3"}; + + public int getSize() { + return strings.length; + } + + public Object getElementAt(int i) { + return strings[i]; + } }); scrollList.setViewportView(listChoices); @@ -501,25 +486,25 @@ public class PickCheckBoxDialog extends MageDialog { javax.swing.GroupLayout panelCommandsLayout = new javax.swing.GroupLayout(panelCommands); panelCommands.setLayout(panelCommandsLayout); panelCommandsLayout.setHorizontalGroup( - panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelCommandsLayout.createSequentialGroup() - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(btClear, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btOK) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 83, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelCommandsLayout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(btClear, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btOK) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 83, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); panelCommandsLayout.setVerticalGroup( - panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelCommandsLayout.createSequentialGroup() - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(btCancel) - .addComponent(btOK) - .addComponent(btClear, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addContainerGap()) + panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelCommandsLayout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(btCancel) + .addComponent(btOK) + .addComponent(btClear, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap()) ); getRootPane().setDefaultButton(btOK); @@ -528,28 +513,28 @@ public class PickCheckBoxDialog extends MageDialog { javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(scrollList, javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(panelCommands, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(panelHeader, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(panelSearch, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap()) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(scrollList, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(panelCommands, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(panelHeader, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(panelSearch, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) ); layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addContainerGap() - .addComponent(panelHeader, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(panelSearch, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(scrollList, javax.swing.GroupLayout.DEFAULT_SIZE, 240, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(panelCommands, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap()) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addComponent(panelHeader, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(panelSearch, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(scrollList, javax.swing.GroupLayout.DEFAULT_SIZE, 240, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(panelCommands, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) ); pack(); diff --git a/Mage.Client/src/main/java/mage/client/dialog/PickChoiceDialog.java b/Mage.Client/src/main/java/mage/client/dialog/PickChoiceDialog.java index 9a73c93a9bb..aa67888aef5 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PickChoiceDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/PickChoiceDialog.java @@ -1,36 +1,17 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ package mage.client.dialog; -import java.awt.Dimension; -import java.awt.Point; -import java.awt.event.ActionEvent; -import java.awt.event.KeyEvent; -import java.awt.event.KeyListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.util.*; -import javax.swing.AbstractAction; -import javax.swing.ActionMap; -import javax.swing.DefaultListModel; -import javax.swing.InputMap; -import javax.swing.JComponent; -import javax.swing.JLabel; -import javax.swing.JLayeredPane; -import javax.swing.KeyStroke; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; import mage.choices.Choice; import mage.client.MageFrame; -import mage.client.util.SettingsManager; -import mage.client.util.gui.GuiDisplayUtil; import mage.client.util.gui.MageDialogState; +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import java.awt.*; +import java.awt.event.*; +import java.util.*; + /** - * * @author JayDi85 */ @@ -39,7 +20,7 @@ public class PickChoiceDialog extends MageDialog { Choice choice; ArrayList allItems = new ArrayList<>(); DefaultListModel dataModel = new DefaultListModel(); - + final private static String HTML_TEMPLATE = "
%s
"; public void showDialog(Choice choice) { @@ -53,31 +34,31 @@ public class PickChoiceDialog extends MageDialog { public void showDialog(Choice choice, UUID objectId, MageDialogState mageDialogState) { showDialog(choice, objectId, mageDialogState, null); } - + public void showDialog(Choice choice, UUID objectId, MageDialogState mageDialogState, String startSelectionValue) { this.choice = choice; - + setLabelText(this.labelMessage, choice.getMessage()); setLabelText(this.labelSubMessage, choice.getSubMessage()); - + btCancel.setEnabled(!choice.isRequired()); - + // 2 modes: string or key-values // sore data in allItems for inremental filtering // http://logicbig.com/tutorials/core-java-tutorial/swing/list-filter/ this.allItems.clear(); - if (choice.isKeyChoice()){ - for (Map.Entry entry: choice.getKeyChoices().entrySet()) { - this.allItems.add(new KeyValueItem(entry.getKey(), entry.getValue())); + if (choice.isKeyChoice()) { + for (Map.Entry entry : choice.getKeyChoices().entrySet()) { + this.allItems.add(new KeyValueItem(entry.getKey(), entry.getValue())); } } else { - for (String value: choice.getChoices()){ - this.allItems.add(new KeyValueItem(value, value)); + for (String value : choice.getChoices()) { + this.allItems.add(new KeyValueItem(value, value)); } } // sorting - if(choice.isSortEnabled()){ + if (choice.isSortEnabled()) { Collections.sort(this.allItems, new Comparator() { @Override public int compare(KeyValueItem o1, KeyValueItem o2) { @@ -87,38 +68,37 @@ public class PickChoiceDialog extends MageDialog { } }); } - + // search - if(choice.isSearchEnabled()) - { + if (choice.isSearchEnabled()) { panelSearch.setVisible(true); this.editSearch.setText(choice.getSearchText()); - }else{ + } else { panelSearch.setVisible(false); this.editSearch.setText(""); } - + // listeners for inremental filtering editSearch.getDocument().addDocumentListener(new DocumentListener() { - @Override - public void insertUpdate(DocumentEvent e) { - choice.setSearchText(editSearch.getText()); - loadData(); - } + @Override + public void insertUpdate(DocumentEvent e) { + choice.setSearchText(editSearch.getText()); + loadData(); + } - @Override - public void removeUpdate(DocumentEvent e) { - choice.setSearchText(editSearch.getText()); - loadData(); - } + @Override + public void removeUpdate(DocumentEvent e) { + choice.setSearchText(editSearch.getText()); + loadData(); + } - @Override - public void changedUpdate(DocumentEvent e) { - choice.setSearchText(editSearch.getText()); - loadData(); - } + @Override + public void changedUpdate(DocumentEvent e) { + choice.setSearchText(editSearch.getText()); + loadData(); + } }); - + // listeners for select up and down without edit focus lost editSearch.addKeyListener(new KeyListener() { @Override @@ -127,10 +107,10 @@ public class PickChoiceDialog extends MageDialog { } @Override - public void keyPressed(KeyEvent e) { - if(e.getKeyCode() == KeyEvent.VK_UP){ + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_UP) { doPrevSelect(); - }else if(e.getKeyCode() == KeyEvent.VK_DOWN){ + } else if (e.getKeyCode() == KeyEvent.VK_DOWN) { doNextSelect(); } } @@ -140,19 +120,19 @@ public class PickChoiceDialog extends MageDialog { //System.out.println("released"); } }); - + // listeners double click choose listChoices.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { - if(e.getClickCount() == 2){ + if (e.getClickCount() == 2) { doChoose(); } } }); - + // listeners for ESC close - if(!choice.isRequired()){ + if (!choice.isRequired()) { String cancelName = "cancel"; InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelName); @@ -163,37 +143,35 @@ public class PickChoiceDialog extends MageDialog { } }); } - + // window settings - if (this.isModal()){ + if (this.isModal()) { MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER); - }else{ + } else { MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER); } if (mageDialogState != null) { mageDialogState.setStateToDialog(this); - + } else { - Point centered = SettingsManager.instance.getComponentPosition(getWidth(), getHeight()); - this.setLocation(centered.x, centered.y); - GuiDisplayUtil.keepComponentInsideScreen(centered.x, centered.y, this); + this.makeWindowCentered(); } // final load loadData(); // start selection - if((startSelectionValue != null)){ + if ((startSelectionValue != null)) { int selectIndex = -1; - for(int i = 0; i < this.listChoices.getModel().getSize(); i++){ - KeyValueItem listItem = (KeyValueItem)this.listChoices.getModel().getElementAt(i); - if (listItem.Key.equals(startSelectionValue)){ + for (int i = 0; i < this.listChoices.getModel().getSize(); i++) { + KeyValueItem listItem = (KeyValueItem) this.listChoices.getModel().getElementAt(i); + if (listItem.Key.equals(startSelectionValue)) { selectIndex = i; break; } } - if(selectIndex >= 0){ + if (selectIndex >= 0) { this.listChoices.setSelectedIndex(selectIndex); this.listChoices.ensureIndexIsVisible(selectIndex); } @@ -201,59 +179,61 @@ public class PickChoiceDialog extends MageDialog { this.setVisible(true); } - - public void setWindowSize(int width, int heigth){ - this.setSize(new Dimension(width, heigth)); + + public void setWindowSize(int width, int height) { + this.setSize(new Dimension(width, height)); } - - private void loadData(){ + + private void loadData() { // load data to datamodel after filter or on startup String filter = choice.getSearchText(); - if (filter == null){ filter = ""; } + if (filter == null) { + filter = ""; + } filter = filter.toLowerCase(Locale.ENGLISH); - + this.dataModel.clear(); - for(KeyValueItem item: this.allItems){ - if(!choice.isSearchEnabled() || item.Value.toLowerCase(Locale.ENGLISH).contains(filter)){ + for (KeyValueItem item : this.allItems) { + if (!choice.isSearchEnabled() || item.Value.toLowerCase(Locale.ENGLISH).contains(filter)) { this.dataModel.addElement(item); } } } - - private void setLabelText(JLabel label, String text){ - if ((text != null) && !text.equals("")){ + + private void setLabelText(JLabel label, String text) { + if ((text != null) && !text.equals("")) { label.setText(String.format(HTML_TEMPLATE, text)); label.setVisible(true); - }else{ + } else { label.setText(""); label.setVisible(false); - } - } - - private void doNextSelect(){ - int newSel = this.listChoices.getSelectedIndex() + 1; - int maxSel = this.listChoices.getModel().getSize() - 1; - if(newSel <= maxSel){ - this.listChoices.setSelectedIndex(newSel); - this.listChoices.ensureIndexIsVisible(newSel); } } - - private void doPrevSelect(){ - int newSel = this.listChoices.getSelectedIndex() - 1; - if(newSel >= 0){ + + private void doNextSelect() { + int newSel = this.listChoices.getSelectedIndex() + 1; + int maxSel = this.listChoices.getModel().getSize() - 1; + if (newSel <= maxSel) { this.listChoices.setSelectedIndex(newSel); this.listChoices.ensureIndexIsVisible(newSel); } } - private void doChoose(){ - if(setChoice()){ + private void doPrevSelect() { + int newSel = this.listChoices.getSelectedIndex() - 1; + if (newSel >= 0) { + this.listChoices.setSelectedIndex(newSel); + this.listChoices.ensureIndexIsVisible(newSel); + } + } + + private void doChoose() { + if (setChoice()) { this.hideDialog(); } } - - private void doCancel(){ + + private void doCancel() { this.listChoices.clearSelection(); this.choice.clearChoice(); hideDialog(); @@ -267,34 +247,33 @@ public class PickChoiceDialog extends MageDialog { this.listChoices.setModel(dataModel); this.setModal(true); } - + public boolean setChoice() { - KeyValueItem item = (KeyValueItem)this.listChoices.getSelectedValue(); - + KeyValueItem item = (KeyValueItem) this.listChoices.getSelectedValue(); + // auto select one item (after incemental filtering) - if((item == null) && (this.listChoices.getModel().getSize() == 1)){ + if ((item == null) && (this.listChoices.getModel().getSize() == 1)) { this.listChoices.setSelectedIndex(0); - item = (KeyValueItem)this.listChoices.getSelectedValue(); + item = (KeyValueItem) this.listChoices.getSelectedValue(); } - - if(item != null){ - if(choice.isKeyChoice()){ + + if (item != null) { + if (choice.isKeyChoice()) { choice.setChoiceByKey(item.getKey()); - }else{ + } else { choice.setChoice(item.getKey()); } return true; - }else{ + } else { choice.clearChoice(); return false; } } - - class KeyValueItem - { + + class KeyValueItem { private final String Key; private final String Value; - + public KeyValueItem(String value, String label) { this.Key = value; this.Value = label; @@ -311,7 +290,7 @@ public class PickChoiceDialog extends MageDialog { @Override public String toString() { return this.Value; - } + } } /** @@ -345,20 +324,20 @@ public class PickChoiceDialog extends MageDialog { javax.swing.GroupLayout panelHeaderLayout = new javax.swing.GroupLayout(panelHeader); panelHeader.setLayout(panelHeaderLayout); panelHeaderLayout.setHorizontalGroup( - panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelHeaderLayout.createSequentialGroup() - .addGroup(panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(labelMessage, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 210, Short.MAX_VALUE) - .addComponent(labelSubMessage, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 210, Short.MAX_VALUE)) - .addGap(0, 0, 0)) + panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelHeaderLayout.createSequentialGroup() + .addGroup(panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(labelMessage, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 210, Short.MAX_VALUE) + .addComponent(labelSubMessage, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 210, Short.MAX_VALUE)) + .addGap(0, 0, 0)) ); panelHeaderLayout.setVerticalGroup( - panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelHeaderLayout.createSequentialGroup() - .addGap(0, 0, 0) - .addComponent(labelMessage) - .addGap(0, 0, 0) - .addComponent(labelSubMessage)) + panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelHeaderLayout.createSequentialGroup() + .addGap(0, 0, 0) + .addComponent(labelMessage) + .addGap(0, 0, 0) + .addComponent(labelSubMessage)) ); labelSearch.setText("Search:"); @@ -368,28 +347,34 @@ public class PickChoiceDialog extends MageDialog { javax.swing.GroupLayout panelSearchLayout = new javax.swing.GroupLayout(panelSearch); panelSearch.setLayout(panelSearchLayout); panelSearchLayout.setHorizontalGroup( - panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelSearchLayout.createSequentialGroup() - .addGap(0, 0, 0) - .addComponent(labelSearch) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(editSearch) - .addGap(0, 0, 0)) + panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelSearchLayout.createSequentialGroup() + .addGap(0, 0, 0) + .addComponent(labelSearch) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(editSearch) + .addGap(0, 0, 0)) ); panelSearchLayout.setVerticalGroup( - panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelSearchLayout.createSequentialGroup() - .addGap(3, 3, 3) - .addGroup(panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(labelSearch) - .addComponent(editSearch, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(3, 3, 3)) + panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelSearchLayout.createSequentialGroup() + .addGap(3, 3, 3) + .addGroup(panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(labelSearch) + .addComponent(editSearch, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(3, 3, 3)) ); listChoices.setModel(new javax.swing.AbstractListModel() { - String[] strings = { "item1", "item2", "item3" }; - public int getSize() { return strings.length; } - public Object getElementAt(int i) { return strings[i]; } + String[] strings = {"item1", "item2", "item3"}; + + public int getSize() { + return strings.length; + } + + public Object getElementAt(int i) { + return strings[i]; + } }); scrollList.setViewportView(listChoices); @@ -410,25 +395,25 @@ public class PickChoiceDialog extends MageDialog { javax.swing.GroupLayout panelCommandsLayout = new javax.swing.GroupLayout(panelCommands); panelCommands.setLayout(panelCommandsLayout); panelCommandsLayout.setHorizontalGroup( - panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelCommandsLayout.createSequentialGroup() - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(btOK) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap()) + panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelCommandsLayout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(btOK) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) ); - panelCommandsLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {btCancel, btOK}); + panelCommandsLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[]{btCancel, btOK}); panelCommandsLayout.setVerticalGroup( - panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelCommandsLayout.createSequentialGroup() - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(btCancel) - .addComponent(btOK)) - .addContainerGap()) + panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelCommandsLayout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(btCancel) + .addComponent(btOK)) + .addContainerGap()) ); getRootPane().setDefaultButton(btOK); @@ -436,28 +421,28 @@ public class PickChoiceDialog extends MageDialog { javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(scrollList, javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(panelCommands, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(panelHeader, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(panelSearch, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap()) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(scrollList, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(panelCommands, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(panelHeader, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(panelSearch, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) ); layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addContainerGap() - .addComponent(panelHeader, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(panelSearch, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(scrollList, javax.swing.GroupLayout.DEFAULT_SIZE, 246, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(panelCommands, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap()) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addComponent(panelHeader, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(panelSearch, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(scrollList, javax.swing.GroupLayout.DEFAULT_SIZE, 246, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(panelCommands, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) ); pack(); diff --git a/Mage.Client/src/main/java/mage/client/dialog/PickNumberDialog.java b/Mage.Client/src/main/java/mage/client/dialog/PickNumberDialog.java index f24f80dc015..4bf068f5538 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PickNumberDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/PickNumberDialog.java @@ -1,31 +1,21 @@ - - -/* - * PickNumberDialog.java - * - * Created on Feb 25, 2010, 12:03:39 PM - */ - package mage.client.dialog; -import java.awt.Point; +import mage.client.MageFrame; + +import javax.swing.*; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; -import javax.swing.*; - -import mage.client.MageFrame; -import mage.client.util.SettingsManager; -import mage.client.util.gui.GuiDisplayUtil; /** - * * @author BetaSteward_at_googlemail.com */ public class PickNumberDialog extends MageDialog { private boolean cancel; - /** Creates new form PickNumberDialog */ + /** + * Creates new form PickNumberDialog + */ public PickNumberDialog() { initComponents(); this.setModal(true); @@ -40,16 +30,16 @@ public class PickNumberDialog extends MageDialog { this.pack(); // window settings - if (this.isModal()){ + if (this.isModal()) { MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER); - }else{ + } else { MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER); } this.getRootPane().setDefaultButton(this.btnOk); // restore default button after root panel change (no need actually) // enable spinner's enter key like text (one enter press instead two) // https://stackoverflow.com/questions/3873870/java-keylistener-not-firing-on-jspinner - ((JSpinner.DefaultEditor)this.spnAmount.getEditor()).getTextField().addKeyListener(new KeyListener(){ + ((JSpinner.DefaultEditor) this.spnAmount.getEditor()).getTextField().addKeyListener(new KeyListener() { @Override public void keyPressed(KeyEvent e) { @@ -68,23 +58,22 @@ public class PickNumberDialog extends MageDialog { }); - Point centered = SettingsManager.instance.getComponentPosition(getWidth(), getHeight()); - this.setLocation(centered.x, centered.y); - GuiDisplayUtil.keepComponentInsideScreen(centered.x, centered.y, this); + this.makeWindowCentered(); // TODO: need to fix focus restore on second popup (it's not focues, test on Manamorphose) this.setVisible(true); } public int getAmount() { - return ((Number)spnAmount.getValue()).intValue(); + return ((Number) spnAmount.getValue()).intValue(); } public boolean isCancel() { return cancel; } - /** This method is called from within the constructor to + /** + * This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. @@ -105,7 +94,7 @@ public class PickNumberDialog extends MageDialog { lblMessage.setEditable(false); lblMessage.setText("long text long text long text long text long text long text long text long text"); - lblMessage.setCursor(null ); + lblMessage.setCursor(null); lblMessage.setFocusable(false); lblMessage.setOpaque(false); jScrollPane1.setViewportView(lblMessage); @@ -129,22 +118,22 @@ public class PickNumberDialog extends MageDialog { javax.swing.GroupLayout panelCommandsLayout = new javax.swing.GroupLayout(panelCommands); panelCommands.setLayout(panelCommandsLayout); panelCommandsLayout.setHorizontalGroup( - panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelCommandsLayout.createSequentialGroup() - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(btnOk) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnCancel) - .addContainerGap()) + panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelCommandsLayout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(btnOk) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnCancel) + .addContainerGap()) ); panelCommandsLayout.setVerticalGroup( - panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelCommandsLayout.createSequentialGroup() - .addContainerGap() - .addGroup(panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(btnOk) - .addComponent(btnCancel)) - .addContainerGap()) + panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelCommandsLayout.createSequentialGroup() + .addContainerGap() + .addGroup(panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(btnOk) + .addComponent(btnCancel)) + .addContainerGap()) ); getRootPane().setDefaultButton(btnOk); @@ -152,27 +141,27 @@ public class PickNumberDialog extends MageDialog { javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 183, Short.MAX_VALUE) - .addComponent(panelCommands, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(layout.createSequentialGroup() - .addComponent(spnAmount, javax.swing.GroupLayout.PREFERRED_SIZE, 74, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, Short.MAX_VALUE))) - .addContainerGap()) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 183, Short.MAX_VALUE) + .addComponent(panelCommands, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(spnAmount, javax.swing.GroupLayout.PREFERRED_SIZE, 74, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, Short.MAX_VALUE))) + .addContainerGap()) ); layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addContainerGap() - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 117, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(spnAmount, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(panelCommands, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap()) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 117, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(spnAmount, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(panelCommands, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) ); pack(); diff --git a/Mage.Client/src/main/java/mage/client/dialog/PickPileDialog.java b/Mage.Client/src/main/java/mage/client/dialog/PickPileDialog.java index 4bed9829d60..442e8ae49d7 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PickPileDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/PickPileDialog.java @@ -1,23 +1,16 @@ - package mage.client.dialog; -import java.awt.BorderLayout; -import java.awt.Component; -import java.awt.Point; -import java.util.UUID; -import javax.swing.JButton; -import javax.swing.JLayeredPane; -import javax.swing.JPanel; import mage.client.MageFrame; import mage.client.cards.BigCard; import mage.client.cards.CardArea; -import mage.client.util.SettingsManager; -import mage.client.util.gui.GuiDisplayUtil; import mage.view.CardsView; import org.mage.card.arcane.CardPanel; +import javax.swing.*; +import java.awt.*; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public class PickPileDialog extends MageDialog { @@ -81,18 +74,16 @@ public class PickPileDialog extends MageDialog { } pack(); - Point centered = SettingsManager.instance.getComponentPosition(getWidth(), getHeight()); - this.setLocation(centered.x, centered.y); - GuiDisplayUtil.keepComponentInsideScreen(centered.x, centered.y, this); + this.makeWindowCentered(); this.revalidate(); this.repaint(); this.setModal(true); // window settings - if (this.isModal()){ + if (this.isModal()) { MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER); - }else{ + } else { MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER); } diff --git a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form index f122cdc1c44..4d8fb9ea080 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form +++ b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form @@ -236,7 +236,7 @@ - + @@ -267,7 +267,7 @@ - + @@ -4425,6 +4425,7 @@ + @@ -4451,6 +4452,7 @@ + diff --git a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java index 4d595a005a8..ef53c3308e9 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java @@ -41,6 +41,8 @@ import mage.client.MageFrame; import mage.client.SessionHandler; import mage.client.components.KeyBindButton; import static mage.client.constants.Constants.BATTLEFIELD_FEEDBACK_COLORIZING_MODE_ENABLE_BY_MULTICOLOR; + +import mage.client.util.CardLanguage; import mage.client.util.Config; import mage.client.util.GUISizeHelper; import mage.client.util.ImageHelper; @@ -222,6 +224,7 @@ public class PreferencesDialog extends javax.swing.JDialog { public static final String KEY_NEW_TABLE_NUMBER_PLAYERS = "newTableNumberPlayers"; public static final String KEY_NEW_TABLE_PLAYER_TYPES = "newTablePlayerTypes"; public static final String KEY_NEW_TABLE_QUIT_RATIO = "newTableQuitRatio"; + public static final String KEY_NEW_TABLE_MINIMUM_RATING = "newTableMinimumRating"; public static final String KEY_NEW_TABLE_RATED = "newTableRated"; // pref setting for new tournament dialog @@ -243,6 +246,7 @@ public class PreferencesDialog extends javax.swing.JDialog { public static final String KEY_NEW_TOURNAMENT_ALLOW_ROLLBACKS = "newTournamentAllowRollbacks"; public static final String KEY_NEW_TOURNAMENT_DECK_FILE = "newTournamentDeckFile"; public static final String KEY_NEW_TOURNAMENT_QUIT_RATIO = "newTournamentQuitRatio"; + public static final String KEY_NEW_TOURNAMENT_MINIMUM_RATING = "newTournamentMinimumRating"; public static final String KEY_NEW_TOURNAMENT_RATED = "newTournamentRated"; // pref setting for deck generator @@ -336,6 +340,10 @@ public class PreferencesDialog extends javax.swing.JDialog { fc_i.addChoosableFileFilter(new ImageFileFilter()); } + public static CardLanguage getPrefImagesLanguage() { + return CardLanguage.valueByCode(getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_PREF_LANGUAGE, CardLanguage.ENGLISH.getCode())); + } + private static class ImageFileFilter extends FileFilter { @Override @@ -372,7 +380,7 @@ public class PreferencesDialog extends javax.swing.JDialog { cbProxyType.setModel(new DefaultComboBoxModel<>(Connection.ProxyType.values())); addAvatars(); - cbPreferedImageLanguage.setModel(new DefaultComboBoxModel<>(new String[]{"en", "de", "fr", "it", "es", "pt", "jp", "cn", "ru", "tw", "ko"})); + cbPreferedImageLanguage.setModel(new DefaultComboBoxModel<>(CardLanguage.toList())); cbNumberOfDownloadThreads.setModel(new DefaultComboBoxModel<>(new String[]{"10", "9", "8", "7", "6", "5", "4", "3", "2", "1"})); } @@ -1556,6 +1564,7 @@ public class PreferencesDialog extends javax.swing.JDialog { } }); + cbPreferedImageLanguage.setMaximumRowCount(20); cbPreferedImageLanguage.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" })); labelPreferedImageLanguage.setText("Prefered image language:"); @@ -1563,6 +1572,7 @@ public class PreferencesDialog extends javax.swing.JDialog { labelNumberOfDownloadThreads.setText("Number of download threads:"); + cbNumberOfDownloadThreads.setMaximumRowCount(20); cbNumberOfDownloadThreads.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" })); org.jdesktop.layout.GroupLayout panelCardImagesLayout = new org.jdesktop.layout.GroupLayout(panelCardImages); @@ -3409,7 +3419,7 @@ public class PreferencesDialog extends javax.swing.JDialog { load(prefs, dialog.cbCheckForNewImages, KEY_CARD_IMAGES_CHECK, "true"); load(prefs, dialog.cbSaveToZipFiles, KEY_CARD_IMAGES_SAVE_TO_ZIP, "true"); dialog.cbNumberOfDownloadThreads.setSelectedItem(MageFrame.getPreferences().get(KEY_CARD_IMAGES_THREADS, "10")); - dialog.cbPreferedImageLanguage.setSelectedItem(MageFrame.getPreferences().get(KEY_CARD_IMAGES_PREF_LANGUAGE, "en")); + dialog.cbPreferedImageLanguage.setSelectedItem(MageFrame.getPreferences().get(KEY_CARD_IMAGES_PREF_LANGUAGE, CardLanguage.ENGLISH.getCode())); // rendering settings load(prefs, dialog.cbCardRenderImageFallback, KEY_CARD_RENDERING_FALLBACK, "true"); diff --git a/Mage.Client/src/main/java/mage/client/draft/DraftPanel.java b/Mage.Client/src/main/java/mage/client/draft/DraftPanel.java index 2ebb71df7a3..9cbff6f1cd1 100644 --- a/Mage.Client/src/main/java/mage/client/draft/DraftPanel.java +++ b/Mage.Client/src/main/java/mage/client/draft/DraftPanel.java @@ -21,7 +21,6 @@ import mage.client.util.audio.AudioManager; import mage.client.util.gui.BufferedImageBuilder; import mage.constants.PlayerAction; import mage.view.*; -import org.apache.log4j.Logger; import javax.swing.*; import javax.swing.Timer; @@ -31,21 +30,16 @@ import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.image.BufferedImage; import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; import java.text.SimpleDateFormat; import java.util.*; +import java.util.List; -/** + /** * * @author BetaSteward_at_googlemail.com */ public class DraftPanel extends javax.swing.JPanel { - private static final Logger LOGGER = Logger.getLogger(DraftPanel.class); - private UUID draftId; private Timer countdown; private int timeout; @@ -63,8 +57,11 @@ public class DraftPanel extends javax.swing.JPanel { // id of card with popup menu protected UUID cardIdPopupMenu; - // Filename for the draft log (only updated if writing the log). - private String logFilename; + // Helper for writing the draft log. + private DraftPickLogger draftLogger; + + // List of set codes (for draft log writing). + private List setCodes; // Number of the current booster (for draft log writing). private int packNo; @@ -73,7 +70,6 @@ public class DraftPanel extends javax.swing.JPanel { private int pickNo; // Cached booster data to be written into the log (see logLastPick). - private String currentBoosterHeader; private String[] currentBooster; private static final CardsView EMPTY_VIEW = new CardsView(); @@ -139,17 +135,11 @@ public class DraftPanel extends javax.swing.JPanel { } if (isLogging()) { - // If we are logging the draft create a file that will contain - // the log. SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss"); - logFilename = "Draft_" + sdf.format(new Date()) + '_' + draftId + ".txt"; - try { - Files.write(pathToDraftLog(), "".getBytes(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); - } catch (IOException ex) { - LOGGER.error(null, ex); - } + String logFilename = "Draft_" + sdf.format(new Date()) + '_' + draftId + ".txt"; + draftLogger = new DraftPickLogger(new File("gamelogs"), logFilename); } else { - logFilename = null; + draftLogger = new DraftPickLogger(); } } @@ -171,6 +161,8 @@ public class DraftPanel extends javax.swing.JPanel { packNo = draftView.getBoosterNum(); pickNo = draftView.getCardNum(); + setCodes = draftView.getSetCodes(); + draftLogger.updateDraft(draftId, draftView); int right = draftView.getPlayers().size() / 2; int left = draftView.getPlayers().size() - right; @@ -251,7 +243,7 @@ public class DraftPanel extends javax.swing.JPanel { } } - public void loadBooster(DraftPickView draftPickView) { + public void loadBooster(DraftPickView draftPickView) { logLastPick(draftPickView); // upper area that shows the picks loadCardsToPickedCardsArea(draftPickView.getPicks()); @@ -416,13 +408,21 @@ public class DraftPanel extends javax.swing.JPanel { if (currentBooster != null) { String lastPick = getCardName(getLastPick(pickView.getPicks().values())); if (lastPick != null && currentBooster.length > 1) { - logPick(lastPick); + draftLogger.logPick(getCurrentSetCode(), packNo, pickNo-1, lastPick, currentBooster); } currentBooster = null; } setCurrentBoosterForLog(pickView.getBooster()); if (currentBooster.length == 1) { - logPick(currentBooster[0]); + draftLogger.logPick(getCurrentSetCode(), packNo, pickNo, currentBooster[0], currentBooster); + } + } + + private String getCurrentSetCode() { + if (!setCodes.isEmpty()) { + return setCodes.get(packNo-1); + } else { + return ""; } } @@ -440,39 +440,10 @@ public class DraftPanel extends javax.swing.JPanel { } } - currentBoosterHeader = "Pack " + packNo + " pick " + pickNo + ":\n"; currentBooster = cards.toArray(new String[cards.size()]); } - private void logPick(String pick) { - StringBuilder b = new StringBuilder(); - b.append(currentBoosterHeader); - for (String name : currentBooster) { - b.append(pick.equals(name) ? "--> " : " "); - b.append(name); - b.append('\n'); - } - b.append('\n'); - appendToDraftLog(b.toString()); - } - - private Path pathToDraftLog() { - File saveDir = new File("gamelogs"); - if (!saveDir.exists()) { - saveDir.mkdirs(); - } - return new File(saveDir, logFilename).toPath(); - } - - private void appendToDraftLog(String data) { - try { - Files.write(pathToDraftLog(), data.getBytes(), StandardOpenOption.APPEND); - } catch (IOException ex) { - LOGGER.error(null, ex); - } - } - - private static SimpleCardView getLastPick(Collection picks) { + private static SimpleCardView getLastPick(Collection picks) { SimpleCardView last = null; for (SimpleCardView pick : picks) { last = pick; diff --git a/Mage.Client/src/main/java/mage/client/draft/DraftPickLogger.java b/Mage.Client/src/main/java/mage/client/draft/DraftPickLogger.java new file mode 100644 index 00000000000..db585e1a227 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/draft/DraftPickLogger.java @@ -0,0 +1,85 @@ +package mage.client.draft; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.UUID; + +import org.apache.log4j.Logger; + +import mage.view.DraftView; + +public class DraftPickLogger { + + private static final Logger LOGGER = Logger.getLogger(DraftPickLogger.class); + + private final Path logPath; + private final boolean logging; + private boolean headerWritten = false; + + public DraftPickLogger(File directory, String logFilename) { + this.logging = true; + if (!directory.exists()) { + directory.mkdirs(); + } + this.logPath = new File(directory, logFilename).toPath(); + try { + Files.write(logPath, new byte[0], StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); + } catch (IOException ex) { + LOGGER.error(null, ex); + } + } + + public DraftPickLogger() { + this.logging = false; + this.logPath = null; + } + + public void updateDraft(UUID draftId, DraftView draftView) { + if (headerWritten) { + return; + } + headerWritten = true; + Date now = new Date(); + SimpleDateFormat formatter = new SimpleDateFormat("M/d/yyyy h:mm:ss a"); + StringBuilder buffer = new StringBuilder() + .append("Event #: ").append(draftId).append("\n") + .append("Time: ").append(formatter.format(now)).append('\n'); + buffer.append("Players:\n"); + for (String player : draftView.getPlayers()) { + buffer.append(" ").append(player).append('\n'); + } + buffer.append('\n'); + appendToDraftLog(buffer.toString()); + } + + public void logPick(String setCode, int packNo, int pickNo, String pick, String[] currentBooster) { + StringBuilder b = new StringBuilder(); + if (pickNo == 1) { + b.append("------ ").append(setCode).append(" ------\n\n"); + } + b.append("Pack ").append(packNo).append(" pick ").append(pickNo).append(":\n"); + for (String name : currentBooster) { + b.append(pick.equals(name) ? "--> " : " "); + b.append(name); + b.append('\n'); + } + b.append('\n'); + appendToDraftLog(b.toString()); + } + + private void appendToDraftLog(String data) { + if (logging) { + try { + Files.write(logPath, data.getBytes(), StandardOpenOption.APPEND); + } catch (IOException ex) { + LOGGER.error(null, ex); + } + } + } + +} diff --git a/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java b/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java index f3bc3dc5d20..894683a8bef 100644 --- a/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java +++ b/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java @@ -353,8 +353,9 @@ public class CallbackClientImpl implements CallbackClient { } case DRAFT_UPDATE: { DraftPanel panel = MageFrame.getDraft(callback.getObjectId()); + DraftClientMessage message = (DraftClientMessage) callback.getData(); if (panel != null) { - panel.updateDraft((DraftView) callback.getData()); + panel.updateDraft(message.getDraftView()); } break; } diff --git a/Mage.Client/src/main/java/mage/client/table/MatchesTableModel.java b/Mage.Client/src/main/java/mage/client/table/MatchesTableModel.java new file mode 100644 index 00000000000..8cf2c28c476 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/table/MatchesTableModel.java @@ -0,0 +1,145 @@ +package mage.client.table; + +import mage.remote.MageRemoteException; +import mage.view.MatchView; + +import javax.swing.table.AbstractTableModel; +import java.util.Collection; +import java.util.Date; +import java.util.UUID; + +public class MatchesTableModel extends AbstractTableModel { + + private final String[] columnNames = new String[]{"Deck Type", "Players", "Game Type", "Rating", "Result", "Duration", "Start Time", "End Time", "Action"}; + public static final int COLUMN_DURATION = 5; + public static final int COLUMN_START = 6; + public static final int COLUMN_END = 7; + public static final int COLUMN_ACTION = 8; // column the action is located (starting with 0) + + private MatchView[] matches = new MatchView[0]; + + public void loadData(Collection matches) throws MageRemoteException { + this.matches = matches.toArray(new MatchView[0]); + this.fireTableDataChanged(); + } + + MatchesTableModel() { + } + + + public String getTableAndGameInfo(int row) { + return this.matches[row].getTableId().toString() + ";" + (!matches[row].getGames().isEmpty() ? matches[row].getGames().get(0).toString() : "null"); + } + + public String findTableAndGameInfoByRow(int row) { + if (row >= 0 && row < this.matches.length) { + return getTableAndGameInfo(row); + } else { + return null; + } + } + + public int findRowByTableAndGameInfo(String tableAndGame) { + for (int i = 0; i < this.matches.length; i++) { + String rowID = this.matches[i].getTableId().toString() + ";" + (!this.matches[i].getGames().isEmpty() ? this.matches[i].getGames().get(0).toString() : "null"); + if (tableAndGame.equals(rowID)) { + return i; + } + } + return -1; + } + + @Override + public int getRowCount() { + return matches.length; + } + + @Override + public int getColumnCount() { + return columnNames.length; + } + + @Override + public Object getValueAt(int arg0, int arg1) { + switch (arg1) { + case 0: + return matches[arg0].getDeckType(); + case 1: + return matches[arg0].getPlayers(); + case 2: + return matches[arg0].getGameType(); + case 3: + return matches[arg0].isRated() ? TablesTableModel.RATED_VALUE_YES : TablesTableModel.RATED_VALUE_NO; + case 4: + return matches[arg0].getResult(); + case 5: + if (matches[arg0].getEndTime() != null) { + return matches[arg0].getEndTime().getTime() - matches[arg0].getStartTime().getTime() + new Date().getTime(); + } else { + return 0L; + } + case 6: + return matches[arg0].getStartTime(); + case 7: + return matches[arg0].getEndTime(); + case 8: + if (matches[arg0].isTournament()) { + return "Show"; + } else if (matches[arg0].isReplayAvailable()) { + return "Replay"; + } else { + return "None"; + } + case 9: + return matches[arg0].getGames(); + } + return ""; + } + + public java.util.List getListofGames(int row) { + return matches[row].getGames(); + } + + public boolean isTournament(int row) { + return matches[row].isTournament(); + } + + public UUID getMatchId(int row) { + return matches[row].getMatchId(); + } + + public UUID getTableId(int row) { + return matches[row].getTableId(); + } + + @Override + public String getColumnName(int columnIndex) { + String colName = ""; + + if (columnIndex <= getColumnCount()) { + colName = columnNames[columnIndex]; + } + + return colName; + } + + @Override + public Class getColumnClass(int columnIndex) { + switch (columnIndex) { + case COLUMN_DURATION: + return Long.class; + case COLUMN_START: + return Date.class; + case COLUMN_END: + return Date.class; + default: + return String.class; + } + } + + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + return columnIndex == COLUMN_ACTION; + } + +} diff --git a/Mage.Client/src/main/java/mage/client/util/ButtonColumn.java b/Mage.Client/src/main/java/mage/client/table/TablesButtonColumn.java similarity index 88% rename from Mage.Client/src/main/java/mage/client/util/ButtonColumn.java rename to Mage.Client/src/main/java/mage/client/table/TablesButtonColumn.java index 91e16d9d030..baaa57846e9 100644 --- a/Mage.Client/src/main/java/mage/client/util/ButtonColumn.java +++ b/Mage.Client/src/main/java/mage/client/table/TablesButtonColumn.java @@ -1,25 +1,21 @@ +package mage.client.table; -package mage.client.util; +import mage.client.util.GUISizeHelper; -import java.awt.Component; +import javax.swing.*; +import javax.swing.table.TableCellEditor; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumnModel; +import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; -import javax.swing.AbstractCellEditor; -import javax.swing.Action; -import javax.swing.JButton; -import javax.swing.JTable; -import javax.swing.UIManager; -import javax.swing.table.TableCellEditor; -import javax.swing.table.TableCellRenderer; -import javax.swing.table.TableColumnModel; /** - * * @author BetaSteward_at_googlemail.com */ -public class ButtonColumn extends AbstractCellEditor implements TableCellRenderer, TableCellEditor, ActionListener, MouseListener { +public class TablesButtonColumn extends AbstractCellEditor implements TableCellRenderer, TableCellEditor, ActionListener, MouseListener { private final JTable table; private final Action action; @@ -28,7 +24,7 @@ public class ButtonColumn extends AbstractCellEditor implements TableCellRendere private String text; private boolean isButtonColumnEditor; - public ButtonColumn(JTable table, Action action, int column) { + public TablesButtonColumn(JTable table, Action action, int column) { super(); this.table = table; this.action = action; @@ -88,7 +84,7 @@ public class ButtonColumn extends AbstractCellEditor implements TableCellRendere if (table.getRowCount() > 0 && table.getRowCount() >= table.getEditingRow() && table.getEditingRow() >= 0) { int row = table.convertRowIndexToModel(table.getEditingRow()); fireEditingStopped(); - ActionEvent event = new ActionEvent(table, ActionEvent.ACTION_PERFORMED, String.valueOf(row)); + ActionEvent event = new ActionEvent(table, ActionEvent.ACTION_PERFORMED, TablesUtil.getSearchIdFromTable(table, row)); action.actionPerformed(event); } } diff --git a/Mage.Client/src/main/java/mage/client/table/TablesPanel.java b/Mage.Client/src/main/java/mage/client/table/TablesPanel.java index 30c5d8e4ac9..7bbd6816add 100644 --- a/Mage.Client/src/main/java/mage/client/table/TablesPanel.java +++ b/Mage.Client/src/main/java/mage/client/table/TablesPanel.java @@ -1,1805 +1,1524 @@ - /* - * TablesPanel.java - * - * Created on 15-Dec-2009, 10:54:01 PM - */ - package mage.client.table; +package mage.client.table; - import mage.cards.decks.importer.DeckImporterUtil; - import mage.client.MageFrame; - import mage.client.SessionHandler; - import mage.client.chat.ChatPanelBasic; - import mage.client.components.MageComponents; - import mage.client.dialog.*; - import mage.client.util.*; - import mage.client.util.gui.GuiDisplayUtil; - import mage.client.util.gui.TableUtil; - import mage.constants.*; - import mage.game.match.MatchOptions; - import mage.players.PlayerType; - import mage.remote.MageRemoteException; - import mage.view.MatchView; - import mage.view.RoomUsersView; - import mage.view.TableView; - import mage.view.UserRequestMessage; - import org.apache.log4j.Logger; - import org.mage.card.arcane.CardRendererUtils; - import org.ocpsoft.prettytime.Duration; - import org.ocpsoft.prettytime.PrettyTime; - import org.ocpsoft.prettytime.units.JustNow; +import mage.cards.decks.importer.DeckImporterUtil; +import mage.client.MageFrame; +import mage.client.SessionHandler; +import mage.client.chat.ChatPanelBasic; +import mage.client.components.MageComponents; +import mage.client.dialog.*; +import mage.client.util.GUISizeHelper; +import mage.client.util.IgnoreList; +import mage.client.util.MageTableRowSorter; +import mage.client.util.URLHandler; +import mage.client.util.gui.GuiDisplayUtil; +import mage.client.util.gui.TableUtil; +import mage.constants.*; +import mage.game.match.MatchOptions; +import mage.players.PlayerType; +import mage.remote.MageRemoteException; +import mage.view.MatchView; +import mage.view.RoomUsersView; +import mage.view.TableView; +import mage.view.UserRequestMessage; +import org.apache.log4j.Logger; +import org.mage.card.arcane.CardRendererUtils; +import org.ocpsoft.prettytime.Duration; +import org.ocpsoft.prettytime.PrettyTime; +import org.ocpsoft.prettytime.units.JustNow; - import javax.swing.*; - import javax.swing.border.EmptyBorder; - import javax.swing.table.AbstractTableModel; - import javax.swing.table.DefaultTableCellRenderer; - import javax.swing.table.TableCellRenderer; - import java.awt.*; - import java.awt.event.ActionEvent; - import java.awt.event.MouseAdapter; - import java.awt.event.MouseEvent; - import java.beans.PropertyVetoException; - import java.io.File; - import java.text.DateFormat; - import java.text.SimpleDateFormat; - import java.util.*; - import java.util.concurrent.CancellationException; - import java.util.concurrent.ExecutionException; - import java.util.concurrent.Executors; - import java.util.concurrent.TimeUnit; +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.TableCellRenderer; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.beans.PropertyVetoException; +import java.io.File; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; - import static mage.client.dialog.PreferencesDialog.*; +import static mage.client.dialog.PreferencesDialog.*; - /** - * @author BetaSteward_at_googlemail.com - */ - public class TablesPanel extends javax.swing.JPanel { +/** + * @author BetaSteward_at_googlemail.com + */ +public class TablesPanel extends javax.swing.JPanel { - private static final Logger LOGGER = Logger.getLogger(TablesPanel.class); - private static final int[] DEFAULT_COLUMNS_WIDTH = {35, 150, 120, 180, 80, 120, 80, 60, 40, 40, 60}; + private static final Logger LOGGER = Logger.getLogger(TablesPanel.class); + private static final int[] DEFAULT_COLUMNS_WIDTH = {35, 150, 120, 180, 80, 120, 80, 60, 40, 40, 60}; - private final TableTableModel tableModel; - private final MatchesTableModel matchesModel; - private UUID roomId; - private UpdateTablesTask updateTablesTask; - private UpdatePlayersTask updatePlayersTask; - private UpdateMatchesTask updateMatchesTask; - private JoinTableDialog joinTableDialog; - private NewTableDialog newTableDialog; - private NewTournamentDialog newTournamentDialog; - private final GameChooser gameChooser; - private java.util.List messages; - private int currentMessage; - private final MageTableRowSorter activeTablesSorter; - private final MageTableRowSorter completedTablesSorter; + private final TablesTableModel tableModel; + private final MatchesTableModel matchesModel; + private UUID roomId; + private UpdateTablesTask updateTablesTask; + private UpdatePlayersTask updatePlayersTask; + private UpdateMatchesTask updateMatchesTask; + private JoinTableDialog joinTableDialog; + private NewTableDialog newTableDialog; + private NewTournamentDialog newTournamentDialog; + private final GameChooser gameChooser; + private java.util.List messages; + private int currentMessage; + private final MageTableRowSorter activeTablesSorter; + private final MageTableRowSorter completedTablesSorter; - private final ButtonColumn actionButton1; - private final ButtonColumn actionButton2; + private final TablesButtonColumn actionButton1; + private final TablesButtonColumn actionButton2; - final JToggleButton[] filterButtons; + final JToggleButton[] filterButtons; - // time formater - private PrettyTime timeFormater = new PrettyTime(); + // time formater + private PrettyTime timeFormater = new PrettyTime(); - // time ago renderer - TableCellRenderer timeAgoCellRenderer = new DefaultTableCellRenderer() { - @Override - public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { - JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); - Date d = (Date) value; - label.setText(timeFormater.format(d)); - return label; - } - }; + // time ago renderer + TableCellRenderer timeAgoCellRenderer = new DefaultTableCellRenderer() { + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + Date d = (Date) value; + label.setText(timeFormater.format(d)); + return label; + } + }; - // duration renderer - TableCellRenderer durationCellRenderer = new DefaultTableCellRenderer() { - @Override - public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { - JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); - Long ms = (Long) value; + // duration renderer + TableCellRenderer durationCellRenderer = new DefaultTableCellRenderer() { + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + Long ms = (Long) value; - if (ms != 0) { - Duration dur = timeFormater.approximateDuration(new Date(ms)); - label.setText((timeFormater.formatDuration(dur))); - } else { - label.setText(""); - } - return label; - } - }; + if (ms != 0) { + Duration dur = timeFormater.approximateDuration(new Date(ms)); + label.setText((timeFormater.formatDuration(dur))); + } else { + label.setText(""); + } + return label; + } + }; - // datetime render - TableCellRenderer datetimeCellRenderer = new DefaultTableCellRenderer() { - DateFormat datetimeFormater = new SimpleDateFormat("HH:mm:ss"); + // datetime render + TableCellRenderer datetimeCellRenderer = new DefaultTableCellRenderer() { + DateFormat datetimeFormater = new SimpleDateFormat("HH:mm:ss"); - @Override - public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { - JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); - Date d = (Date) value; - if (d != null) { - label.setText(datetimeFormater.format(d)); - } else { - label.setText(""); - } + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + Date d = (Date) value; + if (d != null) { + label.setText(datetimeFormater.format(d)); + } else { + label.setText(""); + } - return label; - } - }; + return label; + } + }; - // skill renderer - TableCellRenderer skillCellRenderer = new DefaultTableCellRenderer() { + // skill renderer + TableCellRenderer skillCellRenderer = new DefaultTableCellRenderer() { - // base panel to render - private JPanel renderPanel = new JPanel(); - private ImageIcon skillIcon = new ImageIcon(this.getClass().getResource("/info/yellow_star_16.png")); + // base panel to render + private JPanel renderPanel = new JPanel(); + private ImageIcon skillIcon = new ImageIcon(this.getClass().getResource("/info/yellow_star_16.png")); - @Override - public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { - // get table text cell settings - DefaultTableCellRenderer baseRenderer = (DefaultTableCellRenderer) table.getDefaultRenderer(String.class); - JLabel baseComp = (JLabel) baseRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); - String skillCode = baseComp.getText(); + // get table text cell settings + DefaultTableCellRenderer baseRenderer = (DefaultTableCellRenderer) table.getDefaultRenderer(String.class); + JLabel baseComp = (JLabel) baseRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + String skillCode = baseComp.getText(); - // apply settings to render panel from parent - renderPanel.setOpaque(baseComp.isOpaque()); - renderPanel.setForeground(CardRendererUtils.copyColor(baseComp.getForeground())); - renderPanel.setBackground(CardRendererUtils.copyColor(baseComp.getBackground())); - renderPanel.setBorder(baseComp.getBorder()); + // apply settings to render panel from parent + renderPanel.setOpaque(baseComp.isOpaque()); + renderPanel.setForeground(CardRendererUtils.copyColor(baseComp.getForeground())); + renderPanel.setBackground(CardRendererUtils.copyColor(baseComp.getBackground())); + renderPanel.setBorder(baseComp.getBorder()); - // create each skill symbol as child label - renderPanel.removeAll(); - renderPanel.setLayout(new BoxLayout(renderPanel, BoxLayout.X_AXIS)); - for (char skillSymbol : skillCode.toCharArray()) { - JLabel symbolLabel = new JLabel(); - symbolLabel.setBorder(new EmptyBorder(0, 3, 0, 0)); - symbolLabel.setIcon(skillIcon); - renderPanel.add(symbolLabel); - } + // create each skill symbol as child label + renderPanel.removeAll(); + renderPanel.setLayout(new BoxLayout(renderPanel, BoxLayout.X_AXIS)); + for (char skillSymbol : skillCode.toCharArray()) { + JLabel symbolLabel = new JLabel(); + symbolLabel.setBorder(new EmptyBorder(0, 3, 0, 0)); + symbolLabel.setIcon(skillIcon); + renderPanel.add(symbolLabel); + } - return renderPanel; - } - }; + return renderPanel; + } + }; - /** - * Creates new form TablesPanel - */ - public TablesPanel() { + /** + * Creates new form TablesPanel + */ + public TablesPanel() { - tableModel = new TableTableModel(); - matchesModel = new MatchesTableModel(); - gameChooser = new GameChooser(); + tableModel = new TablesTableModel(); + matchesModel = new MatchesTableModel(); + gameChooser = new GameChooser(); - initComponents(); - // tableModel.setSession(session); + initComponents(); + // tableModel.setSession(session); - // formater - timeFormater.setLocale(Locale.ENGLISH); - JustNow jn = timeFormater.getUnit(JustNow.class); - jn.setMaxQuantity(1000L * 30L); // 30 seconds gap (show "just now" from 0 to 30 secs) + // formater + timeFormater.setLocale(Locale.ENGLISH); + JustNow jn = timeFormater.getUnit(JustNow.class); + jn.setMaxQuantity(1000L * 30L); // 30 seconds gap (show "just now" from 0 to 30 secs) - // 1. TABLE CURRENT - tableTables.createDefaultColumnsFromModel(); - activeTablesSorter = new MageTableRowSorter(tableModel); - tableTables.setRowSorter(activeTablesSorter); + // 1. TABLE CURRENT + tableTables.createDefaultColumnsFromModel(); + activeTablesSorter = new MageTableRowSorter(tableModel); + tableTables.setRowSorter(activeTablesSorter); - // time ago - tableTables.getColumnModel().getColumn(TableTableModel.COLUMN_CREATED).setCellRenderer(timeAgoCellRenderer); - // skill level - tableTables.getColumnModel().getColumn(TableTableModel.COLUMN_SKILL).setCellRenderer(skillCellRenderer); + // time ago + tableTables.getColumnModel().getColumn(TablesTableModel.COLUMN_CREATED).setCellRenderer(timeAgoCellRenderer); + // skill level + tableTables.getColumnModel().getColumn(TablesTableModel.COLUMN_SKILL).setCellRenderer(skillCellRenderer); /* date sorter (not need, default is good - see getColumnClass) - activeTablesSorter.setComparator(TableTableModel.COLUMN_CREATED, new Comparator() { + activeTablesSorter.setComparator(TablesTableModel.COLUMN_CREATED, new Comparator() { @Override public int compare(Date v1, Date v2) { return v1.compareTo(v2); } });*/ - // default sort by created date (last games from above) - ArrayList list = new ArrayList(); - list.add(new RowSorter.SortKey(TableTableModel.COLUMN_CREATED, SortOrder.DESCENDING)); - activeTablesSorter.setSortKeys(list); - - TableUtil.setColumnWidthAndOrder(tableTables, DEFAULT_COLUMNS_WIDTH, KEY_TABLES_COLUMNS_WIDTH, KEY_TABLES_COLUMNS_ORDER); - - // 2. TABLE COMPLETED - completedTablesSorter = new MageTableRowSorter(matchesModel); - tableCompleted.setRowSorter(completedTablesSorter); - - // duration - tableCompleted.getColumnModel().getColumn(MatchesTableModel.COLUMN_DURATION).setCellRenderer(durationCellRenderer); - // start-end - tableCompleted.getColumnModel().getColumn(MatchesTableModel.COLUMN_START).setCellRenderer(datetimeCellRenderer); - tableCompleted.getColumnModel().getColumn(MatchesTableModel.COLUMN_END).setCellRenderer(datetimeCellRenderer); - // default sort by ended date (last games from above) - ArrayList list2 = new ArrayList(); - list2.add(new RowSorter.SortKey(MatchesTableModel.COLUMN_END, SortOrder.DESCENDING)); - completedTablesSorter.setSortKeys(list2); - - // 3. CHAT - chatPanelMain.getUserChatPanel().useExtendedView(ChatPanelBasic.VIEW_MODE.NONE); - chatPanelMain.getUserChatPanel().setBorder(null); - chatPanelMain.getUserChatPanel().setChatType(ChatPanelBasic.ChatType.TABLES); - - // 4. BUTTONS - filterButtons = new JToggleButton[]{btnStateWaiting, btnStateActive, btnStateFinished, - btnTypeMatch, btnTypeTourneyConstructed, btnTypeTourneyLimited, - btnFormatBlock, btnFormatStandard, btnFormatModern, btnFormatLegacy, btnFormatVintage, btnFormatCommander, btnFormatTinyLeader, btnFormatLimited, btnFormatOther, - btnSkillBeginner, btnSkillCasual, btnSkillSerious, btnRated, btnUnrated, btnOpen, btnPassword}; - - JComponent[] components = new JComponent[]{chatPanelMain, jSplitPane1, jScrollPaneTablesActive, jScrollPaneTablesFinished, jPanelTop, jPanelTables}; - for (JComponent component : components) { - component.setOpaque(false); - } - - jScrollPaneTablesActive.getViewport().setBackground(new Color(255, 255, 255, 50)); - jScrollPaneTablesFinished.getViewport().setBackground(new Color(255, 255, 255, 50)); - - restoreFilters(); - setGUISize(); - - Action openTableAction; - openTableAction = new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - int modelRow = Integer.valueOf(e.getActionCommand()); - UUID tableId = (UUID) tableModel.getValueAt(modelRow, TableTableModel.ACTION_COLUMN + 3); - UUID gameId = (UUID) tableModel.getValueAt(modelRow, TableTableModel.ACTION_COLUMN + 2); - String action = (String) tableModel.getValueAt(modelRow, TableTableModel.ACTION_COLUMN); - String deckType = (String) tableModel.getValueAt(modelRow, TableTableModel.COLUMN_DECK_TYPE); - boolean isTournament = (Boolean) tableModel.getValueAt(modelRow, TableTableModel.ACTION_COLUMN + 1); - String owner = (String) tableModel.getValueAt(modelRow, TableTableModel.COLUMN_OWNER); - String pwdColumn = (String) tableModel.getValueAt(modelRow, TableTableModel.COLUMN_PASSWORD); - switch (action) { - case "Join": - if (owner.equals(SessionHandler.getUserName()) || owner.startsWith(SessionHandler.getUserName() + ',')) { - try { - JDesktopPane desktopPane = (JDesktopPane) MageFrame.getUI().getComponent(MageComponents.DESKTOP_PANE); - JInternalFrame[] windows = desktopPane.getAllFramesInLayer(javax.swing.JLayeredPane.DEFAULT_LAYER); - for (JInternalFrame frame : windows) { - if (frame.getTitle().equals("Waiting for players")) { - frame.toFront(); - frame.setVisible(true); - try { - frame.setSelected(true); - } catch (PropertyVetoException ve) { - LOGGER.error(ve); - } - } - - } - } catch (InterruptedException ex) { - LOGGER.error(ex); - } - return; - } - if (isTournament) { - LOGGER.info("Joining tournament " + tableId); - if (deckType.startsWith("Limited")) { - if (TableTableModel.PASSWORD_VALUE_YES.equals(pwdColumn)) { - joinTableDialog.showDialog(roomId, tableId, true, deckType.startsWith("Limited")); - } else { - SessionHandler.joinTournamentTable(roomId, tableId, SessionHandler.getUserName(), PlayerType.HUMAN, 1, null, ""); - } - } else { - joinTableDialog.showDialog(roomId, tableId, true, deckType.startsWith("Limited")); - } - } else { - LOGGER.info("Joining table " + tableId); - joinTableDialog.showDialog(roomId, tableId, false, false); - } - break; - case "Remove": - UserRequestMessage message = new UserRequestMessage("Removing table", "Are you sure you want to remove table?"); - message.setButton1("No", null); - message.setButton2("Yes", PlayerAction.CLIENT_REMOVE_TABLE); - MageFrame.getInstance().showUserRequestDialog(message); - break; - case "Show": - if (isTournament) { - LOGGER.info("Showing tournament table " + tableId); - SessionHandler.watchTable(roomId, tableId); - } - break; - case "Watch": - if (!isTournament) { - LOGGER.info("Watching table " + tableId); - SessionHandler.watchTable(roomId, tableId); - } - break; - case "Replay": - LOGGER.info("Replaying game " + gameId); - SessionHandler.replayGame(gameId); - break; - } - } - }; - - Action closedTableAction; - closedTableAction = new AbstractAction() { - @Override - public void actionPerformed(ActionEvent e) { - int modelRow = Integer.valueOf(e.getActionCommand()); - String action = (String) matchesModel.getValueAt(modelRow, MatchesTableModel.COLUMN_ACTION); - switch (action) { - case "Replay": - java.util.List gameList = matchesModel.getListofGames(modelRow); - if (gameList != null && !gameList.isEmpty()) { - if (gameList.size() == 1) { - SessionHandler.replayGame(gameList.get(0)); - } else { - gameChooser.show(gameList, MageFrame.getDesktop().getMousePosition()); - } - } - // MageFrame.getDesktop().showTournament(tournamentId); - break; - case "Show": - if (matchesModel.isTournament(modelRow)) { - LOGGER.info("Showing tournament table " + matchesModel.getTableId(modelRow)); - SessionHandler.watchTable(roomId, matchesModel.getTableId(modelRow)); - } - break; - } - } - }; - - // !!!! adds action buttons to the table panel (don't delete this) - actionButton1 = new ButtonColumn(tableTables, openTableAction, tableTables.convertColumnIndexToView(TableTableModel.ACTION_COLUMN)); - actionButton2 = new ButtonColumn(tableCompleted, closedTableAction, tableCompleted.convertColumnIndexToView(MatchesTableModel.COLUMN_ACTION)); - // !!!! - addTableDoubleClickListener(tableTables, openTableAction); - addTableDoubleClickListener(tableCompleted, closedTableAction); - } - - private void addTableDoubleClickListener(JTable table, Action action) { - table.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent e) { - if (e.getClickCount() == 2) { - int selRow = table.getSelectedRow(); - if (selRow != -1) { - int dataRow = table.convertRowIndexToModel(selRow); - if (dataRow != -1) { - action.actionPerformed(new ActionEvent(e.getSource(), e.getID(), "" + dataRow)); - } - } - } - } - }); - } - - public void cleanUp() { - saveGuiSettings(); - chatPanelMain.cleanUp(); - } - - public void changeGUISize() { - chatPanelMain.changeGUISize(); - actionButton1.changeGUISize(); - actionButton2.changeGUISize(); - setGUISize(); - } - - private void setGUISize() { - tableTables.getTableHeader().setFont(GUISizeHelper.tableFont); - tableTables.setFont(GUISizeHelper.tableFont); - tableTables.setRowHeight(GUISizeHelper.getTableRowHeight()); - - tableCompleted.getTableHeader().setFont(GUISizeHelper.tableFont); - tableCompleted.setFont(GUISizeHelper.tableFont); - tableCompleted.setRowHeight(GUISizeHelper.getTableRowHeight()); - - jSplitPane1.setDividerSize(GUISizeHelper.dividerBarSize); - jSplitPaneTables.setDividerSize(GUISizeHelper.dividerBarSize); - jScrollPaneTablesActive.getVerticalScrollBar().setPreferredSize(new Dimension(GUISizeHelper.scrollBarSize, 0)); - jScrollPaneTablesActive.getHorizontalScrollBar().setPreferredSize(new Dimension(0, GUISizeHelper.scrollBarSize)); - - ImageIcon icon = new javax.swing.ImageIcon(getClass().getResource("/buttons/state_waiting.png")); - Image img = icon.getImage(); - Image newimg = img.getScaledInstance(GUISizeHelper.menuFont.getSize(), GUISizeHelper.menuFont.getSize(), java.awt.Image.SCALE_SMOOTH); - btnStateWaiting.setIcon(new ImageIcon(newimg)); - - icon = new javax.swing.ImageIcon(getClass().getResource("/buttons/state_active.png")); - img = icon.getImage(); - newimg = img.getScaledInstance(GUISizeHelper.menuFont.getSize(), GUISizeHelper.menuFont.getSize(), java.awt.Image.SCALE_SMOOTH); - btnStateActive.setIcon(new ImageIcon(newimg)); - - icon = new javax.swing.ImageIcon(getClass().getResource("/buttons/state_finished.png")); - img = icon.getImage(); - newimg = img.getScaledInstance(GUISizeHelper.menuFont.getSize(), GUISizeHelper.menuFont.getSize(), java.awt.Image.SCALE_SMOOTH); - btnStateFinished.setIcon(new ImageIcon(newimg)); - - int iconSize = 48 + GUISizeHelper.menuFont.getSize() * 2 - 15; - icon = new javax.swing.ImageIcon(getClass().getResource("/buttons/match_new.png")); - img = icon.getImage(); - newimg = img.getScaledInstance(iconSize, iconSize, java.awt.Image.SCALE_SMOOTH); - btnNewTable.setIcon(new ImageIcon(newimg)); - - icon = new javax.swing.ImageIcon(getClass().getResource("/buttons/tourney_new.png")); - img = icon.getImage(); - newimg = img.getScaledInstance(iconSize, iconSize, java.awt.Image.SCALE_SMOOTH); - btnNewTournament.setIcon(new ImageIcon(newimg)); - - for (JToggleButton component : filterButtons) { - component.setFont(GUISizeHelper.menuFont); - } - Dimension newDimension = new Dimension((int) jPanelBottom.getPreferredSize().getWidth(), GUISizeHelper.menuFont.getSize() + 28); - jPanelBottom.setMinimumSize(newDimension); - jPanelBottom.setPreferredSize(newDimension); - jButtonFooterNext.setFont(GUISizeHelper.menuFont); - jLabelFooterLabel.setFont(new Font(GUISizeHelper.menuFont.getName(), Font.BOLD, GUISizeHelper.menuFont.getSize())); - jLabelFooterText.setFont(GUISizeHelper.menuFont); - } - - private void saveDividerLocations() { - // save divider locations and divider saveDividerLocations - GuiDisplayUtil.saveCurrentBoundsToPrefs(); - GuiDisplayUtil.saveDividerLocationToPrefs(KEY_TABLES_DIVIDER_LOCATION_1, this.jSplitPane1.getDividerLocation()); - GuiDisplayUtil.saveDividerLocationToPrefs(KEY_TABLES_DIVIDER_LOCATION_2, this.jSplitPaneTables.getDividerLocation()); - GuiDisplayUtil.saveDividerLocationToPrefs(KEY_TABLES_DIVIDER_LOCATION_3, chatPanelMain.getSplitDividerLocation()); - } - - private void restoreFilters() { - TableUtil.setActiveFilters(KEY_TABLES_FILTER_SETTINGS, filterButtons); - setTableFilter(); - } - - private void saveGuiSettings() { - TableUtil.saveActiveFiltersToPrefs(KEY_TABLES_FILTER_SETTINGS, filterButtons); - TableUtil.saveColumnWidthAndOrderToPrefs(tableTables, KEY_TABLES_COLUMNS_WIDTH, KEY_TABLES_COLUMNS_ORDER); - } - - private void restoreDividers() { - Rectangle currentBounds = MageFrame.getDesktop().getBounds(); - if (currentBounds != null) { - String firstDivider = PreferencesDialog.getCachedValue(KEY_TABLES_DIVIDER_LOCATION_1, null); - String tableDivider = PreferencesDialog.getCachedValue(KEY_TABLES_DIVIDER_LOCATION_2, null); - String chatDivider = PreferencesDialog.getCachedValue(KEY_TABLES_DIVIDER_LOCATION_3, null); - GuiDisplayUtil.restoreDividerLocations(currentBounds, firstDivider, jSplitPane1); - GuiDisplayUtil.restoreDividerLocations(currentBounds, tableDivider, jSplitPaneTables); - GuiDisplayUtil.restoreDividerLocations(currentBounds, chatDivider, chatPanelMain); - } - } - - public Map getUIComponents() { - Map components = new HashMap<>(); - - components.put("jScrollPane1", jScrollPaneTablesActive); - components.put("jScrollPane1ViewPort", jScrollPaneTablesActive.getViewport()); - components.put("jPanel1", jPanelTop); - components.put("tablesPanel", this); - - return components; - } - - public void updateTables(Collection tables) { - try { - tableModel.loadData(tables); - this.tableTables.repaint(); - } catch (MageRemoteException ex) { - hideTables(); - } - } - - public void updateMatches(Collection matches) { - try { - matchesModel.loadData(matches); - this.tableCompleted.repaint(); - } catch (MageRemoteException ex) { - hideTables(); - } - } - - public void startTasks() { - if (SessionHandler.getSession() != null) { - if (updateTablesTask == null || updateTablesTask.isDone()) { - updateTablesTask = new UpdateTablesTask(roomId, this); - updateTablesTask.execute(); - } - if (updatePlayersTask == null || updatePlayersTask.isDone()) { - updatePlayersTask = new UpdatePlayersTask(roomId, this.chatPanelMain); - updatePlayersTask.execute(); - } - if (this.btnStateFinished.isSelected()) { - if (updateMatchesTask == null || updateMatchesTask.isDone()) { - updateMatchesTask = new UpdateMatchesTask(roomId, this); - updateMatchesTask.execute(); - } - } else if (updateMatchesTask != null) { - updateMatchesTask.cancel(true); - } - } - } - - public void stopTasks() { - if (updateTablesTask != null) { - updateTablesTask.cancel(true); - } - if (updatePlayersTask != null) { - updatePlayersTask.cancel(true); - } - if (updateMatchesTask != null) { - updateMatchesTask.cancel(true); - } - } - - public void showTables(UUID roomId) { - this.roomId = roomId; - UUID chatRoomId = null; - if (SessionHandler.getSession() != null) { - btnQuickStart.setVisible(SessionHandler.isTestMode()); - gameChooser.init(); - chatRoomId = SessionHandler.getRoomChatId(roomId).orElse(null); - } - if (newTableDialog == null) { - newTableDialog = new NewTableDialog(); - MageFrame.getDesktop().add(newTableDialog, JLayeredPane.MODAL_LAYER); - } - if (newTournamentDialog == null) { - newTournamentDialog = new NewTournamentDialog(); - MageFrame.getDesktop().add(newTournamentDialog, JLayeredPane.MODAL_LAYER); - } - if (joinTableDialog == null) { - joinTableDialog = new JoinTableDialog(); - MageFrame.getDesktop().add(joinTableDialog, JLayeredPane.MODAL_LAYER); - } - if (chatRoomId != null) { - this.chatPanelMain.getUserChatPanel().connect(chatRoomId); - startTasks(); - this.setVisible(true); - this.repaint(); - } else { - hideTables(); - } - //tableModel.setSession(session); - - reloadMessages(); - - MageFrame.getUI().addButton(MageComponents.NEW_GAME_BUTTON, btnNewTable); - - // divider locations have to be set with delay else values set are overwritten with system defaults - Executors.newSingleThreadScheduledExecutor().schedule(() -> restoreDividers(), 300, TimeUnit.MILLISECONDS); - - } - - protected void reloadMessages() { - // reload server messages - java.util.List serverMessages = SessionHandler.getServerMessages(); - synchronized (this) { - this.messages = serverMessages; - this.currentMessage = 0; - } - if (serverMessages.isEmpty()) { - this.jPanelBottom.setVisible(false); - } else { - this.jPanelBottom.setVisible(true); - URLHandler.RemoveMouseAdapter(jLabelFooterText); - URLHandler.handleMessage(serverMessages.get(0), this.jLabelFooterText); - this.jButtonFooterNext.setVisible(serverMessages.size() > 1); - } - } - - public void hideTables() { - this.saveDividerLocations(); - for (Component component : MageFrame.getDesktop().getComponents()) { - if (component instanceof TableWaitingDialog) { - ((TableWaitingDialog) component).closeDialog(); - } - } - stopTasks(); - this.chatPanelMain.getUserChatPanel().disconnect(); - - Component c = this.getParent(); - while (c != null && !(c instanceof TablesPane)) { - c = c.getParent(); - } - if (c != null) { - ((TablesPane) c).hideFrame(); - } - } - - public ChatPanelBasic getChatPanel() { - return chatPanelMain.getUserChatPanel(); - } - - public void setTableFilter() { - // state - java.util.List> stateFilterList = new ArrayList<>(); - if (btnStateWaiting.isSelected()) { - stateFilterList.add(RowFilter.regexFilter("Waiting", TableTableModel.COLUMN_STATUS)); - } - if (btnStateActive.isSelected()) { - stateFilterList.add(RowFilter.regexFilter("Dueling|Constructing|Drafting|Sideboard", TableTableModel.COLUMN_STATUS)); - } - - // type - java.util.List> typeFilterList = new ArrayList<>(); - if (btnTypeMatch.isSelected()) { - typeFilterList.add(RowFilter.regexFilter("Two|Commander|Free|Tiny|Momir", TableTableModel.COLUMN_GAME_TYPE)); - } - if (btnTypeTourneyConstructed.isSelected()) { - typeFilterList.add(RowFilter.regexFilter("Constructed", TableTableModel.COLUMN_GAME_TYPE)); - } - if (btnTypeTourneyLimited.isSelected()) { - typeFilterList.add(RowFilter.regexFilter("Booster|Sealed", TableTableModel.COLUMN_GAME_TYPE)); - } - - // format - java.util.List> formatFilterList = new ArrayList<>(); - if (btnFormatBlock.isSelected()) { - formatFilterList.add(RowFilter.regexFilter("^Constructed.*Block", TableTableModel.COLUMN_DECK_TYPE)); - } - if (btnFormatStandard.isSelected()) { - formatFilterList.add(RowFilter.regexFilter("^Constructed - Standard", TableTableModel.COLUMN_DECK_TYPE)); - } - if (btnFormatModern.isSelected()) { - formatFilterList.add(RowFilter.regexFilter("^Constructed - Modern", TableTableModel.COLUMN_DECK_TYPE)); - } - if (btnFormatLegacy.isSelected()) { - formatFilterList.add(RowFilter.regexFilter("^Constructed - Legacy", TableTableModel.COLUMN_DECK_TYPE)); - } - if (btnFormatVintage.isSelected()) { - formatFilterList.add(RowFilter.regexFilter("^Constructed - Vintage", TableTableModel.COLUMN_DECK_TYPE)); - } - if (btnFormatCommander.isSelected()) { - formatFilterList.add(RowFilter.regexFilter("^Commander|^Duel Commander|^Penny Dreadful Commander|^Freeform Commander|^MTGO 1v1 Commander|^Duel Brawl|^Brawl", TableTableModel.COLUMN_DECK_TYPE)); - } - if (btnFormatTinyLeader.isSelected()) { - formatFilterList.add(RowFilter.regexFilter("^Tiny", TableTableModel.COLUMN_DECK_TYPE)); - } - if (btnFormatLimited.isSelected()) { - formatFilterList.add(RowFilter.regexFilter("^Limited", TableTableModel.COLUMN_DECK_TYPE)); - } - if (btnFormatOther.isSelected()) { - formatFilterList.add(RowFilter.regexFilter("^Momir Basic|^Constructed - Pauper|^Constructed - Frontier|^Constructed - Extended|^Constructed - Eternal|^Constructed - Historical|^Constructed - Super|^Constructed - Freeform|^Australian Highlander|^Canadian Highlander|^Constructed - Old", TableTableModel.COLUMN_DECK_TYPE)); - } - - // skill - java.util.List> skillFilterList = new ArrayList<>(); - if (btnSkillBeginner.isSelected()) { - skillFilterList.add(RowFilter.regexFilter(this.tableModel.getSkillLevelAsCode(SkillLevel.BEGINNER, true), TableTableModel.COLUMN_SKILL)); - } - if (btnSkillCasual.isSelected()) { - skillFilterList.add(RowFilter.regexFilter(this.tableModel.getSkillLevelAsCode(SkillLevel.CASUAL, true), TableTableModel.COLUMN_SKILL)); - } - if (btnSkillSerious.isSelected()) { - skillFilterList.add(RowFilter.regexFilter(this.tableModel.getSkillLevelAsCode(SkillLevel.SERIOUS, true), TableTableModel.COLUMN_SKILL)); - } - - String ratedMark = TableTableModel.RATED_VALUE_YES; - java.util.List> ratingFilterList = new ArrayList<>(); - if (btnRated.isSelected()) { - // yes word - ratingFilterList.add(RowFilter.regexFilter("^" + ratedMark, TableTableModel.COLUMN_RATING)); - } - if (btnUnrated.isSelected()) { - // not yes word, see https://stackoverflow.com/a/406408/1276632 - ratingFilterList.add(RowFilter.regexFilter("^((?!" + ratedMark + ").)*$", TableTableModel.COLUMN_RATING)); - } - - // Password - String passwordMark = TableTableModel.PASSWORD_VALUE_YES; - java.util.List> passwordFilterList = new ArrayList<>(); - if (btnPassword.isSelected()) { - // yes - passwordFilterList.add(RowFilter.regexFilter("^" + passwordMark, TableTableModel.COLUMN_PASSWORD)); - } - if (btnOpen.isSelected()) { - // no - passwordFilterList.add(RowFilter.regexFilter("^((?!" + passwordMark + ").)*$", TableTableModel.COLUMN_PASSWORD)); - } - - // Hide games of ignored players - java.util.List> ignoreListFilterList = new ArrayList<>(); - String serverAddress = SessionHandler.getSession().getServerHostname().orElseGet(() -> ""); - final Set ignoreListCopy = IgnoreList.ignoreList(serverAddress); - if (!ignoreListCopy.isEmpty()) { - ignoreListFilterList.add(new RowFilter() { - @Override - public boolean include(Entry entry) { - final String owner = entry.getStringValue(TableTableModel.COLUMN_OWNER); - return !ignoreListCopy.contains(owner); - } - }); - } - - if (stateFilterList.isEmpty() || typeFilterList.isEmpty() || formatFilterList.isEmpty() - || skillFilterList.isEmpty() || ratingFilterList.isEmpty() - || passwordFilterList.isEmpty()) { // no selection - activeTablesSorter.setRowFilter(RowFilter.regexFilter("Nothing", TableTableModel.COLUMN_SKILL)); - } else { - java.util.List> filterList = new ArrayList<>(); - - if (stateFilterList.size() > 1) { - filterList.add(RowFilter.orFilter(stateFilterList)); - } else if (stateFilterList.size() == 1) { - filterList.addAll(stateFilterList); - } - - if (typeFilterList.size() > 1) { - filterList.add(RowFilter.orFilter(typeFilterList)); - } else if (typeFilterList.size() == 1) { - filterList.addAll(typeFilterList); - } - - if (formatFilterList.size() > 1) { - filterList.add(RowFilter.orFilter(formatFilterList)); - } else if (formatFilterList.size() == 1) { - filterList.addAll(formatFilterList); - } - - if (skillFilterList.size() > 1) { - filterList.add(RowFilter.orFilter(skillFilterList)); - } else if (skillFilterList.size() == 1) { - filterList.addAll(skillFilterList); - } - - if (ratingFilterList.size() > 1) { - filterList.add(RowFilter.orFilter(ratingFilterList)); - } else if (ratingFilterList.size() == 1) { - filterList.addAll(ratingFilterList); - } - - if (passwordFilterList.size() > 1) { - filterList.add(RowFilter.orFilter(passwordFilterList)); - } else if (passwordFilterList.size() == 1) { - filterList.addAll(passwordFilterList); - } - - if (ignoreListFilterList.size() > 1) { - filterList.add(RowFilter.orFilter(ignoreListFilterList)); - } else if (ignoreListFilterList.size() == 1) { - filterList.addAll(ignoreListFilterList); - } - - if (filterList.size() == 1) { - activeTablesSorter.setRowFilter(filterList.get(0)); - } else { - activeTablesSorter.setRowFilter(RowFilter.andFilter(filterList)); - } - } - } - - /** - * This method is called from within the constructor to initialize the form. - * WARNING: Do NOT modify this code. The content of this method is always - * regenerated by the Form Editor. - */ - @SuppressWarnings("unchecked") - // //GEN-BEGIN:initComponents - private void initComponents() { - java.awt.GridBagConstraints gridBagConstraints; - - jPanelTop = new javax.swing.JPanel(); - btnNewTable = new javax.swing.JButton(); - btnNewTournament = new javax.swing.JButton(); - filterBar1 = new javax.swing.JToolBar(); - btnStateWaiting = new javax.swing.JToggleButton(); - btnStateActive = new javax.swing.JToggleButton(); - btnStateFinished = new javax.swing.JToggleButton(); - jSeparator1 = new javax.swing.JToolBar.Separator(); - btnTypeMatch = new javax.swing.JToggleButton(); - btnTypeTourneyConstructed = new javax.swing.JToggleButton(); - btnTypeTourneyLimited = new javax.swing.JToggleButton(); - jSeparator4 = new javax.swing.JToolBar.Separator(); - btnSkillBeginner = new javax.swing.JToggleButton(); - btnSkillCasual = new javax.swing.JToggleButton(); - btnSkillSerious = new javax.swing.JToggleButton(); - jSeparator5 = new javax.swing.JToolBar.Separator(); - btnRated = new javax.swing.JToggleButton(); - btnUnrated = new javax.swing.JToggleButton(); - filterBar2 = new javax.swing.JToolBar(); - btnFormatBlock = new javax.swing.JToggleButton(); - btnFormatStandard = new javax.swing.JToggleButton(); - btnFormatModern = new javax.swing.JToggleButton(); - btnFormatLegacy = new javax.swing.JToggleButton(); - btnFormatVintage = new javax.swing.JToggleButton(); - jSeparator3 = new javax.swing.JToolBar.Separator(); - btnFormatCommander = new javax.swing.JToggleButton(); - btnFormatTinyLeader = new javax.swing.JToggleButton(); - jSeparator2 = new javax.swing.JToolBar.Separator(); - btnFormatLimited = new javax.swing.JToggleButton(); - btnFormatOther = new javax.swing.JToggleButton(); - jSeparator5 = new javax.swing.JToolBar.Separator(); - btnOpen = new javax.swing.JToggleButton(); - btnPassword = new javax.swing.JToggleButton(); - btnQuickStart = new javax.swing.JButton(); - jSplitPane1 = new javax.swing.JSplitPane(); - jPanelTables = new javax.swing.JPanel(); - jSplitPaneTables = new javax.swing.JSplitPane(); - jScrollPaneTablesActive = new javax.swing.JScrollPane(); - tableTables = new javax.swing.JTable(); - jScrollPaneTablesFinished = new javax.swing.JScrollPane(); - tableCompleted = new javax.swing.JTable(); - chatPanelMain = new mage.client.table.PlayersChatPanel(); - jPanelBottom = new javax.swing.JPanel(); - jButtonFooterNext = new javax.swing.JButton(); - jLabelFooterLabel = new javax.swing.JLabel(); - jLabelFooterText = new javax.swing.JLabel(); - - setLayout(new java.awt.GridBagLayout()); - - jPanelTop.setBackground(java.awt.Color.white); - jPanelTop.setOpaque(false); - - btnNewTable.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/match_new.png"))); // NOI18N - btnNewTable.setToolTipText("Creates a new match table."); - btnNewTable.setMargin(new java.awt.Insets(2, 2, 2, 2)); - btnNewTable.addActionListener(evt -> btnNewTableActionPerformed(evt)); - - btnNewTournament.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/tourney_new.png"))); // NOI18N - btnNewTournament.setToolTipText("Creates a new tourney table."); - btnNewTournament.setMargin(new java.awt.Insets(2, 2, 2, 2)); - btnNewTournament.addActionListener(evt -> btnNewTournamentActionPerformed(evt)); - - filterBar1.setFloatable(false); - filterBar1.setForeground(new java.awt.Color(102, 102, 255)); - filterBar1.setFocusable(false); - filterBar1.setOpaque(false); - - btnStateWaiting.setSelected(true); - btnStateWaiting.setToolTipText("Shows all tables waiting for players."); - btnStateWaiting.setActionCommand("stateWait"); - btnStateWaiting.setFocusPainted(false); - btnStateWaiting.setFocusable(false); - btnStateWaiting.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - btnStateWaiting.setRequestFocusEnabled(false); - btnStateWaiting.setVerifyInputWhenFocusTarget(false); - btnStateWaiting.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnStateWaiting.addActionListener(evt -> btnFilterActionPerformed(evt)); - filterBar1.add(btnStateWaiting); - - btnStateActive.setSelected(true); - btnStateActive.setToolTipText("Shows all tables with active matches."); - btnStateActive.setActionCommand("stateActive"); - btnStateActive.setFocusPainted(false); - btnStateActive.setFocusable(false); - btnStateActive.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - btnStateActive.setRequestFocusEnabled(false); - btnStateActive.setVerifyInputWhenFocusTarget(false); - btnStateActive.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnStateActive.addActionListener(evt -> btnFilterActionPerformed(evt)); - filterBar1.add(btnStateActive); - - btnStateFinished.setSelected(true); - btnStateFinished.setToolTipText("Toggles the visibility of the table of completed
matches and tournaments in the lower area.\n
Showing the last 50 finished matches."); - btnStateFinished.setActionCommand("stateFinished"); - btnStateFinished.setFocusPainted(false); - btnStateFinished.setFocusable(false); - btnStateFinished.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - btnStateFinished.setRequestFocusEnabled(false); - btnStateFinished.setVerifyInputWhenFocusTarget(false); - btnStateFinished.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnStateFinished.addActionListener(evt -> btnStateFinishedActionPerformed(evt)); - filterBar1.add(btnStateFinished); - filterBar1.add(jSeparator1); - - btnTypeMatch.setSelected(true); - btnTypeMatch.setText("Matches"); - btnTypeMatch.setToolTipText("Shows all non tournament tables."); - btnTypeMatch.setActionCommand("typeMatch"); - btnTypeMatch.setFocusPainted(false); - btnTypeMatch.setFocusable(false); - btnTypeMatch.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - btnTypeMatch.setRequestFocusEnabled(false); - btnTypeMatch.setVerifyInputWhenFocusTarget(false); - btnTypeMatch.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnTypeMatch.addActionListener(evt -> btnFilterActionPerformed(evt)); - filterBar1.add(btnTypeMatch); - - btnTypeTourneyConstructed.setSelected(true); - btnTypeTourneyConstructed.setText("Constructed tourn."); - btnTypeTourneyConstructed.setToolTipText("Shows all constructed tournament tables."); - btnTypeTourneyConstructed.setActionCommand("typeTourneyConstructed"); - btnTypeTourneyConstructed.setFocusPainted(false); - btnTypeTourneyConstructed.setFocusable(false); - btnTypeTourneyConstructed.setRequestFocusEnabled(false); - btnTypeTourneyConstructed.setVerifyInputWhenFocusTarget(false); - btnTypeTourneyConstructed.addActionListener(evt -> btnFilterActionPerformed(evt)); - filterBar1.add(btnTypeTourneyConstructed); - - btnTypeTourneyLimited.setSelected(true); - btnTypeTourneyLimited.setText("Limited tourn."); - btnTypeTourneyLimited.setToolTipText("Shows all limited tournament tables."); - btnTypeTourneyLimited.setActionCommand("typeTourneyLimited"); - btnTypeTourneyLimited.setFocusPainted(false); - btnTypeTourneyLimited.setFocusable(false); - btnTypeTourneyLimited.setMaximumSize(new java.awt.Dimension(72, 20)); - btnTypeTourneyLimited.setRequestFocusEnabled(false); - btnTypeTourneyLimited.setVerifyInputWhenFocusTarget(false); - btnTypeTourneyLimited.addActionListener(evt -> btnFilterActionPerformed(evt)); - filterBar1.add(btnTypeTourneyLimited); - filterBar1.add(jSeparator4); - - btnSkillBeginner.setSelected(true); - btnSkillBeginner.setText("Beginner"); - btnSkillBeginner.setToolTipText("Shows all tables with skill level beginner."); - btnSkillBeginner.setActionCommand("typeMatch"); - btnSkillBeginner.setFocusPainted(false); - btnSkillBeginner.setFocusable(false); - btnSkillBeginner.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - btnSkillBeginner.setRequestFocusEnabled(false); - btnSkillBeginner.setVerifyInputWhenFocusTarget(false); - btnSkillBeginner.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnSkillBeginner.addActionListener(evt -> btnFilterActionPerformed(evt)); - filterBar1.add(btnSkillBeginner); - - btnSkillCasual.setSelected(true); - btnSkillCasual.setText("Casual"); - btnSkillCasual.setToolTipText("Shows all tables with skill level casual."); - btnSkillCasual.setActionCommand("typeMatch"); - btnSkillCasual.setFocusPainted(false); - btnSkillCasual.setFocusable(false); - btnSkillCasual.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - btnSkillCasual.setRequestFocusEnabled(false); - btnSkillCasual.setVerifyInputWhenFocusTarget(false); - btnSkillCasual.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnSkillCasual.addActionListener(evt -> btnFilterActionPerformed(evt)); - filterBar1.add(btnSkillCasual); - - btnSkillSerious.setSelected(true); - btnSkillSerious.setText("Serious"); - btnSkillSerious.setToolTipText("Shows all tables with skill level serious."); - btnSkillSerious.setActionCommand("typeMatch"); - btnSkillSerious.setFocusPainted(false); - btnSkillSerious.setFocusable(false); - btnSkillSerious.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - btnSkillSerious.setRequestFocusEnabled(false); - btnSkillSerious.setVerifyInputWhenFocusTarget(false); - btnSkillSerious.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnSkillSerious.addActionListener(evt -> btnFilterActionPerformed(evt)); - filterBar1.add(btnSkillSerious); - - filterBar1.add(jSeparator4); - - btnRated.setSelected(true); - btnRated.setText("Rated"); - btnRated.setToolTipText("Shows all rated tables."); - btnRated.setFocusPainted(false); - btnRated.setFocusable(false); - btnRated.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - btnRated.setRequestFocusEnabled(false); - btnRated.setVerifyInputWhenFocusTarget(false); - btnRated.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnRated.addActionListener(evt -> btnFilterActionPerformed(evt)); - filterBar1.add(btnRated); - - btnUnrated.setSelected(true); - btnUnrated.setText("Unrated"); - btnUnrated.setToolTipText("Shows all unrated tables."); - btnUnrated.setFocusPainted(false); - btnUnrated.setFocusable(false); - btnUnrated.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - btnUnrated.setRequestFocusEnabled(false); - btnUnrated.setVerifyInputWhenFocusTarget(false); - btnUnrated.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnUnrated.addActionListener(evt -> btnFilterActionPerformed(evt)); - filterBar1.add(btnUnrated); - - // second filter line - filterBar2.setFloatable(false); - filterBar2.setFocusable(false); - filterBar2.setOpaque(false); - - btnFormatBlock.setSelected(true); - btnFormatBlock.setText("Block"); - btnFormatBlock.setToolTipText("Block constructed formats."); - btnFormatBlock.setFocusPainted(false); - btnFormatBlock.setFocusable(false); - btnFormatBlock.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - btnFormatBlock.setRequestFocusEnabled(false); - btnFormatBlock.setVerifyInputWhenFocusTarget(false); - btnFormatBlock.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnFormatBlock.addActionListener(evt -> btnFilterActionPerformed(evt)); - filterBar2.add(btnFormatBlock); - - btnFormatStandard.setSelected(true); - btnFormatStandard.setText("Standard"); - btnFormatStandard.setToolTipText("Standard format."); - btnFormatStandard.setFocusPainted(false); - btnFormatStandard.setFocusable(false); - btnFormatStandard.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - btnFormatStandard.setRequestFocusEnabled(false); - btnFormatStandard.setVerifyInputWhenFocusTarget(false); - btnFormatStandard.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnFormatStandard.addActionListener(evt -> btnFilterActionPerformed(evt)); - filterBar2.add(btnFormatStandard); - - btnFormatModern.setSelected(true); - btnFormatModern.setText("Modern"); - btnFormatModern.setToolTipText("Modern format."); - btnFormatModern.setFocusPainted(false); - btnFormatModern.setFocusable(false); - btnFormatModern.setRequestFocusEnabled(false); - btnFormatModern.setVerifyInputWhenFocusTarget(false); - btnFormatModern.addActionListener(evt -> btnFilterActionPerformed(evt)); - filterBar2.add(btnFormatModern); - - btnFormatLegacy.setSelected(true); - btnFormatLegacy.setText("Legacy"); - btnFormatLegacy.setToolTipText("Legacy format."); - btnFormatLegacy.setFocusPainted(false); - btnFormatLegacy.setFocusable(false); - btnFormatLegacy.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - btnFormatLegacy.setRequestFocusEnabled(false); - btnFormatLegacy.setVerifyInputWhenFocusTarget(false); - btnFormatLegacy.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnFormatLegacy.addActionListener(evt -> btnFilterActionPerformed(evt)); - filterBar2.add(btnFormatLegacy); - - btnFormatVintage.setSelected(true); - btnFormatVintage.setText("Vintage"); - btnFormatVintage.setToolTipText("Vintage format."); - btnFormatVintage.setFocusPainted(false); - btnFormatVintage.setFocusable(false); - btnFormatVintage.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - btnFormatVintage.setRequestFocusEnabled(false); - btnFormatVintage.setVerifyInputWhenFocusTarget(false); - btnFormatVintage.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnFormatVintage.addActionListener(evt -> btnFilterActionPerformed(evt)); - filterBar2.add(btnFormatVintage); - filterBar2.add(jSeparator3); - - btnFormatCommander.setSelected(true); - btnFormatCommander.setText("Commander"); - btnFormatCommander.setToolTipText("Commander format."); - btnFormatCommander.setFocusPainted(false); - btnFormatCommander.setFocusable(false); - btnFormatCommander.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - btnFormatCommander.setRequestFocusEnabled(false); - btnFormatCommander.setVerifyInputWhenFocusTarget(false); - btnFormatCommander.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnFormatCommander.addActionListener(evt -> btnFilterActionPerformed(evt)); - filterBar2.add(btnFormatCommander); - - btnFormatTinyLeader.setSelected(true); - btnFormatTinyLeader.setText("Tiny Leader"); - btnFormatTinyLeader.setToolTipText("Tiny Leader format."); - btnFormatTinyLeader.setFocusPainted(false); - btnFormatTinyLeader.setFocusable(false); - btnFormatTinyLeader.setRequestFocusEnabled(false); - btnFormatTinyLeader.setVerifyInputWhenFocusTarget(false); - btnFormatTinyLeader.addActionListener(evt -> btnFilterActionPerformed(evt)); - filterBar2.add(btnFormatTinyLeader); - filterBar2.add(jSeparator2); - - btnFormatLimited.setSelected(true); - btnFormatLimited.setText("Limited"); - btnFormatLimited.setToolTipText("Limited format."); - btnFormatLimited.setFocusPainted(false); - btnFormatLimited.setFocusable(false); - btnFormatLimited.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - btnFormatLimited.setRequestFocusEnabled(false); - btnFormatLimited.setVerifyInputWhenFocusTarget(false); - btnFormatLimited.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnFormatLimited.addActionListener(evt -> btnFilterActionPerformed(evt)); - filterBar2.add(btnFormatLimited); - - btnFormatOther.setSelected(true); - btnFormatOther.setText("Other"); - btnFormatOther.setToolTipText("Other formats (Freeform, Pauper, Extended, etc.)"); - btnFormatOther.setFocusPainted(false); - btnFormatOther.setFocusable(false); - btnFormatOther.setRequestFocusEnabled(false); - btnFormatOther.setVerifyInputWhenFocusTarget(false); - btnFormatOther.addActionListener(evt -> btnFilterActionPerformed(evt)); - filterBar2.add(btnFormatOther); - filterBar2.add(jSeparator5); - - btnOpen.setSelected(true); - btnOpen.setText("Open"); - btnOpen.setToolTipText("Show open games"); - btnOpen.setFocusPainted(false); - btnOpen.setFocusable(false); - btnOpen.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - btnOpen.setRequestFocusEnabled(false); - btnOpen.setVerifyInputWhenFocusTarget(false); - btnOpen.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnOpen.addActionListener(evt -> btnFilterActionPerformed(evt)); - filterBar2.add(btnOpen); - - btnPassword.setSelected(true); - btnPassword.setText("PW"); - btnPassword.setToolTipText("Show passworded games"); - btnPassword.setFocusPainted(false); - btnPassword.setFocusable(false); - btnPassword.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - btnPassword.setRequestFocusEnabled(false); - btnPassword.setVerifyInputWhenFocusTarget(false); - btnPassword.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnPassword.addActionListener(evt -> btnFilterActionPerformed(evt)); - filterBar2.add(btnPassword); - - btnQuickStart.setText("Quick Start"); - btnQuickStart.setFocusable(false); - btnQuickStart.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - btnQuickStart.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnQuickStart.addActionListener(evt -> btnQuickStartActionPerformed(evt)); - - javax.swing.GroupLayout jPanelTopLayout = new javax.swing.GroupLayout(jPanelTop); - jPanelTop.setLayout(jPanelTopLayout); - jPanelTopLayout.setHorizontalGroup( - jPanelTopLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelTopLayout.createSequentialGroup() - .addContainerGap() - .addComponent(btnNewTable) - .addGap(6, 6, 6) - .addComponent(btnNewTournament) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanelTopLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(filterBar1, javax.swing.GroupLayout.DEFAULT_SIZE, 491, Short.MAX_VALUE) - .addComponent(filterBar2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnQuickStart) - .addContainerGap(835, Short.MAX_VALUE)) - ); - jPanelTopLayout.setVerticalGroup( - jPanelTopLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelTopLayout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanelTopLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelTopLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(btnNewTable) - .addComponent(btnNewTournament)) - .addGroup(jPanelTopLayout.createSequentialGroup() - .addGroup(jPanelTopLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(filterBar1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(btnQuickStart)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(filterBar2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) - .addContainerGap()) - ); - - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; - gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; - add(jPanelTop, gridBagConstraints); - - jSplitPane1.setBorder(null); - jSplitPane1.setDividerSize(10); - jSplitPane1.setResizeWeight(1.0); - - jSplitPaneTables.setBorder(null); - jSplitPaneTables.setDividerSize(10); - jSplitPaneTables.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT); - jSplitPaneTables.setResizeWeight(0.5); - - jScrollPaneTablesActive.setBorder(null); - jScrollPaneTablesActive.setViewportBorder(null); - - tableTables.setModel(this.tableModel); - jScrollPaneTablesActive.setViewportView(tableTables); - - jSplitPaneTables.setLeftComponent(jScrollPaneTablesActive); - - jScrollPaneTablesFinished.setBorder(null); - jScrollPaneTablesFinished.setViewportBorder(null); - jScrollPaneTablesFinished.setMinimumSize(new java.awt.Dimension(23, 0)); - - tableCompleted.setModel(this.matchesModel); - jScrollPaneTablesFinished.setViewportView(tableCompleted); - - jSplitPaneTables.setRightComponent(jScrollPaneTablesFinished); - - javax.swing.GroupLayout jPanelTablesLayout = new javax.swing.GroupLayout(jPanelTables); - jPanelTables.setLayout(jPanelTablesLayout); - jPanelTablesLayout.setHorizontalGroup( - jPanelTablesLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jSplitPaneTables, javax.swing.GroupLayout.PREFERRED_SIZE, 23, Short.MAX_VALUE) - ); - jPanelTablesLayout.setVerticalGroup( - jPanelTablesLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jSplitPaneTables, javax.swing.GroupLayout.DEFAULT_SIZE, 672, Short.MAX_VALUE) - ); - - jSplitPane1.setLeftComponent(jPanelTables); - jSplitPane1.setRightComponent(chatPanelMain); - - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridy = 1; - gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; - gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; - gridBagConstraints.weightx = 1.0; - gridBagConstraints.weighty = 1.0; - add(jSplitPane1, gridBagConstraints); - - jPanelBottom.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); - jPanelBottom.setPreferredSize(new java.awt.Dimension(516, 37)); - jPanelBottom.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT)); - - jButtonFooterNext.setText("Next"); - jButtonFooterNext.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); - jButtonFooterNext.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - jButtonFooterNext.setOpaque(false); - jButtonFooterNext.addActionListener(evt -> jButtonFooterNextActionPerformed(evt)); - jPanelBottom.add(jButtonFooterNext); - - jLabelFooterLabel.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N - jLabelFooterLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); - jLabelFooterLabel.setText("Message of the Day:"); - jLabelFooterLabel.setAlignmentY(0.3F); - jPanelBottom.add(jLabelFooterLabel); - - jLabelFooterText.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); - jLabelFooterText.setText("You are playing Mage version 0.7.5. Welcome! -- Mage dev team --"); - jPanelBottom.add(jLabelFooterText); - - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridy = 2; - gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; - gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; - add(jPanelBottom, gridBagConstraints); - }//
//GEN-END:initComponents - - private void btnNewTournamentActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnNewTournamentActionPerformed - newTournamentDialog.showDialog(roomId); - }//GEN-LAST:event_btnNewTournamentActionPerformed - - private void btnQuickStartActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnQuickStartActionPerformed - TableView table; - try { - File f = new File("test.dck"); - if (!f.exists()) { - JOptionPane.showMessageDialog(null, "Couldn't find test.dck file for quick game start", "Error", JOptionPane.ERROR_MESSAGE); - return; - } - - MatchOptions options = new MatchOptions("1", "Two Player Duel", false, 2); - options.getPlayerTypes().add(PlayerType.HUMAN); - options.getPlayerTypes().add(PlayerType.COMPUTER_MAD); - options.setDeckType("Limited"); - options.setAttackOption(MultiplayerAttackOption.LEFT); - options.setRange(RangeOfInfluence.ALL); - options.setWinsNeeded(1); - options.setMatchTimeLimit(MatchTimeLimit.NONE); - options.setFreeMulligans(2); - options.setSkillLevel(SkillLevel.CASUAL); - options.setRollbackTurnsAllowed(true); - options.setQuitRatio(100); - String serverAddress = SessionHandler.getSession().getServerHostname().orElseGet(() -> ""); - options.setBannedUsers(IgnoreList.ignoreList(serverAddress)); - table = SessionHandler.createTable(roomId, options); - - SessionHandler.joinTable(roomId, table.getTableId(), "Human", PlayerType.HUMAN, 1, DeckImporterUtil.importDeck("test.dck"), ""); - SessionHandler.joinTable(roomId, table.getTableId(), "Computer", PlayerType.COMPUTER_MAD, 5, DeckImporterUtil.importDeck("test.dck"), ""); - SessionHandler.startMatch(roomId, table.getTableId()); - } catch (HeadlessException ex) { - handleError(ex); - } - }//GEN-LAST:event_btnQuickStartActionPerformed - - private void btnNewTableActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnNewTableActionPerformed - newTableDialog.showDialog(roomId); - }//GEN-LAST:event_btnNewTableActionPerformed - - private void jButtonFooterNextActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonFooterNextActionPerformed - synchronized (this) { - if (messages != null && !messages.isEmpty()) { - currentMessage++; - if (currentMessage >= messages.size()) { - currentMessage = 0; - } - - URLHandler.RemoveMouseAdapter(jLabelFooterText); - URLHandler.handleMessage(messages.get(currentMessage), this.jLabelFooterText); - } - } - }//GEN-LAST:event_jButtonFooterNextActionPerformed - - private void btnFilterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnFilterActionPerformed - setTableFilter(); - }//GEN-LAST:event_btnFilterActionPerformed - - private void btnStateFinishedActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnStateFinishedActionPerformed - if (this.btnStateFinished.isSelected()) { - this.jSplitPaneTables.setDividerLocation(-1); - } else { - this.jSplitPaneTables.setDividerLocation(this.jPanelTables.getHeight()); - } - this.startTasks(); - }//GEN-LAST:event_btnStateFinishedActionPerformed - - private void handleError(Exception ex) { - LOGGER.fatal("Error loading deck: ", ex); - JOptionPane.showMessageDialog(MageFrame.getDesktop(), "Error loading deck.", "Error", JOptionPane.ERROR_MESSAGE); - } - - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JToggleButton btnFormatBlock; - private javax.swing.JToggleButton btnFormatCommander; - private javax.swing.JToggleButton btnFormatLegacy; - private javax.swing.JToggleButton btnFormatLimited; - private javax.swing.JToggleButton btnFormatModern; - private javax.swing.JToggleButton btnFormatOther; - private javax.swing.JToggleButton btnFormatStandard; - private javax.swing.JToggleButton btnFormatTinyLeader; - private javax.swing.JToggleButton btnFormatVintage; - private javax.swing.JButton btnNewTable; - private javax.swing.JButton btnNewTournament; - private javax.swing.JToggleButton btnOpen; - private javax.swing.JToggleButton btnPassword; - private javax.swing.JButton btnQuickStart; - private javax.swing.JToggleButton btnSkillBeginner; - private javax.swing.JToggleButton btnSkillCasual; - private javax.swing.JToggleButton btnSkillSerious; - private javax.swing.JToggleButton btnRated; - private javax.swing.JToggleButton btnUnrated; - private javax.swing.JToggleButton btnStateActive; - private javax.swing.JToggleButton btnStateFinished; - private javax.swing.JToggleButton btnStateWaiting; - private javax.swing.JToggleButton btnTypeMatch; - private javax.swing.JToggleButton btnTypeTourneyConstructed; - private javax.swing.JToggleButton btnTypeTourneyLimited; - private mage.client.table.PlayersChatPanel chatPanelMain; - private javax.swing.JToolBar filterBar1; - private javax.swing.JToolBar filterBar2; - private javax.swing.JButton jButtonFooterNext; - private javax.swing.JLabel jLabelFooterLabel; - private javax.swing.JLabel jLabelFooterText; - private javax.swing.JPanel jPanelBottom; - private javax.swing.JPanel jPanelTables; - private javax.swing.JPanel jPanelTop; - private javax.swing.JScrollPane jScrollPaneTablesActive; - private javax.swing.JScrollPane jScrollPaneTablesFinished; - private javax.swing.JToolBar.Separator jSeparator1; - private javax.swing.JToolBar.Separator jSeparator2; - private javax.swing.JToolBar.Separator jSeparator3; - private javax.swing.JToolBar.Separator jSeparator4; - private javax.swing.JToolBar.Separator jSeparator5; - private javax.swing.JSplitPane jSplitPane1; - private javax.swing.JSplitPane jSplitPaneTables; - private javax.swing.JTable tableCompleted; - private javax.swing.JTable tableTables; - // End of variables declaration//GEN-END:variables - - } - - class TableTableModel extends AbstractTableModel { - - final ImageIcon tourneyIcon = new javax.swing.ImageIcon(getClass().getResource("/tables/tourney_icon.png")); - final ImageIcon matchIcon = new javax.swing.ImageIcon(getClass().getResource("/tables/match_icon.png")); - - public static final int COLUMN_ICON = 0; - public static final int COLUMN_DECK_TYPE = 1; // column the deck type is located (starting with 0) Start string is used to check for Limited - public static final int COLUMN_OWNER = 2; - public static final int COLUMN_GAME_TYPE = 3; - public static final int COLUMN_INFO = 4; - public static final int COLUMN_STATUS = 5; - public static final int COLUMN_PASSWORD = 6; - public static final int COLUMN_CREATED = 7; - public static final int COLUMN_SKILL = 8; - public static final int COLUMN_RATING = 9; - public static final int COLUMN_QUIT_RATIO = 10; - public static final int ACTION_COLUMN = 11; // column the action is located (starting with 0) - - public static final String RATED_VALUE_YES = "YES"; - public static final String RATED_VALUE_NO = ""; - - public static final String PASSWORD_VALUE_YES = "YES"; - - private final String[] columnNames = new String[]{"M/T", "Deck Type", "Owner / Players", "Game Type", "Info", "Status", "Password", "Created / Started", "Skill Level", "Rating", "Quit %", "Action"}; - - private TableView[] tables = new TableView[0]; - - TableTableModel() { - } - - public void loadData(Collection tables) throws MageRemoteException { - this.tables = tables.toArray(new TableView[0]); - this.fireTableDataChanged(); - } - - public String getSkillLevelAsCode(SkillLevel skill, boolean asRegExp) { - String res; - switch (skill) { - case BEGINNER: - res = "*"; - break; - case CASUAL: - res = "**"; - break; - case SERIOUS: - res = "***"; - break; - default: - res = ""; - break; - } - - // regexp format for search table rows - if (asRegExp) { - res = String.format("^%s$", res.replace("*", "\\*")); - } - - return res; - } - - @Override - public int getRowCount() { - return tables.length; - } - - @Override - public int getColumnCount() { - return columnNames.length; - } - - @Override - public Object getValueAt(int arg0, int arg1) { - switch (arg1) { - case 0: - return tables[arg0].isTournament() ? tourneyIcon : matchIcon; - case 1: - return tables[arg0].getDeckType(); - case 2: - return tables[arg0].getControllerName(); - case 3: - return tables[arg0].getGameType(); - case 4: - return tables[arg0].getAdditionalInfo(); - case 5: - return tables[arg0].getTableStateText(); - case 6: - return tables[arg0].isPassworded() ? PASSWORD_VALUE_YES : ""; - case 7: - return tables[arg0].getCreateTime(); // use cell render, not format here - case 8: - return this.getSkillLevelAsCode(tables[arg0].getSkillLevel(), false); - case 9: - return tables[arg0].isRated() ? RATED_VALUE_YES : RATED_VALUE_NO; - case 10: - return tables[arg0].getQuitRatio(); - case 11: - switch (tables[arg0].getTableState()) { - - case WAITING: - String owner = tables[arg0].getControllerName(); - if (SessionHandler.getSession() != null && owner.equals(SessionHandler.getUserName())) { - return ""; - } - return "Join"; - case CONSTRUCTING: - case DRAFTING: - if (tables[arg0].isTournament()) { - return "Show"; - } - case DUELING: - if (tables[arg0].isTournament()) { - return "Show"; - } else { - owner = tables[arg0].getControllerName(); - if (SessionHandler.getSession() != null && owner.equals(SessionHandler.getUserName())) { - return ""; - } - if (tables[arg0].getSpectatorsAllowed()) { - return "Watch"; - } - return ""; - } - default: - return ""; - } - case 12: - return tables[arg0].isTournament(); - case 13: - if (!tables[arg0].getGames().isEmpty()) { - return tables[arg0].getGames().get(0); - } - return null; - case 14: - return tables[arg0].getTableId(); - } - return ""; - } - - @Override - public String getColumnName(int columnIndex) { - String colName = ""; - - if (columnIndex <= getColumnCount()) { - colName = columnNames[columnIndex]; - } - - return colName; - } - - @Override - public Class getColumnClass(int columnIndex) { - switch (columnIndex) { - case COLUMN_ICON: - return Icon.class; - case COLUMN_SKILL: - return SkillLevel.class; - case COLUMN_CREATED: - return Date.class; - default: - return String.class; - } - } - - @Override - public boolean isCellEditable(int rowIndex, int columnIndex) { - return columnIndex == ACTION_COLUMN; - } - - } - - class UpdateTablesTask extends SwingWorker> { - - private final UUID roomId; - private final TablesPanel panel; - - private static final Logger logger = Logger.getLogger(UpdateTablesTask.class); - - private int count = 0; - - UpdateTablesTask(UUID roomId, TablesPanel panel) { - - this.roomId = roomId; - this.panel = panel; - } - - @Override - protected Void doInBackground() throws Exception { - while (!isCancelled()) { - Collection tables = SessionHandler.getTables(roomId); - if (tables != null) { - this.publish(tables); - } - TimeUnit.SECONDS.sleep(3); - } - return null; - } - - @Override - protected void process(java.util.List> view) { - panel.updateTables(view.get(0)); - count++; - if (count > 60) { - count = 0; - panel.reloadMessages(); - } - } - - @Override - protected void done() { - try { - get(); - } catch (InterruptedException | ExecutionException ex) { - logger.fatal("Update Tables Task error", ex); - } catch (CancellationException ex) { - } - } - - } - - class UpdatePlayersTask extends SwingWorker> { - - private final UUID roomId; - private final PlayersChatPanel chat; - - private static final Logger logger = Logger.getLogger(UpdatePlayersTask.class); - - UpdatePlayersTask(UUID roomId, PlayersChatPanel chat) { - - this.roomId = roomId; - this.chat = chat; - } - - @Override - protected Void doInBackground() throws Exception { - while (!isCancelled()) { - this.publish(SessionHandler.getRoomUsers(roomId)); - TimeUnit.SECONDS.sleep(3); - } - return null; - } - - @Override - protected void process(java.util.List> roomUserInfo) { - chat.setRoomUserInfo(roomUserInfo); - } - - @Override - protected void done() { - try { - get(); - } catch (InterruptedException | ExecutionException ex) { - logger.fatal("Update Players Task error", ex); - } catch (CancellationException ex) { - } - } - - } - - class MatchesTableModel extends AbstractTableModel { - - private final String[] columnNames = new String[]{"Deck Type", "Players", "Game Type", "Rating", "Result", "Duration", "Start Time", "End Time", "Action"}; - public static final int COLUMN_DURATION = 5; - public static final int COLUMN_START = 6; - public static final int COLUMN_END = 7; - public static final int COLUMN_ACTION = 8; // column the action is located (starting with 0) - - private MatchView[] matches = new MatchView[0]; - - public void loadData(Collection matches) throws MageRemoteException { - this.matches = matches.toArray(new MatchView[0]); - this.fireTableDataChanged(); - } - - MatchesTableModel() { - } - - @Override - public int getRowCount() { - return matches.length; - } - - @Override - public int getColumnCount() { - return columnNames.length; - } - - @Override - public Object getValueAt(int arg0, int arg1) { - switch (arg1) { - case 0: - return matches[arg0].getDeckType(); - case 1: - return matches[arg0].getPlayers(); - case 2: - return matches[arg0].getGameType(); - case 3: - return matches[arg0].isRated() ? TableTableModel.RATED_VALUE_YES : TableTableModel.RATED_VALUE_NO; - case 4: - return matches[arg0].getResult(); - case 5: - if (matches[arg0].getEndTime() != null) { - return matches[arg0].getEndTime().getTime() - matches[arg0].getStartTime().getTime() + new Date().getTime(); - } else { - return 0L; - } - case 6: - return matches[arg0].getStartTime(); - case 7: - return matches[arg0].getEndTime(); - case 8: - if (matches[arg0].isTournament()) { - return "Show"; - } else if (matches[arg0].isReplayAvailable()) { - return "Replay"; - } else { - return "None"; - } - case 9: - return matches[arg0].getGames(); - } - return ""; - } - - public java.util.List getListofGames(int row) { - return matches[row].getGames(); - } - - public boolean isTournament(int row) { - return matches[row].isTournament(); - } - - public UUID getMatchId(int row) { - return matches[row].getMatchId(); - } - - public UUID getTableId(int row) { - return matches[row].getTableId(); - } - - @Override - public String getColumnName(int columnIndex) { - String colName = ""; - - if (columnIndex <= getColumnCount()) { - colName = columnNames[columnIndex]; - } - - return colName; - } - - @Override - public Class getColumnClass(int columnIndex) { - switch (columnIndex) { - case COLUMN_DURATION: - return Long.class; - case COLUMN_START: - return Date.class; - case COLUMN_END: - return Date.class; - default: - return String.class; - } - } - - @Override - public boolean isCellEditable(int rowIndex, int columnIndex) { - return columnIndex == COLUMN_ACTION; - } - - } - - class UpdateMatchesTask extends SwingWorker> { - - private final UUID roomId; - private final TablesPanel panel; - - private static final Logger logger = Logger.getLogger(UpdateTablesTask.class); - - UpdateMatchesTask(UUID roomId, TablesPanel panel) { - this.roomId = roomId; - this.panel = panel; - } - - @Override - protected Void doInBackground() throws Exception { - while (!isCancelled()) { - Collection matches = SessionHandler.getFinishedMatches(roomId); - if (!matches.isEmpty()) { - this.publish(matches); - } - TimeUnit.SECONDS.sleep(10); - } - return null; - } - - @Override - protected void process(java.util.List> view) { - panel.updateMatches(view.get(0)); - } - - @Override - protected void done() { - try { - get(); - } catch (InterruptedException | ExecutionException ex) { - logger.fatal("Update Matches Task error", ex); - } catch (CancellationException ex) { - } - } - - } - - class GameChooser extends JPopupMenu { - - public void init() { - - } - - public void show(java.util.List games, Point p) { - if (p == null) { - return; - } - this.removeAll(); - for (UUID gameId : games) { - this.add(new GameChooserAction(gameId, gameId.toString())); - } - this.show(MageFrame.getDesktop(), p.x, p.y); - GuiDisplayUtil.keepComponentInsideScreen(p.x, p.y, this); - } - - private class GameChooserAction extends AbstractAction { - - private final UUID id; - - public GameChooserAction(UUID id, String choice) { - this.id = id; - putValue(Action.NAME, choice); - } - - @Override - public void actionPerformed(ActionEvent e) { - SessionHandler.replayGame(id); - setVisible(false); - } - - } - - } + + // default sort by created date (last games from above) + ArrayList list = new ArrayList(); + list.add(new RowSorter.SortKey(TablesTableModel.COLUMN_CREATED, SortOrder.DESCENDING)); + activeTablesSorter.setSortKeys(list); + + TableUtil.setColumnWidthAndOrder(tableTables, DEFAULT_COLUMNS_WIDTH, KEY_TABLES_COLUMNS_WIDTH, KEY_TABLES_COLUMNS_ORDER); + + // 2. TABLE COMPLETED + completedTablesSorter = new MageTableRowSorter(matchesModel); + tableCompleted.setRowSorter(completedTablesSorter); + + // duration + tableCompleted.getColumnModel().getColumn(MatchesTableModel.COLUMN_DURATION).setCellRenderer(durationCellRenderer); + // start-end + tableCompleted.getColumnModel().getColumn(MatchesTableModel.COLUMN_START).setCellRenderer(datetimeCellRenderer); + tableCompleted.getColumnModel().getColumn(MatchesTableModel.COLUMN_END).setCellRenderer(datetimeCellRenderer); + // default sort by ended date (last games from above) + ArrayList list2 = new ArrayList(); + list2.add(new RowSorter.SortKey(MatchesTableModel.COLUMN_END, SortOrder.DESCENDING)); + completedTablesSorter.setSortKeys(list2); + + // 3. CHAT + chatPanelMain.getUserChatPanel().useExtendedView(ChatPanelBasic.VIEW_MODE.NONE); + chatPanelMain.getUserChatPanel().setBorder(null); + chatPanelMain.getUserChatPanel().setChatType(ChatPanelBasic.ChatType.TABLES); + + // 4. BUTTONS + filterButtons = new JToggleButton[]{btnStateWaiting, btnStateActive, btnStateFinished, + btnTypeMatch, btnTypeTourneyConstructed, btnTypeTourneyLimited, + btnFormatBlock, btnFormatStandard, btnFormatModern, btnFormatLegacy, btnFormatVintage, btnFormatCommander, btnFormatTinyLeader, btnFormatLimited, btnFormatOther, + btnSkillBeginner, btnSkillCasual, btnSkillSerious, btnRated, btnUnrated, btnOpen, btnPassword}; + + JComponent[] components = new JComponent[]{chatPanelMain, jSplitPane1, jScrollPaneTablesActive, jScrollPaneTablesFinished, jPanelTop, jPanelTables}; + for (JComponent component : components) { + component.setOpaque(false); + } + + jScrollPaneTablesActive.getViewport().setBackground(new Color(255, 255, 255, 50)); + jScrollPaneTablesFinished.getViewport().setBackground(new Color(255, 255, 255, 50)); + + restoreFilters(); + setGUISize(); + + Action openTableAction; + openTableAction = new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + String searchID = e.getActionCommand(); + int modelRow = TablesUtil.findTableRowFromSearchId(tableModel, searchID); + if (modelRow == -1) { + return; + } + UUID tableId = (UUID) tableModel.getValueAt(modelRow, TablesTableModel.ACTION_COLUMN + 3); + UUID gameId = (UUID) tableModel.getValueAt(modelRow, TablesTableModel.ACTION_COLUMN + 2); + String action = (String) tableModel.getValueAt(modelRow, TablesTableModel.ACTION_COLUMN); + String deckType = (String) tableModel.getValueAt(modelRow, TablesTableModel.COLUMN_DECK_TYPE); + boolean isTournament = (Boolean) tableModel.getValueAt(modelRow, TablesTableModel.ACTION_COLUMN + 1); + String owner = (String) tableModel.getValueAt(modelRow, TablesTableModel.COLUMN_OWNER); + String pwdColumn = (String) tableModel.getValueAt(modelRow, TablesTableModel.COLUMN_PASSWORD); + switch (action) { + case "Join": + if (owner.equals(SessionHandler.getUserName()) || owner.startsWith(SessionHandler.getUserName() + ',')) { + try { + JDesktopPane desktopPane = (JDesktopPane) MageFrame.getUI().getComponent(MageComponents.DESKTOP_PANE); + JInternalFrame[] windows = desktopPane.getAllFramesInLayer(javax.swing.JLayeredPane.DEFAULT_LAYER); + for (JInternalFrame frame : windows) { + if (frame.getTitle().equals("Waiting for players")) { + frame.toFront(); + frame.setVisible(true); + try { + frame.setSelected(true); + } catch (PropertyVetoException ve) { + LOGGER.error(ve); + } + } + + } + } catch (InterruptedException ex) { + LOGGER.error(ex); + } + return; + } + if (isTournament) { + LOGGER.info("Joining tournament " + tableId); + if (deckType.startsWith("Limited")) { + if (TablesTableModel.PASSWORD_VALUE_YES.equals(pwdColumn)) { + joinTableDialog.showDialog(roomId, tableId, true, deckType.startsWith("Limited")); + } else { + SessionHandler.joinTournamentTable(roomId, tableId, SessionHandler.getUserName(), PlayerType.HUMAN, 1, null, ""); + } + } else { + joinTableDialog.showDialog(roomId, tableId, true, deckType.startsWith("Limited")); + } + } else { + LOGGER.info("Joining table " + tableId); + joinTableDialog.showDialog(roomId, tableId, false, false); + } + break; + case "Remove": + UserRequestMessage message = new UserRequestMessage("Removing table", "Are you sure you want to remove table?"); + message.setButton1("No", null); + message.setButton2("Yes", PlayerAction.CLIENT_REMOVE_TABLE); + MageFrame.getInstance().showUserRequestDialog(message); + break; + case "Show": + if (isTournament) { + LOGGER.info("Showing tournament table " + tableId); + SessionHandler.watchTable(roomId, tableId); + } + break; + case "Watch": + if (!isTournament) { + LOGGER.info("Watching table " + tableId); + SessionHandler.watchTable(roomId, tableId); + } + break; + case "Replay": + LOGGER.info("Replaying game " + gameId); + SessionHandler.replayGame(gameId); + break; + } + } + }; + + Action closedTableAction; + closedTableAction = new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + String searchID = e.getActionCommand(); + int modelRow = TablesUtil.findTableRowFromSearchId(matchesModel, searchID); + if (modelRow == -1) { + return; + } + String action = (String) matchesModel.getValueAt(modelRow, MatchesTableModel.COLUMN_ACTION); + switch (action) { + case "Replay": + java.util.List gameList = matchesModel.getListofGames(modelRow); + if (gameList != null && !gameList.isEmpty()) { + if (gameList.size() == 1) { + SessionHandler.replayGame(gameList.get(0)); + } else { + gameChooser.show(gameList, MageFrame.getDesktop().getMousePosition()); + } + } + // MageFrame.getDesktop().showTournament(tournamentId); + break; + case "Show": + if (matchesModel.isTournament(modelRow)) { + LOGGER.info("Showing tournament table " + matchesModel.getTableId(modelRow)); + SessionHandler.watchTable(roomId, matchesModel.getTableId(modelRow)); + } + break; + } + } + }; + + // !!!! adds action buttons to the table panel (don't delete this) + actionButton1 = new TablesButtonColumn(tableTables, openTableAction, tableTables.convertColumnIndexToView(TablesTableModel.ACTION_COLUMN)); + actionButton2 = new TablesButtonColumn(tableCompleted, closedTableAction, tableCompleted.convertColumnIndexToView(MatchesTableModel.COLUMN_ACTION)); + // !!!! + addTableDoubleClickListener(tableTables, openTableAction); + addTableDoubleClickListener(tableCompleted, closedTableAction); + } + + private void addTableDoubleClickListener(JTable table, Action action) { + table.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + int row = table.getSelectedRow(); + if (e.getClickCount() == 2 && row != -1) { + action.actionPerformed(new ActionEvent(table, ActionEvent.ACTION_PERFORMED, TablesUtil.getSearchIdFromTable(table, row))); + } + } + }); + } + + public void cleanUp() { + saveGuiSettings(); + chatPanelMain.cleanUp(); + } + + public void changeGUISize() { + chatPanelMain.changeGUISize(); + actionButton1.changeGUISize(); + actionButton2.changeGUISize(); + setGUISize(); + } + + private void setGUISize() { + tableTables.getTableHeader().setFont(GUISizeHelper.tableFont); + tableTables.setFont(GUISizeHelper.tableFont); + tableTables.setRowHeight(GUISizeHelper.getTableRowHeight()); + + tableCompleted.getTableHeader().setFont(GUISizeHelper.tableFont); + tableCompleted.setFont(GUISizeHelper.tableFont); + tableCompleted.setRowHeight(GUISizeHelper.getTableRowHeight()); + + jSplitPane1.setDividerSize(GUISizeHelper.dividerBarSize); + jSplitPaneTables.setDividerSize(GUISizeHelper.dividerBarSize); + jScrollPaneTablesActive.getVerticalScrollBar().setPreferredSize(new Dimension(GUISizeHelper.scrollBarSize, 0)); + jScrollPaneTablesActive.getHorizontalScrollBar().setPreferredSize(new Dimension(0, GUISizeHelper.scrollBarSize)); + + ImageIcon icon = new javax.swing.ImageIcon(getClass().getResource("/buttons/state_waiting.png")); + Image img = icon.getImage(); + Image newimg = img.getScaledInstance(GUISizeHelper.menuFont.getSize(), GUISizeHelper.menuFont.getSize(), java.awt.Image.SCALE_SMOOTH); + btnStateWaiting.setIcon(new ImageIcon(newimg)); + + icon = new javax.swing.ImageIcon(getClass().getResource("/buttons/state_active.png")); + img = icon.getImage(); + newimg = img.getScaledInstance(GUISizeHelper.menuFont.getSize(), GUISizeHelper.menuFont.getSize(), java.awt.Image.SCALE_SMOOTH); + btnStateActive.setIcon(new ImageIcon(newimg)); + + icon = new javax.swing.ImageIcon(getClass().getResource("/buttons/state_finished.png")); + img = icon.getImage(); + newimg = img.getScaledInstance(GUISizeHelper.menuFont.getSize(), GUISizeHelper.menuFont.getSize(), java.awt.Image.SCALE_SMOOTH); + btnStateFinished.setIcon(new ImageIcon(newimg)); + + int iconSize = 48 + GUISizeHelper.menuFont.getSize() * 2 - 15; + icon = new javax.swing.ImageIcon(getClass().getResource("/buttons/match_new.png")); + img = icon.getImage(); + newimg = img.getScaledInstance(iconSize, iconSize, java.awt.Image.SCALE_SMOOTH); + btnNewTable.setIcon(new ImageIcon(newimg)); + + icon = new javax.swing.ImageIcon(getClass().getResource("/buttons/tourney_new.png")); + img = icon.getImage(); + newimg = img.getScaledInstance(iconSize, iconSize, java.awt.Image.SCALE_SMOOTH); + btnNewTournament.setIcon(new ImageIcon(newimg)); + + for (JToggleButton component : filterButtons) { + component.setFont(GUISizeHelper.menuFont); + } + Dimension newDimension = new Dimension((int) jPanelBottom.getPreferredSize().getWidth(), GUISizeHelper.menuFont.getSize() + 28); + jPanelBottom.setMinimumSize(newDimension); + jPanelBottom.setPreferredSize(newDimension); + jButtonFooterNext.setFont(GUISizeHelper.menuFont); + jLabelFooterLabel.setFont(new Font(GUISizeHelper.menuFont.getName(), Font.BOLD, GUISizeHelper.menuFont.getSize())); + jLabelFooterText.setFont(GUISizeHelper.menuFont); + } + + private void saveDividerLocations() { + // save divider locations and divider saveDividerLocations + GuiDisplayUtil.saveCurrentBoundsToPrefs(); + GuiDisplayUtil.saveDividerLocationToPrefs(KEY_TABLES_DIVIDER_LOCATION_1, this.jSplitPane1.getDividerLocation()); + GuiDisplayUtil.saveDividerLocationToPrefs(KEY_TABLES_DIVIDER_LOCATION_2, this.jSplitPaneTables.getDividerLocation()); + GuiDisplayUtil.saveDividerLocationToPrefs(KEY_TABLES_DIVIDER_LOCATION_3, chatPanelMain.getSplitDividerLocation()); + } + + private void restoreFilters() { + TableUtil.setActiveFilters(KEY_TABLES_FILTER_SETTINGS, filterButtons); + setTableFilter(); + } + + private void saveGuiSettings() { + TableUtil.saveActiveFiltersToPrefs(KEY_TABLES_FILTER_SETTINGS, filterButtons); + TableUtil.saveColumnWidthAndOrderToPrefs(tableTables, KEY_TABLES_COLUMNS_WIDTH, KEY_TABLES_COLUMNS_ORDER); + } + + private void restoreDividers() { + Rectangle currentBounds = MageFrame.getDesktop().getBounds(); + if (currentBounds != null) { + String firstDivider = PreferencesDialog.getCachedValue(KEY_TABLES_DIVIDER_LOCATION_1, null); + String tableDivider = PreferencesDialog.getCachedValue(KEY_TABLES_DIVIDER_LOCATION_2, null); + String chatDivider = PreferencesDialog.getCachedValue(KEY_TABLES_DIVIDER_LOCATION_3, null); + GuiDisplayUtil.restoreDividerLocations(currentBounds, firstDivider, jSplitPane1); + GuiDisplayUtil.restoreDividerLocations(currentBounds, tableDivider, jSplitPaneTables); + GuiDisplayUtil.restoreDividerLocations(currentBounds, chatDivider, chatPanelMain); + } + } + + public Map getUIComponents() { + Map components = new HashMap<>(); + + components.put("jScrollPane1", jScrollPaneTablesActive); + components.put("jScrollPane1ViewPort", jScrollPaneTablesActive.getViewport()); + components.put("jPanel1", jPanelTop); + components.put("tablesPanel", this); + + return components; + } + + public void updateTables(Collection tables) { + try { + tableModel.loadData(tables); + this.tableTables.repaint(); + } catch (MageRemoteException ex) { + hideTables(); + } + } + + public void updateMatches(Collection matches) { + try { + matchesModel.loadData(matches); + this.tableCompleted.repaint(); + } catch (MageRemoteException ex) { + hideTables(); + } + } + + public void startTasks() { + if (SessionHandler.getSession() != null) { + if (updateTablesTask == null || updateTablesTask.isDone()) { + updateTablesTask = new UpdateTablesTask(roomId, this); + updateTablesTask.execute(); + } + if (updatePlayersTask == null || updatePlayersTask.isDone()) { + updatePlayersTask = new UpdatePlayersTask(roomId, this.chatPanelMain); + updatePlayersTask.execute(); + } + if (this.btnStateFinished.isSelected()) { + if (updateMatchesTask == null || updateMatchesTask.isDone()) { + updateMatchesTask = new UpdateMatchesTask(roomId, this); + updateMatchesTask.execute(); + } + } else if (updateMatchesTask != null) { + updateMatchesTask.cancel(true); + } + } + } + + public void stopTasks() { + if (updateTablesTask != null) { + updateTablesTask.cancel(true); + } + if (updatePlayersTask != null) { + updatePlayersTask.cancel(true); + } + if (updateMatchesTask != null) { + updateMatchesTask.cancel(true); + } + } + + public void showTables(UUID roomId) { + this.roomId = roomId; + UUID chatRoomId = null; + if (SessionHandler.getSession() != null) { + btnQuickStart.setVisible(SessionHandler.isTestMode()); + gameChooser.init(); + chatRoomId = SessionHandler.getRoomChatId(roomId).orElse(null); + } + if (newTableDialog == null) { + newTableDialog = new NewTableDialog(); + MageFrame.getDesktop().add(newTableDialog, JLayeredPane.MODAL_LAYER); + } + if (newTournamentDialog == null) { + newTournamentDialog = new NewTournamentDialog(); + MageFrame.getDesktop().add(newTournamentDialog, JLayeredPane.MODAL_LAYER); + } + if (joinTableDialog == null) { + joinTableDialog = new JoinTableDialog(); + MageFrame.getDesktop().add(joinTableDialog, JLayeredPane.MODAL_LAYER); + } + if (chatRoomId != null) { + this.chatPanelMain.getUserChatPanel().connect(chatRoomId); + startTasks(); + this.setVisible(true); + this.repaint(); + } else { + hideTables(); + } + //tableModel.setSession(session); + + reloadMessages(); + + MageFrame.getUI().addButton(MageComponents.NEW_GAME_BUTTON, btnNewTable); + + // divider locations have to be set with delay else values set are overwritten with system defaults + Executors.newSingleThreadScheduledExecutor().schedule(() -> restoreDividers(), 300, TimeUnit.MILLISECONDS); + + } + + protected void reloadMessages() { + // reload server messages + java.util.List serverMessages = SessionHandler.getServerMessages(); + synchronized (this) { + this.messages = serverMessages; + this.currentMessage = 0; + } + if (serverMessages.isEmpty()) { + this.jPanelBottom.setVisible(false); + } else { + this.jPanelBottom.setVisible(true); + URLHandler.RemoveMouseAdapter(jLabelFooterText); + URLHandler.handleMessage(serverMessages.get(0), this.jLabelFooterText); + this.jButtonFooterNext.setVisible(serverMessages.size() > 1); + } + } + + public void hideTables() { + this.saveDividerLocations(); + for (Component component : MageFrame.getDesktop().getComponents()) { + if (component instanceof TableWaitingDialog) { + ((TableWaitingDialog) component).closeDialog(); + } + } + stopTasks(); + this.chatPanelMain.getUserChatPanel().disconnect(); + + Component c = this.getParent(); + while (c != null && !(c instanceof TablesPane)) { + c = c.getParent(); + } + if (c != null) { + ((TablesPane) c).hideFrame(); + } + } + + public ChatPanelBasic getChatPanel() { + return chatPanelMain.getUserChatPanel(); + } + + public void setTableFilter() { + // state + java.util.List> stateFilterList = new ArrayList<>(); + if (btnStateWaiting.isSelected()) { + stateFilterList.add(RowFilter.regexFilter("Waiting", TablesTableModel.COLUMN_STATUS)); + } + if (btnStateActive.isSelected()) { + stateFilterList.add(RowFilter.regexFilter("Dueling|Constructing|Drafting|Sideboard", TablesTableModel.COLUMN_STATUS)); + } + + // type + java.util.List> typeFilterList = new ArrayList<>(); + if (btnTypeMatch.isSelected()) { + typeFilterList.add(RowFilter.regexFilter("Two|Commander|Free|Tiny|Momir", TablesTableModel.COLUMN_GAME_TYPE)); + } + if (btnTypeTourneyConstructed.isSelected()) { + typeFilterList.add(RowFilter.regexFilter("Constructed", TablesTableModel.COLUMN_GAME_TYPE)); + } + if (btnTypeTourneyLimited.isSelected()) { + typeFilterList.add(RowFilter.regexFilter("Booster|Sealed", TablesTableModel.COLUMN_GAME_TYPE)); + } + + // format + java.util.List> formatFilterList = new ArrayList<>(); + if (btnFormatBlock.isSelected()) { + formatFilterList.add(RowFilter.regexFilter("^Constructed.*Block", TablesTableModel.COLUMN_DECK_TYPE)); + } + if (btnFormatStandard.isSelected()) { + formatFilterList.add(RowFilter.regexFilter("^Constructed - Standard", TablesTableModel.COLUMN_DECK_TYPE)); + } + if (btnFormatModern.isSelected()) { + formatFilterList.add(RowFilter.regexFilter("^Constructed - Modern", TablesTableModel.COLUMN_DECK_TYPE)); + } + if (btnFormatLegacy.isSelected()) { + formatFilterList.add(RowFilter.regexFilter("^Constructed - Legacy", TablesTableModel.COLUMN_DECK_TYPE)); + } + if (btnFormatVintage.isSelected()) { + formatFilterList.add(RowFilter.regexFilter("^Constructed - Vintage", TablesTableModel.COLUMN_DECK_TYPE)); + } + if (btnFormatCommander.isSelected()) { + formatFilterList.add(RowFilter.regexFilter("^Commander|^Duel Commander|^Penny Dreadful Commander|^Freeform Commander|^MTGO 1v1 Commander|^Duel Brawl|^Brawl", TablesTableModel.COLUMN_DECK_TYPE)); + } + if (btnFormatTinyLeader.isSelected()) { + formatFilterList.add(RowFilter.regexFilter("^Tiny", TablesTableModel.COLUMN_DECK_TYPE)); + } + if (btnFormatLimited.isSelected()) { + formatFilterList.add(RowFilter.regexFilter("^Limited", TablesTableModel.COLUMN_DECK_TYPE)); + } + if (btnFormatOther.isSelected()) { + formatFilterList.add(RowFilter.regexFilter("^Momir Basic|^Constructed - Pauper|^Constructed - Frontier|^Constructed - Extended|^Constructed - Eternal|^Constructed - Historical|^Constructed - Super|^Constructed - Freeform|^Australian Highlander|^Canadian Highlander|^Constructed - Old", TablesTableModel.COLUMN_DECK_TYPE)); + } + + // skill + java.util.List> skillFilterList = new ArrayList<>(); + if (btnSkillBeginner.isSelected()) { + skillFilterList.add(RowFilter.regexFilter(this.tableModel.getSkillLevelAsCode(SkillLevel.BEGINNER, true), TablesTableModel.COLUMN_SKILL)); + } + if (btnSkillCasual.isSelected()) { + skillFilterList.add(RowFilter.regexFilter(this.tableModel.getSkillLevelAsCode(SkillLevel.CASUAL, true), TablesTableModel.COLUMN_SKILL)); + } + if (btnSkillSerious.isSelected()) { + skillFilterList.add(RowFilter.regexFilter(this.tableModel.getSkillLevelAsCode(SkillLevel.SERIOUS, true), TablesTableModel.COLUMN_SKILL)); + } + + String ratedMark = TablesTableModel.RATED_VALUE_YES; + java.util.List> ratingFilterList = new ArrayList<>(); + if (btnRated.isSelected()) { + // yes word + ratingFilterList.add(RowFilter.regexFilter("^" + ratedMark, TablesTableModel.COLUMN_RATING)); + } + if (btnUnrated.isSelected()) { + // not yes word, see https://stackoverflow.com/a/406408/1276632 + ratingFilterList.add(RowFilter.regexFilter("^((?!" + ratedMark + ").)*$", TablesTableModel.COLUMN_RATING)); + } + + // Password + String passwordMark = TablesTableModel.PASSWORD_VALUE_YES; + java.util.List> passwordFilterList = new ArrayList<>(); + if (btnPassword.isSelected()) { + // yes + passwordFilterList.add(RowFilter.regexFilter("^" + passwordMark, TablesTableModel.COLUMN_PASSWORD)); + } + if (btnOpen.isSelected()) { + // no + passwordFilterList.add(RowFilter.regexFilter("^((?!" + passwordMark + ").)*$", TablesTableModel.COLUMN_PASSWORD)); + } + + // Hide games of ignored players + java.util.List> ignoreListFilterList = new ArrayList<>(); + String serverAddress = SessionHandler.getSession().getServerHostname().orElseGet(() -> ""); + final Set ignoreListCopy = IgnoreList.ignoreList(serverAddress); + if (!ignoreListCopy.isEmpty()) { + ignoreListFilterList.add(new RowFilter() { + @Override + public boolean include(Entry entry) { + final String owner = entry.getStringValue(TablesTableModel.COLUMN_OWNER); + return !ignoreListCopy.contains(owner); + } + }); + } + + if (stateFilterList.isEmpty() || typeFilterList.isEmpty() || formatFilterList.isEmpty() + || skillFilterList.isEmpty() || ratingFilterList.isEmpty() + || passwordFilterList.isEmpty()) { // no selection + activeTablesSorter.setRowFilter(RowFilter.regexFilter("Nothing", TablesTableModel.COLUMN_SKILL)); + } else { + java.util.List> filterList = new ArrayList<>(); + + if (stateFilterList.size() > 1) { + filterList.add(RowFilter.orFilter(stateFilterList)); + } else if (stateFilterList.size() == 1) { + filterList.addAll(stateFilterList); + } + + if (typeFilterList.size() > 1) { + filterList.add(RowFilter.orFilter(typeFilterList)); + } else if (typeFilterList.size() == 1) { + filterList.addAll(typeFilterList); + } + + if (formatFilterList.size() > 1) { + filterList.add(RowFilter.orFilter(formatFilterList)); + } else if (formatFilterList.size() == 1) { + filterList.addAll(formatFilterList); + } + + if (skillFilterList.size() > 1) { + filterList.add(RowFilter.orFilter(skillFilterList)); + } else if (skillFilterList.size() == 1) { + filterList.addAll(skillFilterList); + } + + if (ratingFilterList.size() > 1) { + filterList.add(RowFilter.orFilter(ratingFilterList)); + } else if (ratingFilterList.size() == 1) { + filterList.addAll(ratingFilterList); + } + + if (passwordFilterList.size() > 1) { + filterList.add(RowFilter.orFilter(passwordFilterList)); + } else if (passwordFilterList.size() == 1) { + filterList.addAll(passwordFilterList); + } + + if (ignoreListFilterList.size() > 1) { + filterList.add(RowFilter.orFilter(ignoreListFilterList)); + } else if (ignoreListFilterList.size() == 1) { + filterList.addAll(ignoreListFilterList); + } + + if (filterList.size() == 1) { + activeTablesSorter.setRowFilter(filterList.get(0)); + } else { + activeTablesSorter.setRowFilter(RowFilter.andFilter(filterList)); + } + } + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + java.awt.GridBagConstraints gridBagConstraints; + + jPanelTop = new javax.swing.JPanel(); + btnNewTable = new javax.swing.JButton(); + btnNewTournament = new javax.swing.JButton(); + filterBar1 = new javax.swing.JToolBar(); + btnStateWaiting = new javax.swing.JToggleButton(); + btnStateActive = new javax.swing.JToggleButton(); + btnStateFinished = new javax.swing.JToggleButton(); + jSeparator1 = new javax.swing.JToolBar.Separator(); + btnTypeMatch = new javax.swing.JToggleButton(); + btnTypeTourneyConstructed = new javax.swing.JToggleButton(); + btnTypeTourneyLimited = new javax.swing.JToggleButton(); + jSeparator4 = new javax.swing.JToolBar.Separator(); + btnSkillBeginner = new javax.swing.JToggleButton(); + btnSkillCasual = new javax.swing.JToggleButton(); + btnSkillSerious = new javax.swing.JToggleButton(); + jSeparator5 = new javax.swing.JToolBar.Separator(); + btnRated = new javax.swing.JToggleButton(); + btnUnrated = new javax.swing.JToggleButton(); + filterBar2 = new javax.swing.JToolBar(); + btnFormatBlock = new javax.swing.JToggleButton(); + btnFormatStandard = new javax.swing.JToggleButton(); + btnFormatModern = new javax.swing.JToggleButton(); + btnFormatLegacy = new javax.swing.JToggleButton(); + btnFormatVintage = new javax.swing.JToggleButton(); + jSeparator3 = new javax.swing.JToolBar.Separator(); + btnFormatCommander = new javax.swing.JToggleButton(); + btnFormatTinyLeader = new javax.swing.JToggleButton(); + jSeparator2 = new javax.swing.JToolBar.Separator(); + btnFormatLimited = new javax.swing.JToggleButton(); + btnFormatOther = new javax.swing.JToggleButton(); + jSeparator5 = new javax.swing.JToolBar.Separator(); + btnOpen = new javax.swing.JToggleButton(); + btnPassword = new javax.swing.JToggleButton(); + btnQuickStart = new javax.swing.JButton(); + jSplitPane1 = new javax.swing.JSplitPane(); + jPanelTables = new javax.swing.JPanel(); + jSplitPaneTables = new javax.swing.JSplitPane(); + jScrollPaneTablesActive = new javax.swing.JScrollPane(); + tableTables = new javax.swing.JTable(); + jScrollPaneTablesFinished = new javax.swing.JScrollPane(); + tableCompleted = new javax.swing.JTable(); + chatPanelMain = new mage.client.table.PlayersChatPanel(); + jPanelBottom = new javax.swing.JPanel(); + jButtonFooterNext = new javax.swing.JButton(); + jLabelFooterLabel = new javax.swing.JLabel(); + jLabelFooterText = new javax.swing.JLabel(); + + setLayout(new java.awt.GridBagLayout()); + + jPanelTop.setBackground(java.awt.Color.white); + jPanelTop.setOpaque(false); + + btnNewTable.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/match_new.png"))); // NOI18N + btnNewTable.setToolTipText("Creates a new match table."); + btnNewTable.setMargin(new java.awt.Insets(2, 2, 2, 2)); + btnNewTable.addActionListener(evt -> btnNewTableActionPerformed(evt)); + + btnNewTournament.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/tourney_new.png"))); // NOI18N + btnNewTournament.setToolTipText("Creates a new tourney table."); + btnNewTournament.setMargin(new java.awt.Insets(2, 2, 2, 2)); + btnNewTournament.addActionListener(evt -> btnNewTournamentActionPerformed(evt)); + + filterBar1.setFloatable(false); + filterBar1.setForeground(new java.awt.Color(102, 102, 255)); + filterBar1.setFocusable(false); + filterBar1.setOpaque(false); + + btnStateWaiting.setSelected(true); + btnStateWaiting.setToolTipText("Shows all tables waiting for players."); + btnStateWaiting.setActionCommand("stateWait"); + btnStateWaiting.setFocusPainted(false); + btnStateWaiting.setFocusable(false); + btnStateWaiting.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnStateWaiting.setRequestFocusEnabled(false); + btnStateWaiting.setVerifyInputWhenFocusTarget(false); + btnStateWaiting.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + btnStateWaiting.addActionListener(evt -> btnFilterActionPerformed(evt)); + filterBar1.add(btnStateWaiting); + + btnStateActive.setSelected(true); + btnStateActive.setToolTipText("Shows all tables with active matches."); + btnStateActive.setActionCommand("stateActive"); + btnStateActive.setFocusPainted(false); + btnStateActive.setFocusable(false); + btnStateActive.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnStateActive.setRequestFocusEnabled(false); + btnStateActive.setVerifyInputWhenFocusTarget(false); + btnStateActive.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + btnStateActive.addActionListener(evt -> btnFilterActionPerformed(evt)); + filterBar1.add(btnStateActive); + + btnStateFinished.setSelected(true); + btnStateFinished.setToolTipText("Toggles the visibility of the table of completed
matches and tournaments in the lower area.\n
Showing the last 50 finished matches."); + btnStateFinished.setActionCommand("stateFinished"); + btnStateFinished.setFocusPainted(false); + btnStateFinished.setFocusable(false); + btnStateFinished.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnStateFinished.setRequestFocusEnabled(false); + btnStateFinished.setVerifyInputWhenFocusTarget(false); + btnStateFinished.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + btnStateFinished.addActionListener(evt -> btnStateFinishedActionPerformed(evt)); + filterBar1.add(btnStateFinished); + filterBar1.add(jSeparator1); + + btnTypeMatch.setSelected(true); + btnTypeMatch.setText("Matches"); + btnTypeMatch.setToolTipText("Shows all non tournament tables."); + btnTypeMatch.setActionCommand("typeMatch"); + btnTypeMatch.setFocusPainted(false); + btnTypeMatch.setFocusable(false); + btnTypeMatch.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnTypeMatch.setRequestFocusEnabled(false); + btnTypeMatch.setVerifyInputWhenFocusTarget(false); + btnTypeMatch.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + btnTypeMatch.addActionListener(evt -> btnFilterActionPerformed(evt)); + filterBar1.add(btnTypeMatch); + + btnTypeTourneyConstructed.setSelected(true); + btnTypeTourneyConstructed.setText("Constructed tourn."); + btnTypeTourneyConstructed.setToolTipText("Shows all constructed tournament tables."); + btnTypeTourneyConstructed.setActionCommand("typeTourneyConstructed"); + btnTypeTourneyConstructed.setFocusPainted(false); + btnTypeTourneyConstructed.setFocusable(false); + btnTypeTourneyConstructed.setRequestFocusEnabled(false); + btnTypeTourneyConstructed.setVerifyInputWhenFocusTarget(false); + btnTypeTourneyConstructed.addActionListener(evt -> btnFilterActionPerformed(evt)); + filterBar1.add(btnTypeTourneyConstructed); + + btnTypeTourneyLimited.setSelected(true); + btnTypeTourneyLimited.setText("Limited tourn."); + btnTypeTourneyLimited.setToolTipText("Shows all limited tournament tables."); + btnTypeTourneyLimited.setActionCommand("typeTourneyLimited"); + btnTypeTourneyLimited.setFocusPainted(false); + btnTypeTourneyLimited.setFocusable(false); + btnTypeTourneyLimited.setMaximumSize(new java.awt.Dimension(72, 20)); + btnTypeTourneyLimited.setRequestFocusEnabled(false); + btnTypeTourneyLimited.setVerifyInputWhenFocusTarget(false); + btnTypeTourneyLimited.addActionListener(evt -> btnFilterActionPerformed(evt)); + filterBar1.add(btnTypeTourneyLimited); + filterBar1.add(jSeparator4); + + btnSkillBeginner.setSelected(true); + btnSkillBeginner.setText("Beginner"); + btnSkillBeginner.setToolTipText("Shows all tables with skill level beginner."); + btnSkillBeginner.setActionCommand("typeMatch"); + btnSkillBeginner.setFocusPainted(false); + btnSkillBeginner.setFocusable(false); + btnSkillBeginner.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnSkillBeginner.setRequestFocusEnabled(false); + btnSkillBeginner.setVerifyInputWhenFocusTarget(false); + btnSkillBeginner.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + btnSkillBeginner.addActionListener(evt -> btnFilterActionPerformed(evt)); + filterBar1.add(btnSkillBeginner); + + btnSkillCasual.setSelected(true); + btnSkillCasual.setText("Casual"); + btnSkillCasual.setToolTipText("Shows all tables with skill level casual."); + btnSkillCasual.setActionCommand("typeMatch"); + btnSkillCasual.setFocusPainted(false); + btnSkillCasual.setFocusable(false); + btnSkillCasual.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnSkillCasual.setRequestFocusEnabled(false); + btnSkillCasual.setVerifyInputWhenFocusTarget(false); + btnSkillCasual.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + btnSkillCasual.addActionListener(evt -> btnFilterActionPerformed(evt)); + filterBar1.add(btnSkillCasual); + + btnSkillSerious.setSelected(true); + btnSkillSerious.setText("Serious"); + btnSkillSerious.setToolTipText("Shows all tables with skill level serious."); + btnSkillSerious.setActionCommand("typeMatch"); + btnSkillSerious.setFocusPainted(false); + btnSkillSerious.setFocusable(false); + btnSkillSerious.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnSkillSerious.setRequestFocusEnabled(false); + btnSkillSerious.setVerifyInputWhenFocusTarget(false); + btnSkillSerious.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + btnSkillSerious.addActionListener(evt -> btnFilterActionPerformed(evt)); + filterBar1.add(btnSkillSerious); + + filterBar1.add(jSeparator4); + + btnRated.setSelected(true); + btnRated.setText("Rated"); + btnRated.setToolTipText("Shows all rated tables."); + btnRated.setFocusPainted(false); + btnRated.setFocusable(false); + btnRated.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnRated.setRequestFocusEnabled(false); + btnRated.setVerifyInputWhenFocusTarget(false); + btnRated.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + btnRated.addActionListener(evt -> btnFilterActionPerformed(evt)); + filterBar1.add(btnRated); + + btnUnrated.setSelected(true); + btnUnrated.setText("Unrated"); + btnUnrated.setToolTipText("Shows all unrated tables."); + btnUnrated.setFocusPainted(false); + btnUnrated.setFocusable(false); + btnUnrated.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnUnrated.setRequestFocusEnabled(false); + btnUnrated.setVerifyInputWhenFocusTarget(false); + btnUnrated.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + btnUnrated.addActionListener(evt -> btnFilterActionPerformed(evt)); + filterBar1.add(btnUnrated); + + // second filter line + filterBar2.setFloatable(false); + filterBar2.setFocusable(false); + filterBar2.setOpaque(false); + + btnFormatBlock.setSelected(true); + btnFormatBlock.setText("Block"); + btnFormatBlock.setToolTipText("Block constructed formats."); + btnFormatBlock.setFocusPainted(false); + btnFormatBlock.setFocusable(false); + btnFormatBlock.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnFormatBlock.setRequestFocusEnabled(false); + btnFormatBlock.setVerifyInputWhenFocusTarget(false); + btnFormatBlock.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + btnFormatBlock.addActionListener(evt -> btnFilterActionPerformed(evt)); + filterBar2.add(btnFormatBlock); + + btnFormatStandard.setSelected(true); + btnFormatStandard.setText("Standard"); + btnFormatStandard.setToolTipText("Standard format."); + btnFormatStandard.setFocusPainted(false); + btnFormatStandard.setFocusable(false); + btnFormatStandard.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnFormatStandard.setRequestFocusEnabled(false); + btnFormatStandard.setVerifyInputWhenFocusTarget(false); + btnFormatStandard.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + btnFormatStandard.addActionListener(evt -> btnFilterActionPerformed(evt)); + filterBar2.add(btnFormatStandard); + + btnFormatModern.setSelected(true); + btnFormatModern.setText("Modern"); + btnFormatModern.setToolTipText("Modern format."); + btnFormatModern.setFocusPainted(false); + btnFormatModern.setFocusable(false); + btnFormatModern.setRequestFocusEnabled(false); + btnFormatModern.setVerifyInputWhenFocusTarget(false); + btnFormatModern.addActionListener(evt -> btnFilterActionPerformed(evt)); + filterBar2.add(btnFormatModern); + + btnFormatLegacy.setSelected(true); + btnFormatLegacy.setText("Legacy"); + btnFormatLegacy.setToolTipText("Legacy format."); + btnFormatLegacy.setFocusPainted(false); + btnFormatLegacy.setFocusable(false); + btnFormatLegacy.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnFormatLegacy.setRequestFocusEnabled(false); + btnFormatLegacy.setVerifyInputWhenFocusTarget(false); + btnFormatLegacy.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + btnFormatLegacy.addActionListener(evt -> btnFilterActionPerformed(evt)); + filterBar2.add(btnFormatLegacy); + + btnFormatVintage.setSelected(true); + btnFormatVintage.setText("Vintage"); + btnFormatVintage.setToolTipText("Vintage format."); + btnFormatVintage.setFocusPainted(false); + btnFormatVintage.setFocusable(false); + btnFormatVintage.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnFormatVintage.setRequestFocusEnabled(false); + btnFormatVintage.setVerifyInputWhenFocusTarget(false); + btnFormatVintage.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + btnFormatVintage.addActionListener(evt -> btnFilterActionPerformed(evt)); + filterBar2.add(btnFormatVintage); + filterBar2.add(jSeparator3); + + btnFormatCommander.setSelected(true); + btnFormatCommander.setText("Commander"); + btnFormatCommander.setToolTipText("Commander format."); + btnFormatCommander.setFocusPainted(false); + btnFormatCommander.setFocusable(false); + btnFormatCommander.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnFormatCommander.setRequestFocusEnabled(false); + btnFormatCommander.setVerifyInputWhenFocusTarget(false); + btnFormatCommander.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + btnFormatCommander.addActionListener(evt -> btnFilterActionPerformed(evt)); + filterBar2.add(btnFormatCommander); + + btnFormatTinyLeader.setSelected(true); + btnFormatTinyLeader.setText("Tiny Leader"); + btnFormatTinyLeader.setToolTipText("Tiny Leader format."); + btnFormatTinyLeader.setFocusPainted(false); + btnFormatTinyLeader.setFocusable(false); + btnFormatTinyLeader.setRequestFocusEnabled(false); + btnFormatTinyLeader.setVerifyInputWhenFocusTarget(false); + btnFormatTinyLeader.addActionListener(evt -> btnFilterActionPerformed(evt)); + filterBar2.add(btnFormatTinyLeader); + filterBar2.add(jSeparator2); + + btnFormatLimited.setSelected(true); + btnFormatLimited.setText("Limited"); + btnFormatLimited.setToolTipText("Limited format."); + btnFormatLimited.setFocusPainted(false); + btnFormatLimited.setFocusable(false); + btnFormatLimited.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnFormatLimited.setRequestFocusEnabled(false); + btnFormatLimited.setVerifyInputWhenFocusTarget(false); + btnFormatLimited.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + btnFormatLimited.addActionListener(evt -> btnFilterActionPerformed(evt)); + filterBar2.add(btnFormatLimited); + + btnFormatOther.setSelected(true); + btnFormatOther.setText("Other"); + btnFormatOther.setToolTipText("Other formats (Freeform, Pauper, Extended, etc.)"); + btnFormatOther.setFocusPainted(false); + btnFormatOther.setFocusable(false); + btnFormatOther.setRequestFocusEnabled(false); + btnFormatOther.setVerifyInputWhenFocusTarget(false); + btnFormatOther.addActionListener(evt -> btnFilterActionPerformed(evt)); + filterBar2.add(btnFormatOther); + filterBar2.add(jSeparator5); + + btnOpen.setSelected(true); + btnOpen.setText("Open"); + btnOpen.setToolTipText("Show open games"); + btnOpen.setFocusPainted(false); + btnOpen.setFocusable(false); + btnOpen.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnOpen.setRequestFocusEnabled(false); + btnOpen.setVerifyInputWhenFocusTarget(false); + btnOpen.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + btnOpen.addActionListener(evt -> btnFilterActionPerformed(evt)); + filterBar2.add(btnOpen); + + btnPassword.setSelected(true); + btnPassword.setText("PW"); + btnPassword.setToolTipText("Show passworded games"); + btnPassword.setFocusPainted(false); + btnPassword.setFocusable(false); + btnPassword.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnPassword.setRequestFocusEnabled(false); + btnPassword.setVerifyInputWhenFocusTarget(false); + btnPassword.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + btnPassword.addActionListener(evt -> btnFilterActionPerformed(evt)); + filterBar2.add(btnPassword); + + btnQuickStart.setText("Quick Start"); + btnQuickStart.setFocusable(false); + btnQuickStart.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnQuickStart.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + btnQuickStart.addActionListener(evt -> btnQuickStartActionPerformed(evt)); + + javax.swing.GroupLayout jPanelTopLayout = new javax.swing.GroupLayout(jPanelTop); + jPanelTop.setLayout(jPanelTopLayout); + jPanelTopLayout.setHorizontalGroup( + jPanelTopLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanelTopLayout.createSequentialGroup() + .addContainerGap() + .addComponent(btnNewTable) + .addGap(6, 6, 6) + .addComponent(btnNewTournament) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanelTopLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(filterBar1, javax.swing.GroupLayout.DEFAULT_SIZE, 491, Short.MAX_VALUE) + .addComponent(filterBar2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnQuickStart) + .addContainerGap(835, Short.MAX_VALUE)) + ); + jPanelTopLayout.setVerticalGroup( + jPanelTopLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanelTopLayout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanelTopLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanelTopLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(btnNewTable) + .addComponent(btnNewTournament)) + .addGroup(jPanelTopLayout.createSequentialGroup() + .addGroup(jPanelTopLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(filterBar1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(btnQuickStart)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(filterBar2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addContainerGap()) + ); + + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; + add(jPanelTop, gridBagConstraints); + + jSplitPane1.setBorder(null); + jSplitPane1.setDividerSize(10); + jSplitPane1.setResizeWeight(1.0); + + jSplitPaneTables.setBorder(null); + jSplitPaneTables.setDividerSize(10); + jSplitPaneTables.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT); + jSplitPaneTables.setResizeWeight(0.5); + + jScrollPaneTablesActive.setBorder(null); + jScrollPaneTablesActive.setViewportBorder(null); + + tableTables.setModel(this.tableModel); + jScrollPaneTablesActive.setViewportView(tableTables); + + jSplitPaneTables.setLeftComponent(jScrollPaneTablesActive); + + jScrollPaneTablesFinished.setBorder(null); + jScrollPaneTablesFinished.setViewportBorder(null); + jScrollPaneTablesFinished.setMinimumSize(new java.awt.Dimension(23, 0)); + + tableCompleted.setModel(this.matchesModel); + jScrollPaneTablesFinished.setViewportView(tableCompleted); + + jSplitPaneTables.setRightComponent(jScrollPaneTablesFinished); + + javax.swing.GroupLayout jPanelTablesLayout = new javax.swing.GroupLayout(jPanelTables); + jPanelTables.setLayout(jPanelTablesLayout); + jPanelTablesLayout.setHorizontalGroup( + jPanelTablesLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jSplitPaneTables, javax.swing.GroupLayout.PREFERRED_SIZE, 23, Short.MAX_VALUE) + ); + jPanelTablesLayout.setVerticalGroup( + jPanelTablesLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jSplitPaneTables, javax.swing.GroupLayout.DEFAULT_SIZE, 672, Short.MAX_VALUE) + ); + + jSplitPane1.setLeftComponent(jPanelTables); + jSplitPane1.setRightComponent(chatPanelMain); + + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridy = 1; + gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; + gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.weighty = 1.0; + add(jSplitPane1, gridBagConstraints); + + jPanelBottom.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + jPanelBottom.setPreferredSize(new java.awt.Dimension(516, 37)); + jPanelBottom.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT)); + + jButtonFooterNext.setText("Next"); + jButtonFooterNext.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); + jButtonFooterNext.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + jButtonFooterNext.setOpaque(false); + jButtonFooterNext.addActionListener(evt -> jButtonFooterNextActionPerformed(evt)); + jPanelBottom.add(jButtonFooterNext); + + jLabelFooterLabel.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N + jLabelFooterLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); + jLabelFooterLabel.setText("Message of the Day:"); + jLabelFooterLabel.setAlignmentY(0.3F); + jPanelBottom.add(jLabelFooterLabel); + + jLabelFooterText.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); + jLabelFooterText.setText("You are playing Mage version 0.7.5. Welcome! -- Mage dev team --"); + jPanelBottom.add(jLabelFooterText); + + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridy = 2; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; + add(jPanelBottom, gridBagConstraints); + }//
//GEN-END:initComponents + + private void btnNewTournamentActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnNewTournamentActionPerformed + newTournamentDialog.showDialog(roomId); + }//GEN-LAST:event_btnNewTournamentActionPerformed + + private void btnQuickStartActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnQuickStartActionPerformed + TableView table; + try { + File f = new File("test.dck"); + if (!f.exists()) { + JOptionPane.showMessageDialog(null, "Couldn't find test.dck file for quick game start", "Error", JOptionPane.ERROR_MESSAGE); + return; + } + + MatchOptions options = new MatchOptions("1", "Two Player Duel", false, 2); + options.getPlayerTypes().add(PlayerType.HUMAN); + options.getPlayerTypes().add(PlayerType.COMPUTER_MAD); + options.setDeckType("Limited"); + options.setAttackOption(MultiplayerAttackOption.LEFT); + options.setRange(RangeOfInfluence.ALL); + options.setWinsNeeded(1); + options.setMatchTimeLimit(MatchTimeLimit.NONE); + options.setFreeMulligans(2); + options.setSkillLevel(SkillLevel.CASUAL); + options.setRollbackTurnsAllowed(true); + options.setQuitRatio(100); + options.setMinimumRating(0); + String serverAddress = SessionHandler.getSession().getServerHostname().orElseGet(() -> ""); + options.setBannedUsers(IgnoreList.ignoreList(serverAddress)); + table = SessionHandler.createTable(roomId, options); + + SessionHandler.joinTable(roomId, table.getTableId(), "Human", PlayerType.HUMAN, 1, DeckImporterUtil.importDeck("test.dck"), ""); + SessionHandler.joinTable(roomId, table.getTableId(), "Computer", PlayerType.COMPUTER_MAD, 5, DeckImporterUtil.importDeck("test.dck"), ""); + SessionHandler.startMatch(roomId, table.getTableId()); + } catch (HeadlessException ex) { + handleError(ex); + } + }//GEN-LAST:event_btnQuickStartActionPerformed + + private void btnNewTableActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnNewTableActionPerformed + newTableDialog.showDialog(roomId); + }//GEN-LAST:event_btnNewTableActionPerformed + + private void jButtonFooterNextActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonFooterNextActionPerformed + synchronized (this) { + if (messages != null && !messages.isEmpty()) { + currentMessage++; + if (currentMessage >= messages.size()) { + currentMessage = 0; + } + + URLHandler.RemoveMouseAdapter(jLabelFooterText); + URLHandler.handleMessage(messages.get(currentMessage), this.jLabelFooterText); + } + } + }//GEN-LAST:event_jButtonFooterNextActionPerformed + + private void btnFilterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnFilterActionPerformed + setTableFilter(); + }//GEN-LAST:event_btnFilterActionPerformed + + private void btnStateFinishedActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnStateFinishedActionPerformed + if (this.btnStateFinished.isSelected()) { + this.jSplitPaneTables.setDividerLocation(-1); + } else { + this.jSplitPaneTables.setDividerLocation(this.jPanelTables.getHeight()); + } + this.startTasks(); + }//GEN-LAST:event_btnStateFinishedActionPerformed + + private void handleError(Exception ex) { + LOGGER.fatal("Error loading deck: ", ex); + JOptionPane.showMessageDialog(MageFrame.getDesktop(), "Error loading deck.", "Error", JOptionPane.ERROR_MESSAGE); + } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JToggleButton btnFormatBlock; + private javax.swing.JToggleButton btnFormatCommander; + private javax.swing.JToggleButton btnFormatLegacy; + private javax.swing.JToggleButton btnFormatLimited; + private javax.swing.JToggleButton btnFormatModern; + private javax.swing.JToggleButton btnFormatOther; + private javax.swing.JToggleButton btnFormatStandard; + private javax.swing.JToggleButton btnFormatTinyLeader; + private javax.swing.JToggleButton btnFormatVintage; + private javax.swing.JButton btnNewTable; + private javax.swing.JButton btnNewTournament; + private javax.swing.JToggleButton btnOpen; + private javax.swing.JToggleButton btnPassword; + private javax.swing.JButton btnQuickStart; + private javax.swing.JToggleButton btnSkillBeginner; + private javax.swing.JToggleButton btnSkillCasual; + private javax.swing.JToggleButton btnSkillSerious; + private javax.swing.JToggleButton btnRated; + private javax.swing.JToggleButton btnUnrated; + private javax.swing.JToggleButton btnStateActive; + private javax.swing.JToggleButton btnStateFinished; + private javax.swing.JToggleButton btnStateWaiting; + private javax.swing.JToggleButton btnTypeMatch; + private javax.swing.JToggleButton btnTypeTourneyConstructed; + private javax.swing.JToggleButton btnTypeTourneyLimited; + private mage.client.table.PlayersChatPanel chatPanelMain; + private javax.swing.JToolBar filterBar1; + private javax.swing.JToolBar filterBar2; + private javax.swing.JButton jButtonFooterNext; + private javax.swing.JLabel jLabelFooterLabel; + private javax.swing.JLabel jLabelFooterText; + private javax.swing.JPanel jPanelBottom; + private javax.swing.JPanel jPanelTables; + private javax.swing.JPanel jPanelTop; + private javax.swing.JScrollPane jScrollPaneTablesActive; + private javax.swing.JScrollPane jScrollPaneTablesFinished; + private javax.swing.JToolBar.Separator jSeparator1; + private javax.swing.JToolBar.Separator jSeparator2; + private javax.swing.JToolBar.Separator jSeparator3; + private javax.swing.JToolBar.Separator jSeparator4; + private javax.swing.JToolBar.Separator jSeparator5; + private javax.swing.JSplitPane jSplitPane1; + private javax.swing.JSplitPane jSplitPaneTables; + private javax.swing.JTable tableCompleted; + private javax.swing.JTable tableTables; + // End of variables declaration//GEN-END:variables + +} + +class UpdateTablesTask extends SwingWorker> { + + private final UUID roomId; + private final TablesPanel panel; + + private static final Logger logger = Logger.getLogger(UpdateTablesTask.class); + + private int count = 0; + + UpdateTablesTask(UUID roomId, TablesPanel panel) { + + this.roomId = roomId; + this.panel = panel; + } + + @Override + protected Void doInBackground() throws Exception { + while (!isCancelled()) { + Collection tables = SessionHandler.getTables(roomId); + if (tables != null) { + this.publish(tables); + } + TimeUnit.SECONDS.sleep(3); + } + return null; + } + + @Override + protected void process(java.util.List> view) { + panel.updateTables(view.get(0)); + count++; + if (count > 60) { + count = 0; + panel.reloadMessages(); + } + } + + @Override + protected void done() { + try { + get(); + } catch (InterruptedException | ExecutionException ex) { + logger.fatal("Update Tables Task error", ex); + } catch (CancellationException ex) { + } + } + +} + +class UpdatePlayersTask extends SwingWorker> { + + private final UUID roomId; + private final PlayersChatPanel chat; + + private static final Logger logger = Logger.getLogger(UpdatePlayersTask.class); + + UpdatePlayersTask(UUID roomId, PlayersChatPanel chat) { + + this.roomId = roomId; + this.chat = chat; + } + + @Override + protected Void doInBackground() throws Exception { + while (!isCancelled()) { + this.publish(SessionHandler.getRoomUsers(roomId)); + TimeUnit.SECONDS.sleep(3); + } + return null; + } + + @Override + protected void process(java.util.List> roomUserInfo) { + chat.setRoomUserInfo(roomUserInfo); + } + + @Override + protected void done() { + try { + get(); + } catch (InterruptedException | ExecutionException ex) { + logger.fatal("Update Players Task error", ex); + } catch (CancellationException ex) { + } + } + +} + +class UpdateMatchesTask extends SwingWorker> { + + private final UUID roomId; + private final TablesPanel panel; + + private static final Logger logger = Logger.getLogger(UpdateTablesTask.class); + + UpdateMatchesTask(UUID roomId, TablesPanel panel) { + this.roomId = roomId; + this.panel = panel; + } + + @Override + protected Void doInBackground() throws Exception { + while (!isCancelled()) { + Collection matches = SessionHandler.getFinishedMatches(roomId); + if (!matches.isEmpty()) { + this.publish(matches); + } + TimeUnit.SECONDS.sleep(10); + } + return null; + } + + @Override + protected void process(java.util.List> view) { + panel.updateMatches(view.get(0)); + } + + @Override + protected void done() { + try { + get(); + } catch (InterruptedException | ExecutionException ex) { + logger.fatal("Update Matches Task error", ex); + } catch (CancellationException ex) { + } + } + +} + +class GameChooser extends JPopupMenu { + + public void init() { + + } + + public void show(java.util.List games, Point p) { + if (p == null) { + return; + } + this.removeAll(); + for (UUID gameId : games) { + this.add(new GameChooserAction(gameId, gameId.toString())); + } + this.show(MageFrame.getDesktop(), p.x, p.y); + GuiDisplayUtil.keepComponentInsideScreen(p.x, p.y, this); + } + + private class GameChooserAction extends AbstractAction { + + private final UUID id; + + public GameChooserAction(UUID id, String choice) { + this.id = id; + putValue(Action.NAME, choice); + } + + @Override + public void actionPerformed(ActionEvent e) { + SessionHandler.replayGame(id); + setVisible(false); + } + + } + +} diff --git a/Mage.Client/src/main/java/mage/client/table/TablesTableModel.java b/Mage.Client/src/main/java/mage/client/table/TablesTableModel.java new file mode 100644 index 00000000000..ae431fb0879 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/table/TablesTableModel.java @@ -0,0 +1,206 @@ +package mage.client.table; + +import mage.client.SessionHandler; +import mage.constants.SkillLevel; +import mage.remote.MageRemoteException; +import mage.view.TableView; + +import javax.swing.*; +import javax.swing.table.AbstractTableModel; +import java.util.Collection; +import java.util.Date; + +public class TablesTableModel extends AbstractTableModel { + + final ImageIcon tourneyIcon = new ImageIcon(getClass().getResource("/tables/tourney_icon.png")); + final ImageIcon matchIcon = new ImageIcon(getClass().getResource("/tables/match_icon.png")); + + public static final int COLUMN_ICON = 0; + public static final int COLUMN_DECK_TYPE = 1; // column the deck type is located (starting with 0) Start string is used to check for Limited + public static final int COLUMN_OWNER = 2; + public static final int COLUMN_GAME_TYPE = 3; + public static final int COLUMN_INFO = 4; + public static final int COLUMN_STATUS = 5; + public static final int COLUMN_PASSWORD = 6; + public static final int COLUMN_CREATED = 7; + public static final int COLUMN_SKILL = 8; + public static final int COLUMN_RATING = 9; + public static final int COLUMN_QUIT_RATIO = 10; + public static final int COLUMN_MINIMUM_RATING = 11; + public static final int ACTION_COLUMN = 12; // column the action is located (starting with 0) + + public static final String RATED_VALUE_YES = "YES"; + public static final String RATED_VALUE_NO = ""; + + public static final String PASSWORD_VALUE_YES = "YES"; + + private final String[] columnNames = new String[]{"M/T", "Deck Type", "Owner / Players", "Game Type", "Info", "Status", "Password", "Created / Started", "Skill Level", "Rated", "Quit %", "Min Rating", "Action"}; + + private TableView[] tables = new TableView[0]; + + TablesTableModel() { + } + + public void loadData(Collection tables) throws MageRemoteException { + this.tables = tables.toArray(new TableView[0]); + this.fireTableDataChanged(); + } + + public String getTableAndGameInfo(int row) { + return this.tables[row].getTableId().toString() + ";" + (!tables[row].getGames().isEmpty() ? tables[row].getGames().get(0).toString() : "null"); + } + + public String findTableAndGameInfoByRow(int row) { + if (row >= 0 && row < this.tables.length) { + return getTableAndGameInfo(row); + } else { + return null; + } + } + + public int findRowByTableAndGameInfo(String tableAndGame) { + for (int i = 0; i < this.tables.length; i++) { + String rowID = this.tables[i].getTableId().toString() + ";" + (!this.tables[i].getGames().isEmpty() ? this.tables[i].getGames().get(0).toString() : "null"); + if (tableAndGame.equals(rowID)) { + return i; + } + } + return -1; + } + + public String getSkillLevelAsCode(SkillLevel skill, boolean asRegExp) { + String res; + switch (skill) { + case BEGINNER: + res = "*"; + break; + case CASUAL: + res = "**"; + break; + case SERIOUS: + res = "***"; + break; + default: + res = ""; + break; + } + + // regexp format for search table rows + if (asRegExp) { + res = String.format("^%s$", res.replace("*", "\\*")); + } + + return res; + } + + @Override + public int getRowCount() { + return tables.length; + } + + @Override + public int getColumnCount() { + return columnNames.length; + } + + @Override + public Object getValueAt(int arg0, int arg1) { + switch (arg1) { + case 0: + return tables[arg0].isTournament() ? tourneyIcon : matchIcon; + case 1: + return tables[arg0].getDeckType(); + case 2: + return tables[arg0].getControllerName(); + case 3: + return tables[arg0].getGameType(); + case 4: + return tables[arg0].getAdditionalInfo(); + case 5: + return tables[arg0].getTableStateText(); + case 6: + return tables[arg0].isPassworded() ? PASSWORD_VALUE_YES : ""; + case 7: + return tables[arg0].getCreateTime(); // use cell render, not format here + case 8: + return this.getSkillLevelAsCode(tables[arg0].getSkillLevel(), false); + case 9: + return tables[arg0].isRated() ? RATED_VALUE_YES : RATED_VALUE_NO; + case 10: + return tables[arg0].getQuitRatio(); + case 11: + return tables[arg0].getMinimumRating(); + case 12: + switch (tables[arg0].getTableState()) { + + case WAITING: + String owner = tables[arg0].getControllerName(); + if (SessionHandler.getSession() != null && owner.equals(SessionHandler.getUserName())) { + return ""; + } + return "Join"; + case CONSTRUCTING: + case DRAFTING: + if (tables[arg0].isTournament()) { + return "Show"; + } + case DUELING: + if (tables[arg0].isTournament()) { + return "Show"; + } else { + owner = tables[arg0].getControllerName(); + if (SessionHandler.getSession() != null && owner.equals(SessionHandler.getUserName())) { + return ""; + } + if (tables[arg0].getSpectatorsAllowed()) { + return "Watch"; + } + return ""; + } + default: + return ""; + } + case 13: + return tables[arg0].isTournament(); + case 14: + if (!tables[arg0].getGames().isEmpty()) { + return tables[arg0].getGames().get(0); + } + return null; + case 15: + return tables[arg0].getTableId(); + } + return ""; + } + + @Override + public String getColumnName(int columnIndex) { + String colName = ""; + + if (columnIndex <= getColumnCount()) { + colName = columnNames[columnIndex]; + } + + return colName; + } + + @Override + public Class getColumnClass(int columnIndex) { + switch (columnIndex) { + case COLUMN_ICON: + return Icon.class; + case COLUMN_SKILL: + return SkillLevel.class; + case COLUMN_CREATED: + return Date.class; + default: + return String.class; + } + } + + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + return columnIndex == ACTION_COLUMN; + } + +} diff --git a/Mage.Client/src/main/java/mage/client/table/TablesUtil.java b/Mage.Client/src/main/java/mage/client/table/TablesUtil.java new file mode 100644 index 00000000000..475be3d2f96 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/table/TablesUtil.java @@ -0,0 +1,40 @@ +package mage.client.table; + +import org.apache.log4j.Logger; + +import javax.swing.*; + +/** + * @author JayDi85 + */ +public class TablesUtil { + + private static final Logger logger = Logger.getLogger(TablesUtil.class); + + public static String getSearchIdFromTable(JTable table, int row) { + // tableUUID;gameUUID + String searchId = null; + if (table.getModel() instanceof TablesTableModel) { + searchId = ((TablesTableModel) table.getModel()).findTableAndGameInfoByRow(row); + } else if (table.getModel() instanceof MatchesTableModel) { + searchId = ((MatchesTableModel) table.getModel()).findTableAndGameInfoByRow(row); + } else { + logger.error("Not supported tables model " + table.getModel().getClass().toString()); + } + return searchId; + } + + public static int findTableRowFromSearchId(Object tableModel, String searchId) { + // tableUUID;gameUUID + int row = -1; + if (tableModel instanceof TablesTableModel) { + row = ((TablesTableModel) tableModel).findRowByTableAndGameInfo(searchId); + } else if (tableModel instanceof MatchesTableModel) { + row = ((MatchesTableModel) tableModel).findRowByTableAndGameInfo(searchId); + } else { + logger.error("Not supported tables model " + tableModel.getClass().toString()); + } + return row; + } + +} diff --git a/Mage.Client/src/main/java/mage/client/tournament/TournamentPanel.java b/Mage.Client/src/main/java/mage/client/tournament/TournamentPanel.java index 3965214f356..bdafa112a59 100644 --- a/Mage.Client/src/main/java/mage/client/tournament/TournamentPanel.java +++ b/Mage.Client/src/main/java/mage/client/tournament/TournamentPanel.java @@ -1,15 +1,21 @@ - - - /* - * TournamentPanel.java - * - * Created on 20-Jan-2011, 9:18:30 PM - */ package mage.client.tournament; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.Rectangle; +import mage.client.MageFrame; +import mage.client.SessionHandler; +import mage.client.chat.ChatPanelBasic; +import mage.client.dialog.PreferencesDialog; +import mage.client.table.TablesButtonColumn; +import mage.client.util.Format; +import mage.client.util.GUISizeHelper; +import mage.client.util.gui.TableUtil; +import mage.client.util.gui.countryBox.CountryCellRenderer; +import mage.constants.PlayerAction; +import mage.view.*; +import org.apache.log4j.Logger; + +import javax.swing.*; +import javax.swing.table.AbstractTableModel; +import java.awt.*; import java.awt.event.ActionEvent; import java.text.DateFormat; import java.util.ArrayList; @@ -19,34 +25,10 @@ import java.util.UUID; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; -import javax.swing.AbstractAction; -import javax.swing.Action; -import javax.swing.Icon; -import javax.swing.SwingWorker; -import javax.swing.table.AbstractTableModel; -import mage.client.MageFrame; -import mage.client.SessionHandler; -import mage.client.chat.ChatPanelBasic; -import mage.client.dialog.PreferencesDialog; -import static mage.client.dialog.PreferencesDialog.KEY_TOURNAMENT_MATCH_COLUMNS_ORDER; -import static mage.client.dialog.PreferencesDialog.KEY_TOURNAMENT_MATCH_COLUMNS_WIDTH; -import static mage.client.dialog.PreferencesDialog.KEY_TOURNAMENT_PLAYER_COLUMNS_ORDER; -import static mage.client.dialog.PreferencesDialog.KEY_TOURNAMENT_PLAYER_COLUMNS_WIDTH; -import mage.client.util.ButtonColumn; -import mage.client.util.Format; -import mage.client.util.GUISizeHelper; -import mage.client.util.gui.TableUtil; -import mage.client.util.gui.countryBox.CountryCellRenderer; -import mage.constants.PlayerAction; -import mage.view.RoundView; -import mage.view.TournamentGameView; -import mage.view.TournamentPlayerView; -import mage.view.TournamentView; -import mage.view.UserRequestMessage; -import org.apache.log4j.Logger; + +import static mage.client.dialog.PreferencesDialog.*; /** - * * @author BetaSteward_at_googlemail.com */ public class TournamentPanel extends javax.swing.JPanel { @@ -64,7 +46,7 @@ public class TournamentPanel extends javax.swing.JPanel { private UpdateTournamentTask updateTask; private final DateFormat df; - private final ButtonColumn actionButtonColumn1; + private final TablesButtonColumn actionButtonColumn1; /** * Creates new form TournamentPanel @@ -111,7 +93,7 @@ public class TournamentPanel extends javax.swing.JPanel { }; // action button, don't delete this - actionButtonColumn1 = new ButtonColumn(tableMatches, action, tableMatches.convertColumnIndexToView(TournamentMatchesTableModel.ACTION_COLUMN)); + actionButtonColumn1 = new TablesButtonColumn(tableMatches, action, tableMatches.convertColumnIndexToView(TournamentMatchesTableModel.ACTION_COLUMN)); setGUISize(); } @@ -390,67 +372,67 @@ public class TournamentPanel extends javax.swing.JPanel { javax.swing.GroupLayout actionPanelLayout = new javax.swing.GroupLayout(actionPanel); actionPanel.setLayout(actionPanelLayout); actionPanelLayout.setHorizontalGroup( - actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(actionPanelLayout.createSequentialGroup() - .addContainerGap() - .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(lblName) - .addComponent(lblState) - .addComponent(txtName, javax.swing.GroupLayout.DEFAULT_SIZE, 260, Short.MAX_VALUE) - .addComponent(txtTournamentState)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(lblType) - .addComponent(txtType, javax.swing.GroupLayout.PREFERRED_SIZE, 440, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGroup(actionPanelLayout.createSequentialGroup() - .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(txtStartTime, javax.swing.GroupLayout.PREFERRED_SIZE, 220, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblStartTime)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lblEndTime) - .addComponent(txtEndTime)))) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 126, Short.MAX_VALUE) - .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(btnQuitTournament, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(btnCloseWindow, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap()) + actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(actionPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(lblName) + .addComponent(lblState) + .addComponent(txtName, javax.swing.GroupLayout.DEFAULT_SIZE, 260, Short.MAX_VALUE) + .addComponent(txtTournamentState)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(lblType) + .addComponent(txtType, javax.swing.GroupLayout.PREFERRED_SIZE, 440, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(actionPanelLayout.createSequentialGroup() + .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(txtStartTime, javax.swing.GroupLayout.PREFERRED_SIZE, 220, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblStartTime)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lblEndTime) + .addComponent(txtEndTime)))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 126, Short.MAX_VALUE) + .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(btnQuitTournament, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(btnCloseWindow, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) ); actionPanelLayout.setVerticalGroup( - actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(actionPanelLayout.createSequentialGroup() - .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(actionPanelLayout.createSequentialGroup() - .addGap(7, 7, 7) - .addComponent(lblName)) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, actionPanelLayout.createSequentialGroup() - .addContainerGap() - .addComponent(lblType))) - .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(actionPanelLayout.createSequentialGroup() - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(txtType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(btnQuitTournament)) - .addGap(13, 13, 13) - .addComponent(btnCloseWindow)) - .addGroup(actionPanelLayout.createSequentialGroup() - .addGap(6, 6, 6) - .addComponent(txtName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lblState) - .addComponent(lblStartTime) - .addComponent(lblEndTime)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(actionPanelLayout.createSequentialGroup() - .addComponent(txtTournamentState, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, Short.MAX_VALUE)) - .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(txtStartTime) - .addComponent(txtEndTime, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))))) - .addContainerGap()) + actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(actionPanelLayout.createSequentialGroup() + .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(actionPanelLayout.createSequentialGroup() + .addGap(7, 7, 7) + .addComponent(lblName)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, actionPanelLayout.createSequentialGroup() + .addContainerGap() + .addComponent(lblType))) + .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(actionPanelLayout.createSequentialGroup() + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(txtType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(btnQuitTournament)) + .addGap(13, 13, 13) + .addComponent(btnCloseWindow)) + .addGroup(actionPanelLayout.createSequentialGroup() + .addGap(6, 6, 6) + .addComponent(txtName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblState) + .addComponent(lblStartTime) + .addComponent(lblEndTime)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(actionPanelLayout.createSequentialGroup() + .addComponent(txtTournamentState, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, Short.MAX_VALUE)) + .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(txtStartTime) + .addComponent(txtEndTime, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))))) + .addContainerGap()) ); jSplitPane2.setResizeWeight(1.0); @@ -481,17 +463,17 @@ public class TournamentPanel extends javax.swing.JPanel { javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(actionPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jSplitPane2, javax.swing.GroupLayout.Alignment.TRAILING) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(actionPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jSplitPane2, javax.swing.GroupLayout.Alignment.TRAILING) ); layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(actionPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jSplitPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 454, Short.MAX_VALUE) - .addContainerGap()) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(actionPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jSplitPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 454, Short.MAX_VALUE) + .addContainerGap()) ); }// //GEN-END:initComponents diff --git a/Mage.Client/src/main/java/mage/client/util/CardLanguage.java b/Mage.Client/src/main/java/mage/client/util/CardLanguage.java new file mode 100644 index 00000000000..2be99682c20 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/util/CardLanguage.java @@ -0,0 +1,68 @@ +package mage.client.util; + +import java.util.ArrayList; + +/** + * @author JayDi85 + */ +public enum CardLanguage { + + ENGLISH("en", "English"), + SPANISH("es", "Spanish"), + FRENCH("fr", "French"), + GERMAN("de", "German"), + ITALIAN("it", "Italian"), + PORTUGUESE("pt", "Portuguese"), + JAPANESE("jp", "Japanese"), + KOREAN("ko", "Korean"), + RUSSIAN("ru", "Russian"), + CHINES_SIMPLE("cns", "Chinese Simplified"), + CHINES_TRADITION("cnt", "Chinese Traditional"); + + private final String code; + private final String text; + + CardLanguage(String code, String text) { + this.code = code; + this.text = text; + } + + @Override + public String toString() { + return code; + } + + public String getCode() { + return code; + } + + public String getText() { + return text; + } + + public static String[] toList() { + ArrayList res = new ArrayList<>(); + for (CardLanguage l : values()) { + res.add(l.toString()); + } + return res.toArray(new String[0]); + } + + public static CardLanguage valueByText(String text) { + for (CardLanguage type : values()) { + if (type.text.equals(text)) { + return type; + } + } + return CardLanguage.ENGLISH; + } + + public static CardLanguage valueByCode(String code) { + for (CardLanguage type : values()) { + if (type.code.equals(code)) { + return type; + } + } + return CardLanguage.ENGLISH; + } +} diff --git a/Mage.Client/src/main/java/mage/client/util/audio/AudioManager.java b/Mage.Client/src/main/java/mage/client/util/audio/AudioManager.java index da018d0d8f0..5e310ddbf14 100644 --- a/Mage.Client/src/main/java/mage/client/util/audio/AudioManager.java +++ b/Mage.Client/src/main/java/mage/client/util/audio/AudioManager.java @@ -57,7 +57,7 @@ public class AudioManager { try { linePool = new LinePool(); } catch (Exception e) { - log.warn("Failed to initialize AudioManager. No sounds will be played.", e); + log.warn("Failed to initialize AudioManager (can't find compatible sound device). No sounds will be played."); } } diff --git a/Mage.Client/src/main/java/mage/client/util/gui/FastSearchUtil.java b/Mage.Client/src/main/java/mage/client/util/gui/FastSearchUtil.java index f1a22f6f3fa..fe22935c6e8 100644 --- a/Mage.Client/src/main/java/mage/client/util/gui/FastSearchUtil.java +++ b/Mage.Client/src/main/java/mage/client/util/gui/FastSearchUtil.java @@ -19,12 +19,16 @@ public class FastSearchUtil { public static String DEFAULT_EXPANSION_SEARCH_MESSAGE = "Select set or expansion"; public static String DEFAULT_EXPANSION_TOOLTIP_MESSAGE = "Fast search set or expansion"; + public static void showFastSearchForStringComboBox(JComboBox combo, String chooseMessage){ + showFastSearchForStringComboBox(combo, chooseMessage, 300, 500); + } + /** * Show fast choice modal dialog with incremental searching for any string combobox components * @param combo combobox control with default data model * @param chooseMessage caption message for dialog */ - public static void showFastSearchForStringComboBox(JComboBox combo, String chooseMessage){ + public static void showFastSearchForStringComboBox(JComboBox combo, String chooseMessage, int windowWidth, int windowHeight){ // fast search/choice dialog for string combobox mage.choices.Choice choice = new ChoiceImpl(false); @@ -51,7 +55,7 @@ public class FastSearchUtil { // ask for new value PickChoiceDialog dlg = new PickChoiceDialog(); - dlg.setWindowSize(300, 500); + dlg.setWindowSize(windowWidth, windowHeight); dlg.showDialog(choice, needSelectValue); if(choice.isChosen()){ item = choice.getChoiceKey(); diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/CardImageSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/CardImageSource.java index f2d0fabf753..8fb85388bf5 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/CardImageSource.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/CardImageSource.java @@ -1,10 +1,11 @@ package org.mage.plugins.card.dl.sources; -import java.util.ArrayList; +import mage.client.util.CardLanguage; import org.mage.plugins.card.images.CardDownloadData; +import java.util.ArrayList; + /** - * * @author North */ public interface CardImageSource { @@ -31,10 +32,21 @@ public interface CardImageSource { return false; } + default boolean isLanguagesSupport() { + return false; + } + + default void setCurrentLanguage(CardLanguage cardLanguage) { + } + + default CardLanguage getCurrentLanguage() { + return CardLanguage.ENGLISH; + } + void doPause(String httpImageUrl); default ArrayList getSupportedSets() { - return null; + return new ArrayList<>(); } default boolean isSetSupportedComplete(String setCode) { diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MagicCardsImageSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MagicCardsImageSource.java deleted file mode 100644 index dfee0c9a469..00000000000 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MagicCardsImageSource.java +++ /dev/null @@ -1,439 +0,0 @@ -package org.mage.plugins.card.dl.sources; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.Locale; -import java.util.Map; -import java.util.Set; - -import mage.client.dialog.PreferencesDialog; -import org.mage.plugins.card.images.CardDownloadData; -import org.mage.plugins.card.utils.CardImageUtils; - -/** - * @author North - */ -public enum MagicCardsImageSource implements CardImageSource { - - instance; - - private static final Set supportedSets = new LinkedHashSet() { - { - // add("PTC"); // Prerelease Events - add("LEA"); - add("LEB"); - add("2ED"); - add("ARN"); - add("ATQ"); - add("3ED"); - add("LEG"); - add("DRK"); - add("FEM"); - add("4ED"); - add("ICE"); - add("CHR"); - add("HML"); - add("ALL"); - add("MIR"); - add("VIS"); - add("5ED"); - add("POR"); - add("WTH"); - add("TMP"); - add("STH"); - add("EXO"); - add("P02"); - add("UGL"); - add("USG"); - add("DD3DVD"); - add("DD3EVG"); - add("DD3GVL"); - add("DD3JVC"); - - add("ULG"); - add("6ED"); - add("UDS"); - add("PTK"); - add("S99"); - add("MMQ"); - // add("BRB");Battle Royale Box Set - add("NEM"); - add("S00"); - add("PCY"); - add("INV"); - // add("BTD"); // Beatdown Boxset - add("PLS"); - add("7ED"); - add("APC"); - add("ODY"); - // add("DKM"); // Deckmasters 2001 - add("TOR"); - add("JUD"); - add("ONS"); - add("LGN"); - add("SCG"); - add("8ED"); - add("MRD"); - add("DST"); - add("5DN"); - add("CHK"); - add("UNH"); - add("BOK"); - add("SOK"); - add("9ED"); - add("RAV"); - add("GPT"); - add("DIS"); - add("CSP"); - add("TSP"); - add("TSB"); - add("PLC"); - add("FUT"); - add("10E"); - add("MED"); - add("LRW"); - add("EVG"); - add("MOR"); - add("SHM"); - add("EVE"); - add("DRB"); - add("ME2"); - add("ALA"); - add("DD2"); - add("CON"); - add("DDC"); - add("ARB"); - add("M10"); - // add("TD0"); // Magic Online Deck Series - add("V09"); - add("HOP"); - add("ME3"); - add("ZEN"); - add("DDD"); - add("H09"); - add("WWK"); - add("DDE"); - add("ROE"); - add("DPA"); - add("ARC"); - add("M11"); - add("V10"); - add("DDF"); - add("SOM"); - // add("TD0"); // Commander Theme Decks - add("PD2"); - add("ME4"); - add("MBS"); - add("DDG"); - add("NPH"); - add("CMD"); - add("M12"); - add("V11"); - add("DDH"); - add("ISD"); - add("PD3"); - add("DKA"); - add("DDI"); - add("AVR"); - add("PC2"); - add("M13"); - add("V12"); - add("DDJ"); - add("RTR"); - add("CM1"); - // add("TD2"); // Duel Decks: Mirrodin Pure vs. New Phyrexia - add("GTC"); - add("DDK"); - add("DGM"); - add("MMA"); - add("M14"); - add("V13"); - add("DDL"); - add("THS"); - add("C13"); - add("BNG"); - add("DDM"); - add("JOU"); - // add("MD1"); // Modern Event Deck - add("CNS"); - add("VMA"); - add("M15"); - add("V14"); - add("DDN"); - add("KTK"); - add("C14"); - // add("DD3"); // Duel Decks Anthology - add("FRF"); - add("DDO"); - add("DTK"); - add("TPR"); - add("MM2"); - add("ORI"); - add("V15"); - add("DDP"); - add("BFZ"); - add("EXP"); - add("C15"); - // add("PZ1"); // Legendary Cube - add("OGW"); - add("DDQ"); - add("W16"); - add("SOI"); - add("EMA"); - add("EMN"); - add("V16"); - add("CN2"); - add("DDR"); - add("KLD"); - add("MPS"); - // add("PZ2"); // Treasure Chests - add("C16"); - add("PCA"); - add("AER"); - add("MM3"); - add("DDS"); - add("W17"); - add("AKH"); - add("MPS"); - add("CMA"); - add("E01"); - add("HOU"); - add("C17"); - add("XLN"); - add("DDT"); - add("DDU"); - add("IMA"); - add("E02"); - add("V17"); - add("UST"); - add("RIX"); - add("A25"); - add("DOM"); -// add("CM2"); -// add("M19"); - } - }; - - private static final Map setNameTokenReplacement = new HashMap() { - { - put("10E", "tenth-edition"); - put("AER", "aether-revolt"); - put("AKH", "amonkhet"); - put("ALA", "shards-of-alara"); - put("ANB", "archenemy-nicol-bolas"); - put("APAC", "asia-pacific-land-program"); - put("APC", "player-rewards-2001"); - put("ARB", "alara-reborn"); - put("ARC", "archenemy"); - put("ARENA", "arena-league"); - put("AVR", "avacyn-restored"); - put("BFZ", "battle-for-zendikar"); - put("BNG", "born-of-the-gods"); - put("C13", "commander-2013-edition"); - put("C14", "commander-2014"); - put("C15", "commander-2015"); - put("C16", "commander-2016"); - put("CLASH", "clash-pack"); - put("CMA", "commander-anthology"); - put("CMA", "commanders-arsenal"); - put("CMD", "commander"); - put("CN2", "conspiracy-take-the-crown"); - put("CNS", "conspiracy"); - put("CON", "conflux"); - put("CP", "champs"); - put("CSP", "coldsnap"); - put("DD2", "duel-decks-jace-vs-chandra"); - put("DD3DVD", "duel-decks-anthology-divine-vs-demonic"); - put("DD3EVG", "duel-decks-anthology-elves-vs-goblins"); - put("DD3GVL", "duel-decks-anthology-garruk-vs-liliana"); - put("DD3JVC", "duel-decks-anthology-jace-vs-chandra"); - put("DDC", "duel-decks-divine-vs-demonic"); - put("DDD", "duel-decks-garruk-vs-liliana"); - put("DDE", "duel-decks-phyrexia-vs-the-coalition"); - put("DDF", "duel-decks-elspeth-vs-tezzeret"); - put("DDG", "duel-decks-knights-vs-dragons"); - put("DDH", "duel-decks-ajani-vs-nicol-bolas"); - put("DDI", "duel-decks-venser-vs-koth"); - put("DDJ", "duel-decks-izzet-vs-golgari"); - put("DDK", "duel-decks-sorin-vs-tibalt"); - put("DDL", "duel-decks-heroes-vs-monsters"); - put("DDM", "duel-decks-jace-vs-vraska"); - put("DDN", "duel-decks-speed-vs-cunning"); - put("DDO", "duel-decks-elspeth-vs-kiora"); - put("DDP", "duel-decks-zendikar-vs-eldrazi"); - put("DDQ", "duel-decks-blessed-vs-cursed"); - put("DDR", "duel-decks-nissa-vs-ob-nixilis"); - put("DDS", "duel-decks-mind-vs-might"); - put("DDT", "duel-decks-merfolk-vs-goblin"); - put("DDU", "duel-decks-elves-vs-inventors"); - put("DGM", "dragons-maze"); - put("DKA", "dark-ascension"); - put("DRB", "from-the-vault-dragons"); - put("DTK", "dragons-of-tarkir"); - put("EMA", "eternal-masters"); - put("EMN", "eldritch-moon"); - put("EURO", "european-land-program"); - put("EVE", "eventide"); - put("EVG", "duel-decks-elves-vs-goblins"); - put("EXP", "zendikar-expeditions"); - put("FNMP", "friday-night-magic"); - put("FRF", "fate-reforged"); - put("GPX", "grand-prix"); - put("GRC", "wpngateway"); - put("GTC", "gatecrash"); - put("HOP", "planechase"); - put("HOU", "hour-of-devastation"); - put("INV", "player-rewards-2001"); - put("ISD", "innistrad"); - put("JOU", "journey-into-nyx"); - put("JR", "judge-gift-program"); - put("KLD", "kaladesh"); - put("KTK", "khans-of-tarkir"); - put("LRW", "lorwyn"); - put("M10", "magic-2010"); - put("M11", "magic-2011"); - put("M12", "magic-2012"); - put("M13", "magic-2013"); - put("M14", "magic-2014"); - put("M15", "magic-2015"); - put("MBP", "media-inserts"); - put("MBS", "mirrodin-besieged"); - put("MGDC", "magic-game-day-cards"); - put("MLP", "launch-party"); - put("MM2", "modern-masters-2015"); - put("MM3", "modern-masters-2017"); - put("MMA", "modern-masters"); - put("MOR", "morningtide"); - put("MPRP", "magic-player-rewards"); - put("MPS", "masterpiece-series"); - put("NPH", "new-phyrexia"); - put("ODY", "player-rewards-2002"); - put("OGW", "oath-of-the-gatewatch"); - put("ORG", "oath-of-the-gatewatch"); - put("ORI", "magic-origins"); - put("PC2", "planechase-2012-edition"); - put("PO2", "portal-second-age"); - put("PLS", "player-rewards-2001"); - put("POR", "portal"); - put("PTC", "prerelease-events"); - put("PTK", "portal-three-kingdoms"); - put("ROE", "rise-of-the-eldrazi"); - put("RTR", "return-to-ravnica"); - put("SHM", "shadowmoor"); - put("SOI", "shadows-over-innistrad"); - put("SOM", "scars-of-mirrodin"); - put("SUS", "super-series"); - put("THS", "theros"); - put("TPR", "tempest-remastered"); - put("UGIN", "ugins-fate"); - put("V09", "from-the-vault-exiled"); - put("V10", "from-the-vault-relics"); - put("V11", "from-the-vault-legends"); - put("V12", "from-the-vault-realms"); - put("V13", "from-the-vault-twenty"); - put("V14", "from-the-vault-annihilation"); - put("V15", "from-the-vault-angels"); - put("V16", "from-the-vault-lore"); - put("VMA", "vintage-masters"); - put("W16", "welcome-deck-2016"); - put("W17", "welcome-deck-2017"); - put("WMCQ", "world-magic-cup-qualifier"); - put("WWK", "worldwake"); - put("ZEN", "zendikar"); - } - - private static final long serialVersionUID = 1L; - }; - - @Override - public String getSourceName() { - return "magiccards.info"; - } - - @Override - public String getNextHttpImageUrl() { - return null; - } - - @Override - public String getFileForHttpImage(String httpImageUrl) { - return null; - } - - @Override - public CardImageUrls generateURL(CardDownloadData card) throws Exception { - String collectorId = card.getCollectorId(); - String cardSet = card.getSet(); - if (collectorId == null || cardSet == null) { - throw new Exception("Wrong parameters for image: collector id: " + collectorId + ",card set: " + cardSet); - } - String set = CardImageUtils.updateSet(cardSet, true); - - String preferedLanguage = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_PREF_LANGUAGE, "en"); - - StringBuilder url = new StringBuilder("http://magiccards.info/scans/").append(preferedLanguage).append('/'); - url.append(set.toLowerCase(Locale.ENGLISH)).append('/').append(collectorId); - - if (card.isTwoFacedCard()) { - url.append(card.isSecondSide() ? "b" : "a"); - } - if (card.isSplitCard()) { - url.append('a'); - } - if (card.isFlipCard()) { - if (card.isFlippedSide()) { // download rotated by 180 degree image - url.append('b'); - } else { - url.append('a'); - } - } - url.append(".jpg"); - - return new CardImageUrls(url.toString()); - } - - @Override - public CardImageUrls generateTokenUrl(CardDownloadData card) { - String name = card.getName(); - // add type to name if it's not 0 - if (card.getType() > 0) { - name = name + ' ' + card.getType(); - } - name = name.replaceAll(" ", "-").replace(",", "").toLowerCase(Locale.ENGLISH); - String set = "not-supported-set"; - if (setNameTokenReplacement.containsKey(card.getSet())) { - set = setNameTokenReplacement.get(card.getSet()); - } else { - set += '-' + card.getSet(); - } - return new CardImageUrls("http://magiccards.info/extras/token/" + set + '/' + name + ".jpg"); - } - - @Override - public float getAverageSize() { - return 70.0f; - } - - @Override - public int getTotalImages() { - return -1; - } - - @Override - public boolean isTokenSource() { - return true; - } - - @Override - public ArrayList getSupportedSets() { - ArrayList supportedSetsCopy = new ArrayList<>(); - supportedSetsCopy.addAll(supportedSets); - return supportedSetsCopy; - } - - @Override - public void doPause(String httpImageUrl) { - } - -} diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSource.java index fa6dc551c34..f176324825b 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSource.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSource.java @@ -1,6 +1,6 @@ package org.mage.plugins.card.dl.sources; -import mage.client.dialog.PreferencesDialog; +import mage.client.util.CardLanguage; import org.mage.plugins.card.images.CardDownloadData; import java.util.*; @@ -13,21 +13,23 @@ public enum ScryfallImageSource implements CardImageSource { instance; private final Set supportedSets; - private final Map languageAliases; + private final Map languageAliases; + private CardLanguage currentLanguage = CardLanguage.ENGLISH; // working language ScryfallImageSource() { // https://scryfall.com/docs/api/languages languageAliases = new HashMap<>(); - languageAliases.put("en", "en"); - languageAliases.put("es", "es"); - languageAliases.put("jp", "ja"); - languageAliases.put("it", "it"); - languageAliases.put("fr", "fr"); - languageAliases.put("cn", "zhs"); // Simplified Chinese - languageAliases.put("de", "de"); - languageAliases.put("ko", "ko"); - languageAliases.put("pt", "pt"); - languageAliases.put("ru", "ru"); + languageAliases.put(CardLanguage.ENGLISH, "en"); + languageAliases.put(CardLanguage.SPANISH, "es"); + languageAliases.put(CardLanguage.FRENCH, "fr"); + languageAliases.put(CardLanguage.GERMAN, "de"); + languageAliases.put(CardLanguage.ITALIAN, "it"); + languageAliases.put(CardLanguage.PORTUGUESE, "pt"); + languageAliases.put(CardLanguage.JAPANESE, "ja"); + languageAliases.put(CardLanguage.KOREAN, "ko"); + languageAliases.put(CardLanguage.RUSSIAN, "ru"); + languageAliases.put(CardLanguage.CHINES_SIMPLE, "zhs"); + languageAliases.put(CardLanguage.CHINES_TRADITION, "zht"); supportedSets = new LinkedHashSet<>(); // supportedSets.add("PTC"); // @@ -234,6 +236,7 @@ public enum ScryfallImageSource implements CardImageSource { supportedSets.add("GNT"); supportedSets.add("UMA"); supportedSets.add("PUMA"); + supportedSets.add("RNA"); // supportedSets.add("EURO"); supportedSets.add("GPX"); @@ -245,9 +248,9 @@ public enum ScryfallImageSource implements CardImageSource { @Override public CardImageUrls generateURL(CardDownloadData card) throws Exception { - String preferredLanguage = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_PREF_LANGUAGE, "en"); - String defaultCode = "en"; - String localizedCode = languageAliases.getOrDefault(preferredLanguage, defaultCode); + String preferredCode = this.getCurrentLanguage().getCode(); + String defaultCode = CardLanguage.ENGLISH.getCode(); + String localizedCode = languageAliases.getOrDefault(this.getCurrentLanguage(), defaultCode); // loc example: https://api.scryfall.com/cards/xln/121/ru?format=image // WARNING, some cards haven't direct images and uses random GUID: @@ -345,6 +348,21 @@ public enum ScryfallImageSource implements CardImageSource { return false; } + @Override + public boolean isLanguagesSupport() { + return true; + } + + @Override + public void setCurrentLanguage(CardLanguage cardLanguage) { + this.currentLanguage = cardLanguage; + } + + @Override + public CardLanguage getCurrentLanguage() { + return currentLanguage; + } + @Override public void doPause(String httpImageUrl) { @@ -368,6 +386,7 @@ public enum ScryfallImageSource implements CardImageSource { put("WMCQ", "pwcq"); put("EURO", "pelp"); put("GPX", "pgpx"); + put("MED", "me1"); } }; diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/TokensMtgImageSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/TokensMtgImageSource.java index da76bfc8b6f..ae000f70da5 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/TokensMtgImageSource.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/TokensMtgImageSource.java @@ -20,7 +20,7 @@ import java.util.logging.Level; import mage.constants.SubType; import org.apache.log4j.Logger; import org.mage.plugins.card.images.CardDownloadData; -import org.mage.plugins.card.images.DownloadPictures; +import org.mage.plugins.card.images.DownloadPicturesService; import org.mage.plugins.card.utils.CardImageUtils; /** @@ -182,7 +182,7 @@ public enum TokensMtgImageSource implements CardImageSource { private HashMap> getTokensData() throws IOException { synchronized (tokensDataSync) { if (tokensData == null) { - DownloadPictures.getInstance().updateAndViewMessage("Creating token data..."); + DownloadPicturesService.getInstance().updateAndViewMessage("Find tokens data..."); tokensData = new HashMap<>(); // get tokens data from resource file @@ -233,10 +233,10 @@ public enum TokensMtgImageSource implements CardImageSource { } } } - DownloadPictures.getInstance().updateAndViewMessage(""); + DownloadPicturesService.getInstance().updateAndViewMessage(""); } catch (Exception ex) { logger.warn("Failed to get tokens description from tokens.mtg.onl", ex); - DownloadPictures.getInstance().updateAndViewMessage(ex.getMessage()); + DownloadPicturesService.getInstance().updateAndViewMessage(ex.getMessage()); } } } diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/WizardCardsImageSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/WizardCardsImageSource.java index 5d39a943f6f..d0555b82424 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/WizardCardsImageSource.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/WizardCardsImageSource.java @@ -1,22 +1,10 @@ package org.mage.plugins.card.dl.sources; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; import mage.cards.Sets; import mage.cards.repository.CardCriteria; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; -import mage.client.dialog.PreferencesDialog; +import mage.client.util.CardLanguage; import org.apache.log4j.Logger; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; @@ -24,6 +12,12 @@ import org.jsoup.select.Elements; import org.mage.plugins.card.images.CardDownloadData; import org.mage.plugins.card.utils.CardImageUtils; +import java.io.IOException; +import java.util.*; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + /** * @author North */ @@ -34,9 +28,10 @@ public enum WizardCardsImageSource implements CardImageSource { private static final Logger logger = Logger.getLogger(WizardCardsImageSource.class); private final Map setsAliases; - private final Map languageAliases; + private final Map languageAliases; private final Map> sets; private final Set supportedSets; + private CardLanguage currentLanguage = CardLanguage.ENGLISH; // working language @Override public String getSourceName() { @@ -44,6 +39,20 @@ public enum WizardCardsImageSource implements CardImageSource { } WizardCardsImageSource() { + + languageAliases = new HashMap<>(); + languageAliases.put(CardLanguage.ENGLISH, "English"); + languageAliases.put(CardLanguage.SPANISH, "Spanish"); + languageAliases.put(CardLanguage.FRENCH, "French"); + languageAliases.put(CardLanguage.GERMAN, "German"); + languageAliases.put(CardLanguage.ITALIAN, "Italian"); + languageAliases.put(CardLanguage.PORTUGUESE, "Portuguese (Brazil)"); + languageAliases.put(CardLanguage.JAPANESE, "Japanese"); + languageAliases.put(CardLanguage.KOREAN, "Korean"); + languageAliases.put(CardLanguage.RUSSIAN, "Russian"); + languageAliases.put(CardLanguage.CHINES_SIMPLE, "Chinese Simplified"); + languageAliases.put(CardLanguage.CHINES_TRADITION, "Chinese Traditional "); + supportedSets = new LinkedHashSet<>(); // supportedSets.add("PTC"); // Prerelease Events supportedSets.add("LEA"); @@ -430,18 +439,6 @@ public enum WizardCardsImageSource implements CardImageSource { setsAliases.put("WTH", "Weatherlight"); setsAliases.put("WWK", "Worldwake"); setsAliases.put("ZEN", "Zendikar"); - - languageAliases = new HashMap<>(); - languageAliases.put("en", "English"); - languageAliases.put("es", "Spanish"); - languageAliases.put("jp", "Japanese"); - languageAliases.put("it", "Italian"); - languageAliases.put("fr", "French"); - languageAliases.put("cn", "Chinese Simplified"); - languageAliases.put("de", "German"); - languageAliases.put("ko", "Korean"); - languageAliases.put("pt", "Portuguese (Brazil)"); - languageAliases.put("ru", "Russian"); } @Override @@ -517,7 +514,7 @@ public enum WizardCardsImageSource implements CardImageSource { if (setNames == null) { setNames = Sets.getInstance().get(cardSet).getName(); } - String preferredLanguage = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_PREF_LANGUAGE, "en"); + for (String setName : setNames.split("\\^")) { // String URLSetName = URLEncoder.encode(setName, "UTF-8"); String URLSetName = setName.replaceAll(" ", "%20"); @@ -555,7 +552,7 @@ public enum WizardCardsImageSource implements CardImageSource { cardName = cardName.substring(0, pos1); } } - Integer preferredMultiverseId = getLocalizedMultiverseId(preferredLanguage, multiverseId); + Integer preferredMultiverseId = getLocalizedMultiverseId(getCurrentLanguage(), multiverseId); setLinks.put(cardName.toLowerCase(Locale.ENGLISH) + numberChar, generateLink(preferredMultiverseId)); } } @@ -617,8 +614,8 @@ public enum WizardCardsImageSource implements CardImageSource { return "/Handlers/Image.ashx?multiverseid=" + landMultiverseId + "&type=card"; } - private int getLocalizedMultiverseId(String preferredLanguage, Integer multiverseId) throws IOException { - if (preferredLanguage.equals("en")) { + private int getLocalizedMultiverseId(CardLanguage preferredLanguage, Integer multiverseId) throws IOException { + if (preferredLanguage.equals(CardLanguage.ENGLISH)) { return multiverseId; } @@ -682,43 +679,6 @@ public enum WizardCardsImageSource implements CardImageSource { return 60.0f; } - // private final class GetImageLinkTask implements Runnable { -// -// private int multiverseId; -// private String cardName; -// private String preferredLanguage; -// private LinkedHashMap setLinks; -// -// public GetImageLinkTask(int multiverseId, String cardName, String preferredLanguage, LinkedHashMap setLinks) { -// try { -// this.multiverseId = multiverseId; -// this.cardName = cardName; -// this.preferredLanguage = preferredLanguage; -// this.setLinks = setLinks; -// } catch (Exception ex) { -// logger.error(ex.getMessage()); -// logger.error("multiverseId: " + multiverseId); -// logger.error("cardName: " + cardName); -// logger.error("preferredLanguage: " + preferredLanguage); -// logger.error("setLinks: " + setLinks.toString()); -// } -// } -// -// @Override -// public void run() { -// try { -// if (cardName.equals("Forest") || cardName.equals("Swamp") || cardName.equals("Mountain") || cardName.equals("Island") || cardName.equals("Plains")) { -// setLinks.putAll(getLandVariations(multiverseId, cardName)); -// } else { -// Integer preferredMultiverseId = getLocalizedMultiverseId(preferredLanguage, multiverseId); -// setLinks.put(cardName.toLowerCase(Locale.ENGLISH), generateLink(preferredMultiverseId)); -// } -// } catch (IOException | NumberFormatException ex) { -// logger.error("Exception when parsing the wizards page: " + ex.getMessage()); -// } -// } -// -// } @Override public int getTotalImages() { return -1; @@ -729,6 +689,21 @@ public enum WizardCardsImageSource implements CardImageSource { return false; } + @Override + public boolean isLanguagesSupport() { + return true; + } + + @Override + public void setCurrentLanguage(CardLanguage cardLanguage) { + this.currentLanguage = cardLanguage; + } + + @Override + public CardLanguage getCurrentLanguage() { + return currentLanguage; + } + @Override public void doPause(String httpImageUrl) { } diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java b/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPicturesService.java similarity index 62% rename from Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java rename to Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPicturesService.java index 7be47db2d1f..10a78aef31e 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPicturesService.java @@ -1,28 +1,14 @@ package org.mage.plugins.card.images; -import java.awt.*; -import java.awt.event.ItemEvent; -import java.io.*; -import java.net.*; -import java.nio.file.AccessDeniedException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Set; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import javax.swing.*; - import mage.cards.ExpansionSet; import mage.cards.Sets; import mage.cards.repository.CardCriteria; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; import mage.client.MageFrame; +import mage.client.dialog.DownloadImagesDialog; import mage.client.dialog.PreferencesDialog; +import mage.client.util.CardLanguage; import mage.client.util.sets.ConstructedFormats; import mage.remote.Connection; import mage.util.StreamUtils; @@ -35,46 +21,49 @@ import org.mage.plugins.card.dl.sources.*; import org.mage.plugins.card.properties.SettingsManager; import org.mage.plugins.card.utils.CardImageUtils; +import javax.swing.*; +import java.awt.*; +import java.awt.event.ItemEvent; +import java.io.*; +import java.net.*; +import java.nio.file.AccessDeniedException; +import java.util.List; +import java.util.*; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + import static org.mage.plugins.card.utils.CardImageUtils.getImagesDir; -public class DownloadPictures extends DefaultBoundedRangeModel implements Runnable { +/** + * @author JayDi85 + */ +public class DownloadPicturesService extends DefaultBoundedRangeModel implements Runnable { - // don't forget to remove new sets from ignore.urls to download (propeties file in resources) - private static DownloadPictures instance; + // don't forget to remove new sets from ignore.urls to download (properties file in resources) + private static DownloadPicturesService instance; + private static final Logger logger = Logger.getLogger(DownloadPicturesService.class); - private static final Logger logger = Logger.getLogger(DownloadPictures.class); + public static final String ALL_IMAGES = "- ALL images from selected source (can be slow)"; + public static final String ALL_MODERN_IMAGES = "- MODERN images (can be slow)"; + public static final String ALL_STANDARD_IMAGES = "- STANDARD images"; + public static final String ALL_TOKENS = "- TOKEN images"; - public static final String ALL_IMAGES = "- ALL images from selected source (CAN BE VERY SLOW)"; - public static final String ALL_STANDARD_IMAGES = "- Only images from STANDARD sets"; - public static final String ALL_TOKENS = "- Only token images from selected source"; - - private JDialog dialog; - private final JProgressBar bar; - private final JOptionPane dlg; - private boolean cancel; - private final JButton closeButton; - private final JButton startDownloadButton; + private DownloadImagesDialog uiDialog; + private boolean needCancel; private int cardIndex; - private List allCardsMissingImage; - private List cardsToDownload; - private int missingCards = 0; - private int missingTokens = 0; + private List cardsAll; + private List cardsMissing; + private List cardsDownloadQueue; + private int missingCardsCount = 0; + private int missingTokensCount = 0; - List selectedSetCodes = new ArrayList<>(); - - private final JComboBox jComboBoxServer; - private final JLabel jLabelMessage; - private final JLabel jLabelAllMissing; - private final JLabel jLabelServer; - - private final JComboBox jComboBoxSet; - private final JLabel jLabelSet; + List selectedSets = new ArrayList<>(); + private static CardImageSource selectedSource; private final Object sync = new Object(); - - private static CardImageSource cardImageSource; - private Proxy p = Proxy.NO_PROXY; enum DownloadSources { @@ -87,7 +76,6 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab ALTERNATIVE("7. alternative.mtg.onl", AltMtgOnlTokensImageSource.instance), COPYPASTE("8. Copy and Paste Image URLs", CopyPasteImageSource.instance); // MTG_ONL("mtg.onl", MtgOnlTokensImageSource.instance), Not working correctly yet - // MAGICCARDS("magiccards.info", MagicCardsImageSource.instance) private final String text; private final CardImageSource source; @@ -108,7 +96,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab } - public static DownloadPictures getInstance() { + public static DownloadPicturesService getInstance() { return instance; } @@ -117,245 +105,245 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab } public static void startDownload() { + // load images info in background task + instance = new DownloadPicturesService(MageFrame.getInstance()); + new Thread(new LoadMissingCardDataNew(instance)).start(); - /* - * if (cards == null || cards.isEmpty()) { - * JOptionPane.showMessageDialog(null, - * "All card pictures have been downloaded."); return; } - */ - instance = new DownloadPictures(MageFrame.getInstance()); - Thread t1 = new Thread(new LoadMissingCardData(instance)); - t1.start(); - instance.getDlg().setVisible(true); - instance.getDlg().dispose(); - instance.cancel = true; + // show dialog + instance.setNeedCancel(false); + instance.uiDialog.showDialog(); + instance.uiDialog.dispose(); + instance.setNeedCancel(true); } - public JDialog getDlg() { - return dialog; + public boolean getNeedCancel() { + return this.needCancel; } - public void setCancel(boolean cancel) { - this.cancel = cancel; + public void setNeedCancel(boolean needCancel) { + this.needCancel = needCancel; } - static int WIDTH = 400; + public DownloadPicturesService(JFrame frame) { + // init service and dialog + cardsAll = Collections.synchronizedList(new ArrayList<>()); + cardsMissing = Collections.synchronizedList(new ArrayList<>()); + cardsDownloadQueue = Collections.synchronizedList(new ArrayList<>()); + uiDialog = new DownloadImagesDialog(); - public DownloadPictures(JFrame frame) { + // MESSAGE + uiDialog.setGlobalInfo("Initializing image download..."); - cardsToDownload = new ArrayList<>(); - - JPanel p0 = new JPanel(); - p0.setLayout(new BoxLayout(p0, BoxLayout.Y_AXIS)); - - p0.add(Box.createVerticalStrut(5)); - - jLabelMessage = new JLabel(); - jLabelMessage.setAlignmentX(Component.CENTER_ALIGNMENT); - jLabelMessage.setText("Initializing image download..."); - p0.add(jLabelMessage); - p0.add(Box.createVerticalStrut(5)); - - jLabelAllMissing = new JLabel(); - - jLabelAllMissing.setAlignmentX(Component.LEFT_ALIGNMENT); - // jLabelAllMissing.setText("Computing number of missing images..."); - p0.add(jLabelAllMissing); - p0.add(Box.createVerticalStrut(5)); - - jLabelServer = new JLabel(); - jLabelServer.setText("Please select image source:"); - jLabelServer.setAlignmentX(Component.LEFT_ALIGNMENT); - jLabelServer.setVisible(false); - p0.add(jLabelServer); - - p0.add(Box.createVerticalStrut(5)); - - jComboBoxServer = new JComboBox(); - jComboBoxServer.setModel(new DefaultComboBoxModel(DownloadSources.values())); - jComboBoxServer.setAlignmentX(Component.LEFT_ALIGNMENT); - jComboBoxServer.setAlignmentY(Component.LEFT_ALIGNMENT); - jComboBoxServer.addItemListener((ItemEvent event) -> { + // SOURCES - scryfall is default source + uiDialog.getSourcesCombo().setModel(new DefaultComboBoxModel(DownloadSources.values())); + uiDialog.getSourcesCombo().setSelectedItem(DownloadSources.SCRYFALL); + selectedSource = ScryfallImageSource.instance; + uiDialog.getSourcesCombo().addItemListener((ItemEvent event) -> { if (event.getStateChange() == ItemEvent.SELECTED) { - comboBoxServerItemSelected(event); - } - }); - Dimension d = jComboBoxServer.getPreferredSize(); - d.width = WIDTH; - jComboBoxServer.setPreferredSize(d); - p0.add(jComboBoxServer); - jComboBoxServer.setVisible(false); - - // set the first source as default - cardImageSource = WizardCardsImageSource.instance; - - p0.add(Box.createVerticalStrut(5)); - - // Set selection --------------------------------- - jLabelSet = new JLabel(); - jLabelSet.setText("Please select sets to download the images for:"); - jLabelSet.setAlignmentX(Component.LEFT_ALIGNMENT); - jLabelSet.setVisible(false); - p0.add(jLabelSet); - - jComboBoxSet = new JComboBox(); -// jComboBoxSet.setModel(new DefaultComboBoxModel<>(getSetsForCurrentImageSource())); - jComboBoxSet.setAlignmentX(Component.LEFT_ALIGNMENT); - jComboBoxSet.addItemListener((ItemEvent event) -> { - if (event.getStateChange() == ItemEvent.SELECTED) { - comboBoxSetItemSelected(event); + comboboxSourceSelected(event); } }); - p0.add(jComboBoxSet); - jComboBoxSet.setVisible(false); + // LANGUAGES + uiDialog.getLaunguagesCombo().setModel(new DefaultComboBoxModel(CardLanguage.values())); + uiDialog.getLaunguagesCombo().setSelectedItem(PreferencesDialog.getPrefImagesLanguage()); + reloadLanguagesForSelectedSource(); - p0.add(Box.createVerticalStrut(5)); + // REDOWNLOAD + uiDialog.getRedownloadCheckbox().setSelected(false); + uiDialog.getRedownloadCheckbox().addItemListener(this::checkboxRedowloadChanged); - // Start - startDownloadButton = new JButton("Start download"); - startDownloadButton.addActionListener(e -> { - new Thread(DownloadPictures.this).start(); - startDownloadButton.setEnabled(false); + + // SETS (fills after source and language select) + //uiDialog.getSetsCombo().setModel(new DefaultComboBoxModel(DownloadSources.values())); + uiDialog.getSetsCombo().addItemListener((ItemEvent event) -> { + if (event.getStateChange() == ItemEvent.SELECTED) { + comboboxSetSelected(event); + } }); - p0.add(Box.createVerticalStrut(5)); - // Progress - bar = new JProgressBar(this); - p0.add(bar); - bar.setStringPainted(true); + // BUTTON START + uiDialog.getStartButton().addActionListener(e -> { + // selected language setup + if (selectedSource != null) { + if (selectedSource.isLanguagesSupport()) { + selectedSource.setCurrentLanguage((CardLanguage) uiDialog.getLaunguagesCombo().getSelectedItem()); + } + } - d = bar.getPreferredSize(); - d.width = WIDTH; - bar.setPreferredSize(d); - bar.setVisible(false); + // run + uiDialog.enableActionControls(false); + uiDialog.getStartButton().setEnabled(false); + new Thread(DownloadPicturesService.this).start(); + }); - // JOptionPane - Object[] options = {startDownloadButton, closeButton = new JButton("Cancel")}; - startDownloadButton.setVisible(false); - closeButton.addActionListener(e -> dialog.setVisible(false)); - closeButton.setVisible(false); + // BUTTON CANCEL (dialog and loading) + uiDialog.getCancelButton().addActionListener(e -> uiDialog.setVisible(false)); + uiDialog.getStopButton().addActionListener(e -> uiDialog.setVisible(false)); - dlg = new JOptionPane(p0, JOptionPane.PLAIN_MESSAGE, JOptionPane.DEFAULT_OPTION, null, options, options[1]); - dialog = this.dlg.createDialog(frame, "Downloading images"); + // PROGRESS BAR + uiDialog.getProgressBar().setValue(0); + + uiDialog.showDownloadControls(false); } - public void setAllMissingCards() { - updateAndViewMessage("Get all available cards from the repository..."); - List cards = CardRepository.instance.findCards(new CardCriteria()); - updateAndViewMessage("Check which images are missing ..."); - this.allCardsMissingImage = getNeededCards(cards); - updateAndViewMessage("Check which images the current source is providing ..."); - jComboBoxSet.setModel(new DefaultComboBoxModel<>(getSetsForCurrentImageSource())); + public void findMissingCards() { + updateAndViewMessage("Loading..."); + this.cardsAll.clear(); + this.cardsMissing.clear(); + this.cardsDownloadQueue.clear(); - updateCardsToDownload(jComboBoxSet.getSelectedItem().toString()); + updateAndViewMessage("Loading cards list..."); + this.cardsAll = Collections.synchronizedList(CardRepository.instance.findCards(new CardCriteria())); - jComboBoxServer.setVisible(true); - jLabelServer.setVisible(true); - jComboBoxSet.setVisible(true); - jLabelSet.setVisible(true); - bar.setVisible(true); - startDownloadButton.setVisible(true); - closeButton.setVisible(true); + updateAndViewMessage("Finding missing images..."); + this.cardsMissing = prepareMissingCards(this.cardsAll, uiDialog.getRedownloadCheckbox().isSelected()); + updateAndViewMessage("Finding available sets from selected source..."); + this.uiDialog.getSetsCombo().setModel(new DefaultComboBoxModel<>(getSetsForCurrentImageSource())); + reloadCardsToDownload(this.uiDialog.getSetsCombo().getSelectedItem().toString()); + + this.uiDialog.showDownloadControls(true); updateAndViewMessage(""); } - private void comboBoxServerItemSelected(ItemEvent evt) { - if (jComboBoxServer.isEnabled()) { - cardImageSource = ((DownloadSources) evt.getItem()).getSource(); - // update the available sets / token comboBox - jComboBoxSet.setModel(new DefaultComboBoxModel<>(getSetsForCurrentImageSource())); - updateCardsToDownload(jComboBoxSet.getSelectedItem().toString()); + private void reloadLanguagesForSelectedSource() { + this.uiDialog.showLanguagesSupport(selectedSource != null && selectedSource.isLanguagesSupport()); + } + + private void reloadSetsForSelectedSource() { + // update the available sets / token combobox + Object oldSelection = this.uiDialog.getSetsCombo().getSelectedItem(); + this.uiDialog.getSetsCombo().setModel(new DefaultComboBoxModel<>(getSetsForCurrentImageSource())); + if (oldSelection != null) { + this.uiDialog.getSetsCombo().setSelectedItem(oldSelection); + } + reloadCardsToDownload(this.uiDialog.getSetsCombo().getSelectedItem().toString()); + } + + private void comboboxSourceSelected(ItemEvent evt) { + if (this.uiDialog.getSourcesCombo().isEnabled()) { + selectedSource = ((DownloadSources) evt.getItem()).getSource(); + reloadSetsForSelectedSource(); + reloadLanguagesForSelectedSource(); } } public void updateAndViewMessage(String text) { - jLabelMessage.setText(text); - if (dialog != null) { - dialog.pack(); - dialog.validate(); - dialog.repaint(); + this.uiDialog.setGlobalInfo(text); + + // auto-size on empty message (on complete) + if (text.isEmpty()) { + this.uiDialog.showDownloadControls(true); } } + private String getSetNameWithYear(ExpansionSet exp) { + Calendar cal = Calendar.getInstance(); + cal.setTime(exp.getReleaseDate()); + String year = String.valueOf(cal.get(Calendar.YEAR)); + + return exp.getName() + " (" + exp.getCode() + ", " + year + ")"; + + /* + if (!exp.getName().contains(year)) { + return exp.getName() + " (" + year + ")"; + } else { + return exp.getName(); + } + */ + } + + private ExpansionSet findSetByNameWithYear(String name) { + return Sets.getInstance().values().stream() + .filter(exp -> getSetNameWithYear(exp).equals(name)) + .findFirst() + .orElse(null); + } + private Object[] getSetsForCurrentImageSource() { // Set the available sets to the combo box - ArrayList supportedSets = cardImageSource.getSupportedSets(); + ArrayList supportedSets = selectedSource.getSupportedSets(); List setNames = new ArrayList<>(); - if (supportedSets != null) { - setNames.add(ALL_IMAGES); - setNames.add(ALL_STANDARD_IMAGES); - } - if (cardImageSource.isTokenSource()) { + + // multiple sets selection + setNames.add(ALL_IMAGES); + setNames.add(ALL_MODERN_IMAGES); + setNames.add(ALL_STANDARD_IMAGES); + if (selectedSource.isTokenSource()) { setNames.add(ALL_TOKENS); } - if (supportedSets != null) { - for (String setCode : supportedSets) { - ExpansionSet expansionSet = Sets.findSet(setCode); - if (expansionSet != null) { - setNames.add(expansionSet.getName()); - } else { - logger.warn("Source: " + cardImageSource.getSourceName() + ": Expansion set for code " + setCode + " not found in xmage sets!"); - } - } - } + // single set selection + Collection dbSets = Sets.getInstance().values(); + Collection comboSets = dbSets.stream() + .filter(exp -> supportedSets.contains(exp.getCode())) + .sorted(Comparator.comparing(ExpansionSet::getReleaseDate).reversed()) + .map(this::getSetNameWithYear) + .collect(Collectors.toList()); + setNames.addAll(comboSets); + if (setNames.isEmpty()) { - logger.error("Source " + cardImageSource.getSourceName() + " creates no selectable items."); - setNames.add("not avalable"); + logger.error("Source " + selectedSource.getSourceName() + " creates no selectable items."); + setNames.add("not available"); } return setNames.toArray(new String[0]); } - private void updateCardsToDownload(String itemText) { - selectedSetCodes.clear(); - switch (itemText) { + private void reloadCardsToDownload(String selectedItem) { + // find selected sets + selectedSets.clear(); + List formatSets; + List sourceSets = selectedSource.getSupportedSets(); + switch (selectedItem) { + case ALL_IMAGES: - if (cardImageSource.getSupportedSets() == null) { - selectedSetCodes = cardImageSource.getSupportedSets(); - } else { - selectedSetCodes.addAll(cardImageSource.getSupportedSets()); - } + selectedSets.addAll(selectedSource.getSupportedSets()); break; + case ALL_STANDARD_IMAGES: - List standardSets = ConstructedFormats.getSetsByFormat(ConstructedFormats.STANDARD); - for (String setCode : cardImageSource.getSupportedSets()) { - if (standardSets.contains(setCode)) { - selectedSetCodes.add(setCode); - } else { - logger.debug("Set code " + setCode + " from download source " + cardImageSource.getSourceName()); - } - } + formatSets = ConstructedFormats.getSetsByFormat(ConstructedFormats.STANDARD); + formatSets.stream() + .filter(sourceSets::contains) + .forEachOrdered(selectedSets::add); break; + + case ALL_MODERN_IMAGES: + formatSets = ConstructedFormats.getSetsByFormat(ConstructedFormats.MODERN); + formatSets.stream() + .filter(sourceSets::contains) + .forEachOrdered(selectedSets::add); + break; + case ALL_TOKENS: break; + default: - int nonSetEntries = 0; - if (cardImageSource.getSupportedSets() != null) { - nonSetEntries = 2; + // selects one set + ExpansionSet selectedExp = findSetByNameWithYear(selectedItem); + if (selectedExp != null) { + selectedSets.add(selectedExp.getCode()); } - if (cardImageSource.isTokenSource()) { - nonSetEntries++; - } - selectedSetCodes.add(cardImageSource.getSupportedSets().get(jComboBoxSet.getSelectedIndex() - nonSetEntries)); + break; } - cardsToDownload.clear(); + + // find missing cards to download + cardsDownloadQueue.clear(); int numberTokenImagesAvailable = 0; int numberCardImagesAvailable = 0; - for (CardDownloadData data : allCardsMissingImage) { + for (CardDownloadData data : cardsMissing) { if (data.isToken()) { - if (cardImageSource.isTokenSource() && cardImageSource.isImageProvided(data.getSet(), data.getName())) { + if (selectedSource.isTokenSource() && selectedSource.isImageProvided(data.getSet(), data.getName())) { numberTokenImagesAvailable++; - cardsToDownload.add(data); + cardsDownloadQueue.add(data); } else { //logger.warn("Source do not support token (set " + data.getSet() + ", token " + data.getName() + ")"); } } else { - if (selectedSetCodes != null && selectedSetCodes.contains(data.getSet())) { - if (cardImageSource.isSetSupportedComplete(data.getSet()) || cardImageSource.isImageProvided(data.getSet(), data.getName())) { + if (selectedSets != null && selectedSets.contains(data.getSet())) { + if (selectedSource.isSetSupportedComplete(data.getSet()) || selectedSource.isImageProvided(data.getSet(), data.getName())) { numberCardImagesAvailable++; - cardsToDownload.add(data); + cardsDownloadQueue.add(data); } } } @@ -363,24 +351,40 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab updateProgressText(numberCardImagesAvailable, numberTokenImagesAvailable); } - private void comboBoxSetItemSelected(ItemEvent event) { + private void comboboxSetSelected(ItemEvent event) { // Update the cards to download related to the selected set - updateCardsToDownload(event.getItem().toString()); + reloadCardsToDownload(event.getItem().toString()); + } + + private void checkboxRedowloadChanged(ItemEvent event) { + MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR)); + try { + this.cardsMissing.clear(); + this.cardsMissing = prepareMissingCards(this.cardsAll, uiDialog.getRedownloadCheckbox().isSelected()); + reloadCardsToDownload(uiDialog.getSetsCombo().getSelectedItem().toString()); + } finally { + MageFrame.getDesktop().setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); + } } private void updateProgressText(int cardCount, int tokenCount) { - missingTokens = 0; - for (CardDownloadData card : allCardsMissingImage) { + missingTokensCount = 0; + for (CardDownloadData card : cardsMissing) { if (card.isToken()) { - missingTokens++; + missingTokensCount++; } } - missingCards = allCardsMissingImage.size() - missingTokens; - jLabelAllMissing.setText("Missing: " + missingCards + " card images / " + missingTokens + " token images"); + missingCardsCount = cardsMissing.size() - missingTokensCount; + + uiDialog.setCurrentInfo("Missing: " + missingCardsCount + " card images / " + missingTokensCount + " token images"); int imageSum = cardCount + tokenCount; - float mb = (imageSum * cardImageSource.getAverageSize()) / 1024; - bar.setString(String.format(cardIndex == imageSum ? "%d of %d (%d cards/%d tokens) image downloads finished! Please close!" - : "%d of %d (%d cards/%d tokens) image downloads finished! Please wait! [%.1f Mb]", 0, imageSum, cardCount, tokenCount, mb)); + float mb = (imageSum * selectedSource.getAverageSize()) / 1024; + uiDialog.getProgressBar().setString(String.format( + cardIndex == imageSum + ? "%d of %d (%d cards/%d tokens) image downloads finished! Please close!" + : "%d of %d (%d cards/%d tokens) image downloads finished! Please wait! [%.1f Mb]", + 0, imageSum, cardCount, tokenCount, mb + )); } private static String createDownloadName(CardInfo card) { @@ -388,16 +392,10 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab return className.substring(className.lastIndexOf('.') + 1); } - private static List getNeededCards(List allCards) { - - /** - * read all card names and urls - */ + private static List prepareMissingCards(List allCards, boolean redownloadMode) { HashSet ignoreUrls = SettingsManager.getIntance().getIgnoreUrls(); - /** - * get filter for Standard Type 2 cards - */ + // get filter for Standard Type 2 cards Set type2SetsFilter = new HashSet<>(); List constructedFormats = ConstructedFormats.getSetsByFormat(ConstructedFormats.STANDARD); if (constructedFormats != null && !constructedFormats.isEmpty()) { @@ -406,6 +404,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab logger.warn("No formats defined. Try connecting to a server first!"); } + // prepare checking list List allCardsUrls = Collections.synchronizedList(new ArrayList<>()); try { allCards.parallelStream().forEach(card -> { @@ -455,32 +454,33 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab logger.info("Card was not selected: " + card.getName()); } }); + allCardsUrls.addAll(getTokenCardUrls()); } catch (Exception e) { logger.error(e); } - /** - * check to see which cards we already have - */ + // find missing files List cardsToDownload = Collections.synchronizedList(new ArrayList<>()); allCardsUrls.parallelStream().forEach(card -> { - File file = new TFile(CardImageUtils.buildImagePathToCard(card)); - logger.debug(card.getName() + " (is_token=" + card.isToken() + "). Image is here:" + file.getAbsolutePath() + " (exists=" + file.exists() + ')'); - if (!file.exists()) { - logger.debug("Missing: " + file.getAbsolutePath()); - // logger.info("Missing image: " + (card.isToken() ? "TOKEN " : "CARD ") + card.getSet() + "/" + card.getName() + " type: " + card.getType()); + if (redownloadMode) { + // need all cards cardsToDownload.add(card); + } else { + // need missing cards + File file = new TFile(CardImageUtils.buildImagePathToCard(card)); + if (!file.exists()) { + cardsToDownload.add(card); + } } }); - return new ArrayList<>(cardsToDownload); + return Collections.synchronizedList(new ArrayList<>(cardsToDownload)); } public static ArrayList getTokenCardUrls() throws RuntimeException { ArrayList list = new ArrayList<>(); - InputStream in = DownloadPictures.class - .getClassLoader().getResourceAsStream("card-pictures-tok.txt"); + InputStream in = DownloadPicturesService.class.getClassLoader().getResourceAsStream("card-pictures-tok.txt"); if (in == null) { logger.error("resources input stream is null"); @@ -545,7 +545,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab } catch (Exception ex) { logger.error(ex); - throw new RuntimeException("DownloadPictures : readFile() error"); + throw new RuntimeException("DownloadPicturesService : readFile() error"); } return list; } @@ -581,62 +581,62 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab Integer port = Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_PROXY_PORT, "80")); p = new Proxy(type, new InetSocketAddress(address, port)); } catch (Exception ex) { - throw new RuntimeException("Gui_DownloadPictures : error 1 - " + ex); + throw new RuntimeException("Gui_DownloadPicturesService : error 1 - " + ex); } } if (p != null) { HashSet ignoreUrls = SettingsManager.getIntance().getIgnoreUrls(); - update(0, cardsToDownload.size()); - logger.info("Started download of " + cardsToDownload.size() + " images from source: " + cardImageSource.getSourceName()); + update(0, cardsDownloadQueue.size()); + logger.info("Started download of " + cardsDownloadQueue.size() + " images" + + " from source: " + selectedSource.getSourceName() + + ", language: " + selectedSource.getCurrentLanguage().getCode()); int numberOfThreads = Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_THREADS, "10")); ExecutorService executor = Executors.newFixedThreadPool(numberOfThreads); - for (int i = 0; i < cardsToDownload.size() && !cancel; i++) { + for (int i = 0; i < cardsDownloadQueue.size() && !this.getNeedCancel(); i++) { try { - - CardDownloadData card = cardsToDownload.get(i); + CardDownloadData card = cardsDownloadQueue.get(i); logger.debug("Downloading image: " + card.getName() + " (" + card.getSet() + ')'); CardImageUrls urls; - if (ignoreUrls.contains(card.getSet()) || card.isToken()) { if (!"0".equals(card.getCollectorId())) { continue; } - urls = cardImageSource.generateTokenUrl(card); + urls = selectedSource.generateTokenUrl(card); } else { - urls = cardImageSource.generateURL(card); + urls = selectedSource.generateURL(card); } if (urls == null) { - String imageRef = cardImageSource.getNextHttpImageUrl(); - String fileName = cardImageSource.getFileForHttpImage(imageRef); + String imageRef = selectedSource.getNextHttpImageUrl(); + String fileName = selectedSource.getFileForHttpImage(imageRef); if (imageRef != null && fileName != null) { - imageRef = cardImageSource.getSourceName() + imageRef; + imageRef = selectedSource.getSourceName() + imageRef; try { - card.setToken(cardImageSource.isTokenSource()); - Runnable task = new DownloadTask(card, imageRef, fileName, cardImageSource.getTotalImages()); + card.setToken(selectedSource.isTokenSource()); + Runnable task = new DownloadTask(card, imageRef, fileName, selectedSource.getTotalImages()); executor.execute(task); } catch (Exception ex) { } - } else if (cardImageSource.getTotalImages() == -1) { - logger.info("Image not available on " + cardImageSource.getSourceName() + ": " + card.getName() + " (" + card.getSet() + ')'); + } else if (selectedSource.getTotalImages() == -1) { + logger.info("Image not available on " + selectedSource.getSourceName() + ": " + card.getName() + " (" + card.getSet() + ')'); synchronized (sync) { - update(cardIndex + 1, cardsToDownload.size()); + update(cardIndex + 1, cardsDownloadQueue.size()); } } } else { - Runnable task = new DownloadTask(card, urls, cardsToDownload.size()); + Runnable task = new DownloadTask(card, urls, cardsDownloadQueue.size()); executor.execute(task); } - } catch (Exception ex) { logger.error(ex, ex); } } + executor.shutdown(); while (!executor.isTerminated()) { try { @@ -645,6 +645,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab } } } + try { TVFS.umount(); } catch (FsSyncException e) { @@ -653,11 +654,15 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab } finally { // } - closeButton.setText("Close"); - updateCardsToDownload(jComboBoxSet.getSelectedItem().toString()); + + // stop + reloadCardsToDownload(uiDialog.getSetsCombo().getSelectedItem().toString()); + + // reset images cache + ImageCache.clearCache(); } - static String convertStreamToString(java.io.InputStream is) { + static String convertStreamToString(InputStream is) { java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A"); return s.hasNext() ? s.next() : ""; } @@ -670,10 +675,6 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab private final String actualFilename; private final boolean useSpecifiedPaths; - DownloadTask(CardDownloadData card, String baseUrl, int count) { - this(card, new CardImageUrls(baseUrl, null), count); - } - DownloadTask(CardDownloadData card, CardImageUrls urls, int count) { this.card = card; this.urls = urls; @@ -692,7 +693,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab @Override public void run() { - if (cancel) { + if (DownloadPicturesService.getInstance().getNeedCancel()) { synchronized (sync) { update(cardIndex + 1, count); } @@ -736,20 +737,23 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab } // FILE already exists (in zip or in dir) + // don't use, images can be re-downloaded + /* if (destFile.exists()) { synchronized (sync) { update(cardIndex + 1, count); } return; } + */ - // zip can't be read + // check zip access TFile testArchive = destFile.getTopLevelArchive(); if (testArchive != null && testArchive.exists()) { try { testArchive.list(); } catch (Exception e) { - logger.error("Error reading archive, may be it was corrapted. Try to delete it: " + testArchive.toString()); + logger.error("Error reading archive, it's can be corrupted. Try to delete it: " + testArchive.toString()); synchronized (sync) { update(cardIndex + 1, count); @@ -773,12 +777,12 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab URL url = new URL(currentUrl); // on download cancel need to stop - if (cancel) { + if (DownloadPicturesService.getInstance().getNeedCancel()) { return; } // download - cardImageSource.doPause(url.getPath()); + selectedSource.doPause(url.getPath()); httpConn = url.openConnection(p); httpConn.setRequestProperty("User-Agent", "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.4; en-US; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2"); httpConn.connect(); @@ -819,7 +823,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab int len; while ((len = in.read(buf)) != -1) { // user cancelled - if (cancel) { + if (DownloadPicturesService.getInstance().getNeedCancel()) { // stop download, save current state and exit TFile archive = destFile.getTopLevelArchive(); ///* not need to unmout/close - it's auto action @@ -881,34 +885,38 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab } } - private void update(int card, int count) { - this.cardIndex = card; + private void update(int lastCardIndex, int needDownloadCount) { + this.cardIndex = lastCardIndex; - if (cardIndex < count) { - float mb = ((count - card) * cardImageSource.getAverageSize()) / 1024; - bar.setString(String.format("%d of %d image downloads finished! Please wait! [%.1f Mb]", - card, count, mb)); + if (cardIndex < needDownloadCount) { + // downloading + float mb = ((needDownloadCount - lastCardIndex) * selectedSource.getAverageSize()) / 1024; + uiDialog.getProgressBar().setString(String.format("%d of %d image downloads finished! Please wait! [%.1f Mb]", + lastCardIndex, needDownloadCount, mb)); } else { - List remainingCards = Collections.synchronizedList(new ArrayList<>()); - DownloadPictures.this.allCardsMissingImage.parallelStream().forEach(cardDownloadData -> { + // finished + List downloadedCards = Collections.synchronizedList(new ArrayList<>()); + DownloadPicturesService.this.cardsMissing.parallelStream().forEach(cardDownloadData -> { TFile file = new TFile(CardImageUtils.buildImagePathToCard(cardDownloadData)); - if (!file.exists()) { - remainingCards.add(cardDownloadData); + if (file.exists()) { + downloadedCards.add(cardDownloadData); } }); - // remove the cards not downloaded to get the siccessfull downloaded cards - DownloadPictures.this.cardsToDownload.removeAll(remainingCards); - DownloadPictures.this.allCardsMissingImage.removeAll(DownloadPictures.this.cardsToDownload); + // remove all downloaded cards, missing must be remains + this.cardsDownloadQueue.removeAll(downloadedCards); + this.cardsMissing.removeAll(downloadedCards); - count = remainingCards.size(); - - if (count == 0) { - bar.setString("0 images remaining! Please close!"); + if (this.cardsDownloadQueue.size() == 0) { + // stop download + uiDialog.getProgressBar().setString("0 images remaining. Please close."); } else { -// bar.setString(String.format("%d cards remaining! Please choose another source!", count)); - startDownloadButton.setEnabled(true); + // try download again } + + this.uiDialog.getRedownloadCheckbox().setSelected(false); + uiDialog.enableActionControls(true); + uiDialog.getStartButton().setEnabled(true); } } @@ -916,22 +924,21 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab } -class LoadMissingCardData implements Runnable { +class LoadMissingCardDataNew implements Runnable { - private static DownloadPictures downloadPictures; + private static DownloadPicturesService downloadPicturesService; - public LoadMissingCardData(DownloadPictures downloadPictures) { - LoadMissingCardData.downloadPictures = downloadPictures; + public LoadMissingCardDataNew(DownloadPicturesService downloadPicturesService) { + this.downloadPicturesService = downloadPicturesService; } @Override public void run() { - downloadPictures.setAllMissingCards(); + downloadPicturesService.findMissingCards(); } public static void main() { - - (new Thread(new LoadMissingCardData(downloadPictures))).start(); + (new Thread(new LoadMissingCardDataNew(downloadPicturesService))).start(); } } diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/images/ImageCache.java b/Mage.Client/src/main/java/org/mage/plugins/card/images/ImageCache.java index 2edf005832f..a3aac320d49 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/images/ImageCache.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/images/ImageCache.java @@ -3,15 +3,6 @@ package org.mage.plugins.card.images; import com.google.common.base.Function; import com.google.common.collect.ComputationException; import com.google.common.collect.MapMaker; -import java.awt.*; -import java.awt.geom.RoundRectangle2D; -import java.awt.image.BufferedImage; -import java.io.File; -import java.io.IOException; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import javax.imageio.ImageIO; import mage.client.constants.Constants; import mage.client.dialog.PreferencesDialog; import mage.client.util.TransformedImageCache; @@ -23,13 +14,23 @@ import org.apache.log4j.Logger; import org.mage.plugins.card.dl.sources.DirectLinksForDownload; import org.mage.plugins.card.utils.CardImageUtils; +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.geom.RoundRectangle2D; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** * This class stores ALL card images in a cache with soft values. this means * that the images may be garbage collected when they are not needed any more, * but will be kept as long as possible. - * + *

* Key format: "[cardname]#[setname]#[type]#[collectorID]#[param]" - * + *

* where param is: *

    *
  • size of image
  • @@ -228,6 +229,10 @@ public final class ImageCache { }); } + public static void clearCache() { + IMAGE_CACHE.clear(); + } + public static String getFilePath(CardView card, int width) { String key = getKey(card, card.getName(), Integer.toString(width)); boolean usesVariousArt = false; @@ -389,7 +394,7 @@ public final class ImageCache { return getImage(getKey(card, card.getName(), "")); } -// public static BufferedImage getImageFaceOriginal(CardView card) { + // public static BufferedImage getImageFaceOriginal(CardView card) { // return getFaceImage(getFaceKey(card, card.getName(), card.getExpansionSetCode())); // } public static BufferedImage getImageOriginalAlternateName(CardView card) { @@ -472,6 +477,7 @@ public final class ImageCache { // return alternateName + "#" + card.getExpansionSetCode() + "#" +card.getType()+ "#" + card.getCardNumber() + "#" // + (card.getTokenSetCode() == null ? "":card.getTokenSetCode()); // } + /** * Load image from file * diff --git a/Mage.Client/src/main/resources/META-INF/MANIFEST.MF b/Mage.Client/src/main/resources/META-INF/MANIFEST.MF deleted file mode 100644 index 342098cf3fb..00000000000 --- a/Mage.Client/src/main/resources/META-INF/MANIFEST.MF +++ /dev/null @@ -1,3 +0,0 @@ -Manifest-Version: 1.0 -X-COMMENT: Main-Class will be added automatically by build -SplashScreen-Image: splash.jpg diff --git a/Mage.Client/src/main/resources/card-pictures-tok.txt b/Mage.Client/src/main/resources/card-pictures-tok.txt index d6fb91a0d8c..bdb9410a86a 100644 --- a/Mage.Client/src/main/resources/card-pictures-tok.txt +++ b/Mage.Client/src/main/resources/card-pictures-tok.txt @@ -187,6 +187,7 @@ |Generate|TOK:ALL|Graveborn|||SekKuarDeathkeeperGravebornToken| |Generate|TOK:ALL|Hippo|||HippoToken| |Generate|TOK:ALL|Soldier|||SoldierToken| +|Generate|TOK:ALL|Starfish|||StarfishToken| |Generate|TOK:ALL|Zombie|||ZombieToken| |Generate|TOK:APC|Angel|||HauntedAngelToken| |Generate|TOK:APC|Cat|||PenumbraBobcatToken| diff --git a/Mage.Client/src/test/java/mage/client/game/MultiConnectTest.java b/Mage.Client/src/test/java/mage/client/game/MultiConnectTest.java index 1974187c4d4..7db5992ad1a 100644 --- a/Mage.Client/src/test/java/mage/client/game/MultiConnectTest.java +++ b/Mage.Client/src/test/java/mage/client/game/MultiConnectTest.java @@ -1,8 +1,5 @@ package mage.client.game; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import javax.swing.*; import mage.client.components.MageUI; import mage.interfaces.MageClient; import mage.interfaces.callback.ClientCallback; @@ -13,6 +10,10 @@ import mage.utils.MageVersion; import org.apache.log4j.Logger; import org.junit.Ignore; +import javax.swing.*; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + /** * Test for emulating the connection from multi mage clients. * @@ -30,7 +31,7 @@ public class MultiConnectTest { private static final CountDownLatch latch = new CountDownLatch(USER_CONNECT_COUNT); - private static final MageVersion version = new MageVersion(MageVersion.MAGE_VERSION_MAJOR, MageVersion.MAGE_VERSION_MINOR, MageVersion.MAGE_VERSION_PATCH, MageVersion.MAGE_VERSION_MINOR_PATCH, MageVersion.MAGE_VERSION_INFO); + private static final MageVersion version = new MageVersion(MultiConnectTest.class); private static volatile int connected; diff --git a/Mage.Common/pom.xml b/Mage.Common/pom.xml index a139eab9600..5eb7a110dab 100644 --- a/Mage.Common/pom.xml +++ b/Mage.Common/pom.xml @@ -7,7 +7,7 @@ org.mage mage-root - 1.4.31 + 1.4.32 mage-common diff --git a/Mage.Common/src/main/java/mage/remote/SessionImpl.java b/Mage.Common/src/main/java/mage/remote/SessionImpl.java index 91878a97979..a17883857c8 100644 --- a/Mage.Common/src/main/java/mage/remote/SessionImpl.java +++ b/Mage.Common/src/main/java/mage/remote/SessionImpl.java @@ -1,15 +1,5 @@ - package mage.remote; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; -import java.lang.reflect.UndeclaredThrowableException; -import java.net.*; -import java.util.*; -import java.util.concurrent.TimeUnit; import mage.MageException; import mage.cards.decks.DeckCardLists; import mage.cards.repository.CardInfo; @@ -38,6 +28,12 @@ import org.jboss.remoting.transport.bisocket.Bisocket; import org.jboss.remoting.transport.socket.SocketWrapper; import org.jboss.remoting.transporter.TransporterClient; +import java.io.*; +import java.lang.reflect.UndeclaredThrowableException; +import java.net.*; +import java.util.*; +import java.util.concurrent.TimeUnit; + /** * @author BetaSteward_at_googlemail.com */ @@ -94,37 +90,38 @@ public class SessionImpl implements Session { return remoting.run(); } catch (MalformedURLException ex) { logger.fatal("", ex); - client.showMessage("Unable to connect to server. " + ex.getMessage()); + client.showMessage("Unable connect to server. " + ex.getMessage()); } catch (UndeclaredThrowableException ex) { String addMessage = ""; Throwable cause = ex.getCause(); if (cause instanceof InvocationFailureException) { InvocationFailureException exep = (InvocationFailureException) cause; if (exep.getCause() instanceof IOException) { - if (exep.getCause().getMessage().startsWith("Field hash null is not available on current")) { - addMessage = "Probabaly the server version is not compatible to the client. "; + if (exep.getCause().getMessage().startsWith("Field hash null is not available on current") + || exep.getCause().getMessage().endsWith("end of file")) { + addMessage = "Probably the server version is not compatible with the client. "; } } } else if (cause instanceof NoSuchMethodException) { // NoSuchMethodException is thrown on an invocation of an unknow JBoss remoting // method, so it's likely to be because of a version incompatibility. addMessage = "The following method is not available in the server, probably the " - + "server version is not compatible to the client: " + cause.getMessage(); + + "server version is not compatible with the client: " + cause.getMessage(); } if (addMessage.isEmpty()) { logger.fatal("", ex); } - client.showMessage("Unable to connect to server. " + addMessage + (ex.getMessage() != null ? ex.getMessage() : "")); + client.showMessage("Unable connect to server. " + addMessage + (ex.getMessage() != null ? ex.getMessage() : "")); } catch (IOException ex) { logger.fatal("", ex); String addMessage = ""; if (ex.getMessage() != null && ex.getMessage().startsWith("Unable to perform invocation")) { addMessage = "Maybe the server version is not compatible. "; } - client.showMessage("Unable to connect to server. " + addMessage + ex.getMessage() != null ? ex.getMessage() : ""); + client.showMessage("Unable connect to server. " + addMessage + ex.getMessage() != null ? ex.getMessage() : ""); } catch (MageVersionException ex) { if (!canceled) { - client.showMessage("Unable to connect to server. " + ex.getMessage()); + client.showMessage("Unable connect to server. " + ex.getMessage()); } disconnect(false); } catch (CannotConnectException ex) { @@ -132,11 +129,11 @@ public class SessionImpl implements Session { handleCannotConnectException(ex); } } catch (Throwable t) { - logger.fatal("Unable to connect to server - ", t); + logger.fatal("Unable connect to server - ", t); if (!canceled) { disconnect(false); StringBuilder sb = new StringBuilder(); - sb.append("Unable to connect to server.\n"); + sb.append("Unable connect to server.\n"); for (StackTraceElement element : t.getStackTrace()) { sb.append(element.toString()).append('\n'); } @@ -196,32 +193,32 @@ public class SessionImpl implements Session { public synchronized boolean connect(final Connection connection) { return establishJBossRemotingConnection(connection) && handleRemotingTaskExceptions(new RemotingTask() { - @Override - public boolean run() throws Throwable { - logger.info("Trying to log-in as " + getUserName() + " to XMAGE server at " + connection.getHost() + ':' + connection.getPort()); - boolean registerResult; - if (connection.getAdminPassword() == null) { - // for backward compatibility. don't remove twice call - first one does nothing but for version checking - registerResult = server.connectUser(connection.getUsername(), connection.getPassword(), sessionId, client.getVersion(), connection.getUserIdStr()); - if (registerResult) { - server.setUserData(connection.getUsername(), sessionId, connection.getUserData(), client.getVersion().toString(), connection.getUserIdStr()); - } - } else { - registerResult = server.connectAdmin(connection.getAdminPassword(), sessionId, client.getVersion()); - } - if (registerResult) { - serverState = server.getServerState(); - if (!connection.getUsername().equals("Admin")) { - updateDatabase(connection.isForceDBComparison(), serverState); - } - logger.info("Logged-in as " + getUserName() + " to MAGE server at " + connection.getHost() + ':' + connection.getPort()); - client.connected(getUserName() + '@' + connection.getHost() + ':' + connection.getPort() + ' '); - return true; - } - disconnect(false); - return false; + @Override + public boolean run() throws Throwable { + logger.info("Trying to log-in as " + getUserName() + " to XMAGE server at " + connection.getHost() + ':' + connection.getPort()); + boolean registerResult; + if (connection.getAdminPassword() == null) { + // for backward compatibility. don't remove twice call - first one does nothing but for version checking + registerResult = server.connectUser(connection.getUsername(), connection.getPassword(), sessionId, client.getVersion(), connection.getUserIdStr()); + if (registerResult) { + server.setUserData(connection.getUsername(), sessionId, connection.getUserData(), client.getVersion().toString(), connection.getUserIdStr()); } - }); + } else { + registerResult = server.connectAdmin(connection.getAdminPassword(), sessionId, client.getVersion()); + } + if (registerResult) { + serverState = server.getServerState(); + if (!connection.getUsername().equals("Admin")) { + updateDatabase(connection.isForceDBComparison(), serverState); + } + logger.info("Logged-in as " + getUserName() + " to MAGE server at " + connection.getHost() + ':' + connection.getPort()); + client.connected(getUserName() + '@' + connection.getHost() + ':' + connection.getPort() + ' '); + return true; + } + disconnect(false); + return false; + } + }); } @Override @@ -442,7 +439,7 @@ public class SessionImpl implements Session { t = t.getCause(); } - client.showMessage("Unable to connect to server. " + message); + client.showMessage("Unable connect to server. " + message); if (logger.isTraceEnabled()) { logger.trace("StackTrace", t); } @@ -450,7 +447,7 @@ public class SessionImpl implements Session { /** * @param askForReconnect - true = connection was lost because of error and - * ask the user if he want to try to reconnect + * ask the user if he want to try to reconnect */ @Override public synchronized void disconnect(boolean askForReconnect) { diff --git a/Mage.Common/src/main/java/mage/utils/MageVersion.java b/Mage.Common/src/main/java/mage/utils/MageVersion.java index 4a0feb9728e..e4550bddf11 100644 --- a/Mage.Common/src/main/java/mage/utils/MageVersion.java +++ b/Mage.Common/src/main/java/mage/utils/MageVersion.java @@ -1,9 +1,10 @@ package mage.utils; +import mage.util.JarVersion; + import java.io.Serializable; /** - * * @author BetaSteward_at_googlemail.com */ public class MageVersion implements Serializable, Comparable { @@ -13,23 +14,31 @@ public class MageVersion implements Serializable, Comparable { */ public final static int MAGE_VERSION_MAJOR = 1; public final static int MAGE_VERSION_MINOR = 4; - public final static int MAGE_VERSION_PATCH = 31; - public final static String MAGE_VERSION_MINOR_PATCH = "V4"; - public final static String MAGE_VERSION_INFO = ""; + public final static int MAGE_VERSION_PATCH = 32; + public final static String MAGE_EDITION_INFO = ""; // set "-beta" for 1.4.32-betaV0 + public final static String MAGE_VERSION_MINOR_PATCH = "V0"; private final int major; private final int minor; private final int patch; private final String minorPatch; // doesn't matter for compatibility + private final String buildTime; + private String editionInfo; + private final boolean showBuildTime = true; - private String info = ""; + public MageVersion(Class sourceClass) { + this(MAGE_VERSION_MAJOR, MAGE_VERSION_MINOR, MAGE_VERSION_PATCH, MAGE_VERSION_MINOR_PATCH, MAGE_EDITION_INFO, sourceClass); + } - public MageVersion(int major, int minor, int patch, String minorPatch, String info) { + public MageVersion(int major, int minor, int patch, String minorPatch, String editionInfo, Class sourceClass) { this.major = major; this.minor = minor; this.patch = patch; this.minorPatch = minorPatch; - this.info = info; + this.editionInfo = editionInfo; + + // build time + this.buildTime = showBuildTime ? JarVersion.getBuildTime(sourceClass) : ""; } public int getMajor() { @@ -50,7 +59,8 @@ public class MageVersion implements Serializable, Comparable { @Override public String toString() { - return major + "." + minor + '.' + patch + info + minorPatch; + // 1.4.32-betaV0 (build: time) + return major + "." + minor + '.' + patch + editionInfo + minorPatch + (!this.buildTime.isEmpty() ? " (build: " + this.buildTime + ")" : ""); } @Override @@ -64,7 +74,7 @@ public class MageVersion implements Serializable, Comparable { if (patch != o.patch) { return patch - o.patch; } - return info.compareTo(o.info); + return editionInfo.compareTo(o.editionInfo); } } diff --git a/Mage.Common/src/main/java/mage/view/DraftClientMessage.java b/Mage.Common/src/main/java/mage/view/DraftClientMessage.java index 33bf75f2129..dfaaf2bc226 100644 --- a/Mage.Common/src/main/java/mage/view/DraftClientMessage.java +++ b/Mage.Common/src/main/java/mage/view/DraftClientMessage.java @@ -13,21 +13,12 @@ public class DraftClientMessage implements Serializable { private DraftView draftView; private DraftPickView draftPickView; - private String message; - public DraftClientMessage(DraftView draftView) { + public DraftClientMessage(DraftView draftView, DraftPickView draftPickView) { this.draftView = draftView; - } - - public DraftClientMessage(DraftPickView draftPickView) { this.draftPickView = draftPickView; } - public DraftClientMessage(DraftView draftView, String message) { - this.message = message; - this.draftView = draftView; - } - public DraftPickView getDraftPickView() { return draftPickView; } diff --git a/Mage.Common/src/main/java/mage/view/DraftView.java b/Mage.Common/src/main/java/mage/view/DraftView.java index 241c6a840ff..b1f2b960a48 100644 --- a/Mage.Common/src/main/java/mage/view/DraftView.java +++ b/Mage.Common/src/main/java/mage/view/DraftView.java @@ -7,6 +7,7 @@ import java.util.ArrayList; import java.util.List; import mage.cards.ExpansionSet; import mage.game.draft.Draft; +import mage.game.draft.DraftCube; import mage.game.draft.DraftPlayer; /** @@ -17,6 +18,7 @@ public class DraftView implements Serializable { private static final long serialVersionUID = 1L; private final List sets = new ArrayList<>(); + private final List setCodes = new ArrayList<>(); private final int boosterNum; private final int cardNum; private final List players = new ArrayList<>(); @@ -24,11 +26,14 @@ public class DraftView implements Serializable { public DraftView(Draft draft) { if (draft.getDraftCube() != null) { for (int i = 0; i < draft.getNumberBoosters(); i++) { - sets.add(draft.getDraftCube().getName()); + DraftCube cube = draft.getDraftCube(); + sets.add(cube.getName()); + setCodes.add(cube.getCode()); } } else { for (ExpansionSet set: draft.getSets()) { sets.add(set.getName()); + setCodes.add(set.getCode()); } } this.boosterNum = draft.getBoosterNum(); @@ -42,6 +47,10 @@ public class DraftView implements Serializable { return sets; } + public List getSetCodes() { + return setCodes; + } + public List getPlayers() { return players; } diff --git a/Mage.Common/src/main/java/mage/view/TableView.java b/Mage.Common/src/main/java/mage/view/TableView.java index c3d748c3446..948c7717bf1 100644 --- a/Mage.Common/src/main/java/mage/view/TableView.java +++ b/Mage.Common/src/main/java/mage/view/TableView.java @@ -36,6 +36,7 @@ public class TableView implements Serializable { private List seats = new ArrayList<>(); private List games = new ArrayList<>(); private final String quitRatio; + private final String minimumRating; private final boolean limited; private final boolean rated; private final boolean passworded; @@ -111,6 +112,7 @@ public class TableView implements Serializable { this.additionalInfo = addInfo.toString(); this.skillLevel = table.getMatch().getOptions().getSkillLevel(); this.quitRatio = Integer.toString(table.getMatch().getOptions().getQuitRatio()); + this.minimumRating = Integer.toString(table.getMatch().getOptions().getMinimumRating()); this.limited = table.getMatch().getOptions().isLimited(); this.rated = table.getMatch().getOptions().isRated(); this.passworded = !table.getMatch().getOptions().getPassword().isEmpty(); @@ -159,6 +161,7 @@ public class TableView implements Serializable { this.deckType = table.getDeckType() + ' ' + table.getTournament().getBoosterInfo() + (tableNameInfo != null ? tableNameInfo : ""); this.skillLevel = table.getTournament().getOptions().getMatchOptions().getSkillLevel(); this.quitRatio = Integer.toString(table.getTournament().getOptions().getQuitRatio()); + this.minimumRating = Integer.toString(table.getTournament().getOptions().getMinimumRating()); this.limited = table.getTournament().getOptions().getMatchOptions().isLimited(); this.rated = table.getTournament().getOptions().getMatchOptions().isRated(); this.passworded = !table.getTournament().getOptions().getPassword().isEmpty(); @@ -223,9 +226,9 @@ public class TableView implements Serializable { return skillLevel; } - public String getQuitRatio() { - return quitRatio; - } + public String getQuitRatio() { return quitRatio; } + + public String getMinimumRating() { return minimumRating; } public boolean isLimited() { return limited; diff --git a/Mage.Common/src/main/java/mage/view/TournamentGameView.java b/Mage.Common/src/main/java/mage/view/TournamentGameView.java index c50662f21e4..e2ca098709f 100644 --- a/Mage.Common/src/main/java/mage/view/TournamentGameView.java +++ b/Mage.Common/src/main/java/mage/view/TournamentGameView.java @@ -43,7 +43,7 @@ public class TournamentGameView implements Serializable { String duelingTime = ""; if (game.hasEnded()) { - if (game.getEndTime() != null) { + if (game.getEndTime() != null && game.getStartTime() != null) { duelingTime = " (" + DateFormat.getDuration((game.getEndTime().getTime() - game.getStartTime().getTime())/1000) + ')'; } this.state = "Finished" + duelingTime; diff --git a/Mage.Plugins/Mage.Counter.Plugin/pom.xml b/Mage.Plugins/Mage.Counter.Plugin/pom.xml index a8af62ad9da..27f3f04daa8 100644 --- a/Mage.Plugins/Mage.Counter.Plugin/pom.xml +++ b/Mage.Plugins/Mage.Counter.Plugin/pom.xml @@ -7,7 +7,7 @@ org.mage mage-plugins - 1.4.31 + 1.4.32 mage-counter-plugin diff --git a/Mage.Plugins/pom.xml b/Mage.Plugins/pom.xml index 19abee5bda1..8ae91a6e66c 100644 --- a/Mage.Plugins/pom.xml +++ b/Mage.Plugins/pom.xml @@ -7,7 +7,7 @@ org.mage mage-root - 1.4.31 + 1.4.32 mage-plugins diff --git a/Mage.Server.Console/pom.xml b/Mage.Server.Console/pom.xml index a48379e45c7..c754825bb39 100644 --- a/Mage.Server.Console/pom.xml +++ b/Mage.Server.Console/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.31 + 1.4.32 org.mage @@ -53,7 +53,6 @@ maven-jar-plugin - ${manifest.file} true mage.server.console.ConsoleFrame diff --git a/Mage.Server.Console/src/main/java/mage/server/console/ConsoleFrame.java b/Mage.Server.Console/src/main/java/mage/server/console/ConsoleFrame.java index 80737a9b56a..33033b39be1 100644 --- a/Mage.Server.Console/src/main/java/mage/server/console/ConsoleFrame.java +++ b/Mage.Server.Console/src/main/java/mage/server/console/ConsoleFrame.java @@ -1,11 +1,3 @@ - - -/* - * ConsoleFrame.java - * - * Created on May 13, 2011, 2:39:10 PM - */ - package mage.server.console; import mage.interfaces.MageClient; @@ -25,7 +17,6 @@ import java.util.concurrent.TimeUnit; import java.util.prefs.Preferences; /** - * * @author BetaSteward_at_googlemail.com */ public class ConsoleFrame extends javax.swing.JFrame implements MageClient { @@ -35,9 +26,10 @@ public class ConsoleFrame extends javax.swing.JFrame implements MageClient { private static Session session; private ConnectDialog connectDialog; private static final Preferences prefs = Preferences.userNodeForPackage(ConsoleFrame.class); - private static final MageVersion version = new MageVersion(MageVersion.MAGE_VERSION_MAJOR, MageVersion.MAGE_VERSION_MINOR, MageVersion.MAGE_VERSION_PATCH, MageVersion.MAGE_VERSION_MINOR_PATCH, MageVersion.MAGE_VERSION_INFO); - + private static final MageVersion version = new MageVersion(ConsoleFrame.class); + private static final ScheduledExecutorService pingTaskExecutor = Executors.newSingleThreadScheduledExecutor(); + /** * @return the session */ @@ -54,7 +46,9 @@ public class ConsoleFrame extends javax.swing.JFrame implements MageClient { return version; } - /** Creates new form ConsoleFrame */ + /** + * Creates new form ConsoleFrame + */ public ConsoleFrame() { addWindowListener(new WindowAdapter() { @@ -72,11 +66,11 @@ public class ConsoleFrame extends javax.swing.JFrame implements MageClient { } catch (Exception ex) { logger.fatal("", ex); } - + pingTaskExecutor.scheduleAtFixedRate(() -> session.ping(), 60, 60, TimeUnit.SECONDS); } - public boolean connect(Connection connection) { + public boolean connect(Connection connection) { if (session.connect(connection)) { this.consolePanel1.start(); return true; @@ -100,7 +94,8 @@ public class ConsoleFrame extends javax.swing.JFrame implements MageClient { btnSendMessage.setEnabled(false); } - /** This method is called from within the constructor to + /** + * This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. @@ -143,16 +138,16 @@ public class ConsoleFrame extends javax.swing.JFrame implements MageClient { javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jToolBar1, javax.swing.GroupLayout.DEFAULT_SIZE, 933, Short.MAX_VALUE) - .addComponent(consolePanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 933, Short.MAX_VALUE) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jToolBar1, javax.swing.GroupLayout.DEFAULT_SIZE, 933, Short.MAX_VALUE) + .addComponent(consolePanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 933, Short.MAX_VALUE) ); layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(jToolBar1, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, 0) - .addComponent(consolePanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 432, Short.MAX_VALUE)) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(jToolBar1, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(consolePanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 432, Short.MAX_VALUE)) ); pack(); @@ -177,8 +172,8 @@ public class ConsoleFrame extends javax.swing.JFrame implements MageClient { }//GEN-LAST:event_btnSendMessageActionPerformed /** - * @param args the command line arguments - */ + * @param args the command line arguments + */ public static void main(String args[]) { logger.info("Starting MAGE server console version " + version); logger.info("Logging level: " + logger.getEffectiveLevel()); @@ -205,9 +200,8 @@ public class ConsoleFrame extends javax.swing.JFrame implements MageClient { public void connected(final String message) { if (SwingUtilities.isEventDispatchThread()) { setStatusText(message); - enableButtons(); - } - else { + enableButtons(); + } else { SwingUtilities.invokeLater(() -> { setStatusText(message); enableButtons(); @@ -221,8 +215,7 @@ public class ConsoleFrame extends javax.swing.JFrame implements MageClient { consolePanel1.stop(); setStatusText("Not connected"); disableButtons(); - } - else { + } else { SwingUtilities.invokeLater(() -> { consolePanel1.stop(); setStatusText("Not connected"); @@ -235,8 +228,7 @@ public class ConsoleFrame extends javax.swing.JFrame implements MageClient { public void showMessage(final String message) { if (SwingUtilities.isEventDispatchThread()) { JOptionPane.showMessageDialog(this, message); - } - else { + } else { SwingUtilities.invokeLater(() -> JOptionPane.showMessageDialog(getFrame(), message)); } } @@ -245,8 +237,7 @@ public class ConsoleFrame extends javax.swing.JFrame implements MageClient { public void showError(final String message) { if (SwingUtilities.isEventDispatchThread()) { JOptionPane.showMessageDialog(this, message, "Error", JOptionPane.ERROR_MESSAGE); - } - else { + } else { SwingUtilities.invokeLater(() -> JOptionPane.showMessageDialog(getFrame(), message, "Error", JOptionPane.ERROR_MESSAGE)); } } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/pom.xml b/Mage.Server.Plugins/Mage.Deck.Constructed/pom.xml index 34ac2c8b537..ae308a042c8 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/pom.xml +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.32 mage-deck-constructed diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AusHighlander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AusHighlander.java index ed5a331ce34..460a3f9c9a9 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AusHighlander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AusHighlander.java @@ -4,7 +4,6 @@ import mage.cards.ExpansionSet; import mage.cards.Sets; import mage.cards.decks.Constructed; import mage.cards.decks.Deck; -import mage.constants.SetType; import java.util.HashMap; import java.util.Map; @@ -82,7 +81,7 @@ public class AusHighlander extends Constructed { public AusHighlander() { this("Australian Highlander"); for (ExpansionSet set : Sets.getInstance().values()) { - if (set.getSetType() != SetType.CUSTOM_SET) { + if (set.isEternalLegal()) { setCodes.add(set.getCode()); } } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/CanadianHighlander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/CanadianHighlander.java index da4955be6ab..5ec2856facd 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/CanadianHighlander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/CanadianHighlander.java @@ -4,7 +4,6 @@ import mage.cards.ExpansionSet; import mage.cards.Sets; import mage.cards.decks.Constructed; import mage.cards.decks.Deck; -import mage.constants.SetType; import java.util.HashMap; import java.util.Map; @@ -64,7 +63,7 @@ public class CanadianHighlander extends Constructed { public CanadianHighlander() { this("Canadian Highlander"); for (ExpansionSet set : Sets.getInstance().values()) { - if (set.getSetType() != SetType.CUSTOM_SET) { + if (set.isEternalLegal()) { setCodes.add(set.getCode()); } } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java index 439e7bf928e..bbd28dcfa7a 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java @@ -1,6 +1,5 @@ package mage.deck; -import java.util.*; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.CanBeYourCommanderAbility; @@ -12,11 +11,11 @@ import mage.cards.ExpansionSet; import mage.cards.Sets; import mage.cards.decks.Constructed; import mage.cards.decks.Deck; -import mage.constants.SetType; import mage.filter.FilterMana; +import java.util.*; + /** - * * @author Plopman */ public class Commander extends Constructed { @@ -27,7 +26,7 @@ public class Commander extends Constructed { public Commander() { this("Commander"); for (ExpansionSet set : Sets.getInstance().values()) { - if (set.getSetType() != SetType.CUSTOM_SET) { + if (set.isEternalLegal()) { setCodes.add(set.getCode()); } } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Eternal.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Eternal.java index c9fd0ae21af..9f84e84deaa 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Eternal.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Eternal.java @@ -4,7 +4,6 @@ package mage.deck; import mage.cards.ExpansionSet; import mage.cards.Sets; import mage.cards.decks.Constructed; -import mage.constants.SetType; /** * This class implements the new casual format "Eternal", which is legacy with @@ -18,7 +17,7 @@ public class Eternal extends Constructed { public Eternal() { super("Constructed - Eternal"); for (ExpansionSet set : Sets.getInstance().values()) { - if (set.getSetType() != SetType.CUSTOM_SET) { + if (set.isEternalLegal()) { setCodes.add(set.getCode()); } } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Legacy.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Legacy.java index 90f4ee51ba8..0b9b55a451e 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Legacy.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Legacy.java @@ -14,7 +14,7 @@ public class Legacy extends Constructed { public Legacy() { super("Constructed - Legacy"); for (ExpansionSet set : Sets.getInstance().values()) { - if (set.getSetType() != SetType.CUSTOM_SET) { + if (set.isEternalLegal()) { setCodes.add(set.getCode()); } } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Pauper.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Pauper.java index 7e14fd84802..d0425c8d8d1 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Pauper.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Pauper.java @@ -9,10 +9,8 @@ import mage.cards.ExpansionSet; import mage.cards.Sets; import mage.cards.decks.Constructed; import mage.constants.Rarity; -import mage.constants.SetType; /** - * * @author LevelX2 */ public class Pauper extends Constructed { @@ -22,7 +20,7 @@ public class Pauper extends Constructed { //TODO: Add only Magic Online sets for pauper for (ExpansionSet set : Sets.getInstance().values()) { - if (set.getSetType() != SetType.CUSTOM_SET) { + if (set.isEternalLegal()) { setCodes.add(set.getCode()); } } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/PennyDreadfulCommander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/PennyDreadfulCommander.java index bf23f9f9dd1..164cf8c1cf4 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/PennyDreadfulCommander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/PennyDreadfulCommander.java @@ -1,8 +1,6 @@ package mage.deck; -import java.util.*; -import java.util.Map.Entry; import mage.abilities.Ability; import mage.abilities.common.CanBeYourCommanderAbility; import mage.abilities.keyword.PartnerAbility; @@ -12,11 +10,12 @@ import mage.cards.ExpansionSet; import mage.cards.Sets; import mage.cards.decks.Constructed; import mage.cards.decks.Deck; -import mage.constants.SetType; import mage.filter.FilterMana; +import java.util.*; +import java.util.Map.Entry; + /** - * * @author spjspj */ public class PennyDreadfulCommander extends Constructed { @@ -28,7 +27,7 @@ public class PennyDreadfulCommander extends Constructed { public PennyDreadfulCommander() { this("Penny Dreadful Commander"); for (ExpansionSet set : Sets.getInstance().values()) { - if (set.getSetType() != SetType.CUSTOM_SET) { + if (set.isEternalLegal()) { setCodes.add(set.getCode()); } } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java index ab94951f680..f2250b79fb9 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java @@ -1,10 +1,6 @@ package mage.deck; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import mage.abilities.common.CanBeYourCommanderAbility; import mage.cards.Card; import mage.cards.ExpansionSet; @@ -12,12 +8,15 @@ import mage.cards.Sets; import mage.cards.SplitCard; import mage.cards.decks.Constructed; import mage.cards.decks.Deck; -import mage.constants.SetType; import mage.filter.FilterMana; import mage.game.GameTinyLeadersImpl; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + /** - * * @author JRHerlehy */ public class TinyLeaders extends Constructed { @@ -27,7 +26,7 @@ public class TinyLeaders extends Constructed { public TinyLeaders() { this("Tiny Leaders"); for (ExpansionSet set : Sets.getInstance().values()) { - if (set.getSetType() != SetType.CUSTOM_SET) { + if (set.isEternalLegal()) { setCodes.add(set.getCode()); } } @@ -85,7 +84,6 @@ public class TinyLeaders extends Constructed { } /** - * * @param deck * @return - True if deck is valid */ @@ -212,9 +210,8 @@ public class TinyLeaders extends Constructed { } /** - * * @param commander FilterMana object with Color Identity of Commander set - * @param card Card to validate + * @param card Card to validate * @return True if card has a valid color identity */ public boolean cardHasValideColor(FilterMana commander, Card card) { diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Vintage.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Vintage.java index 5c8ac0ec49f..6ce5836ca87 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Vintage.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Vintage.java @@ -4,10 +4,8 @@ package mage.deck; import mage.cards.ExpansionSet; import mage.cards.Sets; import mage.cards.decks.Constructed; -import mage.constants.SetType; /** - * * @author BetaSteward_at_googlemail.com */ public class Vintage extends Constructed { @@ -15,7 +13,7 @@ public class Vintage extends Constructed { public Vintage() { super("Constructed - Vintage"); for (ExpansionSet set : Sets.getInstance().values()) { - if (set.getSetType() != SetType.CUSTOM_SET) { + if (set.isEternalLegal()) { setCodes.add(set.getCode()); } } diff --git a/Mage.Server.Plugins/Mage.Deck.Limited/pom.xml b/Mage.Server.Plugins/Mage.Deck.Limited/pom.xml index 831c92012e6..98e6f8d47fb 100644 --- a/Mage.Server.Plugins/Mage.Deck.Limited/pom.xml +++ b/Mage.Server.Plugins/Mage.Deck.Limited/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.32 mage-deck-limited diff --git a/Mage.Server.Plugins/Mage.Game.BrawlDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.BrawlDuel/pom.xml index be720b6a91e..c8e41100ec6 100644 --- a/Mage.Server.Plugins/Mage.Game.BrawlDuel/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.BrawlDuel/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.32 mage-game-brawlduel diff --git a/Mage.Server.Plugins/Mage.Game.BrawlFreeForAll/pom.xml b/Mage.Server.Plugins/Mage.Game.BrawlFreeForAll/pom.xml index 45666026043..6acd4acfc23 100644 --- a/Mage.Server.Plugins/Mage.Game.BrawlFreeForAll/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.BrawlFreeForAll/pom.xml @@ -6,7 +6,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.32 mage-game-brawlfreeforall diff --git a/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/pom.xml index 5b32376a59e..6a96d18e1ea 100644 --- a/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.32 mage-game-canadianhighlanderduel diff --git a/Mage.Server.Plugins/Mage.Game.CommanderDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.CommanderDuel/pom.xml index 3bc9525794c..6bdd993258d 100644 --- a/Mage.Server.Plugins/Mage.Game.CommanderDuel/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.CommanderDuel/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.32 mage-game-commanderduel diff --git a/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/pom.xml b/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/pom.xml index 1888b3a1fb6..159cbc07010 100644 --- a/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/pom.xml @@ -6,7 +6,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.32 mage-game-commanderfreeforall diff --git a/Mage.Server.Plugins/Mage.Game.FreeForAll/pom.xml b/Mage.Server.Plugins/Mage.Game.FreeForAll/pom.xml index 239c59dcdf3..9c8f09b34e8 100644 --- a/Mage.Server.Plugins/Mage.Game.FreeForAll/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.FreeForAll/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.32 mage-game-freeforall diff --git a/Mage.Server.Plugins/Mage.Game.FreeformCommanderFreeForAll/pom.xml b/Mage.Server.Plugins/Mage.Game.FreeformCommanderFreeForAll/pom.xml index eaa55ae4e9c..3c49cfae83e 100644 --- a/Mage.Server.Plugins/Mage.Game.FreeformCommanderFreeForAll/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.FreeformCommanderFreeForAll/pom.xml @@ -6,7 +6,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.32 mage-game-freeformcommanderfreeforall diff --git a/Mage.Server.Plugins/Mage.Game.MomirDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.MomirDuel/pom.xml index e4ec5b48a76..2c78b0d5ad6 100644 --- a/Mage.Server.Plugins/Mage.Game.MomirDuel/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.MomirDuel/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.32 mage-game-momirduel diff --git a/Mage.Server.Plugins/Mage.Game.MomirGame/pom.xml b/Mage.Server.Plugins/Mage.Game.MomirGame/pom.xml index e17bfe1289a..79f3c5abdf1 100644 --- a/Mage.Server.Plugins/Mage.Game.MomirGame/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.MomirGame/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.32 mage-game-momirfreeforall diff --git a/Mage.Server.Plugins/Mage.Game.PennyDreadfulCommanderFreeForAll/pom.xml b/Mage.Server.Plugins/Mage.Game.PennyDreadfulCommanderFreeForAll/pom.xml index 60538dc66c3..f110bd92500 100644 --- a/Mage.Server.Plugins/Mage.Game.PennyDreadfulCommanderFreeForAll/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.PennyDreadfulCommanderFreeForAll/pom.xml @@ -6,7 +6,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.32 mage-game-pennydreadfulcommanderfreeforall diff --git a/Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/pom.xml index 111fedc13fb..c0744d767fe 100644 --- a/Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.32 mage-game-tinyleadersduel diff --git a/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/pom.xml index 5d5ba7eb623..9f0fcd6fc9d 100644 --- a/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.32 mage-game-twoplayerduel diff --git a/Mage.Server.Plugins/Mage.Player.AI.DraftBot/pom.xml b/Mage.Server.Plugins/Mage.Player.AI.DraftBot/pom.xml index 75c0e758224..6bf13c4d634 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.DraftBot/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.AI.DraftBot/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.32 mage-player-ai-draftbot diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/pom.xml b/Mage.Server.Plugins/Mage.Player.AI.MA/pom.xml index 9f8a8b0e53d..f5503335224 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.32 mage-player-ai-ma diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java index 628472299c1..448105209f1 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java @@ -111,9 +111,8 @@ public class ComputerPlayer7 extends ComputerPlayer6 { Game sim = createSimulation(game); SimulationNode2.resetCount(); root = new SimulationNode2(null, sim, maxDepth, playerId); - addActionsTimed(); - if (root.children != null - && !root.children.isEmpty()) { + addActionsTimed(); // TODO: root can be null again after addActionsTimed O_o need to research (it's a CPU AI problem?) + if (root != null && root.children != null && !root.children.isEmpty()) { logger.trace("After add actions timed: root.children.size = " + root.children.size()); root = root.children.get(0); // prevent repeating always the same action with no cost diff --git a/Mage.Server.Plugins/Mage.Player.AI/pom.xml b/Mage.Server.Plugins/Mage.Player.AI/pom.xml index 81f988b7341..3d07accfddf 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.AI/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.32 mage-player-ai diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/resources/ratings/uma.csv b/Mage.Server.Plugins/Mage.Player.AI/src/main/resources/ratings/uma.csv new file mode 100644 index 00000000000..35b73095988 --- /dev/null +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/resources/ratings/uma.csv @@ -0,0 +1,254 @@ +Bitterblossom:1000 +Mana Vault:986 +Liliana of the Veil:974 +Karn Liberated:964 +Mikaeus, the Unhallowed:954 +Sublime Archangel:945 +Sigarda, Host of Herons:937 +Noble Hierarch:929 +Shriekmaw:922 +Snapcaster Mage:915 +Glen Elendra Archmage:908 +Balefire Dragon:902 +Vengevine:896 +Demonic Tutor:891 +Maelstrom Pulse:885 +Celestial Colonnade:880 +Tasigur, the Golden Fang:875 +Reveillark:870 +Lord of Extinction:865 +Eternal Witness:861 +Tarmogoyf:856 +Woodfall Primus:852 +Eldrazi Conscription:848 +Kitchen Finks:843 +Temporal Manipulation:839 +Fiend Hunter:836 +Dig Through Time:832 +Talrand, Sky Summoner:828 +Chainer's Edict:824 +Faith's Fetters:821 +Creeping Tar Pit:817 +Fire // Ice:814 +Raging Ravine:810 +Reanimate:807 +Platinum Emperion:804 +Moan of the Unhallowed:801 +Fauna Shaman:797 +Sovereigns of Lost Alara:794 +Ancient Tomb:791 +Spider Spawning:788 +Kozilek, Butcher of Truth:785 +Urban Evolution:782 +Young Pyromancer:779 +Angel of Despair:776 +Last Gasp:774 +Rolling Temblor:771 +All Is Dust:768 +Devoted Druid:765 +Fiery Temper:763 +Murderous Redcap:760 +Leovold, Emissary of Trest:757 +Wall of Reverence:755 +Golgari Grave-Troll:752 +Unburial Rites:749 +Mahamoti Djinn:747 +Ulamog, the Infinite Gyre:744 +Stirring Wildwood:742 +Swift Reckoning:739 +Pattern of Rebirth:737 +Dimir Guildmage:735 +Warleader's Helix:732 +Thermo-Alchemist:730 +Penumbra Wurm:727 +Unholy Hunger:725 +Through the Breach:723 +Gurmag Angler:720 +Emancipation Angel:718 +Sleight of Hand:716 +Wild Mongrel:713 +Boar Umbra:711 +Reckless Wurm:709 +Kodama's Reach:707 +Magmaw:705 +Phalanx Leader:702 +Vengeful Rebirth:700 +Emrakul, the Aeons Torn:698 +Daybreak Coronet:696 +Treasure Cruise:694 +Rise from the Tides:691 +Firewing Phoenix:689 +Travel Preparations:687 +Satyr Wayfinder:685 +Engineered Explosives:683 +Entomb:681 +Hero of Iroas:679 +Reya Dawnbringer:677 +Soul's Fire:675 +Become Immense:673 +Containment Priest:670 +Archaeomancer:668 +Slum Reaper:666 +Forbidden Alchemy:664 +Stingerfling Spider:662 +Anger:660 +Artisan of Kozilek:658 +Garna, the Bloodflame:656 +Lavaclaw Reaches:654 +Think Twice:652 +Vexing Devil:650 +Shirei, Shizo's Caretaker:648 +Magus of the Bazaar:646 +Snake Umbra:644 +Ulamog's Crusher:642 +Aethersnipe:640 +Iridescent Drake:638 +Hero of Leina Tower:636 +Mad Prophet:634 +Blast of Genius:633 +Brazen Scourge:631 +Stitched Drake:629 +Faithless Looting:627 +Squee, Goblin Nabob:625 +Ghoulsteed:623 +Resurrection:621 +Life from the Loam:619 +Safehold Elite:617 +Canker Abomination:615 +Flight of Fancy:613 +Frantic Search:611 +Rune Snag:609 +Sigil of the New Dawn:607 +Circular Logic:605 +Hooting Mandrills:603 +Just the Wind:602 +Gaddock Teeg:600 +Wickerbough Elder:598 +Seismic Assault:596 +Deranged Assistant:594 +Marang River Prowler:592 +Rally the Peasants:590 +Wingsteed Rider:588 +Walker of the Grove:586 +Gods Willing:584 +Basking Rootwalla:582 +Scuzzback Marauders:580 +Slippery Bogle:578 +Spider Umbra:576 +Boneyard Wurm:574 +Skywing Aven:572 +Death Denied:571 +Sparkspitter:569 +Staunch-Hearted Warrior:567 +Goryo's Vengeance:565 +Icatian Crier:563 +Golgari Thug:561 +Lotus-Eye Mystics:559 +Conflagrate:557 +Seize the Day:555 +Miraculous Recovery:553 +Molten Birth:551 +Fulminator Mage:549 +Prismatic Lens:547 +Karakas:545 +Dreamscape Artist:543 +Eel Umbra:541 +Skyspear Cavalry:539 +Cathodion:537 +Prey Upon:535 +Grave Scrabbler:533 +Brawn:531 +Wild Hunger:529 +Apprentice Necromancer:527 +Heliod's Pilgrim:525 +Olivia's Dragoon:522 +Phyrexian Tower:520 +Generator Servant:518 +Cavern of Souls:516 +Ghoulcaller's Accomplice:514 +Plumeveil:512 +Pulse of Murasa:510 +Foil:508 +Dark Depths:506 +Hissing Iguanar:503 +Visions of Beyond:501 +Mystic Retrieval:499 +Golgari Charm:497 +Desolate Lighthouse:495 +Disrupting Shoal:492 +Mammoth Umbra:490 +Double Cleave:488 +Verdant Eidolon:486 +Living Lore:483 +Reviving Vapors:481 +Whirlwind Adept:479 +Hyena Umbra:477 +Tethmos High Priest:474 +Countersquall:472 +Terramorphic Expanse:469 +Crow of Dark Tidings:467 +Miming Slime:465 +Ancestor's Chosen:462 +Spirit Cairn:460 +Unstable Mutation:457 +Urborg, Tomb of Yawgmoth:455 +Twins of Maurer Estate:452 +Malevolent Whispers:450 +Shed Weakness:447 +Shielding Plax:445 +Golgari Brownscale:442 +Buried Alive:439 +Arena Athlete:437 +Dawn Charm:434 +Ronom Unicorn:431 +Fecundity:428 +Gamble:426 +Akroan Crusader:423 +Bloodflow Connoisseur:420 +Myr Servitor:417 +Fume Spitter:414 +Sultai Skullkeeper:411 +Rakdos Shred-Freak:408 +Undying Rage:405 +Raid Bombardment:402 +Turn to Mist:399 +Lava Spike:396 +Wandering Champion:392 +Desperate Ritual:389 +Martyr of Sands:386 +Spoils of the Vault:382 +Phyrexian Altar:379 +Conviction:375 +Thespian's Stage:371 +Angelic Renewal:368 +Furnace Celebration:364 +Laboratory Maniac:360 +Reckless Charge:356 +Stitcher's Apprentice:352 +Grave Strength:348 +Runed Halo:343 +Dark Dabbling:339 +Crushing Canopy:334 +Flagstones of Trokair:329 +Rogue's Passage:325 +Mark of the Vampire:320 +Vessel of Endless Rest:314 +Beckon Apparition:309 +Offalsnout:303 +Songs of the Damned:297 +Appetite for Brains:291 +Mage-Ring Network:285 +Nightbird's Clutches:278 +Bridge from Below:271 +Patchwork Gnomes:263 +Ingot Chewer:255 +Sanitarium Skeleton:246 +Mistveil Plains:236 +Repel the Darkness:226 +Back to Basics:214 +Dakmor Salvage:201 +Groundskeeper:186 +Defy Gravity:168 +Nourishing Shoal:145 +Stream of Consciousness:115 +Heap Doll:66 \ No newline at end of file diff --git a/Mage.Server.Plugins/Mage.Player.AIMCTS/pom.xml b/Mage.Server.Plugins/Mage.Player.AIMCTS/pom.xml index d8a75c7fde3..c3c78bb4e93 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMCTS/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.AIMCTS/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.32 mage-player-ai-mcts diff --git a/Mage.Server.Plugins/Mage.Player.AIMinimax/pom.xml b/Mage.Server.Plugins/Mage.Player.AIMinimax/pom.xml index 1cc373afd2b..1a6103ef54d 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMinimax/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.AIMinimax/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.32 mage-player-aiminimax diff --git a/Mage.Server.Plugins/Mage.Player.Human/pom.xml b/Mage.Server.Plugins/Mage.Player.Human/pom.xml index b295f64ad4d..59ecd9969b5 100644 --- a/Mage.Server.Plugins/Mage.Player.Human/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.Human/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.32 mage-player-human diff --git a/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/pom.xml b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/pom.xml index f3cecab6e5f..8e791631f4f 100644 --- a/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/pom.xml +++ b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.32 mage-tournament-boosterdraft diff --git a/Mage.Server.Plugins/Mage.Tournament.Constructed/pom.xml b/Mage.Server.Plugins/Mage.Tournament.Constructed/pom.xml index bec51f060af..91a6ef148f1 100644 --- a/Mage.Server.Plugins/Mage.Tournament.Constructed/pom.xml +++ b/Mage.Server.Plugins/Mage.Tournament.Constructed/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.32 mage-tournament-constructed diff --git a/Mage.Server.Plugins/Mage.Tournament.Sealed/pom.xml b/Mage.Server.Plugins/Mage.Tournament.Sealed/pom.xml index b9aab5d4f47..d51fc65a620 100644 --- a/Mage.Server.Plugins/Mage.Tournament.Sealed/pom.xml +++ b/Mage.Server.Plugins/Mage.Tournament.Sealed/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.32 mage-tournament-sealed diff --git a/Mage.Server.Plugins/pom.xml b/Mage.Server.Plugins/pom.xml index a3ac123d038..6e660046e92 100644 --- a/Mage.Server.Plugins/pom.xml +++ b/Mage.Server.Plugins/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.31 + 1.4.32 mage-server-plugins diff --git a/Mage.Server/manifest.mf b/Mage.Server/manifest.mf deleted file mode 100644 index 1574df4a2de..00000000000 --- a/Mage.Server/manifest.mf +++ /dev/null @@ -1,3 +0,0 @@ -Manifest-Version: 1.0 -X-COMMENT: Main-Class will be added automatically by build - diff --git a/Mage.Server/pom.xml b/Mage.Server/pom.xml index 91d840c5a8c..1ca377aaf5f 100644 --- a/Mage.Server/pom.xml +++ b/Mage.Server/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.31 + 1.4.32 mage-server @@ -258,7 +258,6 @@ mage.server.util.config ./src/main/xml-resources/jaxb/Config/ - -Xcommons-lang diff --git a/Mage.Server/src/main/java/mage/server/MageServerImpl.java b/Mage.Server/src/main/java/mage/server/MageServerImpl.java index 899f113519b..bb6845df113 100644 --- a/Mage.Server/src/main/java/mage/server/MageServerImpl.java +++ b/Mage.Server/src/main/java/mage/server/MageServerImpl.java @@ -1,10 +1,5 @@ - package mage.server; -import java.security.SecureRandom; -import java.util.*; -import java.util.concurrent.ExecutorService; -import javax.management.timer.Timer; import mage.MageException; import mage.cards.decks.DeckCardLists; import mage.cards.repository.CardInfo; @@ -43,6 +38,11 @@ import mage.view.ChatMessage.MessageColor; import org.apache.commons.lang3.StringEscapeUtils; import org.apache.log4j.Logger; +import javax.management.timer.Timer; +import java.security.SecureRandom; +import java.util.*; +import java.util.concurrent.ExecutorService; + /** * @author BetaSteward_at_googlemail.com, noxx */ @@ -227,6 +227,20 @@ public class MageServerImpl implements MageServer { user.showUserMessage("Create tournament", message); throw new MageException("No message"); } + // check if the user satisfies the minimumRating requirement. + int minimumRating = options.getMinimumRating(); + int userRating; + if (options.getMatchOptions().isLimited()) { + userRating = user.getUserData().getLimitedRating(); + } else { + userRating = user.getUserData().getConstructedRating(); + } + if (userRating < minimumRating) { + String message = new StringBuilder("Your rating ").append(userRating) + .append(" is lower than the table requirement ").append(minimumRating).toString(); + user.showUserMessage("Create tournament", message); + throw new MageException("No message"); + } Optional room = GamesRoomManager.instance.getRoom(roomId); if (!room.isPresent()) { @@ -813,27 +827,27 @@ public class MageServerImpl implements MageServer { public void quitDraft(final UUID draftId, final String sessionId) throws MageException { execute("quitDraft", sessionId, () -> { - try { - callExecutor.execute( - () -> { - Optional session = SessionManager.instance.getSession(sessionId); - if (!session.isPresent()) { - logger.error("Session not found : " + sessionId); - } else { - UUID userId = session.get().getUserId(); - UUID tableId = DraftManager.instance.getControllerByDraftId(draftId).getTableId(); - Table table = TableManager.instance.getTable(tableId); - if (table.isTournament()) { - UUID tournamentId = table.getTournament().getId(); - TournamentManager.instance.quit(tournamentId, userId); + try { + callExecutor.execute( + () -> { + Optional session = SessionManager.instance.getSession(sessionId); + if (!session.isPresent()) { + logger.error("Session not found : " + sessionId); + } else { + UUID userId = session.get().getUserId(); + UUID tableId = DraftManager.instance.getControllerByDraftId(draftId).getTableId(); + Table table = TableManager.instance.getTable(tableId); + if (table.isTournament()) { + UUID tournamentId = table.getTournament().getId(); + TournamentManager.instance.quit(tournamentId, userId); + } + } } - } - } - ); - } catch (Exception ex) { - handleException(ex); - } - } + ); + } catch (Exception ex) { + handleException(ex); + } + } ); } @@ -1127,12 +1141,12 @@ public class MageServerImpl implements MageServer { public void toggleActivation(final String sessionId, final String userName) throws MageException { execute("toggleActivation", sessionId, () -> UserManager.instance.getUserByName(userName).ifPresent(user - -> { - user.setActive(!user.isActive()); - if (!user.isActive() && user.isConnected()) { - SessionManager.instance.disconnectUser(sessionId, user.getSessionId()); - } - })); + -> { + user.setActive(!user.isActive()); + if (!user.isActive() && user.isConnected()) { + SessionManager.instance.disconnectUser(sessionId, user.getSessionId()); + } + })); } @Override @@ -1167,8 +1181,8 @@ public class MageServerImpl implements MageServer { if (title != null && message != null) { execute("sendFeedbackMessage", sessionId, () -> SessionManager.instance.getSession(sessionId).ifPresent( - session -> FeedbackServiceImpl.instance.feedback(username, title, type, message, email, session.getHost()) - )); + session -> FeedbackServiceImpl.instance.feedback(username, title, type, message, email, session.getHost()) + )); } } @@ -1293,8 +1307,8 @@ public class MageServerImpl implements MageServer { logger.error("Session not found : " + sessionId); return null; } else { - UUID userId = session.get().getUserId(); - return GameManager.instance.getGameView(gameId, userId, playerId); + //UUID userId = session.get().getUserId(); + return GameManager.instance.getGameView(gameId, playerId); } } } @@ -1386,7 +1400,19 @@ public class MageServerImpl implements MageServer { user.showUserMessage("Create table", "Your quit ratio " + user.getMatchQuitRatio() + "% is higher than the table requirement " + quitRatio + '%'); throw new MageException("No message"); } - + // check if the user satisfies the minimumRating requirement. + int minimumRating = options.getMinimumRating(); + int userRating; + if (options.isLimited()) { + userRating = user.getUserData().getLimitedRating(); + } else { + userRating = user.getUserData().getConstructedRating(); + } + if (userRating < minimumRating) { + String message = new StringBuilder("Your rating ").append(userRating).append(" is lower than the table requirement ").append(minimumRating).toString(); + user.showUserMessage("Create table", message); + throw new MageException("No message"); + } Optional room = GamesRoomManager.instance.getRoom(roomId); if (room.isPresent()) { TableView table = room.get().createTable(userId, options); diff --git a/Mage.Server/src/main/java/mage/server/Main.java b/Mage.Server/src/main/java/mage/server/Main.java index cd64c6086de..39cfef9c589 100644 --- a/Mage.Server/src/main/java/mage/server/Main.java +++ b/Mage.Server/src/main/java/mage/server/Main.java @@ -1,12 +1,5 @@ - package mage.server; -import java.io.File; -import java.io.IOException; -import java.net.InetAddress; -import java.net.MalformedURLException; -import java.util.*; -import javax.management.MBeanServer; import mage.cards.ExpansionSet; import mage.cards.Sets; import mage.cards.repository.CardScanner; @@ -39,13 +32,20 @@ import org.jboss.remoting.transporter.TransporterClient; import org.jboss.remoting.transporter.TransporterServer; import org.w3c.dom.Element; +import javax.management.MBeanServer; +import java.io.File; +import java.io.IOException; +import java.net.InetAddress; +import java.net.MalformedURLException; +import java.util.*; + /** * @author BetaSteward_at_googlemail.com */ public final class Main { private static final Logger logger = Logger.getLogger(Main.class); - private static final MageVersion version = new MageVersion(MageVersion.MAGE_VERSION_MAJOR, MageVersion.MAGE_VERSION_MINOR, MageVersion.MAGE_VERSION_PATCH, MageVersion.MAGE_VERSION_MINOR_PATCH, MageVersion.MAGE_VERSION_INFO); + private static final MageVersion version = new MageVersion(Main.class); private static final String testModeArg = "-testMode="; private static final String fastDBModeArg = "-fastDbMode="; diff --git a/Mage.Server/src/main/java/mage/server/TableController.java b/Mage.Server/src/main/java/mage/server/TableController.java index 1f4d9808cd3..90e7638c6e3 100644 --- a/Mage.Server/src/main/java/mage/server/TableController.java +++ b/Mage.Server/src/main/java/mage/server/TableController.java @@ -1,4 +1,3 @@ - package mage.server; import java.util.Locale; @@ -172,6 +171,21 @@ public class TableController { return false; } + // Check minimum rating. + int minimumRating = table.getTournament().getOptions().getMinimumRating(); + int userRating; + if (table.getTournament().getOptions().getMatchOptions().isLimited()) { + userRating = user.getUserData().getLimitedRating(); + } else { + userRating = user.getUserData().getConstructedRating(); + } + if (userRating < minimumRating) { + String message = new StringBuilder("Your rating ").append(userRating) + .append(" is lower than the table requirement ").append(minimumRating).toString(); + user.showUserMessage("Join Table", message); + return false; + } + Optional playerOptional = createPlayer(name, seat.getPlayerType(), skill); if (playerOptional.isPresent()) { Player player = playerOptional.get(); @@ -225,6 +239,7 @@ public class TableController { public synchronized boolean joinTable(UUID userId, String name, PlayerType playerType, int skill, DeckCardLists deckList, String password) throws MageException { Optional _user = UserManager.instance.getUser(userId); if (!_user.isPresent()) { + logger.error("Join Table: can't find user to join " + name + " Id = " + userId); return false; } User user = _user.get(); @@ -272,6 +287,21 @@ public class TableController { return false; } + // Check minimum rating. + int minimumRating = table.getMatch().getOptions().getMinimumRating(); + int userRating; + if (table.getMatch().getOptions().isLimited()) { + userRating = user.getUserData().getLimitedRating(); + } else { + userRating = user.getUserData().getConstructedRating(); + } + if (userRating < minimumRating) { + String message = new StringBuilder("Your rating ").append(userRating) + .append(" is lower than the table requirement ").append(minimumRating).toString(); + user.showUserMessage("Join Table", message); + return false; + } + // Check power level for table (currently only used for EDH/Commander table) int edhPowerLevel = table.getMatch().getOptions().getEdhPowerLevel(); if (edhPowerLevel > 0 && table.getValidator().getName().toLowerCase(Locale.ENGLISH).equals("commander")) { diff --git a/Mage.Server/src/main/java/mage/server/draft/DraftSession.java b/Mage.Server/src/main/java/mage/server/draft/DraftSession.java index d1e087899a3..1ab6320e97d 100644 --- a/Mage.Server/src/main/java/mage/server/draft/DraftSession.java +++ b/Mage.Server/src/main/java/mage/server/draft/DraftSession.java @@ -48,7 +48,8 @@ public class DraftSession { if (user.isPresent()) { if (futureTimeout != null && !futureTimeout.isDone()) { int remaining = (int) futureTimeout.getDelay(TimeUnit.SECONDS); - user.get().fireCallback(new ClientCallback(ClientCallbackMethod.DRAFT_INIT, draft.getId(), new DraftClientMessage(getDraftPickView(remaining)))); + user.get().fireCallback(new ClientCallback(ClientCallbackMethod.DRAFT_INIT, draft.getId(), + new DraftClientMessage(getDraftView(), getDraftPickView(remaining)))); } return true; } @@ -60,8 +61,8 @@ public class DraftSession { if (!killed) { UserManager.instance .getUser(userId). - ifPresent(user -> user.fireCallback( - new ClientCallback(ClientCallbackMethod.DRAFT_UPDATE, draft.getId(), getDraftView()))); + ifPresent(user -> user.fireCallback(new ClientCallback(ClientCallbackMethod.DRAFT_UPDATE, draft.getId(), + new DraftClientMessage(getDraftView(), null)))); } } @@ -70,7 +71,6 @@ public class DraftSession { UserManager.instance .getUser(userId) .ifPresent(user -> user.fireCallback(new ClientCallback(ClientCallbackMethod.DRAFT_OVER, draft.getId()))); - } } @@ -79,7 +79,8 @@ public class DraftSession { setupTimeout(timeout); UserManager.instance .getUser(userId) - .ifPresent(user -> user.fireCallback(new ClientCallback(ClientCallbackMethod.DRAFT_PICK, draft.getId(), new DraftClientMessage(getDraftPickView(timeout))))); + .ifPresent(user -> user.fireCallback(new ClientCallback(ClientCallbackMethod.DRAFT_PICK, draft.getId(), + new DraftClientMessage(getDraftView(), getDraftPickView(timeout))))); } } diff --git a/Mage.Server/src/main/java/mage/server/game/GameManager.java b/Mage.Server/src/main/java/mage/server/game/GameManager.java index eb5e16b5a57..15884f453cc 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameManager.java +++ b/Mage.Server/src/main/java/mage/server/game/GameManager.java @@ -1,6 +1,12 @@ - package mage.server.game; +import mage.cards.decks.DeckCardLists; +import mage.constants.ManaType; +import mage.constants.PlayerAction; +import mage.game.Game; +import mage.game.GameOptions; +import mage.view.GameView; + import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -9,15 +15,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; -import mage.cards.decks.DeckCardLists; -import mage.constants.ManaType; -import mage.constants.PlayerAction; -import mage.game.Game; -import mage.game.GameOptions; -import mage.view.GameView; /** - * * @author BetaSteward_at_googlemail.com */ public enum GameManager { @@ -38,15 +37,25 @@ public enum GameManager { return gameController.getSessionId(); } + private GameController getGameControllerSafe(UUID gameId) { + final Lock r = gameControllersLock.readLock(); + r.lock(); + try { + return gameControllers.get(gameId); + } finally { + r.unlock(); + } + } + public void joinGame(UUID gameId, UUID userId) { - GameController gameController = gameControllers.get(gameId); + GameController gameController = getGameControllerSafe(gameId); if (gameController != null) { gameController.join(userId); } } public Optional getChatId(UUID gameId) { - GameController gameController = gameControllers.get(gameId); + GameController gameController = getGameControllerSafe(gameId); if (gameController != null) { return Optional.of(gameController.getChatId()); } @@ -54,56 +63,56 @@ public enum GameManager { } public void sendPlayerUUID(UUID gameId, UUID userId, UUID data) { - GameController gameController = gameControllers.get(gameId); + GameController gameController = getGameControllerSafe(gameId); if (gameController != null) { gameController.sendPlayerUUID(userId, data); } } public void sendPlayerString(UUID gameId, UUID userId, String data) { - GameController gameController = gameControllers.get(gameId); + GameController gameController = getGameControllerSafe(gameId); if (gameController != null) { gameController.sendPlayerString(userId, data); } } public void sendPlayerManaType(UUID gameId, UUID playerId, UUID userId, ManaType data) { - GameController gameController = gameControllers.get(gameId); + GameController gameController = getGameControllerSafe(gameId); if (gameController != null) { gameController.sendPlayerManaType(userId, playerId, data); } } public void sendPlayerBoolean(UUID gameId, UUID userId, Boolean data) { - GameController gameController = gameControllers.get(gameId); + GameController gameController = getGameControllerSafe(gameId); if (gameController != null) { gameController.sendPlayerBoolean(userId, data); } } public void sendPlayerInteger(UUID gameId, UUID userId, Integer data) { - GameController gameController = gameControllers.get(gameId); + GameController gameController = getGameControllerSafe(gameId); if (gameController != null) { gameController.sendPlayerInteger(userId, data); } } public void quitMatch(UUID gameId, UUID userId) { - GameController gameController = gameControllers.get(gameId); + GameController gameController = getGameControllerSafe(gameId); if (gameController != null) { gameController.quitMatch(userId); } } public void sendPlayerAction(PlayerAction playerAction, UUID gameId, UUID userId, Object data) { - GameController gameController = gameControllers.get(gameId); + GameController gameController = getGameControllerSafe(gameId); if (gameController != null) { gameController.sendPlayerAction(playerAction, userId, data); } } public boolean watchGame(UUID gameId, UUID userId) { - GameController gameController = gameControllers.get(gameId); + GameController gameController = getGameControllerSafe(gameId); if (gameController != null) { return gameController.watch(userId); } @@ -111,21 +120,21 @@ public enum GameManager { } public void stopWatching(UUID gameId, UUID userId) { - GameController gameController = gameControllers.get(gameId); + GameController gameController = getGameControllerSafe(gameId); if (gameController != null) { gameController.stopWatching(userId); } } public void cheat(UUID gameId, UUID userId, UUID playerId, DeckCardLists deckList) { - GameController gameController = gameControllers.get(gameId); + GameController gameController = getGameControllerSafe(gameId); if (gameController != null) { gameController.cheat(userId, playerId, deckList); } } public boolean cheat(UUID gameId, UUID userId, UUID playerId, String cardName) { - GameController gameController = gameControllers.get(gameId); + GameController gameController = getGameControllerSafe(gameId); if (gameController != null) { return gameController.cheat(userId, playerId, cardName); } @@ -133,7 +142,7 @@ public enum GameManager { } public void removeGame(UUID gameId) { - GameController gameController = gameControllers.get(gameId); + GameController gameController = getGameControllerSafe(gameId); if (gameController != null) { gameController.cleanUp(); final Lock w = gameControllersLock.writeLock(); @@ -147,15 +156,15 @@ public enum GameManager { } public boolean saveGame(UUID gameId) { - GameController gameController = gameControllers.get(gameId); + GameController gameController = getGameControllerSafe(gameId); if (gameController != null) { return gameController.saveGame(); } return false; } - public GameView getGameView(UUID gameId, UUID userId, UUID playerId) { - GameController gameController = gameControllers.get(gameId); + public GameView getGameView(UUID gameId, UUID playerId) { + GameController gameController = getGameControllerSafe(gameId); if (gameController != null) { return gameController.getGameView(playerId); } @@ -163,7 +172,7 @@ public enum GameManager { } public int getNumberActiveGames() { - return gameControllers.size(); + return getGameController().size(); } public Map getGameController() { diff --git a/Mage.Sets/pom.xml b/Mage.Sets/pom.xml index f478419c232..6f88ade019a 100644 --- a/Mage.Sets/pom.xml +++ b/Mage.Sets/pom.xml @@ -7,7 +7,7 @@ org.mage mage-root - 1.4.31 + 1.4.32 org.mage diff --git a/Mage.Sets/src/mage/cards/a/Aeromunculus.java b/Mage.Sets/src/mage/cards/a/Aeromunculus.java new file mode 100644 index 00000000000..0dca6864e6e --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/Aeromunculus.java @@ -0,0 +1,45 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.keyword.AdaptEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Aeromunculus extends CardImpl { + + public Aeromunculus(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{U}"); + + this.subtype.add(SubType.HOMUNCULUS); + this.subtype.add(SubType.MUTANT); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // {2}{G}{U}: Adapt 1. + this.addAbility(new SimpleActivatedAbility( + new AdaptEffect(1), new ManaCostsImpl("{2}{G}{U}") + )); + } + + public Aeromunculus(final Aeromunculus card) { + super(card); + } + + @Override + public Aeromunculus copy() { + return new Aeromunculus(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AetherTide.java b/Mage.Sets/src/mage/cards/a/AetherTide.java new file mode 100644 index 00000000000..fc3c6c4915b --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AetherTide.java @@ -0,0 +1,144 @@ +package mage.cards.a; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.costs.Cost; +import mage.abilities.costs.VariableCostImpl; +import mage.abilities.costs.common.DiscardTargetCost; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.common.FilterCreatureCard; +import mage.filter.common.FilterCreaturePermanent; +import mage.game.Game; +import mage.game.stack.StackObject; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetCardInHand; + +/** + * + * @author jeffwadsworth + */ +public final class AetherTide extends CardImpl { + + public AetherTide(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{U}"); + + // As an additional cost to cast Aether Tide, discard X creature cards. + this.getSpellAbility().addCost(new AetherTideCost()); + + // Return X target creatures to their owners' hands. + this.getSpellAbility().addEffect(new ReturnToHandTargetPermanentEffect()); + + } + + public AetherTide(final AetherTide card) { + super(card); + } + + @Override + public AetherTide copy() { + return new AetherTide(this); + } +} + +class AetherTideCost extends VariableCostImpl { + + public AetherTideCost() { + super("discard X creature cards"); + text = "As an additional cost to cast {this}, discard X creature cards"; + } + + public AetherTideCost(AetherTideCost cost) { + super(cost); + } + + @Override + public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { + return (game.getPlayer(controllerId).getHand().count(new FilterCreatureCard(), game) > 0); + } + + @Override + public int getMaxValue(Ability source, Game game) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + return controller.getHand().count(new FilterCreatureCard(), game); + } + return 0; + } + + @Override + public int getMinValue(Ability source, Game game) { + return 0; + } + + @Override + public Cost getFixedCostsFromAnnouncedValue(int xValue) { + TargetCardInHand target = new TargetCardInHand(xValue, new FilterCreatureCard()); + return new DiscardTargetCost(target); + } + + @Override + public int announceXValue(Ability source, Game game) { + int xValue = 0; + Player controller = game.getPlayer(source.getControllerId()); + StackObject stackObject = game.getStack().getStackObject(source.getId()); + if (controller != null + && stackObject != null) { + xValue = controller.announceXCost(getMinValue(source, game), getMaxValue(source, game), + "Announce the number of creature cards to discard", game, source, this); + } + return xValue; + } + + @Override + public AetherTideCost copy() { + return new AetherTideCost(this); + } + +} + +class ReturnToHandTargetPermanentEffect extends OneShotEffect { + + public ReturnToHandTargetPermanentEffect() { + super(Outcome.ReturnToHand); + setText("Return X target creatures to their owners' hands"); + } + + public ReturnToHandTargetPermanentEffect(final ReturnToHandTargetPermanentEffect effect) { + super(effect); + } + + @Override + public ReturnToHandTargetPermanentEffect copy() { + return new ReturnToHandTargetPermanentEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + int xPaid = source.getCosts().getVariableCosts().get(0).getAmount(); + if (controller != null + && xPaid > 0) { + int available = game.getBattlefield().count(new FilterCreaturePermanent(), + source.getSourceId(), + source.getControllerId(), game); + if (available > 0) { + TargetPermanent target = new TargetPermanent(Math.min(xPaid, available), + xPaid, + new FilterCreaturePermanent("creatures to return to their owner's hands"), + true); + if (controller.chooseTarget(outcome.Detriment, target, source, game)) { + controller.moveCards(new CardsImpl(target.getTargets()), Zone.HAND, source, game); + } + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/a/ApproachOfTheSecondSun.java b/Mage.Sets/src/mage/cards/a/ApproachOfTheSecondSun.java index 1877fee325f..574c2ce7b7c 100644 --- a/Mage.Sets/src/mage/cards/a/ApproachOfTheSecondSun.java +++ b/Mage.Sets/src/mage/cards/a/ApproachOfTheSecondSun.java @@ -1,6 +1,5 @@ package mage.cards.a; -import java.util.*; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -16,6 +15,10 @@ import mage.game.stack.Spell; import mage.players.Player; import mage.watchers.Watcher; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + /** * @author stravant */ @@ -64,7 +67,7 @@ class ApproachOfTheSecondSunEffect extends OneShotEffect { ApproachOfTheSecondSunWatcher watcher = (ApproachOfTheSecondSunWatcher) game.getState().getWatchers().get(ApproachOfTheSecondSunWatcher.class.getSimpleName()); if (watcher != null - && !spell.isCopiedSpell() + && !spell.isCopy() && watcher.getApproachesCast(controller.getId()) > 1 && spell.getFromZone() == Zone.HAND) { // Win the game @@ -74,7 +77,7 @@ class ApproachOfTheSecondSunEffect extends OneShotEffect { controller.gainLife(7, game, source); // Put this into the library as the 7th from the top - if (spell.isCopiedSpell()) { + if (spell.isCopy()) { return true; } Card spellCard = game.getStack().getSpell(source.getSourceId()).getCard(); diff --git a/Mage.Sets/src/mage/cards/b/BeckonApparition.java b/Mage.Sets/src/mage/cards/b/BeckonApparition.java index 523332f22d7..0f22b77c302 100644 --- a/Mage.Sets/src/mage/cards/b/BeckonApparition.java +++ b/Mage.Sets/src/mage/cards/b/BeckonApparition.java @@ -6,7 +6,7 @@ import mage.abilities.effects.common.ExileTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.game.permanent.token.BeckonApparitionToken; +import mage.game.permanent.token.WhiteBlackSpiritToken; import mage.target.common.TargetCardInGraveyard; import java.util.UUID; @@ -22,7 +22,7 @@ public final class BeckonApparition extends CardImpl { // Exile target card from a graveyard. Create a 1/1 white and black Spirit creature token with flying. this.getSpellAbility().addEffect(new ExileTargetEffect()); this.getSpellAbility().addTarget(new TargetCardInGraveyard()); - this.getSpellAbility().addEffect(new CreateTokenEffect(new BeckonApparitionToken(), 1)); + this.getSpellAbility().addEffect(new CreateTokenEffect(new WhiteBlackSpiritToken(), 1)); } public BeckonApparition(final BeckonApparition card) { diff --git a/Mage.Sets/src/mage/cards/b/Bedevil.java b/Mage.Sets/src/mage/cards/b/Bedevil.java new file mode 100644 index 00000000000..83e93908106 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/Bedevil.java @@ -0,0 +1,45 @@ +package mage.cards.b; + +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Bedevil extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("artifact, creature, or planeswalker"); + + static { + filter.add(Predicates.or( + new CardTypePredicate(CardType.ARTIFACT), + new CardTypePredicate(CardType.CREATURE), + new CardTypePredicate(CardType.PLANESWALKER) + )); + } + + public Bedevil(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{B}{B}{R}"); + + // Destroy target artifact, creature, or planeswalker. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); + } + + public Bedevil(final Bedevil card) { + super(card); + } + + @Override + public Bedevil copy() { + return new Bedevil(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BileBlight.java b/Mage.Sets/src/mage/cards/b/BileBlight.java index 64440f8042d..0b237561908 100644 --- a/Mage.Sets/src/mage/cards/b/BileBlight.java +++ b/Mage.Sets/src/mage/cards/b/BileBlight.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.common.continuous.BoostAllEffect; @@ -12,15 +10,17 @@ import mage.constants.Duration; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author Quercitron */ public final class BileBlight extends CardImpl { public BileBlight(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{B}{B}"); // Target creature and all creatures with the same name as that creature get -3/-3 until end of turn. @@ -56,12 +56,12 @@ class BileBlightEffect extends BoostAllEffect { if (this.affectedObjectsSet) { Permanent target = game.getPermanent(getTargetPointer().getFirst(game, source)); if (target != null) { - if (target.getName().isEmpty()) { // face down creature + if (CardUtil.haveEmptyName(target)) { // face down creature affectedObjectList.add(new MageObjectReference(target, game)); } else { String name = target.getName(); for (Permanent perm : game.getBattlefield().getActivePermanents(source.getControllerId(), game)) { - if (perm.getName().equals(name)) { + if (CardUtil.haveSameNames(perm.getName(), name)) { affectedObjectList.add(new MageObjectReference(perm, game)); } } diff --git a/Mage.Sets/src/mage/cards/b/BrainPry.java b/Mage.Sets/src/mage/cards/b/BrainPry.java index 2bebd65d8db..4628af7111f 100644 --- a/Mage.Sets/src/mage/cards/b/BrainPry.java +++ b/Mage.Sets/src/mage/cards/b/BrainPry.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -14,15 +12,17 @@ import mage.constants.Outcome; import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author Styxo */ public final class BrainPry extends CardImpl { public BrainPry(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}"); //Name a nonland card. Target player reveals their hand. That player discards a card with that name. If he or she can't, you draw a card. this.getSpellAbility().addEffect((new ChooseACardNameEffect(ChooseACardNameEffect.TypeOfName.NON_LAND_NAME))); @@ -60,7 +60,7 @@ class BrainPryEffect extends OneShotEffect { if (targetPlayer != null && controller != null && sourceObject != null && cardName != null) { boolean hasDiscarded = false; for (Card card : targetPlayer.getHand().getCards(game)) { - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { targetPlayer.discard(card, source, game); hasDiscarded = true; break; diff --git a/Mage.Sets/src/mage/cards/b/BronzeHorse.java b/Mage.Sets/src/mage/cards/b/BronzeHorse.java new file mode 100644 index 00000000000..28180cf2bb4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BronzeHorse.java @@ -0,0 +1,91 @@ + +package mage.cards.b; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalReplacementEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.PreventAllDamageToSourceEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.stack.Spell; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.target.Target; + +/** + * + * @author L_J + */ +public final class BronzeHorse extends CardImpl { + + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); + + static { + filter.add(new AnotherPredicate()); + } + + public BronzeHorse(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT, CardType.CREATURE},"{7}"); + this.subtype.add(SubType.HORSE); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // As long as you control another creature, prevent all damage that would be dealt to Bronze Horse by spells that target it. + Effect effect = new ConditionalReplacementEffect(new PreventDamageToSourceBySpellsThatTargetIt(), new PermanentsOnTheBattlefieldCondition(filter)); + effect.setText("As long as you control another creature, prevent all damage that would be dealt to {this} by spells that target it."); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + } + + public BronzeHorse(final BronzeHorse card) { + super(card); + } + + @Override + public BronzeHorse copy() { + return new BronzeHorse(this); + } +} + +class PreventDamageToSourceBySpellsThatTargetIt extends PreventAllDamageToSourceEffect { + + public PreventDamageToSourceBySpellsThatTargetIt() { + super(Duration.WhileOnBattlefield); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (super.applies(event, source, game)) { + if (event.getTargetId().equals(source.getSourceId())) { + Spell spell = game.getStack().getSpell(event.getSourceId()); + if (spell != null) { + for (UUID modeId : spell.getStackAbility().getModes().getSelectedModes()) { + Mode mode = spell.getStackAbility().getModes().get(modeId); + for (Target target : mode.getTargets()) { + for (UUID targetId : target.getTargets()) { + if (targetId.equals(source.getSourceId())) { + return true; + } + } + } + } + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/c/CabalTherapy.java b/Mage.Sets/src/mage/cards/c/CabalTherapy.java index 70d7f7863cb..ba03643b0a7 100644 --- a/Mage.Sets/src/mage/cards/c/CabalTherapy.java +++ b/Mage.Sets/src/mage/cards/c/CabalTherapy.java @@ -15,11 +15,11 @@ import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; import mage.target.common.TargetControlledCreaturePermanent; +import mage.util.CardUtil; import java.util.UUID; /** - * * @author jonubuu */ public final class CabalTherapy extends CardImpl { @@ -71,13 +71,13 @@ class CabalTherapyEffect extends OneShotEffect { for (Card card : hand.getCards(game)) { if (card.isSplitCard()) { SplitCard splitCard = (SplitCard) card; - if (splitCard.getLeftHalfCard().getName().equals(cardName)) { + if (CardUtil.haveSameNames(splitCard.getLeftHalfCard().getName(), cardName)) { targetPlayer.discard(card, source, game); - } else if (splitCard.getRightHalfCard().getName().equals(cardName)) { + } else if (CardUtil.haveSameNames(splitCard.getRightHalfCard().getName(), cardName)) { targetPlayer.discard(card, source, game); } } - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { targetPlayer.discard(card, source, game); } } diff --git a/Mage.Sets/src/mage/cards/c/CanalDredger.java b/Mage.Sets/src/mage/cards/c/CanalDredger.java new file mode 100644 index 00000000000..d1a8d2b7bbe --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CanalDredger.java @@ -0,0 +1,52 @@ + +package mage.cards.c; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.InfoEffect; +import mage.abilities.effects.common.PutOnLibraryTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.target.common.TargetCardInYourGraveyard; + +/** + * + * @author L_J + */ +public final class CanalDredger extends CardImpl { + + public CanalDredger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{4}"); + this.subtype.add(SubType.CONSTRUCT); + this.power = new MageInt(1); + this.toughness = new MageInt(5); + + // TODO: Draft specific abilities not implemented + // Draft Canal Dredger face up. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Draft Canal Dredger face up."))); + + // Each player passes the last card from each booster pack to a player who drafted a card named Canal Dredger. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Each player passes the last card from each booster pack to a player who drafted a card named Canal Dredger."))); + + // {T}: Put target card from your graveyard on the bottom of your library. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PutOnLibraryTargetEffect(false), new TapSourceCost()); + ability.addTarget(new TargetCardInYourGraveyard()); + this.addAbility(ability); + } + + public CanalDredger(final CanalDredger card) { + super(card); + } + + @Override + public CanalDredger copy() { + return new CanalDredger(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CandlesOfLeng.java b/Mage.Sets/src/mage/cards/c/CandlesOfLeng.java index a6a8de33be5..ca0dd9384f0 100644 --- a/Mage.Sets/src/mage/cards/c/CandlesOfLeng.java +++ b/Mage.Sets/src/mage/cards/c/CandlesOfLeng.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -17,9 +15,11 @@ import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; import mage.players.Player; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author Styxo */ public final class CandlesOfLeng extends CardImpl { @@ -73,7 +73,7 @@ class CandlesOfLengEffect extends OneShotEffect { controller.revealCards(sourceObject.getName(), cards, game); boolean hasTheSameName = false; for (UUID uuid : controller.getGraveyard()) { - if (card.getName().equals(game.getCard(uuid).getName())) { + if (CardUtil.haveSameNames(card, game.getCard(uuid))) { hasTheSameName = true; } } diff --git a/Mage.Sets/src/mage/cards/c/CircuDimirLobotomist.java b/Mage.Sets/src/mage/cards/c/CircuDimirLobotomist.java index 84ec986fd29..8d8972b26a0 100644 --- a/Mage.Sets/src/mage/cards/c/CircuDimirLobotomist.java +++ b/Mage.Sets/src/mage/cards/c/CircuDimirLobotomist.java @@ -1,4 +1,3 @@ - package mage.cards.c; import mage.MageInt; @@ -136,7 +135,7 @@ class CircuDimirLobotomistRuleModifyingEffect extends ContinuousRuleModifyingEff ExileZone exileZone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source)); if ((exileZone != null)) { for (Card card : exileZone.getCards(game)) { - if ((card.getName().equals(object.getName()))) { + if (CardUtil.haveSameNames(card, object)) { return true; } } diff --git a/Mage.Sets/src/mage/cards/c/CloakOfConfusion.java b/Mage.Sets/src/mage/cards/c/CloakOfConfusion.java new file mode 100644 index 00000000000..782df614d47 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CloakOfConfusion.java @@ -0,0 +1,191 @@ +package mage.cards.c; + +import java.util.UUID; +import mage.constants.SubType; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.AttachEffect; +import mage.constants.Outcome; +import mage.target.TargetPermanent; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.combat.CombatGroup; +import mage.game.events.DamageEvent; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author jeffwadsworth + */ +public final class CloakOfConfusion extends CardImpl { + + public CloakOfConfusion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature you control + TargetPermanent auraTarget = new TargetControlledCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Whenever enchanted creature attacks and isn't blocked, you may have it assign no combat damage this turn. + // If you do, defending player discards a card at random. + this.addAbility(new CloakOfConfusionTriggeredAbility()); + + } + + public CloakOfConfusion(final CloakOfConfusion card) { + super(card); + } + + @Override + public CloakOfConfusion copy() { + return new CloakOfConfusion(this); + } +} + +class CloakOfConfusionTriggeredAbility extends TriggeredAbilityImpl { + + public CloakOfConfusionTriggeredAbility() { + super(Zone.BATTLEFIELD, new CloakOfConfusionEffect(), true); + } + + public CloakOfConfusionTriggeredAbility(final CloakOfConfusionTriggeredAbility ability) { + super(ability); + } + + @Override + public CloakOfConfusionTriggeredAbility copy() { + return new CloakOfConfusionTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.DECLARE_BLOCKERS_STEP; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Permanent aura = game.getPermanentOrLKIBattlefield(getSourceId()); + if (aura != null) { + Permanent enchantedCreature = game.getPermanent(aura.getAttachedTo()); + if (enchantedCreature != null + && enchantedCreature.isAttacking()) { + for (CombatGroup combatGroup : game.getCombat().getGroups()) { + if (combatGroup.getBlockers().isEmpty() + && combatGroup.getAttackers().contains(enchantedCreature.getId())) { + this.getEffects().setTargetPointer( + new FixedTarget(game.getCombat().getDefendingPlayerId( + enchantedCreature.getId(), game))); + return true; + } + } + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever enchanted creature attacks and isn't blocked, " + super.getRule(); + } +} + +class CloakOfConfusionEffect extends OneShotEffect { + + public CloakOfConfusionEffect() { + super(Outcome.Neutral); + this.staticText = "you may have it assign no combat damage this turn. " + + "If you do, defending player discards a card at random"; + } + + public CloakOfConfusionEffect(final CloakOfConfusionEffect effect) { + super(effect); + } + + @Override + public CloakOfConfusionEffect copy() { + return new CloakOfConfusionEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent enchantedCreature = game.getPermanent(game.getPermanent(source.getSourceId()).getAttachedTo()); + if (controller != null) { + if (controller.chooseUse(outcome, "Do you wish to not assign combat damage from " + + enchantedCreature.getName() + " and have the defending player discard a card at random?", source, game)) { + ContinuousEffect effect = new AssignNoCombatDamageTargetEffect(); + effect.setTargetPointer(new FixedTarget(enchantedCreature.getId())); + game.addEffect(effect, source); + Player defendingPlayer = game.getPlayer(targetPointer.getFirst(game, source)); + if (defendingPlayer != null) { + defendingPlayer.discard(1, true, source, game); + } + } + return true; + } + return false; + } +} + +class AssignNoCombatDamageTargetEffect extends ReplacementEffectImpl { + + public AssignNoCombatDamageTargetEffect() { + super(Duration.EndOfTurn, Outcome.Neutral); + } + + public AssignNoCombatDamageTargetEffect(final AssignNoCombatDamageTargetEffect effect) { + super(effect); + } + + @Override + public AssignNoCombatDamageTargetEffect copy() { + return new AssignNoCombatDamageTargetEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + return true; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + switch (event.getType()) { + case DAMAGE_CREATURE: + case DAMAGE_PLAYER: + case DAMAGE_PLANESWALKER: + return true; + default: + return false; + } + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + DamageEvent damageEvent = (DamageEvent) event; + return event.getSourceId().equals(targetPointer.getFirst(game, source)) + && damageEvent.isCombatDamage(); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CommitMemory.java b/Mage.Sets/src/mage/cards/c/CommitMemory.java index eaebaa461e1..4d6c2e77e37 100644 --- a/Mage.Sets/src/mage/cards/c/CommitMemory.java +++ b/Mage.Sets/src/mage/cards/c/CommitMemory.java @@ -82,7 +82,7 @@ class CommitEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + Permanent permanent = game.getPermanent(source.getFirstTarget()); if (permanent != null) { return controller.putCardOnTopXOfLibrary(permanent, game, source, 2); } diff --git a/Mage.Sets/src/mage/cards/c/CommuneWithLava.java b/Mage.Sets/src/mage/cards/c/CommuneWithLava.java index 08cf2112e74..6f4f3bb193a 100644 --- a/Mage.Sets/src/mage/cards/c/CommuneWithLava.java +++ b/Mage.Sets/src/mage/cards/c/CommuneWithLava.java @@ -1,7 +1,5 @@ package mage.cards.c; -import java.util.Set; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.ContinuousEffect; @@ -15,6 +13,9 @@ import mage.players.Player; import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; +import java.util.Set; +import java.util.UUID; + /** * * @author jeffwadsworth @@ -78,7 +79,7 @@ class CommuneWithLavaEffect extends OneShotEffect { class CommuneWithLavaMayPlayEffect extends AsThoughEffectImpl { - int castOnTurn = 0; + private int castOnTurn = 0; public CommuneWithLavaMayPlayEffect() { super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.Custom, Outcome.Benefit); diff --git a/Mage.Sets/src/mage/cards/c/Contempt.java b/Mage.Sets/src/mage/cards/c/Contempt.java new file mode 100644 index 00000000000..1aa4800d05e --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/Contempt.java @@ -0,0 +1,93 @@ +package mage.cards.c; + +import java.util.UUID; +import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; +import mage.abilities.Ability; +import mage.abilities.common.AttacksAttachedTriggeredAbility; +import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.ReturnToHandSourceEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.constants.Outcome; +import mage.target.TargetPermanent; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author jeffwadsworth + */ +public final class Contempt extends CardImpl { + + public Contempt(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Whenever enchanted creature attacks, return it and Contempt to their owners' hands at end of combat. + this.addAbility(new AttacksAttachedTriggeredAbility(new ContemptEffect())); + + } + + public Contempt(final Contempt card) { + super(card); + } + + @Override + public Contempt copy() { + return new Contempt(this); + } +} + +class ContemptEffect extends OneShotEffect { + + ContemptEffect() { + super(Outcome.Detriment); + this.staticText = "return it and {this} to their owners' hands at end of combat."; + } + + ContemptEffect(final ContemptEffect effect) { + super(effect); + } + + @Override + public ContemptEffect copy() { + return new ContemptEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent contempt = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (contempt != null) { + Permanent attachedToPermanent = game.getPermanent(contempt.getAttachedTo()); + if (attachedToPermanent != null) { + Effect effect = new ReturnToHandTargetEffect(); + effect.setTargetPointer(new FixedTarget( + attachedToPermanent.getId())).setText("return " + + attachedToPermanent.getName() + " to owner's hand."); + AtTheEndOfCombatDelayedTriggeredAbility ability = new AtTheEndOfCombatDelayedTriggeredAbility(effect); + game.addDelayedTriggeredAbility(ability, source); + } + Effect effect = new ReturnToHandSourceEffect(); + AtTheEndOfCombatDelayedTriggeredAbility ability = new AtTheEndOfCombatDelayedTriggeredAbility(effect); + game.addDelayedTriggeredAbility(ability, source); + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/c/ConundrumSphinx.java b/Mage.Sets/src/mage/cards/c/ConundrumSphinx.java index dc03cb3c691..ae2ce4eaafc 100644 --- a/Mage.Sets/src/mage/cards/c/ConundrumSphinx.java +++ b/Mage.Sets/src/mage/cards/c/ConundrumSphinx.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -18,9 +16,11 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.players.Player; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author BetaSteward_at_googlemail.com */ public final class ConundrumSphinx extends CardImpl { @@ -85,7 +85,7 @@ class ConundrumSphinxEffect extends OneShotEffect { if (card != null) { Cards cards = new CardsImpl(card); player.revealCards(source, player.getName(), cards, game); - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { player.moveCards(cards, Zone.HAND, source, game); } else { player.putCardsOnBottomOfLibrary(cards, game, source, false); diff --git a/Mage.Sets/src/mage/cards/c/CopyEnchantment.java b/Mage.Sets/src/mage/cards/c/CopyEnchantment.java index f84ee371ddd..53ecbe3072a 100644 --- a/Mage.Sets/src/mage/cards/c/CopyEnchantment.java +++ b/Mage.Sets/src/mage/cards/c/CopyEnchantment.java @@ -2,6 +2,8 @@ package mage.cards.c; import java.util.UUID; + +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.common.EntersBattlefieldAbility; @@ -17,6 +19,7 @@ import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.game.permanent.PermanentCard; import mage.players.Player; import mage.target.Target; import mage.util.functions.EmptyApplyToPermanent; diff --git a/Mage.Sets/src/mage/cards/c/CorrosiveOoze.java b/Mage.Sets/src/mage/cards/c/CorrosiveOoze.java index ac19501f19b..b135e5b7e78 100644 --- a/Mage.Sets/src/mage/cards/c/CorrosiveOoze.java +++ b/Mage.Sets/src/mage/cards/c/CorrosiveOoze.java @@ -1,13 +1,5 @@ - package mage.cards.c; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; @@ -18,12 +10,7 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.TurnPhase; -import mage.constants.WatcherScope; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.EquippedPredicate; import mage.game.Game; @@ -31,10 +18,12 @@ import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.util.CardUtil; import mage.watchers.Watcher; +import java.util.*; + /** - * * @author rscoates */ public final class CorrosiveOoze extends CardImpl { @@ -156,7 +145,7 @@ class CorrosiveOozeCombatWatcher extends Watcher { if (event.getType() == GameEvent.EventType.BLOCKER_DECLARED) { Permanent attacker = game.getPermanent(event.getTargetId()); Permanent blocker = game.getPermanent(event.getSourceId()); - if (attacker != null && attacker.getName().equals("Corrosive Ooze")) { // To check for name is not working if Ooze is copied but name changed + if (attacker != null && CardUtil.haveSameNames(attacker.getName(), "Corrosive Ooze")) { // To check for name is not working if Ooze is copied but name changed if (blocker != null && hasAttachedEquipment(game, blocker)) { MageObjectReference oozeMor = new MageObjectReference(attacker, game); HashSet relatedCreatures = oozeBlocksOrBlocked.getOrDefault(oozeMor, new HashSet<>()); @@ -164,7 +153,7 @@ class CorrosiveOozeCombatWatcher extends Watcher { oozeBlocksOrBlocked.put(oozeMor, relatedCreatures); } } - if (blocker != null && blocker.getName().equals("Corrosive Ooze")) { + if (blocker != null && CardUtil.haveSameNames(blocker.getName(), "Corrosive Ooze")) { if (attacker != null && hasAttachedEquipment(game, attacker)) { MageObjectReference oozeMor = new MageObjectReference(blocker, game); HashSet relatedCreatures = oozeBlocksOrBlocked.getOrDefault(oozeMor, new HashSet<>()); diff --git a/Mage.Sets/src/mage/cards/c/CouncilOfTheAbsolute.java b/Mage.Sets/src/mage/cards/c/CouncilOfTheAbsolute.java index b9b2f943eb3..bf527160874 100644 --- a/Mage.Sets/src/mage/cards/c/CouncilOfTheAbsolute.java +++ b/Mage.Sets/src/mage/cards/c/CouncilOfTheAbsolute.java @@ -1,6 +1,5 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -19,8 +18,9 @@ import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class CouncilOfTheAbsolute extends CardImpl { @@ -92,7 +92,8 @@ class CouncilOfTheAbsoluteReplacementEffect extends ContinuousRuleModifyingEffec public boolean applies(GameEvent event, Ability source, Game game) { if (game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { MageObject object = game.getObject(event.getSourceId()); - if (object != null && object.getName().equals(game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY))) { + String needName = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY); + if (object != null && CardUtil.haveSameNames(object.getName(), needName)) { return true; } } @@ -122,7 +123,8 @@ class CouncilOfTheAbsoluteCostReductionEffect extends CostModificationEffectImpl if ((abilityToModify instanceof SpellAbility) && abilityToModify.isControlledBy(source.getControllerId())) { Card card = game.getCard(abilityToModify.getSourceId()); - return card.getName().equals(game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY)); + String needName = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY); + return CardUtil.haveSameNames(card.getName(), needName); } return false; } diff --git a/Mage.Sets/src/mage/cards/c/CrownOfEmpires.java b/Mage.Sets/src/mage/cards/c/CrownOfEmpires.java index 91c4c727e5b..f5bfddfe290 100644 --- a/Mage.Sets/src/mage/cards/c/CrownOfEmpires.java +++ b/Mage.Sets/src/mage/cards/c/CrownOfEmpires.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.common.SimpleActivatedAbility; @@ -17,6 +15,9 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; + +import java.util.UUID; /** * @author nantuko @@ -24,7 +25,7 @@ import mage.target.targetpointer.FixedTarget; public final class CrownOfEmpires extends CardImpl { public CrownOfEmpires(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); // {3}, {tap}: Tap target creature. Gain control of that creature instead if you control artifacts named Scepter of Empires and Throne of Empires. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CrownOfEmpiresEffect(), new GenericManaCost(3)); @@ -60,9 +61,9 @@ class CrownOfEmpiresEffect extends OneShotEffect { boolean scepter = false; boolean throne = false; for (Permanent permanent : game.getBattlefield().getAllActivePermanents(source.getControllerId())) { - if (permanent.getName().equals("Scepter of Empires")) { + if (CardUtil.haveSameNames(permanent.getName(), "Scepter of Empires")) { scepter = true; - } else if (permanent.getName().equals("Throne of Empires")) { + } else if (CardUtil.haveSameNames(permanent.getName(), "Throne of Empires")) { throne = true; } if (scepter && throne) break; diff --git a/Mage.Sets/src/mage/cards/c/Cunning.java b/Mage.Sets/src/mage/cards/c/Cunning.java new file mode 100644 index 00000000000..505c10898ac --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/Cunning.java @@ -0,0 +1,89 @@ +package mage.cards.c; + +import java.util.UUID; +import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.AttacksOrBlocksEnchantedTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.delayed.AtTheBeginOfNextCleanupDelayedTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.constants.Outcome; +import mage.target.TargetPermanent; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author jeffwadsworth + */ +public final class Cunning extends CardImpl { + + public Cunning(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Enchanted creature gets +3/+3. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(3, 3))); + + // When enchanted creature attacks or blocks, sacrifice Cunning at the beginning of the next cleanup step. + this.addAbility(new AttacksOrBlocksEnchantedTriggeredAbility(Zone.BATTLEFIELD, + new SacrificeSourceBeginningCleanupStepEffect())); + } + + public Cunning(final Cunning card) { + super(card); + } + + @Override + public Cunning copy() { + return new Cunning(this); + } +} + +class SacrificeSourceBeginningCleanupStepEffect extends OneShotEffect { + + public SacrificeSourceBeginningCleanupStepEffect() { + super(Outcome.Sacrifice); + this.staticText = "sacrifice {this} at the beginning of the next cleanup step"; + } + + public SacrificeSourceBeginningCleanupStepEffect(final SacrificeSourceBeginningCleanupStepEffect effect) { + super(effect); + } + + @Override + public SacrificeSourceBeginningCleanupStepEffect copy() { + return new SacrificeSourceBeginningCleanupStepEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent cunning = game.getPermanent(source.getSourceId()); + if (cunning != null) { + DelayedTriggeredAbility delayedAbility + = new AtTheBeginOfNextCleanupDelayedTriggeredAbility( + new SacrificeSourceEffect()); + game.addDelayedTriggeredAbility(delayedAbility, source); + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/c/CursedScroll.java b/Mage.Sets/src/mage/cards/c/CursedScroll.java index 0278616567f..e0ec2592d77 100644 --- a/Mage.Sets/src/mage/cards/c/CursedScroll.java +++ b/Mage.Sets/src/mage/cards/c/CursedScroll.java @@ -1,6 +1,5 @@ package mage.cards.c; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -16,11 +15,12 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetAnyTarget; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author jeffwadsworth - * */ public final class CursedScroll extends CardImpl { @@ -70,7 +70,7 @@ class CursedScrollEffect extends OneShotEffect { } revealed.add(card); controller.revealCards(sourceObject.getIdName(), revealed, game); - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { Permanent creature = game.getPermanent(targetPointer.getFirst(game, source)); if (creature != null) { creature.damage(2, source.getSourceId(), game, false, true); diff --git a/Mage.Sets/src/mage/cards/d/DealBroker.java b/Mage.Sets/src/mage/cards/d/DealBroker.java new file mode 100644 index 00000000000..432f5836934 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DealBroker.java @@ -0,0 +1,50 @@ + +package mage.cards.d; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.DrawDiscardControllerEffect; +import mage.abilities.effects.common.InfoEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; + +/** + * + * @author L_J + */ +public final class DealBroker extends CardImpl { + + public DealBroker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT, CardType.CREATURE},"{3}"); + this.subtype.add(SubType.CONSTRUCT); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // TODO: Draft specific abilities not implemented + // Draft Deal Broker face up. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Draft Deal Broker face up."))); + + // Immediately after the draft, you may reveal a card in your card pool. Each other player may offer you one card in their card pool in exchange. You may accept any one offer. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Immediately after the draft, you may reveal a card in your card pool. " + + "Each other player may offer you one card in their card pool in exchange. You may accept any one offer."))); + + // {T}: Draw a card, then discard a card. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawDiscardControllerEffect(), new TapSourceCost())); + } + + public DealBroker(final DealBroker card) { + super(card); + } + + @Override + public DealBroker copy() { + return new DealBroker(this); + } + +} diff --git a/Mage.Sets/src/mage/cards/d/DeclarationInStone.java b/Mage.Sets/src/mage/cards/d/DeclarationInStone.java index f53ddd93aea..45cfb5b117f 100644 --- a/Mage.Sets/src/mage/cards/d/DeclarationInStone.java +++ b/Mage.Sets/src/mage/cards/d/DeclarationInStone.java @@ -1,9 +1,5 @@ - package mage.cards.d; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -20,9 +16,13 @@ import mage.game.permanent.PermanentToken; import mage.game.permanent.token.ClueArtifactToken; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import mage.util.CardUtil; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; /** - * * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) */ public final class DeclarationInStone extends CardImpl { @@ -66,7 +66,7 @@ class DeclarationInStoneEffect extends OneShotEffect { if (targetPermanent != null) { Set cardsToExile = new HashSet<>(); int nonTokenCount = 0; - if (targetPermanent.getName().isEmpty()) { // face down creature + if (CardUtil.haveEmptyName(targetPermanent)) { // face down creature cardsToExile.add(targetPermanent); if (!(targetPermanent instanceof PermanentToken)) { nonTokenCount++; @@ -78,7 +78,7 @@ class DeclarationInStoneEffect extends OneShotEffect { } for (Permanent permanent : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURES, targetPermanent.getControllerId(), game)) { if (!permanent.getId().equals(targetPermanent.getId()) - && permanent.getName().equals(targetPermanent.getName())) { + && CardUtil.haveSameNames(permanent, targetPermanent)) { cardsToExile.add(permanent); // exiled count only matters for non-tokens if (!(permanent instanceof PermanentToken)) { diff --git a/Mage.Sets/src/mage/cards/d/DementiaSliver.java b/Mage.Sets/src/mage/cards/d/DementiaSliver.java index b6ed7191236..40719b4412a 100644 --- a/Mage.Sets/src/mage/cards/d/DementiaSliver.java +++ b/Mage.Sets/src/mage/cards/d/DementiaSliver.java @@ -1,6 +1,5 @@ package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -18,9 +17,11 @@ import mage.filter.predicate.mageobject.SubtypePredicate; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetOpponent; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author fireshoes */ public final class DementiaSliver extends CardImpl { @@ -44,9 +45,9 @@ public final class DementiaSliver extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect(gainedAbility, Duration.WhileOnBattlefield, filter, "All Slivers have \"{T}: Choose a card name. " - + "Target opponent reveals a card at random from their hand." - + " If that card has the chosen name, that player discards it." - + " Activate this ability only during your turn.\"" + + "Target opponent reveals a card at random from their hand." + + " If that card has the chosen name, that player discards it." + + " Activate this ability only during your turn.\"" ) )); } @@ -84,7 +85,7 @@ class DementiaSliverEffect extends OneShotEffect { if (card != null) { revealed.add(card); opponent.revealCards(sourceObject.getName(), revealed, game); - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { opponent.discard(card, source, game); } } diff --git a/Mage.Sets/src/mage/cards/d/Denied.java b/Mage.Sets/src/mage/cards/d/Denied.java index 534d1a1a5f6..a896f1e1630 100644 --- a/Mage.Sets/src/mage/cards/d/Denied.java +++ b/Mage.Sets/src/mage/cards/d/Denied.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ChooseACardNameEffect; @@ -11,19 +9,21 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.game.Game; -import mage.players.Player; import mage.game.stack.Spell; +import mage.players.Player; import mage.target.TargetSpell; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author L_J */ public final class Denied extends CardImpl { public Denied(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{U}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}"); + // Choose a card name, then target spell's controller reveals their hand. If a card with the chosen name is revealed this way, counter that spell. this.getSpellAbility().addEffect(new ChooseACardNameEffect(ChooseACardNameEffect.TypeOfName.ALL)); this.getSpellAbility().addEffect(new DeniedEffect()); @@ -63,7 +63,7 @@ class DeniedEffect extends OneShotEffect { player.revealCards("Denied!", player.getHand(), game, true); String namedCard = (String) object; for (Card card : player.getHand().getCards(game)) { - if (card != null && card.getName().equals(namedCard)) { + if (card != null && CardUtil.haveSameNames(card.getName(), namedCard)) { game.getStack().counter(targetSpell.getId(), source.getSourceId(), game); break; } diff --git a/Mage.Sets/src/mage/cards/d/DetentionSphere.java b/Mage.Sets/src/mage/cards/d/DetentionSphere.java index 5c7466c0b93..64943101ae9 100644 --- a/Mage.Sets/src/mage/cards/d/DetentionSphere.java +++ b/Mage.Sets/src/mage/cards/d/DetentionSphere.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -25,8 +23,9 @@ import mage.target.TargetPermanent; import mage.util.CardUtil; import org.apache.log4j.Logger; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class DetentionSphere extends CardImpl { @@ -81,12 +80,12 @@ class DetentionSphereEntersEffect extends OneShotEffect { MageObject sourceObject = game.getObject(source.getSourceId()); if (sourceObject != null && exileId != null && targetPermanent != null && controller != null) { - if (targetPermanent.getName().isEmpty()) { // face down creature + if (CardUtil.haveEmptyName(targetPermanent)) { // face down creature controller.moveCardToExileWithInfo(targetPermanent, exileId, sourceObject.getIdName(), source.getSourceId(), game, Zone.BATTLEFIELD, true); } else { String name = targetPermanent.getName(); for (Permanent permanent : game.getBattlefield().getActivePermanents(source.getControllerId(), game)) { - if (permanent != null && permanent.getName().equals(name)) { + if (permanent != null && CardUtil.haveSameNames(permanent.getName(), name)) { controller.moveCardToExileWithInfo(permanent, exileId, sourceObject.getIdName(), source.getSourceId(), game, Zone.BATTLEFIELD, true); } } diff --git a/Mage.Sets/src/mage/cards/d/DiviningWitch.java b/Mage.Sets/src/mage/cards/d/DiviningWitch.java index 1a7c10667c8..39e231aa203 100644 --- a/Mage.Sets/src/mage/cards/d/DiviningWitch.java +++ b/Mage.Sets/src/mage/cards/d/DiviningWitch.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -21,9 +19,11 @@ import mage.constants.Zone; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInHand; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author maxlebedev */ public final class DiviningWitch extends CardImpl { @@ -92,7 +92,7 @@ public final class DiviningWitch extends CardImpl { if (card != null) { cardsToReaveal.add(card); // Put that card into your hand - if (card.getName().equals(name)) { + if (CardUtil.haveSameNames(card.getName(), name)) { cardToHand = card; break; } diff --git a/Mage.Sets/src/mage/cards/d/DizzyingGaze.java b/Mage.Sets/src/mage/cards/d/DizzyingGaze.java new file mode 100644 index 00000000000..83f24c04ec2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DizzyingGaze.java @@ -0,0 +1,71 @@ +package mage.cards.d; + +import java.util.UUID; +import mage.constants.SubType; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.constants.Outcome; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author jeffwadsworth + */ +public final class DizzyingGaze extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("with flying"); + + static { + filter.add(new AbilityPredicate(FlyingAbility.class)); + } + + public DizzyingGaze(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{R}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature you control + TargetPermanent auraTarget = new TargetControlledCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // {R}: Enchanted creature deals 1 damage to target creature with flying. + Ability ability2 = new SimpleActivatedAbility(new DamageTargetEffect(1), new ManaCostsImpl("{R}")); + ability2.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new GainAbilityAttachedEffect( + ability2, + AttachmentType.AURA, + Duration.WhileOnBattlefield))); + + } + + public DizzyingGaze(final DizzyingGaze card) { + super(card); + } + + @Override + public DizzyingGaze copy() { + return new DizzyingGaze(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DragonlordKolaghan.java b/Mage.Sets/src/mage/cards/d/DragonlordKolaghan.java index dab3732b81f..5c793c9bf7e 100644 --- a/Mage.Sets/src/mage/cards/d/DragonlordKolaghan.java +++ b/Mage.Sets/src/mage/cards/d/DragonlordKolaghan.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.SimpleStaticAbility; @@ -13,20 +11,18 @@ import mage.abilities.keyword.HasteAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.SuperType; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.stack.Spell; import mage.players.Player; import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class DragonlordKolaghan extends CardImpl { @@ -95,7 +91,7 @@ class DragonlordKolaghanTriggeredAbility extends TriggeredAbilityImpl { Player opponent = game.getPlayer(event.getPlayerId()); boolean sameName = false; for (Card graveCard : opponent.getGraveyard().getCards(game)) { - if (graveCard.getName().equals(spell.getName())) { + if (CardUtil.haveSameNames(graveCard, spell)) { sameName = true; break; } diff --git a/Mage.Sets/src/mage/cards/d/DreadWight.java b/Mage.Sets/src/mage/cards/d/DreadWight.java new file mode 100644 index 00000000000..0bdf71c0ee8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DreadWight.java @@ -0,0 +1,237 @@ +package mage.cards.d; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.ContinuousRuleModifyingEffect; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.effects.common.counter.RemoveCounterSourceEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.permanent.Permanent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author jeffwadsworth + */ +public final class DreadWight extends CardImpl { + + public DreadWight(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); + + this.subtype.add(SubType.ZOMBIE); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // At end of combat, put a paralyzation counter on each creature blocking or blocked by Dread Wight and tap those creatures. Each of those creatures doesn't untap during its controller's untap step for as long as it has a paralyzation counter on it. Each of those creatures gains "{4}: Remove a paralyzation counter from this creature." + this.addAbility(new DreadWightTriggeredAbility( + new CreateDelayedTriggeredAbilityEffect( + new AtTheEndOfCombatDelayedTriggeredAbility( + new DreadWightEffect())))); + + } + + public DreadWight(final DreadWight card) { + super(card); + } + + @Override + public DreadWight copy() { + return new DreadWight(this); + } +} + +class DreadWightTriggeredAbility extends TriggeredAbilityImpl { + + DreadWightTriggeredAbility(Effect effect) { + super(Zone.BATTLEFIELD, effect); + this.usesStack = false; + } + + DreadWightTriggeredAbility(final DreadWightTriggeredAbility ability) { + super(ability); + } + + @Override + public DreadWightTriggeredAbility copy() { + return new DreadWightTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return (event.getType() == EventType.BLOCKER_DECLARED); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getSourceId().equals(getSourceId())) { // Dread Wight is the blocker + getAllEffects().setTargetPointer(new FixedTarget(event.getTargetId())); + return true; + } + if (event.getTargetId().equals(getSourceId())) { // Dread Wight is the attacker + getAllEffects().setTargetPointer(new FixedTarget(event.getSourceId())); + return true; + } + return false; + } + + @Override + public String getRule() { + return super.getRule(); + } +} + +class DreadWightEffect extends OneShotEffect { + + String rule = "doesn't untap during its controller's untap step for as long as it has a paralyzation counter on it."; + + public DreadWightEffect() { + super(Outcome.Detriment); + this.staticText = "put a paralyzation counter on each creature blocking or blocked by {this} and tap those creatures. " + + "Each of those creatures doesn't untap during its controller's untap step for as long as it has a paralyzation counter on it. " + + "Each of those creatures gains \"{4}: Remove a paralyzation counter from this creature.\""; + } + + public DreadWightEffect(final DreadWightEffect effect) { + super(effect); + } + + @Override + public DreadWightEffect copy() { + return new DreadWightEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source)); + if (permanent != null) { + // add paralyzation counter + Effect effect = new AddCountersTargetEffect(CounterType.PARALYZATION.createInstance()); + effect.setTargetPointer(new FixedTarget(permanent.getId())); + effect.apply(game, source); + // tap permanent + permanent.tap(game); + // does not untap while paralyzation counter is on it + ContinuousRuleModifyingEffect effect2 = new DreadWightDoNotUntapEffect( + Duration.WhileOnBattlefield, + permanent.getId()); + effect2.setText("This creature doesn't untap during its controller's untap step for as long as it has a paralyzation counter on it"); + Condition condition = new DreadWightCounterCondition(permanent.getId()); + ConditionalContinuousRuleModifyingEffect conditionalEffect = new ConditionalContinuousRuleModifyingEffect( + effect2, + condition); + Ability ability = new SimpleStaticAbility( + Zone.BATTLEFIELD, + conditionalEffect); + ContinuousEffect effect3 = new GainAbilityTargetEffect( + ability, + Duration.WhileOnBattlefield); + ability.setRuleVisible(true); + effect3.setTargetPointer(new FixedTarget(permanent.getId())); + game.addEffect(effect3, source); + // each gains 4: remove paralyzation counter + Ability activatedAbility = new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new RemoveCounterSourceEffect(CounterType.PARALYZATION.createInstance()), + new ManaCostsImpl("{4}")); + ContinuousEffect effect4 = new GainAbilityTargetEffect( + activatedAbility, + Duration.WhileOnBattlefield); + effect4.setTargetPointer(new FixedTarget(permanent.getId())); + game.addEffect(effect4, source); + return true; + } + return false; + } +} + +class DreadWightDoNotUntapEffect extends ContinuousRuleModifyingEffectImpl { + + UUID permanentId; + + public DreadWightDoNotUntapEffect(Duration duration, UUID permanentId) { + super(duration, Outcome.Detriment); + this.permanentId = permanentId; + } + + public DreadWightDoNotUntapEffect(final DreadWightDoNotUntapEffect effect) { + super(effect); + this.permanentId = effect.permanentId; + } + + @Override + public DreadWightDoNotUntapEffect copy() { + return new DreadWightDoNotUntapEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public String getInfoMessage(Ability source, GameEvent event, Game game) { + Permanent permanentToUntap = game.getPermanent((event.getTargetId())); + if (permanentToUntap != null) { + return permanentToUntap.getLogName() + " doesn't untap."; + } + return null; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.UNTAP; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return event.getTargetId() == permanentId + && game.isActivePlayer(game.getPermanent(permanentId).getControllerId()); + } +} + +class DreadWightCounterCondition implements Condition { + + UUID permanentId; + + public DreadWightCounterCondition(UUID permanentId) { + this.permanentId = permanentId; + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(permanentId); + if (permanent != null) { + return permanent.getCounters(game).getCount(CounterType.PARALYZATION) > 0; + } + return false; + } + + @Override + public String toString() { + return "has counter on it"; + } +} diff --git a/Mage.Sets/src/mage/cards/d/Duplicity.java b/Mage.Sets/src/mage/cards/d/Duplicity.java new file mode 100644 index 00000000000..42fd7d75ab4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/Duplicity.java @@ -0,0 +1,200 @@ +package mage.cards.d; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.BeginningOfYourEndStepTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.discard.DiscardControllerEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.players.Player; +import mage.util.CardUtil; + +/** + * + * @author jeffwadsworth + */ +public final class Duplicity extends CardImpl { + + public Duplicity(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}{U}"); + + // When Duplicity enters the battlefield, exile the top five cards of your library face down. + this.addAbility(new EntersBattlefieldTriggeredAbility(new DuplicityEffect(), false)); + + // At the beginning of your upkeep, you may exile all cards from your hand face down. If you do, put all other cards you own exiled with Duplicity into your hand. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new DuplicityExileHandEffect(), TargetController.YOU, true)); + + // At the beginning of your end step, discard a card. + this.addAbility(new BeginningOfYourEndStepTriggeredAbility(new DiscardControllerEffect(1), false)); + + // When you lose control of Duplicity, put all cards exiled with Duplicity into their owner's graveyard. + this.addAbility(new LoseControlDuplicity()); + + } + + public Duplicity(final Duplicity card) { + super(card); + } + + @Override + public Duplicity copy() { + return new Duplicity(this); + } +} + +class DuplicityEffect extends OneShotEffect { + + public DuplicityEffect() { + super(Outcome.Exile); + staticText = "exile the top five cards of your library face down"; + } + + public DuplicityEffect(final DuplicityEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = game.getObject(source.getSourceId()); + if (controller != null + && sourceObject != null) { + if (controller.getLibrary().hasCards()) { + UUID exileId = CardUtil.getCardExileZoneId(game, source); + Set cardsToExile = controller.getLibrary().getTopCards(game, 5); + for (Card card : cardsToExile) { + controller.moveCardsToExile(card, source, game, true, exileId, sourceObject.getName()); + card.setFaceDown(true, game); + } + } + return true; + } + return false; + } + + @Override + public DuplicityEffect copy() { + return new DuplicityEffect(this); + } +} + +class DuplicityExileHandEffect extends OneShotEffect { + + public DuplicityExileHandEffect() { + super(Outcome.Exile); + staticText = "you may exile all cards from your hand face down. If you do, put all other cards you own exiled with {this} into your hand"; + } + + public DuplicityExileHandEffect(final DuplicityExileHandEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = game.getObject(source.getSourceId()); + if (controller != null + && sourceObject != null) { + if (!controller.getHand().isEmpty()) { + UUID exileId = CardUtil.getCardExileZoneId(game, source); + Set cardsFromHandToExile = controller.getHand().getCards(game); + for (Card card : cardsFromHandToExile) { + controller.moveCardsToExile(card, source, game, true, exileId, sourceObject.getName()); + card.setFaceDown(true, game); + } + Set cardsInExile = game.getExile().getExileZone(exileId).getCards(game); + Set cardsToReturnToHandFromExile = new HashSet<>(); + for (Card card : cardsInExile) { + if (!cardsFromHandToExile.contains(card)) { + cardsToReturnToHandFromExile.add(card); + } + } + controller.moveCards(cardsToReturnToHandFromExile, Zone.HAND, source, game); + } + return true; + } + return false; + } + + @Override + public DuplicityExileHandEffect copy() { + return new DuplicityExileHandEffect(this); + } +} + +class LoseControlDuplicity extends DelayedTriggeredAbility { + + public LoseControlDuplicity() { + super(new PutExiledCardsInOwnersGraveyard(), Duration.EndOfGame, false); + } + + public LoseControlDuplicity(final LoseControlDuplicity ability) { + super(ability); + } + + @Override + public LoseControlDuplicity copy() { + return new LoseControlDuplicity(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.LOST_CONTROL; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return event.getPlayerId().equals(controllerId); + } + + @Override + public String getRule() { + return "When you lose control of {this}, put all cards exiled with {this} into their owner's graveyard."; + } +} + +class PutExiledCardsInOwnersGraveyard extends OneShotEffect { + + public PutExiledCardsInOwnersGraveyard() { + super(Outcome.Neutral); + staticText = " put all cards exiled with {this} into their owner's graveyard."; + } + + public PutExiledCardsInOwnersGraveyard(final PutExiledCardsInOwnersGraveyard effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = game.getObject(source.getSourceId()); + if (controller != null + && sourceObject != null) { + UUID exileId = CardUtil.getCardExileZoneId(game, source); + Set cardsInExile = game.getExile().getExileZone(exileId).getCards(game); + controller.moveCardsToGraveyardWithInfo(cardsInExile, source, game, Zone.EXILED); + return true; + } + return false; + } + + @Override + public PutExiledCardsInOwnersGraveyard copy() { + return new PutExiledCardsInOwnersGraveyard(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EchoingCalm.java b/Mage.Sets/src/mage/cards/e/EchoingCalm.java index badff50bda7..681ad75a60a 100644 --- a/Mage.Sets/src/mage/cards/e/EchoingCalm.java +++ b/Mage.Sets/src/mage/cards/e/EchoingCalm.java @@ -1,7 +1,5 @@ - package mage.cards.e; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; @@ -12,6 +10,9 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetEnchantmentPermanent; +import mage.util.CardUtil; + +import java.util.UUID; /** * @author Loki @@ -19,7 +20,7 @@ import mage.target.common.TargetEnchantmentPermanent; public final class EchoingCalm extends CardImpl { public EchoingCalm(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); // Destroy target enchantment and all other enchantments with the same name as that enchantment. @@ -58,9 +59,9 @@ class EchoingCalmEffect extends OneShotEffect { Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); if (controller != null && permanent != null) { permanent.destroy(source.getSourceId(), game, false); - if (!permanent.getName().isEmpty()) { // in case of face down enchantment creature + if (!CardUtil.haveEmptyName(permanent)) { // in case of face down enchantment creature for (Permanent perm : game.getBattlefield().getActivePermanents(source.getControllerId(), game)) { - if (!perm.getId().equals(permanent.getId()) && perm.getName().equals(permanent.getName()) && perm.isEnchantment()) { + if (!perm.getId().equals(permanent.getId()) && CardUtil.haveSameNames(perm, permanent) && perm.isEnchantment()) { perm.destroy(source.getSourceId(), game, false); } } diff --git a/Mage.Sets/src/mage/cards/e/EchoingCourage.java b/Mage.Sets/src/mage/cards/e/EchoingCourage.java index abacfc33859..b256f031a22 100644 --- a/Mage.Sets/src/mage/cards/e/EchoingCourage.java +++ b/Mage.Sets/src/mage/cards/e/EchoingCourage.java @@ -1,7 +1,5 @@ - package mage.cards.e; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; @@ -17,15 +15,17 @@ import mage.filter.predicate.permanent.PermanentIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class EchoingCourage extends CardImpl { public EchoingCourage(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); // Target creature and all other creatures with the same name as that creature get +2/+2 until end of turn. @@ -64,12 +64,12 @@ class EchoingCourageEffect extends OneShotEffect { Permanent targetPermanent = game.getPermanent(targetPointer.getFirst(game, source)); if (targetPermanent != null) { FilterCreaturePermanent filter = new FilterCreaturePermanent(); - if (targetPermanent.getName().isEmpty()) { + if (CardUtil.haveEmptyName(targetPermanent)) { filter.add(new PermanentIdPredicate(targetPermanent.getId())); // if no name (face down creature) only the creature itself is selected } else { filter.add(new NamePredicate(targetPermanent.getName())); } - ContinuousEffect effect = new BoostAllEffect(2,2, Duration.EndOfTurn, filter, false); + ContinuousEffect effect = new BoostAllEffect(2, 2, Duration.EndOfTurn, filter, false); game.addEffect(effect, source); return true; } diff --git a/Mage.Sets/src/mage/cards/e/EchoingDecay.java b/Mage.Sets/src/mage/cards/e/EchoingDecay.java index 2d4523d0dca..89d14b83f82 100644 --- a/Mage.Sets/src/mage/cards/e/EchoingDecay.java +++ b/Mage.Sets/src/mage/cards/e/EchoingDecay.java @@ -1,7 +1,5 @@ - package mage.cards.e; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; @@ -17,15 +15,17 @@ import mage.filter.predicate.permanent.PermanentIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author fireshoes */ public final class EchoingDecay extends CardImpl { public EchoingDecay(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}"); // Target creature and all other creatures with the same name as that creature get -2/-2 until end of turn. this.getSpellAbility().addEffect(new EchoingDecayEffect()); @@ -63,12 +63,12 @@ class EchoingDecayEffect extends OneShotEffect { Permanent targetPermanent = game.getPermanent(targetPointer.getFirst(game, source)); if (targetPermanent != null) { FilterCreaturePermanent filter = new FilterCreaturePermanent(); - if (targetPermanent.getName().isEmpty()) { + if (CardUtil.haveEmptyName(targetPermanent)) { filter.add(new PermanentIdPredicate(targetPermanent.getId())); // if no name (face down creature) only the creature itself is selected } else { filter.add(new NamePredicate(targetPermanent.getName())); } - ContinuousEffect effect = new BoostAllEffect(-2,-2, Duration.EndOfTurn, filter, false); + ContinuousEffect effect = new BoostAllEffect(-2, -2, Duration.EndOfTurn, filter, false); game.addEffect(effect, source); return true; } diff --git a/Mage.Sets/src/mage/cards/e/EchoingRuin.java b/Mage.Sets/src/mage/cards/e/EchoingRuin.java index abc6a98bc00..738dba3ba8e 100644 --- a/Mage.Sets/src/mage/cards/e/EchoingRuin.java +++ b/Mage.Sets/src/mage/cards/e/EchoingRuin.java @@ -1,7 +1,5 @@ - package mage.cards.e; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; @@ -14,21 +12,23 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPermanent; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author fireshoes */ public final class EchoingRuin extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("artifact"); + private static final FilterPermanent filter = new FilterPermanent("artifact"); + - static { filter.add(new CardTypePredicate(CardType.ARTIFACT)); } public EchoingRuin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{R}"); // Destroy target artifact and all other artifacts with the same name as that artifact. this.getSpellAbility().addTarget(new TargetPermanent(filter)); @@ -66,9 +66,9 @@ class EchoingRuinEffect extends OneShotEffect { Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); if (controller != null && permanent != null) { permanent.destroy(source.getSourceId(), game, false); - if (!permanent.getName().isEmpty()) { // in case of face down artifact creature + if (!CardUtil.haveEmptyName(permanent)) { // in case of face down artifact creature for (Permanent perm : game.getBattlefield().getActivePermanents(source.getControllerId(), game)) { - if (!perm.getId().equals(permanent.getId()) && perm.getName().equals(permanent.getName()) && perm.isArtifact()) { + if (!perm.getId().equals(permanent.getId()) && CardUtil.haveSameNames(perm, permanent) && perm.isArtifact()) { perm.destroy(source.getSourceId(), game, false); } } diff --git a/Mage.Sets/src/mage/cards/e/EchoingTruth.java b/Mage.Sets/src/mage/cards/e/EchoingTruth.java index d48bd10ee2d..d7a542dbc4f 100644 --- a/Mage.Sets/src/mage/cards/e/EchoingTruth.java +++ b/Mage.Sets/src/mage/cards/e/EchoingTruth.java @@ -1,7 +1,5 @@ - package mage.cards.e; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.effects.OneShotEffect; @@ -20,15 +18,17 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; import mage.target.common.TargetNonlandPermanent; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class EchoingTruth extends CardImpl { public EchoingTruth(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); // Return target nonland permanent and all other permanents with the same name as that permanent to their owners' hands. Target target = new TargetNonlandPermanent(); @@ -67,7 +67,7 @@ class ReturnToHandAllNamedPermanentsEffect extends OneShotEffect { Permanent permanent = game.getPermanent(source.getFirstTarget()); if (controller != null && permanent != null) { FilterPermanent filter = new FilterPermanent(); - if (permanent.getName().isEmpty()) { + if (CardUtil.haveEmptyName(permanent)) { filter.add(new PermanentIdPredicate(permanent.getId())); // if no name (face down creature) only the creature itself is selected } else { filter.add(new NamePredicate(permanent.getName())); diff --git a/Mage.Sets/src/mage/cards/e/ElderSpawn.java b/Mage.Sets/src/mage/cards/e/ElderSpawn.java new file mode 100644 index 00000000000..1d65526cdcb --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ElderSpawn.java @@ -0,0 +1,102 @@ + +package mage.cards.e; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleEvasionAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author L_J + */ +public final class ElderSpawn extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("red creatures"); + + static { + filter.add(new ColorPredicate(ObjectColor.RED)); + } + + public ElderSpawn(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}{U}{U}"); + this.subtype.add(SubType.SPAWN); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // At the beginning of your upkeep, unless you sacrifice an Island, sacrifice Elder Spawn and it deals 6 damage to you. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new ElderSpawnEffect(), TargetController.YOU, false)); + + // Elder Spawn can't be blocked by red creatures. + this.addAbility(new SimpleEvasionAbility(new CantBeBlockedByCreaturesSourceEffect(filter, Duration.WhileOnBattlefield))); + } + + public ElderSpawn(final ElderSpawn card) { + super(card); + } + + @Override + public ElderSpawn copy() { + return new ElderSpawn(this); + } +} + +class ElderSpawnEffect extends OneShotEffect { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("an Island"); + static { + filter.add(new SubtypePredicate(SubType.ISLAND)); + } + + public ElderSpawnEffect() { + super(Outcome.Sacrifice); + staticText = "unless you sacrifice an Island, sacrifice {this} and it deals 6 damage to you"; + } + + public ElderSpawnEffect(final ElderSpawnEffect effect) { + super(effect); + } + + @Override + public ElderSpawnEffect copy() { + return new ElderSpawnEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (controller != null && sourcePermanent != null) { + TargetControlledPermanent target = new TargetControlledPermanent(1, 1, filter, true); + SacrificeTargetCost cost = new SacrificeTargetCost(target); + if (!controller.chooseUse(Outcome.AIDontUseIt, "Do you wish to sacrifice an Island?", source, game) + || !cost.canPay(source, source.getSourceId(), source.getControllerId(), game) + || !cost.pay(source, game, source.getSourceId(), source.getControllerId(), true)) { + sourcePermanent.sacrifice(source.getSourceId(), game); + controller.damage(6, sourcePermanent.getId(), game, false, true); + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/e/EmergencyPowers.java b/Mage.Sets/src/mage/cards/e/EmergencyPowers.java new file mode 100644 index 00000000000..c206d8450f5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EmergencyPowers.java @@ -0,0 +1,58 @@ +package mage.cards.e; + +import mage.abilities.condition.common.MyMainPhaseCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DrawCardAllEffect; +import mage.abilities.effects.common.ExileSpellEffect; +import mage.abilities.effects.common.PutCardFromHandOntoBattlefieldEffect; +import mage.abilities.effects.common.ShuffleHandGraveyardAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.filter.common.FilterPermanentCard; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EmergencyPowers extends CardImpl { + + public static final FilterPermanentCard filter + = new FilterPermanentCard("a permanent card with converted mana cost 7 or less"); + + static { + filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, 8)); + } + + public EmergencyPowers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{5}{W}{U}"); + + // Each player shuffles their hand and graveyard into their library, then draws seven cards. Exile Emergency Powers. + this.getSpellAbility().addEffect(new ShuffleHandGraveyardAllEffect()); + this.getSpellAbility().addEffect(new DrawCardAllEffect(7).setText(", then draws seven cards")); + this.getSpellAbility().addEffect(ExileSpellEffect.getInstance()); + + // Addendum — If you cast this spell during your main phase, you may put a permanent card with converted mana cost 7 or less from your hand onto the battlefield. + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new PutCardFromHandOntoBattlefieldEffect(filter), + MyMainPhaseCondition.instance, + "
    Addendum — " + + "If you cast this spell during your main phase, " + + "you may put a permanent card with converted mana cost 7 or less " + + "from your hand onto the battlefield." + )); + } + + private EmergencyPowers(final EmergencyPowers card) { + super(card); + } + + @Override + public EmergencyPowers copy() { + return new EmergencyPowers(this); + } +} +// I am the senate! diff --git a/Mage.Sets/src/mage/cards/e/EnchantedBeing.java b/Mage.Sets/src/mage/cards/e/EnchantedBeing.java new file mode 100644 index 00000000000..0843ff51f8a --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EnchantedBeing.java @@ -0,0 +1,79 @@ + +package mage.cards.e; + +import java.util.UUID; +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.PreventAllDamageToSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; + +/** + * + * @author L_J + */ +public final class EnchantedBeing extends CardImpl { + + public EnchantedBeing(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{W}"); + this.subtype.add(SubType.HUMAN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Prevent all damage that would be dealt to Enchanted Being by enchanted creatures. + Effect effect = new PreventDamageToSourceByEnchantedCreatures(); + effect.setText("Prevent all damage that would be dealt to {this} by enchanted creatures."); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + } + + public EnchantedBeing(final EnchantedBeing card) { + super(card); + } + + @Override + public EnchantedBeing copy() { + return new EnchantedBeing(this); + } +} + +class PreventDamageToSourceByEnchantedCreatures extends PreventAllDamageToSourceEffect { + + public PreventDamageToSourceByEnchantedCreatures() { + super(Duration.WhileOnBattlefield); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (super.applies(event, source, game)) { + if (isEnchantedCreature(game.getObject(event.getSourceId()), game)) { + if (event.getTargetId().equals(source.getSourceId())) { + return true; + } + } + } + return false; + } + + public boolean isEnchantedCreature(MageObject input, Game game) { + if (input == null || input.isCreature()) { + return false; + } + for (UUID attachmentId : ((Permanent) input).getAttachments()) { + Permanent attachment = game.getPermanent(attachmentId); + if (attachment != null && attachment.isEnchantment()) { + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/e/EvilTwin.java b/Mage.Sets/src/mage/cards/e/EvilTwin.java index 51a77803e5e..cda27f37ff9 100644 --- a/Mage.Sets/src/mage/cards/e/EvilTwin.java +++ b/Mage.Sets/src/mage/cards/e/EvilTwin.java @@ -1,7 +1,5 @@ - package mage.cards.e; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -24,10 +22,12 @@ import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; +import mage.util.CardUtil; import mage.util.functions.ApplyToPermanent; +import java.util.UUID; + /** - * * @author BetaSteward */ public final class EvilTwin extends CardImpl { @@ -90,7 +90,7 @@ class EvilTwinPredicate implements ObjectSourcePlayerPredicate input, Game game) { Permanent permanent = input.getObject(); Permanent twin = game.getPermanent(input.getSourceId()); - return permanent != null && twin != null && !twin.getName().isEmpty() && permanent.getName().equals(twin.getName()); + return CardUtil.haveSameNames(permanent, twin); } @Override diff --git a/Mage.Sets/src/mage/cards/f/Flickerform.java b/Mage.Sets/src/mage/cards/f/Flickerform.java index 550ae27ce61..0f0ef9da3e1 100644 --- a/Mage.Sets/src/mage/cards/f/Flickerform.java +++ b/Mage.Sets/src/mage/cards/f/Flickerform.java @@ -156,39 +156,44 @@ class FlickerformReturnEffect extends OneShotEffect { } ExileZone exileZone = game.getExile().getExileZone(exileZoneId); Card enchantedCard = exileZone.get(enchantedCardId, game); + //skip if exiled card is missing if (enchantedCard != null) { - controller.moveCards(enchantedCard, Zone.BATTLEFIELD, source, game); - Permanent newPermanent = game.getPermanent(enchantedCardId); - if (newPermanent != null) { - Set toBattlefieldAttached = new HashSet(); - for (Card enchantment : exileZone.getCards(game)) { - if (filterAura.match(enchantment, game)) { - boolean canTarget = false; - for (Target target : enchantment.getSpellAbility().getTargets()) { - Filter filter = target.getFilter(); - if (filter.match(newPermanent, game)) { - canTarget = true; - break; + Player owner = game.getPlayer(enchantedCard.getOwnerId()); + //skip if card's owner is missing + if (owner != null) { + owner.moveCards(enchantedCard, Zone.BATTLEFIELD, source, game); + Permanent newPermanent = game.getPermanent(enchantedCardId); + if (newPermanent != null) { + Set toBattlefieldAttached = new HashSet(); + for (Card enchantment : exileZone.getCards(game)) { + if (filterAura.match(enchantment, game)) { + boolean canTarget = false; + for (Target target : enchantment.getSpellAbility().getTargets()) { + Filter filter = target.getFilter(); + if (filter.match(newPermanent, game)) { + canTarget = true; + break; + } + } + if (!canTarget) { + // Aura stays exiled + continue; + } + game.getState().setValue("attachTo:" + enchantment.getId(), newPermanent); + } + toBattlefieldAttached.add(enchantment); + } + if (!toBattlefieldAttached.isEmpty()) { + controller.moveCards(toBattlefieldAttached, Zone.BATTLEFIELD, source, game); + for (Card card : toBattlefieldAttached) { + if (game.getState().getZone(card.getId()) == Zone.BATTLEFIELD) { + newPermanent.addAttachment(card.getId(), game); } } - if (!canTarget) { - // Aura stays exiled - continue; - } - game.getState().setValue("attachTo:" + enchantment.getId(), newPermanent); - } - toBattlefieldAttached.add(enchantment); - } - if (!toBattlefieldAttached.isEmpty()) { - controller.moveCards(toBattlefieldAttached, Zone.BATTLEFIELD, source, game); - for (Card card : toBattlefieldAttached) { - if (game.getState().getZone(card.getId()) == Zone.BATTLEFIELD) { - newPermanent.addAttachment(card.getId(), game); - } } } + return true; } - return true; } return false; } diff --git a/Mage.Sets/src/mage/cards/f/Foreshadow.java b/Mage.Sets/src/mage/cards/f/Foreshadow.java index 6299ff05b75..e1d86d5e569 100644 --- a/Mage.Sets/src/mage/cards/f/Foreshadow.java +++ b/Mage.Sets/src/mage/cards/f/Foreshadow.java @@ -1,13 +1,11 @@ - package mage.cards.f; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.delayed.AtTheBeginOfNextUpkeepDelayedTriggeredAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChooseACardNameEffect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.ChooseACardNameEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -17,21 +15,23 @@ import mage.constants.Zone; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetOpponent; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author Quercitron & L_J */ public final class Foreshadow extends CardImpl { public Foreshadow(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); // Choose a card name, then target opponent puts the top card of their library into their graveyard. If that card has the chosen name, you draw a card. this.getSpellAbility().addEffect(new ChooseACardNameEffect(ChooseACardNameEffect.TypeOfName.ALL)); this.getSpellAbility().addEffect(new ForeshadowEffect()); this.getSpellAbility().addTarget(new TargetOpponent()); - + // Draw a card at the beginning of the next turn's upkeep. this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect( new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new DrawCardSourceControllerEffect(1)), false)); @@ -72,8 +72,8 @@ class ForeshadowEffect extends OneShotEffect { Card card = targetPlayer.getLibrary().getFromTop(game); if (card != null) { controller.moveCards(card, Zone.GRAVEYARD, source, game); - if (card.getName().equals(cardName)) { - controller.drawCards(1, game); + if (CardUtil.haveSameNames(card.getName(), cardName)) { + controller.drawCards(1, game); } } return true; diff --git a/Mage.Sets/src/mage/cards/f/ForethoughtAmulet.java b/Mage.Sets/src/mage/cards/f/ForethoughtAmulet.java new file mode 100644 index 00000000000..f6eff9d8ff1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/ForethoughtAmulet.java @@ -0,0 +1,91 @@ + +package mage.cards.f; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.SacrificeSourceUnlessPaysEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent; + +/** + * + * @author L_J + */ +public final class ForethoughtAmulet extends CardImpl { + + public ForethoughtAmulet(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{5}"); + + // At the beginning of your upkeep, sacrifice Forethought Amulet unless you pay {3}. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new SacrificeSourceUnlessPaysEffect(new GenericManaCost(3)), TargetController.YOU, false)); + + // If an instant or sorcery source would deal 3 or more damage to you, it deals 2 damage to you instead. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ForethoughtAmuletEffect())); + } + + public ForethoughtAmulet(final ForethoughtAmulet card) { + super(card); + } + + @Override + public ForethoughtAmulet copy() { + return new ForethoughtAmulet(this); + } +} + +class ForethoughtAmuletEffect extends ReplacementEffectImpl { + + public ForethoughtAmuletEffect() { + super(Duration.WhileOnBattlefield, Outcome.Neutral); + staticText = "If an instant or sorcery source would deal 3 or more damage to you, it deals 2 damage to you instead"; + } + + public ForethoughtAmuletEffect(final ForethoughtAmuletEffect effect) { + super(effect); + } + + @Override + public ForethoughtAmuletEffect copy() { + return new ForethoughtAmuletEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGE_PLAYER; + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (event.getAmount() >= 3) { + MageObject object = game.getObject(event.getSourceId()); + return object != null && (object.isInstant() || object.isSorcery()); + } + return false; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + if (event.getTargetId().equals(source.getControllerId())) { + event.setAmount(2); + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/f/FrenziedArynx.java b/Mage.Sets/src/mage/cards/f/FrenziedArynx.java new file mode 100644 index 00000000000..26ceb3e0ca3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FrenziedArynx.java @@ -0,0 +1,51 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.RiotAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FrenziedArynx extends CardImpl { + + public FrenziedArynx(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{G}"); + + this.subtype.add(SubType.CAT); + this.subtype.add(SubType.BEAST); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Riot + this.addAbility(new RiotAbility()); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // {4}{R}{G}: Frenzied Arynx gets +3/+0 until end of turn. + this.addAbility(new SimpleActivatedAbility( + new BoostSourceEffect(3, 0, Duration.EndOfTurn), + new ManaCostsImpl("{4}{R}{G}") + )); + } + + public FrenziedArynx(final FrenziedArynx card) { + super(card); + } + + @Override + public FrenziedArynx copy() { + return new FrenziedArynx(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GateColossus.java b/Mage.Sets/src/mage/cards/g/GateColossus.java new file mode 100644 index 00000000000..161b449d1dc --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GateColossus.java @@ -0,0 +1,101 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.common.SimpleEvasionAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.PutOnLibrarySourceEffect; +import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesSourceEffect; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GateColossus extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures with power 2 or less"); + + static { + filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, 3)); + } + + public GateColossus(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{8}"); + + this.subtype.add(SubType.CONSTRUCT); + this.power = new MageInt(8); + this.toughness = new MageInt(8); + + // This spell costs {1} less to cast for each Gate you control. + this.addAbility(new SimpleStaticAbility(Zone.STACK, new GateColossusCostReductionEffect())); + + // Gate Colossus can't be blocked by creatures with power 2 or less. + this.addAbility(new SimpleEvasionAbility(new CantBeBlockedByCreaturesSourceEffect(filter, Duration.WhileOnBattlefield))); + + // Whenever a Gate enters the battlefield under your control, you may put Gate Colossus from your graveyard on top of your library. + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + Zone.GRAVEYARD, + new PutOnLibrarySourceEffect( + true, "put {this} from your graveyard on top of your library" + ), GateColossusCostReductionEffect.filter, true + )); + } + + public GateColossus(final GateColossus card) { + super(card); + } + + @Override + public GateColossus copy() { + return new GateColossus(this); + } +} + +class GateColossusCostReductionEffect extends CostModificationEffectImpl { + + static final FilterControlledPermanent filter = new FilterControlledPermanent(); + + static { + filter.add(new SubtypePredicate(SubType.GATE)); + } + + public GateColossusCostReductionEffect() { + super(Duration.WhileOnStack, Outcome.Benefit, CostModificationType.REDUCE_COST); + staticText = "This spell costs {1} less to cast for each Gate you control"; + } + + protected GateColossusCostReductionEffect(final GateColossusCostReductionEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + int count = game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game).size(); + if (count > 0) { + CardUtil.reduceCost(abilityToModify, count); + } + return true; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + return abilityToModify.getSourceId().equals(source.getSourceId()); + } + + @Override + public GateColossusCostReductionEffect copy() { + return new GateColossusCostReductionEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GearseekerSerpent.java b/Mage.Sets/src/mage/cards/g/GearseekerSerpent.java index 9cd45332981..1bc10b186ed 100644 --- a/Mage.Sets/src/mage/cards/g/GearseekerSerpent.java +++ b/Mage.Sets/src/mage/cards/g/GearseekerSerpent.java @@ -58,7 +58,7 @@ class GearseekerSerpentCostReductionEffect extends CostModificationEffectImpl { public GearseekerSerpentCostReductionEffect() { super(Duration.WhileOnStack, Outcome.Benefit, CostModificationType.REDUCE_COST); - staticText = "{this} costs {1} less to cast for each artifact you control"; + staticText = "This spell costs {1} less to cast for each artifact you control"; } protected GearseekerSerpentCostReductionEffect(final GearseekerSerpentCostReductionEffect effect) { diff --git a/Mage.Sets/src/mage/cards/g/GoblinMachinist.java b/Mage.Sets/src/mage/cards/g/GoblinMachinist.java index 2e217d109bf..8ff675b00e9 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinMachinist.java +++ b/Mage.Sets/src/mage/cards/g/GoblinMachinist.java @@ -77,9 +77,9 @@ class GoblinMachinistEffect extends OneShotEffect { break; } } - controller.revealCards(source, cards, game); - controller.putCardsOnBottomOfLibrary(cards, game, source, true); } + controller.revealCards(source, cards, game); + controller.putCardsOnBottomOfLibrary(cards, game, source, true); return true; } return false; diff --git a/Mage.Sets/src/mage/cards/g/Grollub.java b/Mage.Sets/src/mage/cards/g/Grollub.java new file mode 100644 index 00000000000..45071e13b92 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/Grollub.java @@ -0,0 +1,73 @@ +package mage.cards.g; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DealtDamageToSourceTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author jeffwadsworth + */ +public final class Grollub extends CardImpl { + + public Grollub(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.BEAST); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Whenever Grollub is dealt damage, each opponent gains that much life. + this.addAbility(new DealtDamageToSourceTriggeredAbility( + Zone.BATTLEFIELD, + new EachOpponentGainsLifeEffect(), false, false, true)); + + } + + public Grollub(final Grollub card) { + super(card); + } + + @Override + public Grollub copy() { + return new Grollub(this); + } +} + +class EachOpponentGainsLifeEffect extends OneShotEffect { + + public EachOpponentGainsLifeEffect() { + super(Outcome.Neutral); + this.staticText = "each opponent gains that much life"; + } + + public EachOpponentGainsLifeEffect(final EachOpponentGainsLifeEffect effect) { + super(effect); + } + + @Override + public EachOpponentGainsLifeEffect copy() { + return new EachOpponentGainsLifeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + game.getOpponents(source.getControllerId()).stream().map((opponentId) -> game.getPlayer(opponentId)).filter((opponent) -> (opponent != null)).forEachOrdered((opponent) -> { + int amount = (Integer) getValue("damage"); + if (amount > 0) { + opponent.gainLife(amount, game, source); + } + }); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GrowthSpiral.java b/Mage.Sets/src/mage/cards/g/GrowthSpiral.java new file mode 100644 index 00000000000..1168e1cfa3f --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GrowthSpiral.java @@ -0,0 +1,33 @@ +package mage.cards.g; + +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.PutCardFromHandOntoBattlefieldEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GrowthSpiral extends CardImpl { + + public GrowthSpiral(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{G}{U}"); + + // Draw a card. You may put a land card from your hand onto the battlefield. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new PutCardFromHandOntoBattlefieldEffect(StaticFilters.FILTER_CARD_LAND_A)); + } + + public GrowthSpiral(final GrowthSpiral card) { + super(card); + } + + @Override + public GrowthSpiral copy() { + return new GrowthSpiral(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GruulSpellbreaker.java b/Mage.Sets/src/mage/cards/g/GruulSpellbreaker.java new file mode 100644 index 00000000000..399e17078b9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GruulSpellbreaker.java @@ -0,0 +1,68 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.GainAbilityControllerEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.HexproofAbility; +import mage.abilities.keyword.RiotAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GruulSpellbreaker extends CardImpl { + + public GruulSpellbreaker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{G}"); + + this.subtype.add(SubType.OGRE); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Riot + this.addAbility(new RiotAbility()); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // As long as it's your turn, you and Gruul Spellbreaker have hexproof. + Ability ability = new SimpleStaticAbility( + Zone.BATTLEFIELD, + new ConditionalContinuousEffect( + new GainAbilityControllerEffect( + HexproofAbility.getInstance(), + Duration.WhileOnBattlefield + ), MyTurnCondition.instance, "As long as it's your turn, you and" + ) + ); + ability.addEffect(new ConditionalContinuousEffect( + new GainAbilitySourceEffect( + HexproofAbility.getInstance(), + Duration.WhileOnBattlefield + ), MyTurnCondition.instance, "{this} have hexproof." + )); + this.addAbility(ability); + } + + public GruulSpellbreaker(final GruulSpellbreaker card) { + super(card); + } + + @Override + public GruulSpellbreaker copy() { + return new GruulSpellbreaker(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HeraldsHorn.java b/Mage.Sets/src/mage/cards/h/HeraldsHorn.java index 1dfbd2b6ec3..f95458daedb 100644 --- a/Mage.Sets/src/mage/cards/h/HeraldsHorn.java +++ b/Mage.Sets/src/mage/cards/h/HeraldsHorn.java @@ -13,10 +13,11 @@ import mage.abilities.effects.common.cost.SpellsCostReductionAllOfChosenSubtypeE import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.TargetController; import mage.constants.Zone; import mage.filter.common.FilterCreatureCard; -import mage.filter.predicate.mageobject.ChosenSubtypePredicate; +import mage.filter.predicate.mageobject.SubtypePredicate; import mage.game.Game; import mage.players.Player; @@ -79,15 +80,18 @@ class HeraldsHornEffect extends OneShotEffect { // If it's a creature card of the chosen type, you may reveal it and put it into your hand. FilterCreatureCard filter = new FilterCreatureCard("creature card of the chosen type"); - filter.add(new ChosenSubtypePredicate()); + SubType subtype = ChooseCreatureTypeEffect.getChosenCreatureType(source.getSourceId(), game); + filter.add(new SubtypePredicate(subtype)); String message = "Reveal the top card of your library and put that card into your hand?"; if (card != null) { - if (filter.match(card, game) && controller.chooseUse(Outcome.Benefit, message, source, game)) { + if (filter.match(card, game) + && controller.chooseUse(Outcome.Benefit, message, source, game)) { controller.moveCards(card, Zone.HAND, source, game); controller.revealCards(sourceObject.getIdName() + " put into hand", cards, game); + return true; } } } - return true; + return false; } } diff --git a/Mage.Sets/src/mage/cards/h/HiddenRetreat.java b/Mage.Sets/src/mage/cards/h/HiddenRetreat.java new file mode 100644 index 00000000000..b90d3d088a3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HiddenRetreat.java @@ -0,0 +1,76 @@ +package mage.cards.h; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.PutCardFromHandOnTopOfLibraryCost; +import mage.abilities.effects.PreventionEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import java.util.UUID; +import mage.filter.StaticFilters; +import mage.game.events.DamageEvent; +import mage.target.TargetSpell; + +/** + * + * @author bunchOfDevs + */ +public class HiddenRetreat extends CardImpl { + + public HiddenRetreat(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); + + //Put a card from your hand on top of your library: Prevent all damage that would be dealt by target instant or sorcery spell this turn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new HiddenRetreatEffect(), new PutCardFromHandOnTopOfLibraryCost()); + ability.addTarget(new TargetSpell(StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY)); + this.addAbility(ability); + + } + + public HiddenRetreat(final HiddenRetreat hiddenRetreat) { + super(hiddenRetreat); + } + + @Override + public HiddenRetreat copy() { + return new HiddenRetreat(this); + } +} + +class HiddenRetreatEffect extends PreventionEffectImpl { + + public HiddenRetreatEffect() { + super(Duration.EndOfTurn, Integer.MAX_VALUE, false, false); + this.staticText = "Prevent all damage that would be dealt by target instant or sorcery spell this turn."; + } + + public HiddenRetreatEffect(final HiddenRetreatEffect effect) { + super(effect); + } + + @Override + public HiddenRetreatEffect copy() { + return new HiddenRetreatEffect(this); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + return true; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return (super.applies(event, source, game) + && event instanceof DamageEvent + && event.getAmount() > 0 + && game.getObject(source.getFirstTarget()) != null + && game.getObject(event.getSourceId()) != null + && game.getObject(source.getFirstTarget()).equals(game.getObject(event.getSourceId())) + && game.getObject(source.getFirstTarget()).isInstantOrSorcery()); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HomingLightning.java b/Mage.Sets/src/mage/cards/h/HomingLightning.java index db04b8b8ac4..9e73c445f26 100644 --- a/Mage.Sets/src/mage/cards/h/HomingLightning.java +++ b/Mage.Sets/src/mage/cards/h/HomingLightning.java @@ -1,7 +1,5 @@ - package mage.cards.h; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; @@ -14,15 +12,17 @@ import mage.filter.predicate.permanent.PermanentIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class HomingLightning extends CardImpl { public HomingLightning(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}{R}"); // Homing Lightning deals 4 damage to target creature and each other creature with the same name as that creature. @@ -58,7 +58,7 @@ class HomingLightningEffect extends OneShotEffect { return false; } FilterCreaturePermanent filter = new FilterCreaturePermanent(); - if (targetPermanent.getName().isEmpty()) { + if (CardUtil.haveEmptyName(targetPermanent)) { filter.add(new PermanentIdPredicate(targetPermanent.getId())); // if no name (face down creature) only the creature itself is selected } else { filter.add(new NamePredicate(targetPermanent.getName())); diff --git a/Mage.Sets/src/mage/cards/i/ImperiousOligarch.java b/Mage.Sets/src/mage/cards/i/ImperiousOligarch.java new file mode 100644 index 00000000000..0a4a81eb5ff --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/ImperiousOligarch.java @@ -0,0 +1,41 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.abilities.keyword.AfterlifeAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ImperiousOligarch extends CardImpl { + + public ImperiousOligarch(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CLERIC); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Afterlife 1 + this.addAbility(new AfterlifeAbility(1)); + } + + public ImperiousOligarch(final ImperiousOligarch card) { + super(card); + } + + @Override + public ImperiousOligarch copy() { + return new ImperiousOligarch(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/IncubationIncongruity.java b/Mage.Sets/src/mage/cards/i/IncubationIncongruity.java new file mode 100644 index 00000000000..9e8278b9898 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IncubationIncongruity.java @@ -0,0 +1,81 @@ +package mage.cards.i; + +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.cards.CardSetInfo; +import mage.cards.SplitCard; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SpellAbilityType; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.FrogLizardToken; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class IncubationIncongruity extends SplitCard { + + public IncubationIncongruity(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, new CardType[]{CardType.INSTANT}, "{G/U}", "{1}{G}{U}", SpellAbilityType.SPLIT); + + // Incubation + // Look at the top five cards of your library. You may reveal a creature card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. + this.getLeftHalfCard().getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( + new StaticValue(5), false, + new StaticValue(1), StaticFilters.FILTER_CARD_CREATURE_A, + Zone.LIBRARY, false, true, false, + Zone.HAND, false, false, false + )); + + // Incongruity + // Exile target creature. That creature's controller creates a 3/3 green Frog Lizard creature token. + this.getRightHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getRightHalfCard().getSpellAbility().addEffect(new ExileTargetEffect()); + this.getRightHalfCard().getSpellAbility().addEffect(new IncongruityEffect()); + } + + private IncubationIncongruity(final IncubationIncongruity card) { + super(card); + } + + @Override + public IncubationIncongruity copy() { + return new IncubationIncongruity(this); + } +} + +class IncongruityEffect extends OneShotEffect { + + public IncongruityEffect() { + super(Outcome.PutCreatureInPlay); + staticText = "That creature's controller creates a 3/3 green Frog Lizard creature token"; + } + + public IncongruityEffect(final IncongruityEffect effect) { + super(effect); + } + + @Override + public IncongruityEffect copy() { + return new IncongruityEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanentOrLKIBattlefield(targetPointer.getFirst(game, source)); + if (permanent != null) { + FrogLizardToken token = new FrogLizardToken(); + token.putOntoBattlefield(1, game, source.getSourceId(), permanent.getControllerId()); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/i/IridescentDrake.java b/Mage.Sets/src/mage/cards/i/IridescentDrake.java index 348549ee278..d9f08f524a0 100644 --- a/Mage.Sets/src/mage/cards/i/IridescentDrake.java +++ b/Mage.Sets/src/mage/cards/i/IridescentDrake.java @@ -14,6 +14,8 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.SubtypePredicate; import mage.filter.predicate.other.AuraCardCanAttachToPermanentId; import mage.game.Game; import mage.game.permanent.Permanent; @@ -26,6 +28,12 @@ import mage.target.common.TargetCardInGraveyard; * @author TheElk801 */ public final class IridescentDrake extends CardImpl { + + private static final FilterCard filter = new FilterCard("Aura from a graveyard"); + + static { + filter.add(new SubtypePredicate(SubType.AURA)); + } public IridescentDrake(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); @@ -39,7 +47,7 @@ public final class IridescentDrake extends CardImpl { // When Iridescent Drake enters the battlefield, put target Aura card from a graveyard onto the battlefield under your control attached to Iridescent Drake. Ability ability = new EntersBattlefieldTriggeredAbility(new IridescentDrakeEffect()); - ability.addTarget(new TargetCardInGraveyard()); + ability.addTarget(new TargetCardInGraveyard(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/i/IzzetStaticaster.java b/Mage.Sets/src/mage/cards/i/IzzetStaticaster.java index ee90f7d8f8f..84f9257a7fa 100644 --- a/Mage.Sets/src/mage/cards/i/IzzetStaticaster.java +++ b/Mage.Sets/src/mage/cards/i/IzzetStaticaster.java @@ -1,7 +1,5 @@ - package mage.cards.i; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -12,8 +10,8 @@ import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.NamePredicate; @@ -21,15 +19,17 @@ import mage.filter.predicate.permanent.PermanentIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class IzzetStaticaster extends CardImpl { public IzzetStaticaster(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{R}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); @@ -79,7 +79,7 @@ class IzzetStaticasterDamageEffect extends OneShotEffect { Permanent targetPermanent = game.getPermanent(targetPointer.getFirst(game, source)); if (targetPermanent != null) { FilterCreaturePermanent filter = new FilterCreaturePermanent(); - if (targetPermanent.getName().isEmpty()) { + if (CardUtil.haveEmptyName(targetPermanent)) { filter.add(new PermanentIdPredicate(targetPermanent.getId())); // if no name (face down creature) only the creature itself is selected } else { filter.add(new NamePredicate(targetPermanent.getName())); diff --git a/Mage.Sets/src/mage/cards/j/JaceArchitectOfThought.java b/Mage.Sets/src/mage/cards/j/JaceArchitectOfThought.java index 09ebb7644ef..4f6b074b34f 100644 --- a/Mage.Sets/src/mage/cards/j/JaceArchitectOfThought.java +++ b/Mage.Sets/src/mage/cards/j/JaceArchitectOfThought.java @@ -1,7 +1,8 @@ - package mage.cards.j; import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.UUID; import mage.MageObjectReference; @@ -9,7 +10,6 @@ import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.LoyaltyAbility; import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.Card; @@ -24,7 +24,10 @@ import mage.constants.SubType; import mage.constants.SuperType; import mage.constants.Zone; import mage.filter.FilterCard; +import mage.filter.FilterPlayer; import mage.filter.common.FilterNonlandCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.other.PlayerIdPredicate; import mage.game.ExileZone; import mage.game.Game; import mage.game.events.GameEvent; @@ -32,6 +35,7 @@ import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetCard; +import mage.target.TargetPlayer; import mage.target.common.TargetCardInExile; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetOpponent; @@ -119,9 +123,9 @@ class JaceArchitectOfThoughtDelayedTriggeredAbility extends DelayedTriggeredAbil @Override public boolean checkTrigger(GameEvent event, Game game) { if (game.getOpponents(getControllerId()).contains(event.getPlayerId())) { - for (Effect effect : getEffects()) { + getEffects().forEach((effect) -> { effect.setTargetPointer(new FixedTarget(event.getSourceId())); - } + }); return true; } return false; @@ -180,7 +184,6 @@ class JaceArchitectOfThoughtEffect2 extends OneShotEffect { if (opponent == null) { opponent = game.getPlayer(opponents.iterator().next()); } - TargetCard target = new TargetCard(0, allCards.size(), Zone.LIBRARY, new FilterCard("cards to put in the first pile")); target.setNotTarget(true); opponent.choose(Outcome.Neutral, allCards, target, game); @@ -206,9 +209,9 @@ class JaceArchitectOfThoughtEffect2 extends OneShotEffect { private void postPileToLog(String pileName, Set cards, Game game) { StringBuilder message = new StringBuilder(pileName).append(": "); - for (Card card : cards) { + cards.forEach((card) -> { message.append(card.getName()).append(' '); - } + }); if (cards.isEmpty()) { message.append(" (empty)"); } @@ -239,30 +242,65 @@ class JaceArchitectOfThoughtEffect3 extends OneShotEffect { if (controller == null || sourcePermanent == null) { return false; } - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - Player player = game.getPlayer(playerId); - String playerName = new StringBuilder(player.getLogName()).append("'s").toString(); - if (source.isControlledBy(player.getId())) { - playerName = "your"; - } - TargetCardInLibrary target = new TargetCardInLibrary(new FilterNonlandCard(new StringBuilder("nonland card from ").append(playerName).append(" library").toString())); - if (controller.searchLibrary(target, game, playerId)) { - UUID targetId = target.getFirstTarget(); - Card card = player.getLibrary().remove(targetId, game); - if (card != null) { - controller.moveCardToExileWithInfo(card, CardUtil.getCardExileZoneId(game, source), sourcePermanent.getIdName(), source.getSourceId(), game, Zone.LIBRARY, true); - } - } - player.shuffleLibrary(source, game); + if (controller.chooseUse(Outcome.Benefit, "Look at all players' libraries before card select?", null, game)) { + game.informPlayers(controller.getLogName() + " is looking at all players' libraries."); + controller.lookAtAllLibraries(source, game); } - + List playerList = new ArrayList<>(); + playerList.addAll(game.getState().getPlayersInRange(controller.getId(), game)); + Set checkList = new HashSet<>(); + while (!playerList.isEmpty()) { + FilterPlayer filter = new FilterPlayer(); + List playerPredicates = new ArrayList<>(); + playerList.forEach((playerId) -> { + playerPredicates.add(new PlayerIdPredicate(playerId)); + }); + filter.add(Predicates.or(playerPredicates)); + TargetPlayer targetPlayer = new TargetPlayer(1, 1, true, filter); + targetPlayer.setRequired(!checkList.containsAll(playerList)); + if (controller.chooseTarget(outcome, targetPlayer, source, game)) { + UUID playerId = targetPlayer.getFirstTarget(); + Player player = game.getPlayer(playerId); + if (player != null) { + String playerName = new StringBuilder(player.getLogName()).append("'s").toString(); + if (source.isControlledBy(player.getId())) { + playerName = "your"; + } + TargetCardInLibrary target = new TargetCardInLibrary(new FilterNonlandCard(new StringBuilder("nonland card from ").append(playerName).append(" library").toString())); + if (controller.searchLibrary(target, game, playerId, !checkList.contains(playerId))) { + checkList.add(playerId); + UUID targetId = target.getFirstTarget(); + Card card = player.getLibrary().remove(targetId, game); + if (card != null) { + controller.moveCardsToExile(card, source, game, true, CardUtil.getCardExileZoneId(game, source), sourcePermanent.getName()); + playerList.remove(playerId); + } + } else { + playerList.remove(playerId); + } + } else { + playerList.remove(playerId); + } + } else { + break; + } + playerList.stream().map((playerId) -> game.getPlayer(playerId)).filter((player) -> (player == null + || !player.canRespond())).forEachOrdered((player) -> { + playerList.remove(player.getId()); + }); + } + checkList.stream().map((playerId) -> game.getPlayer(playerId)).filter((player) -> (player != null)).forEachOrdered((player) -> { + player.shuffleLibrary(source, game); + }); ExileZone jaceExileZone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source)); if (jaceExileZone == null) { return true; } FilterCard filter = new FilterCard("card to cast without mana costs"); TargetCardInExile target = new TargetCardInExile(filter, source.getSourceId()); - while (jaceExileZone.count(filter, game) > 0 && controller.choose(Outcome.PlayForFree, jaceExileZone, target, game)) { + while (jaceExileZone.count(filter, game) > 0 + && controller.chooseUse(Outcome.Benefit, "Cast another spell from exile zone for free?", source, game)) { + controller.choose(Outcome.PlayForFree, jaceExileZone, target, game); Card card = game.getCard(target.getFirstTarget()); if (card != null) { if (controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game))) { diff --git a/Mage.Sets/src/mage/cards/j/JelevaNephaliasScourge.java b/Mage.Sets/src/mage/cards/j/JelevaNephaliasScourge.java index d4d7341f1ae..2af20fd0760 100644 --- a/Mage.Sets/src/mage/cards/j/JelevaNephaliasScourge.java +++ b/Mage.Sets/src/mage/cards/j/JelevaNephaliasScourge.java @@ -1,4 +1,3 @@ - package mage.cards.j; import java.util.HashMap; @@ -92,7 +91,6 @@ class JelevaNephaliasScourgeEffect extends OneShotEffect { for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { - // player.moveCardsToExile(player.getLibrary().getTopCards(game, xValue), source, game, true, CardUtil.getCardExileZoneId(game, source), sourceObject.getIdName()); } } @@ -130,7 +128,7 @@ class JelevaNephaliasCastEffect extends OneShotEffect { if (controller.choose(Outcome.PlayForFree, exileZone, target, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { - return controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); + return controller.playCard(card, game, true, false, new MageObjectReference(source.getSourceId(), game)); } } } diff --git a/Mage.Sets/src/mage/cards/k/KeeperOfTheFlame.java b/Mage.Sets/src/mage/cards/k/KeeperOfTheFlame.java new file mode 100644 index 00000000000..9c1bcdd170f --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KeeperOfTheFlame.java @@ -0,0 +1,79 @@ +package mage.cards.k; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterOpponent; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetPlayer; + +/** + * + * @author jeffwadsworth + */ +public final class KeeperOfTheFlame extends CardImpl { + + private static final FilterOpponent filter = new FilterOpponent(); + + static { + filter.add(new KeeperOfTheFlamePredicate()); + } + + public KeeperOfTheFlame(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // {R}, {tap}: Choose target opponent who had more life than you did as you activated this ability. Keeper of the Flame deals 2 damage to him or her. + Ability ability = new SimpleActivatedAbility( + new DamageTargetEffect(2).setText("Choose target opponent who had more life than you did as you activated this ability. {this} deals 2 damage to him or her"), + new ManaCostsImpl("{R}")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetPlayer(1, 1, false, filter)); + this.addAbility(ability); + + } + + public KeeperOfTheFlame(final KeeperOfTheFlame card) { + super(card); + } + + @Override + public KeeperOfTheFlame copy() { + return new KeeperOfTheFlame(this); + } +} + +class KeeperOfTheFlamePredicate implements ObjectSourcePlayerPredicate> { + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + Player targetOpponent = input.getObject(); + Player controller = game.getPlayer(input.getPlayerId()); + if (targetOpponent == null + || controller == null + || !controller.hasOpponent(targetOpponent.getId(), game)) { + return false; + } + return targetOpponent.getLife() > controller.getLife(); + } + + @Override + public String toString() { + return "opponent who had more life than you did as you activated this ability"; + } +} diff --git a/Mage.Sets/src/mage/cards/k/KheruSpellsnatcher.java b/Mage.Sets/src/mage/cards/k/KheruSpellsnatcher.java index 1576cc697bf..d5e5bf5a3d8 100644 --- a/Mage.Sets/src/mage/cards/k/KheruSpellsnatcher.java +++ b/Mage.Sets/src/mage/cards/k/KheruSpellsnatcher.java @@ -1,7 +1,5 @@ - package mage.cards.k; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -14,13 +12,7 @@ import mage.abilities.keyword.MorphAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AsThoughEffectType; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.constants.ZoneDetail; +import mage.constants.*; import mage.game.Game; import mage.game.stack.Spell; import mage.game.stack.StackObject; @@ -28,14 +20,15 @@ import mage.players.Player; import mage.target.TargetSpell; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author emerald000 */ public final class KheruSpellsnatcher extends CardImpl { public KheruSpellsnatcher(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); this.subtype.add(SubType.NAGA); this.subtype.add(SubType.WIZARD); @@ -85,7 +78,7 @@ class KheruSpellsnatcherEffect extends OneShotEffect { StackObject stackObject = game.getStack().getStackObject(objectId); if (stackObject != null && game.getStack().counter(targetPointer.getFirst(game, source), source.getSourceId(), game, Zone.EXILED, false, ZoneDetail.NONE)) { - if (!((Spell) stackObject).isCopiedSpell()) { + if (!((Spell) stackObject).isCopy()) { MageObject card = game.getObject(stackObject.getSourceId()); if (card instanceof Card) { ((Card) card).moveToZone(Zone.EXILED, sourceId, game, true); diff --git a/Mage.Sets/src/mage/cards/k/KryShield.java b/Mage.Sets/src/mage/cards/k/KryShield.java new file mode 100644 index 00000000000..8fc55fc5dc4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KryShield.java @@ -0,0 +1,49 @@ + +package mage.cards.k; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.dynamicvalue.common.TargetConvertedManaCost; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.PreventDamageByTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.target.common.TargetControlledCreaturePermanent; + +/** + * + * @author L_J + */ +public final class KryShield extends CardImpl { + + public KryShield(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); + + // {2}, {T}: Prevent all damage that would be dealt this turn by target creature you control. That creature gets +0/+X until end of turn, where X is its converted mana cost. + Effect effect = new PreventDamageByTargetEffect(Duration.EndOfTurn); + effect.setText("Prevent all damage that would be dealt this turn by target creature you control"); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new GenericManaCost(2)); + ability.addEffect(new BoostTargetEffect(new StaticValue(0), new TargetConvertedManaCost(), Duration.EndOfTurn, true) + .setText("That creature gets +0/+X until end of turn, where X is its converted mana cost")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + } + + public KryShield(final KryShield card) { + super(card); + } + + @Override + public KryShield copy() { + return new KryShield(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LammastideWeave.java b/Mage.Sets/src/mage/cards/l/LammastideWeave.java index a67cac45851..9cd195c43b9 100644 --- a/Mage.Sets/src/mage/cards/l/LammastideWeave.java +++ b/Mage.Sets/src/mage/cards/l/LammastideWeave.java @@ -1,10 +1,9 @@ package mage.cards.l; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.ChooseACardNameEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -14,9 +13,11 @@ import mage.constants.Zone; import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author Styxo */ public final class LammastideWeave extends CardImpl { @@ -70,7 +71,7 @@ class LammastideWeaveEffect extends OneShotEffect { Card card = targetPlayer.getLibrary().getFromTop(game); if (card != null) { controller.moveCards(card, Zone.GRAVEYARD, source, game); - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { controller.gainLife(card.getConvertedManaCost(), game, source); } } diff --git a/Mage.Sets/src/mage/cards/l/LiarsPendulum.java b/Mage.Sets/src/mage/cards/l/LiarsPendulum.java index 5163fdcb7f4..bf86998ce4d 100644 --- a/Mage.Sets/src/mage/cards/l/LiarsPendulum.java +++ b/Mage.Sets/src/mage/cards/l/LiarsPendulum.java @@ -1,7 +1,5 @@ - package mage.cards.l; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; @@ -20,9 +18,11 @@ import mage.constants.Zone; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetOpponent; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author L_J */ public final class LiarsPendulum extends CardImpl { @@ -93,7 +93,7 @@ class LiarsPendulumEffect extends OneShotEffect { rightGuess = opponentGuess; } } - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { rightGuess = opponentGuess; } } diff --git a/Mage.Sets/src/mage/cards/l/LightUpTheStage.java b/Mage.Sets/src/mage/cards/l/LightUpTheStage.java new file mode 100644 index 00000000000..2a48c3106cf --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LightUpTheStage.java @@ -0,0 +1,127 @@ +package mage.cards.l; + +import mage.abilities.Ability; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.SpectacleAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; + +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 and jeffwadsworth + */ +public final class LightUpTheStage extends CardImpl { + + public LightUpTheStage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}"); + + // Spectacle {R} + this.addAbility(new SpectacleAbility(this, new ManaCostsImpl("{R}"))); + + // Exile the top two cards of your library. Until the end of your next turn, you may play those cards. + this.getSpellAbility().addEffect(new LightUpTheStageEffect()); + } + + public LightUpTheStage(final LightUpTheStage card) { + super(card); + } + + @Override + public LightUpTheStage copy() { + return new LightUpTheStage(this); + } +} + +class LightUpTheStageEffect extends OneShotEffect { + + public LightUpTheStageEffect() { + super(Outcome.PlayForFree); + this.staticText = "Exile the top two cards of your library. Until the end of your next turn, you may play those cards"; + } + + public LightUpTheStageEffect(final LightUpTheStageEffect effect) { + super(effect); + } + + @Override + public LightUpTheStageEffect copy() { + return new LightUpTheStageEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Card sourceCard = game.getCard(source.getSourceId()); + if (controller != null) { + Set cards = controller.getLibrary().getTopCards(game, 2); + controller.moveCardsToExile(cards, source, game, true, CardUtil.getCardExileZoneId(game, source), sourceCard.getIdName()); + + for (Card card : cards) { + ContinuousEffect effect = new LightUpTheStageMayPlayEffect(); + effect.setTargetPointer(new FixedTarget(card.getId())); + game.addEffect(effect, source); + } + + return true; + } + return false; + } +} + +class LightUpTheStageMayPlayEffect extends AsThoughEffectImpl { + + private int castOnTurn = 0; + + public LightUpTheStageMayPlayEffect() { + super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.Custom, Outcome.Benefit); + this.staticText = "Until the end of your next turn, you may play that card."; + } + + public LightUpTheStageMayPlayEffect(final LightUpTheStageMayPlayEffect effect) { + super(effect); + castOnTurn = effect.castOnTurn; + } + + @Override + public LightUpTheStageMayPlayEffect copy() { + return new LightUpTheStageMayPlayEffect(this); + } + + @Override + public void init(Ability source, Game game) { + super.init(source, game); + castOnTurn = game.getTurnNum(); + } + + @Override + public boolean isInactive(Ability source, Game game) { + if (castOnTurn != game.getTurnNum() && game.getPhase().getStep().getType() == PhaseStep.END_TURN) { + if (game.isActivePlayer(source.getControllerId())) { + return true; + } + } + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { + return source.isControlledBy(affectedControllerId) + && getTargetPointer().getTargets(game, source).contains(sourceId); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LimitedResources.java b/Mage.Sets/src/mage/cards/l/LimitedResources.java new file mode 100644 index 00000000000..fc97e014235 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LimitedResources.java @@ -0,0 +1,124 @@ +package mage.cards.l; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.common.FilterControlledLandPermanent; +import mage.filter.common.FilterLandPermanent; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.players.Player; +import mage.target.common.TargetLandPermanent; + +/** + * + * @author jeffwadsworth + */ +public final class LimitedResources extends CardImpl { + + public LimitedResources(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}"); + + // When Limited Resources enters the battlefield, each player chooses five lands he or she controls and sacrifices the rest. + this.addAbility(new EntersBattlefieldTriggeredAbility(new LimitedResourcesEffect(), false)); + + // Players can't play lands as long as ten or more lands are on the battlefield. + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new ConditionalContinuousRuleModifyingEffect( + new CantPlayLandEffect(), + new PermanentsOnTheBattlefieldCondition( + new FilterLandPermanent(), + ComparisonType.MORE_THAN, 9)))); + + } + + public LimitedResources(final LimitedResources card) { + super(card); + } + + @Override + public LimitedResources copy() { + return new LimitedResources(this); + } +} + +class LimitedResourcesEffect extends OneShotEffect { + + public LimitedResourcesEffect() { + super(Outcome.Benefit); + this.staticText = "each player chooses five lands he or she controls and sacrifices the rest"; + } + + public LimitedResourcesEffect(final LimitedResourcesEffect effect) { + super(effect); + } + + @Override + public LimitedResourcesEffect copy() { + return new LimitedResourcesEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + game.getState().getPlayersInRange(source.getControllerId(), game).forEach((playerId) -> { + Player player = game.getPlayer(playerId); + if (player != null) { + int lands = game.getBattlefield().countAll(new FilterControlledLandPermanent(), playerId, game); + TargetLandPermanent target = new TargetLandPermanent(Integer.min(5, lands)); + target.setNotTarget(true); + target.setRequired(true); + player.chooseTarget(outcome.Benefit, target, source, game); + game.getBattlefield().getAllActivePermanents(new FilterControlledLandPermanent(), playerId, game).stream().filter((land) -> (!target.getTargets().contains(land.getId()))).forEachOrdered((land) -> { + land.sacrifice(source.getSourceId(), game); + }); + } + }); + return true; + } +} + +class CantPlayLandEffect extends ContinuousRuleModifyingEffectImpl { + + public CantPlayLandEffect() { + super(Duration.WhileOnBattlefield, Outcome.Detriment); + this.staticText = "Players can't play lands as long as ten or more lands are on the battlefield"; + } + + public CantPlayLandEffect(final CantPlayLandEffect effect) { + super(effect); + } + + @Override + public CantPlayLandEffect copy() { + return new CantPlayLandEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.PLAY_LAND; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return true; + } + +} diff --git a/Mage.Sets/src/mage/cards/m/MagusOfTheScroll.java b/Mage.Sets/src/mage/cards/m/MagusOfTheScroll.java index cc23294d283..c5d0627c377 100644 --- a/Mage.Sets/src/mage/cards/m/MagusOfTheScroll.java +++ b/Mage.Sets/src/mage/cards/m/MagusOfTheScroll.java @@ -1,7 +1,5 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -10,11 +8,7 @@ import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ChooseACardNameEffect; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; +import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; @@ -23,9 +17,11 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetAnyTarget; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author fireshoes */ public final class MagusOfTheScroll extends CardImpl { @@ -80,7 +76,7 @@ class MagusOfTheScrollEffect extends OneShotEffect { } revealed.add(card); you.revealCards(sourceObject.getName(), revealed, game); - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { Permanent creature = game.getPermanent(targetPointer.getFirst(game, source)); if (creature != null) { creature.damage(2, source.getSourceId(), game, false, true); diff --git a/Mage.Sets/src/mage/cards/m/MindMaggots.java b/Mage.Sets/src/mage/cards/m/MindMaggots.java new file mode 100644 index 00000000000..a53f2ceb1eb --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MindMaggots.java @@ -0,0 +1,88 @@ +package mage.cards.m; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.Card; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.counters.CounterType; +import mage.filter.common.FilterCreatureCard; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInHand; + +/** + * + * @author jeffwadsworth + */ +public final class MindMaggots extends CardImpl { + + public MindMaggots(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + + this.subtype.add(SubType.INSECT); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When Mind Maggots enters the battlefield, discard any number of creature cards. + // For each card discarded this way, put two +1/+1 counters on Mind Maggots. + this.addAbility(new EntersBattlefieldTriggeredAbility(new MindMaggotsEffect())); + + } + + public MindMaggots(final MindMaggots card) { + super(card); + } + + @Override + public MindMaggots copy() { + return new MindMaggots(this); + } +} + +class MindMaggotsEffect extends OneShotEffect { + + MindMaggotsEffect() { + super(Outcome.BoostCreature); + this.staticText = "discard any number of creature cards. For each card discarded this way, put two +1/+1 counters on {this}"; + } + + MindMaggotsEffect(final MindMaggotsEffect effect) { + super(effect); + } + + @Override + public MindMaggotsEffect copy() { + return new MindMaggotsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + int numToDiscard = controller.getAmount(0, + controller.getHand().getCards(new FilterCreatureCard(), game).size(), + "Discard how many creature cards?", + game); + TargetCardInHand target = new TargetCardInHand(numToDiscard, new FilterCreatureCard()); + if (controller.choose(Outcome.Benefit, target, source.getSourceId(), game)) { + for (UUID targetId : target.getTargets()) { + Card card = game.getCard(targetId); + if (card != null + && controller.discard(card, source, game)) { + new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)).apply(game, source); + } + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/m/Mirari.java b/Mage.Sets/src/mage/cards/m/Mirari.java index 0c0b0fe580f..da05fc00c09 100644 --- a/Mage.Sets/src/mage/cards/m/Mirari.java +++ b/Mage.Sets/src/mage/cards/m/Mirari.java @@ -1,7 +1,5 @@ - package mage.cards.m; -import java.util.UUID; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.Effect; @@ -19,17 +17,17 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.stack.Spell; -import mage.target.TargetSpell; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class Mirari extends CardImpl { public Mirari(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{5}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{5}"); addSuperType(SuperType.LEGENDARY); // Whenever you cast an instant or sorcery spell, you may pay {3}. If you do, copy that spell. You may choose new targets for the copy. @@ -58,8 +56,9 @@ class MirariTriggeredAbility extends TriggeredAbilityImpl { } MirariTriggeredAbility() { - super(Zone.BATTLEFIELD, new DoIfCostPaid(new CopyTargetSpellEffect(true), new GenericManaCost(3)), false); - this.addTarget(new TargetSpell(filter)); + super(Zone.BATTLEFIELD, new DoIfCostPaid( + new CopyTargetSpellEffect(true), + new GenericManaCost(3)), false); } MirariTriggeredAbility(final MirariTriggeredAbility ability) { @@ -82,7 +81,11 @@ class MirariTriggeredAbility extends TriggeredAbilityImpl { Spell spell = game.getStack().getSpell(event.getTargetId()); if (isControlledInstantOrSorcery(spell)) { for (Effect effect : getEffects()) { - effect.setTargetPointer(new FixedTarget(spell.getId())); + if (effect instanceof DoIfCostPaid) { + for (Effect execEffect : ((DoIfCostPaid) effect).getExecutingEffects()) { + execEffect.setTargetPointer(new FixedTarget(spell.getId())); + } + } } return true; } diff --git a/Mage.Sets/src/mage/cards/m/MoggBombers.java b/Mage.Sets/src/mage/cards/m/MoggBombers.java new file mode 100644 index 00000000000..65700c1643e --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MoggBombers.java @@ -0,0 +1,60 @@ +package mage.cards.m; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.target.TargetPlayer; + +/** + * + * @author jeffwadsworth + */ +public final class MoggBombers extends CardImpl { + + private static final String rule = "When another creature enters the battlefield, sacrifice {this} and it deals 3 damage to target player."; + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); + + static { + filter.add(new AnotherPredicate()); + } + + public MoggBombers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.subtype.add(SubType.GOBLIN); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // When another creature enters the battlefield, sacrifice Mogg Bombers and it deals 3 damage to target player. + Effect sacrificeMoggBombers = new SacrificeSourceEffect(); + Effect damageTargetPlayer = new DamageTargetEffect(3); + Ability ability = new EntersBattlefieldAllTriggeredAbility( + Zone.BATTLEFIELD, + sacrificeMoggBombers, + filter, false, rule); + ability.addEffect(damageTargetPlayer); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + + } + + public MoggBombers(final MoggBombers card) { + super(card); + } + + @Override + public MoggBombers copy() { + return new MoggBombers(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MonstrousHound.java b/Mage.Sets/src/mage/cards/m/MonstrousHound.java new file mode 100644 index 00000000000..06dc331a670 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MonstrousHound.java @@ -0,0 +1,131 @@ +package mage.cards.m; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.RestrictionEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.filter.common.FilterControlledLandPermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author jeffwadsworth + */ +public final class MonstrousHound extends CardImpl { + + public MonstrousHound(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.subtype.add(SubType.HOUND); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Monstrous Hound can't attack unless you control more lands than defending player. + Effect effect = new CantAttackUnlessControllerControlsMoreLandsEffect(); + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + effect.setText("{this} can't attack unless you control more lands than defending player"))); + + // Monstrous Hound can't block unless you control more lands than attacking player. + Effect effect2 = new CantBlockUnlessControllerControlsMoreLandsEffect(); + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + effect2.setText("{this} can't block unless you control more lands than attacking player"))); + + } + + public MonstrousHound(final MonstrousHound card) { + super(card); + } + + @Override + public MonstrousHound copy() { + return new MonstrousHound(this); + } +} + +class CantAttackUnlessControllerControlsMoreLandsEffect extends RestrictionEffect { + + CantAttackUnlessControllerControlsMoreLandsEffect() { + super(Duration.WhileOnBattlefield); + } + + CantAttackUnlessControllerControlsMoreLandsEffect(final CantAttackUnlessControllerControlsMoreLandsEffect effect) { + super(effect); + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + return permanent.getId().equals(source.getSourceId()); + } + + @Override + public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) { + UUID defendingPlayerId; + Player defender = game.getPlayer(defenderId); + if (defender == null) { + Permanent permanent = game.getPermanent(defenderId); + if (permanent != null) { + defendingPlayerId = permanent.getControllerId(); + } else { + return false; + } + } else { + defendingPlayerId = defenderId; + } + if (defendingPlayerId != null) { + return game.getBattlefield().countAll(new FilterControlledLandPermanent(), + source.getControllerId(), game) > game.getBattlefield().countAll(new FilterControlledLandPermanent(), + defendingPlayerId, game); + } else { + return true; + } + } + + @Override + public CantAttackUnlessControllerControlsMoreLandsEffect copy() { + return new CantAttackUnlessControllerControlsMoreLandsEffect(this); + } +} + +class CantBlockUnlessControllerControlsMoreLandsEffect extends RestrictionEffect { + + CantBlockUnlessControllerControlsMoreLandsEffect() { + super(Duration.WhileOnBattlefield); + } + + CantBlockUnlessControllerControlsMoreLandsEffect(final CantBlockUnlessControllerControlsMoreLandsEffect effect) { + super(effect); + } + + @Override + public CantBlockUnlessControllerControlsMoreLandsEffect copy() { + return new CantBlockUnlessControllerControlsMoreLandsEffect(this); + } + + @Override + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + UUID attackingPlayerId = attacker.getControllerId(); + if (attackingPlayerId != null) { + return game.getBattlefield().countAll(new FilterControlledLandPermanent(), + source.getControllerId(), game) > game.getBattlefield().countAll(new FilterControlledLandPermanent(), + attackingPlayerId, game); + } + return true; + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + return permanent.getId().equals(source.getSourceId()); + } +} diff --git a/Mage.Sets/src/mage/cards/o/OathOfLieges.java b/Mage.Sets/src/mage/cards/o/OathOfLieges.java index be8afeaef33..9fc5d053366 100644 --- a/Mage.Sets/src/mage/cards/o/OathOfLieges.java +++ b/Mage.Sets/src/mage/cards/o/OathOfLieges.java @@ -1,4 +1,3 @@ - package mage.cards.o; import mage.abilities.Ability; @@ -18,6 +17,7 @@ import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; import mage.players.Player; +import mage.target.Target; import mage.target.TargetPlayer; import mage.target.common.TargetCardInLibrary; import mage.target.targetpointer.FixedTarget; @@ -25,12 +25,10 @@ import mage.target.targetpointer.FixedTarget; import java.util.UUID; /** - * * @author emerald000 */ public final class OathOfLieges extends CardImpl { - private final UUID originalId; private static final FilterPlayer FILTER = new FilterPlayer("player who controls more lands than you do and is your opponent"); static { @@ -43,26 +41,19 @@ public final class OathOfLieges extends CardImpl { // At the beginning of each player's upkeep, that player chooses target player who controls more lands than he or she does and is their opponent. The first player may search their library for a basic land card, put that card onto the battlefield, then shuffle their library. Ability ability = new BeginningOfUpkeepTriggeredAbility(new OathOfLiegesEffect(), TargetController.ANY, false); ability.addTarget(new TargetPlayer(1, 1, false, FILTER)); - originalId = ability.getOriginalId(); this.addAbility(ability); } @Override public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(originalId)) { - Player activePlayer = game.getPlayer(game.getActivePlayerId()); - if (activePlayer != null) { - ability.getTargets().clear(); - TargetPlayer target = new TargetPlayer(1, 1, false, FILTER); - target.setTargetController(activePlayer.getId()); - ability.getTargets().add(target); - } + // target controller must be active player (even for copies) + for (Target target : ability.getTargets()) { + target.setTargetController(game.getActivePlayerId()); } } public OathOfLieges(final OathOfLieges card) { super(card); - this.originalId = card.originalId; } @Override @@ -93,7 +84,7 @@ class OathOfLiegesEffect extends OneShotEffect { Player activePlayer = game.getPlayer(game.getActivePlayerId()); if (activePlayer != null) { if (activePlayer.chooseUse(outcome, "Search your library for a basic land card, put that card onto the battlefield, then shuffle your library?", source, game)) { - Effect effect = new SearchLibraryPutInPlayTargetPlayerEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND), false, true, Outcome.PutLandInPlay, true); + Effect effect = new SearchLibraryPutInPlayTargetPlayerEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND), false, false, Outcome.PutLandInPlay, true); effect.setTargetPointer(new FixedTarget(game.getActivePlayerId())); return effect.apply(game, source); } @@ -110,18 +101,25 @@ class OathOfLiegesPredicate implements ObjectSourcePlayerPredicate input, Game game) { + // input.getPlayerId() -- source controller id + // input.getObject() -- checking player + Player targetPlayer = input.getObject(); //Get active input.playerId because adjust target is used after canTarget function - UUID activePlayerId = game.getActivePlayerId(); - if (targetPlayer == null || activePlayerId == null) { - return false; - } - if (!targetPlayer.hasOpponent(activePlayerId, game)) { - return false; - } - int countTargetPlayer = game.getBattlefield().countAll(FILTER, targetPlayer.getId(), game); - int countActivePlayer = game.getBattlefield().countAll(FILTER, activePlayerId, game); + Player activePlayer = game.getPlayer(game.getActivePlayerId()); + if (targetPlayer == null || activePlayer == null) { + return false; + } + + // must be opponent + if (!activePlayer.hasOpponent(targetPlayer.getId(), game)) { + return false; + } + + // must have more lands than active player + int countTargetPlayer = game.getBattlefield().countAll(FILTER, targetPlayer.getId(), game); + int countActivePlayer = game.getBattlefield().countAll(FILTER, activePlayer.getId(), game); return countTargetPlayer > countActivePlayer; } diff --git a/Mage.Sets/src/mage/cards/p/PalisadeGiant.java b/Mage.Sets/src/mage/cards/p/PalisadeGiant.java index 10a8ffde346..0ceed13bfb4 100644 --- a/Mage.Sets/src/mage/cards/p/PalisadeGiant.java +++ b/Mage.Sets/src/mage/cards/p/PalisadeGiant.java @@ -1,23 +1,20 @@ - package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ReplacementEffectImpl; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.events.DamageEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.util.CardUtil; + +import java.util.UUID; /** * @author LevelX2 @@ -43,7 +40,7 @@ import mage.players.Player; public final class PalisadeGiant extends CardImpl { public PalisadeGiant(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}{W}"); this.subtype.add(SubType.GIANT); this.subtype.add(SubType.SOLDIER); @@ -51,7 +48,7 @@ public final class PalisadeGiant extends CardImpl { this.toughness = new MageInt(7); // All damage that would be dealt to you or another permanent you control is dealt to Palisade Giant instead. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PalisadeGiantReplacementEffect())); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PalisadeGiantReplacementEffect())); } public PalisadeGiant(final PalisadeGiant card) { @@ -77,7 +74,7 @@ class PalisadeGiantReplacementEffect extends ReplacementEffectImpl { @Override public boolean checksEventType(GameEvent event, Game game) { - switch(event.getType()) { + switch (event.getType()) { case DAMAGE_CREATURE: case DAMAGE_PLAYER: case DAMAGE_PLANESWALKER: @@ -89,17 +86,15 @@ class PalisadeGiantReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == GameEvent.EventType.DAMAGE_PLAYER && event.getPlayerId().equals(source.getControllerId())) - { - return true; + if (event.getType() == GameEvent.EventType.DAMAGE_PLAYER && event.getPlayerId().equals(source.getControllerId())) { + return true; } - if (event.getType() == GameEvent.EventType.DAMAGE_CREATURE || event.getType() == GameEvent.EventType.DAMAGE_PLANESWALKER) - { + if (event.getType() == GameEvent.EventType.DAMAGE_CREATURE || event.getType() == GameEvent.EventType.DAMAGE_PLANESWALKER) { Permanent targetPermanent = game.getPermanent(event.getTargetId()); Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - if (targetPermanent != null && + if (targetPermanent != null && targetPermanent.isControlledBy(source.getControllerId()) && - !targetPermanent.getName().equals(sourcePermanent.getName())) { // no redirection from or to other Palisade Giants + !CardUtil.haveSameNames(targetPermanent, sourcePermanent)) { // no redirection from or to other Palisade Giants return true; } } @@ -108,7 +103,7 @@ class PalisadeGiantReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - DamageEvent damageEvent = (DamageEvent)event; + DamageEvent damageEvent = (DamageEvent) event; Permanent sourcePermanent = game.getPermanent(source.getSourceId()); if (sourcePermanent != null) { // get name of old target @@ -118,13 +113,11 @@ class PalisadeGiantReplacementEffect extends ReplacementEffectImpl { message.append(damageEvent.getAmount()).append(" damage redirected from "); if (targetPermanent != null) { message.append(targetPermanent.getName()); - } - else { + } else { Player targetPlayer = game.getPlayer(event.getTargetId()); if (targetPlayer != null) { message.append(targetPlayer.getLogName()); - } - else { + } else { message.append("unknown"); } diff --git a/Mage.Sets/src/mage/cards/p/Paroxysm.java b/Mage.Sets/src/mage/cards/p/Paroxysm.java new file mode 100644 index 00000000000..753951b5c18 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/Paroxysm.java @@ -0,0 +1,111 @@ +package mage.cards.p; + +import java.util.UUID; +import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.constants.Outcome; +import mage.target.TargetPermanent; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author jeffwadsworth + */ +public final class Paroxysm extends CardImpl { + + public Paroxysm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // At the beginning of the upkeep of enchanted creature's controller, that player reveals the top card of his or her library. + // If that card is a land card, destroy that creature. Otherwise, it gets +3/+3 until end of turn. + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + Zone.BATTLEFIELD, + new ParoxysmEffect(), + TargetController.CONTROLLER_ATTACHED_TO, + false, false, "At the beginning of the upkeep of enchanted creature's controller, ")); + } + + public Paroxysm(final Paroxysm card) { + super(card); + } + + @Override + public Paroxysm copy() { + return new Paroxysm(this); + } +} + +class ParoxysmEffect extends OneShotEffect { + + ParoxysmEffect() { + super(Outcome.BoostCreature); + this.staticText = "that player reveals the top card of his or her library. \n" + + "If that card is a land card, destroy that creature. \n" + + "Otherwise, it gets +3/+3 until end of turn."; + } + + ParoxysmEffect(final ParoxysmEffect effect) { + super(effect); + } + + @Override + public ParoxysmEffect copy() { + return new ParoxysmEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent aura = game.getPermanent(source.getSourceId()); + if (aura != null) { + Permanent creatureAttachedTo = game.getPermanent(aura.getAttachedTo()); + if (creatureAttachedTo != null) { + Player controllerOfCreature = game.getPlayer(creatureAttachedTo.getControllerId()); + if (controllerOfCreature != null) { + Card revealCardFromTop = controllerOfCreature.getLibrary().getFromTop(game); + if (revealCardFromTop != null) { + Cards cards = new CardsImpl(); + cards.add(revealCardFromTop); + controllerOfCreature.revealCards(source, cards, game); + if (revealCardFromTop.isLand()) { + creatureAttachedTo.destroy(source.getSourceId(), game, false); + } else { + ContinuousEffect effect = new BoostTargetEffect(3, 3, Duration.EndOfTurn); + effect.setTargetPointer(new FixedTarget(creatureAttachedTo.getId())); + game.addEffect(effect, source); + } + return true; + } + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/p/PatternOfRebirth.java b/Mage.Sets/src/mage/cards/p/PatternOfRebirth.java index a9cc52feb65..8184f1d0602 100644 --- a/Mage.Sets/src/mage/cards/p/PatternOfRebirth.java +++ b/Mage.Sets/src/mage/cards/p/PatternOfRebirth.java @@ -1,7 +1,5 @@ - package mage.cards.p; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.DiesAttachedTriggeredAbility; import mage.abilities.effects.Effect; @@ -11,22 +9,23 @@ import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; import mage.constants.SetTargetPointer; +import mage.constants.SubType; import mage.filter.common.FilterCreatureCard; import mage.target.TargetPermanent; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class PatternOfRebirth extends CardImpl { public PatternOfRebirth(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}"); this.subtype.add(SubType.AURA); // Enchant creature @@ -37,7 +36,7 @@ public final class PatternOfRebirth extends CardImpl { this.addAbility(ability); // When enchanted creature dies, that creature's controller may search their library for a creature card and put that card onto the battlefield. If that player does, he or she shuffles their library. - Effect effect = new SearchLibraryPutInPlayTargetPlayerEffect(new TargetCardInLibrary(new FilterCreatureCard()), false, true, Outcome.PutCreatureInPlay); + Effect effect = new SearchLibraryPutInPlayTargetPlayerEffect(new TargetCardInLibrary(new FilterCreatureCard()), false, false, Outcome.PutCreatureInPlay); effect.setText("that creature's controller may search their library for a creature card and put that card onto the battlefield. If that player does, he or she shuffles their library"); this.addAbility(new DiesAttachedTriggeredAbility(effect, "enchanted creature", true, true, SetTargetPointer.ATTACHED_TO_CONTROLLER)); diff --git a/Mage.Sets/src/mage/cards/p/PetraSphinx.java b/Mage.Sets/src/mage/cards/p/PetraSphinx.java index cb6197c333a..253d4e77f01 100644 --- a/Mage.Sets/src/mage/cards/p/PetraSphinx.java +++ b/Mage.Sets/src/mage/cards/p/PetraSphinx.java @@ -1,7 +1,5 @@ - package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -20,8 +18,9 @@ import mage.players.Player; import mage.target.TargetPlayer; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com & L_J */ public final class PetraSphinx extends CardImpl { @@ -79,7 +78,7 @@ class PetraSphinxEffect extends OneShotEffect { if (card != null) { Cards cards = new CardsImpl(card); player.revealCards(source, cards, game); - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { player.moveCards(cards, Zone.HAND, source, game); } else { player.moveCards(cards, Zone.GRAVEYARD, source, game); diff --git a/Mage.Sets/src/mage/cards/p/Predict.java b/Mage.Sets/src/mage/cards/p/Predict.java index 193ae9b8c0f..c2ae143a7af 100644 --- a/Mage.Sets/src/mage/cards/p/Predict.java +++ b/Mage.Sets/src/mage/cards/p/Predict.java @@ -1,6 +1,5 @@ package mage.cards.p; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ChooseACardNameEffect; @@ -13,9 +12,11 @@ import mage.constants.Zone; import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author Quercitron */ public final class Predict extends CardImpl { @@ -66,7 +67,7 @@ class PredictEffect extends OneShotEffect { Card card = targetPlayer.getLibrary().getFromTop(game); if (card != null) { controller.moveCards(card, Zone.GRAVEYARD, source, game); - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { amount = 2; } } diff --git a/Mage.Sets/src/mage/cards/p/ProwlingPangolin.java b/Mage.Sets/src/mage/cards/p/ProwlingPangolin.java index a6c373ffd12..e6eed743932 100644 --- a/Mage.Sets/src/mage/cards/p/ProwlingPangolin.java +++ b/Mage.Sets/src/mage/cards/p/ProwlingPangolin.java @@ -1,4 +1,3 @@ - package mage.cards.p; import java.util.UUID; @@ -11,8 +10,8 @@ import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; @@ -26,7 +25,7 @@ import mage.target.common.TargetControlledPermanent; public final class ProwlingPangolin extends CardImpl { public ProwlingPangolin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); this.subtype.add(SubType.BEAST, SubType.PANGOLIN); this.power = new MageInt(6); this.toughness = new MageInt(5); diff --git a/Mage.Sets/src/mage/cards/p/PyromancerAscension.java b/Mage.Sets/src/mage/cards/p/PyromancerAscension.java index c4831f5dd24..2f6f1760781 100644 --- a/Mage.Sets/src/mage/cards/p/PyromancerAscension.java +++ b/Mage.Sets/src/mage/cards/p/PyromancerAscension.java @@ -1,8 +1,5 @@ - - package mage.cards.p; -import java.util.UUID; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.common.CopyTargetSpellEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; @@ -17,19 +14,21 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.game.stack.Spell; import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author nantuko */ public final class PyromancerAscension extends CardImpl { public PyromancerAscension(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}"); // Whenever you cast an instant or sorcery spell that has the same name as a card in your graveyard, you may put a quest counter on Pyromancer Ascension. this.addAbility(new PyromancerAscensionQuestTriggeredAbility()); - + // Whenever you cast an instant or sorcery spell while Pyromancer Ascension has two or more quest counters on it, you may copy that spell. You may choose new targets for the copy. this.addAbility(new PyromancerAscensionCopyTriggeredAbility()); } @@ -75,21 +74,21 @@ class PyromancerAscensionQuestTriggeredAbility extends TriggeredAbilityImpl { for (UUID uuid : game.getPlayer(this.getControllerId()).getGraveyard()) { if (!uuid.equals(sourceCard.getId())) { Card card = game.getCard(uuid); - if (card != null && card.getName().equals(sourceCard.getName())) { + if (CardUtil.haveSameNames(card, sourceCard)) { return true; } } } - } + } } } return false; } private boolean isControlledInstantOrSorcery(Spell spell) { - return spell != null && - (spell.isControlledBy(this.getControllerId())) && - (spell.isInstant() || spell.isSorcery()); + return spell != null && + (spell.isControlledBy(this.getControllerId())) && + (spell.isInstant() || spell.isSorcery()); } @Override @@ -112,12 +111,12 @@ class PyromancerAscensionCopyTriggeredAbility extends TriggeredAbilityImpl { public PyromancerAscensionCopyTriggeredAbility copy() { return new PyromancerAscensionCopyTriggeredAbility(this); } - + @Override public boolean checkEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.SPELL_CAST; } - + @Override public boolean checkTrigger(GameEvent event, Game game) { if (event.getPlayerId().equals(this.getControllerId())) { @@ -134,9 +133,9 @@ class PyromancerAscensionCopyTriggeredAbility extends TriggeredAbilityImpl { } private boolean isControlledInstantOrSorcery(Spell spell) { - return spell != null && - (spell.isControlledBy(this.getControllerId())) && - (spell.isInstant() || spell.isSorcery()); + return spell != null && + (spell.isControlledBy(this.getControllerId())) && + (spell.isInstant() || spell.isSorcery()); } @Override diff --git a/Mage.Sets/src/mage/cards/r/RafterDemon.java b/Mage.Sets/src/mage/cards/r/RafterDemon.java new file mode 100644 index 00000000000..10e7f1afef7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RafterDemon.java @@ -0,0 +1,53 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.common.SpectacleCondition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.discard.DiscardEachPlayerEffect; +import mage.abilities.keyword.SpectacleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RafterDemon extends CardImpl { + + public RafterDemon(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{R}"); + + this.subtype.add(SubType.DEMON); + this.power = new MageInt(4); + this.toughness = new MageInt(2); + + // Spectacle {3}{B}{R} + this.addAbility(new SpectacleAbility(this, new ManaCostsImpl("{3}{B}{R}"))); + + // When Rafter Demon enters the battlefield, if its spectacle cost was paid, each opponent discards a card. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new EntersBattlefieldTriggeredAbility(new DiscardEachPlayerEffect( + new StaticValue(1), false, TargetController.OPPONENT + )), SpectacleCondition.instance, + "When {this} enters the battlefield, " + + "if its spectacle cost was paid, " + + "each opponent discards a card." + )); + } + + public RafterDemon(final RafterDemon card) { + super(card); + } + + @Override + public RafterDemon copy() { + return new RafterDemon(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RakdosFirewheeler.java b/Mage.Sets/src/mage/cards/r/RakdosFirewheeler.java new file mode 100644 index 00000000000..95b66c9ad04 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RakdosFirewheeler.java @@ -0,0 +1,49 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; +import mage.target.common.TargetCreatureOrPlaneswalker; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author jmharmon + */ + +public final class RakdosFirewheeler extends CardImpl { + + public RakdosFirewheeler(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{B}{R}{R}"); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // When Rakdos Firewheeler enters the battlefield, it deals 2 damage to target opponent and 2 damage to up to one target creature or planeswalker. + Effect effect = new DamageTargetEffect(2); + effect.setText("it deals 2 damage to target opponent and 2 damage to up to one target creature or planeswalker"); + Ability ability = new EntersBattlefieldTriggeredAbility(effect, false); + ability.addTarget(new TargetOpponent()); + ability.addTarget(new TargetCreatureOrPlaneswalker(0, 1, new FilterCreatureOrPlaneswalkerPermanent(), false)); + this.addAbility(ability); + } + + public RakdosFirewheeler(final RakdosFirewheeler card) { + super(card); + } + + @Override + public RakdosFirewheeler copy() { + return new RakdosFirewheeler(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/Ransack.java b/Mage.Sets/src/mage/cards/r/Ransack.java new file mode 100644 index 00000000000..32e69f711fe --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/Ransack.java @@ -0,0 +1,87 @@ +package mage.cards.r; + +import static java.lang.Integer.min; +import java.util.Set; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.TargetPlayer; + +/** + * + * @author jeffwadsworth + */ +public final class Ransack extends CardImpl { + + public Ransack(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{U}"); + + // Look at the top five cards of target player's library. + //Put any number of them on the bottom of that library in any order + //and the rest on top of the library in any order. + this.getSpellAbility().addEffect(new RansackEffect()); + this.getSpellAbility().addTarget(new TargetPlayer()); + + } + + public Ransack(final Ransack card) { + super(card); + } + + @Override + public Ransack copy() { + return new Ransack(this); + } +} + +class RansackEffect extends OneShotEffect { + + public RansackEffect() { + super(Outcome.Detriment); + this.staticText = "Look at the top five cards of target player's library. " + + "Put any number of them on the bottom of that library in any order " + + "and the rest on top of the library in any order"; + } + + public RansackEffect(final RansackEffect effect) { + super(effect); + } + + @Override + public RansackEffect copy() { + return new RansackEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getFirstTarget()); + FilterCard filter = new FilterCard("cards to put on the bottom of your library"); + if (player != null) { + int number = min(player.getLibrary().size(), 5); + Set cards = player.getLibrary().getTopCards(game, number); + Cards cardsRemaining = new CardsImpl(); + cardsRemaining.addAll(cards); + TargetCard target = new TargetCard((true ? 0 : number), number, Zone.LIBRARY, filter); + if (player.choose(Outcome.DrawCard, cardsRemaining, target, game)) { + Cards pickedCards = new CardsImpl(target.getTargets()); + cardsRemaining.removeAll(pickedCards); + player.putCardsOnBottomOfLibrary(pickedCards, game, source, true); + player.putCardsOnTopOfLibrary(cardsRemaining, game, source, true); + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RapidHybridization.java b/Mage.Sets/src/mage/cards/r/RapidHybridization.java index c86b017c128..5c157eeb927 100644 --- a/Mage.Sets/src/mage/cards/r/RapidHybridization.java +++ b/Mage.Sets/src/mage/cards/r/RapidHybridization.java @@ -11,7 +11,7 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.game.permanent.token.RapidHybridizationToken; +import mage.game.permanent.token.FrogLizardToken; import mage.target.common.TargetCreaturePermanent; /** @@ -59,7 +59,7 @@ class RapidHybridizationEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanentOrLKIBattlefield(targetPointer.getFirst(game, source)); if (permanent != null) { - RapidHybridizationToken token = new RapidHybridizationToken(); + FrogLizardToken token = new FrogLizardToken(); token.putOntoBattlefield(1, game, source.getSourceId(), permanent.getControllerId()); } return true; diff --git a/Mage.Sets/src/mage/cards/r/Rebound.java b/Mage.Sets/src/mage/cards/r/Rebound.java new file mode 100644 index 00000000000..5afdee305da --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/Rebound.java @@ -0,0 +1,77 @@ +package mage.cards.r; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.FilterSpell; +import mage.filter.predicate.other.TargetsOnlyOnePlayerPredicate; +import mage.game.Game; +import mage.game.stack.Spell; +import mage.players.Player; +import mage.target.TargetPlayer; +import mage.target.TargetSpell; + +/** + * + * @author jeffwadsworth + */ +public final class Rebound extends CardImpl { + + public Rebound(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); + + // Change the target of target spell that targets only a player. The new target must be a player. + this.getSpellAbility().addEffect(new ReboundEffect()); + FilterSpell filter = new FilterSpell("spell that targets only a player"); + filter.add(new TargetsOnlyOnePlayerPredicate()); + this.getSpellAbility().addTarget(new TargetSpell(filter)); + + } + + public Rebound(final Rebound card) { + super(card); + } + + @Override + public Rebound copy() { + return new Rebound(this); + } +} + +class ReboundEffect extends OneShotEffect { + + public ReboundEffect() { + super(Outcome.Neutral); + this.staticText = "Change the target of target spell that targets only a player. The new target must be a player"; + } + + public ReboundEffect(final ReboundEffect effect) { + super(effect); + } + + @Override + public ReboundEffect copy() { + return new ReboundEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Spell spell = game.getStack().getSpell(source.getFirstTarget()); + Player controller = game.getPlayer(source.getControllerId()); + if (spell != null + && controller != null) { + spell.getSpellAbility().getTargets().clear(); + TargetPlayer targetPlayer = new TargetPlayer(); + if (controller.choose(Outcome.Neutral, targetPlayer, source.getSourceId(), game)) { + spell.getSpellAbility().addTarget(targetPlayer); + game.informPlayers("The target of the spell was changed to " + targetPlayer.getTargetedName(game)); + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/r/ReflectorMage.java b/Mage.Sets/src/mage/cards/r/ReflectorMage.java index a2514e833ed..a7a087b19e2 100644 --- a/Mage.Sets/src/mage/cards/r/ReflectorMage.java +++ b/Mage.Sets/src/mage/cards/r/ReflectorMage.java @@ -1,8 +1,5 @@ - package mage.cards.r; -import java.util.Objects; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -11,12 +8,7 @@ import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerPredicate; import mage.game.Game; @@ -25,9 +17,12 @@ import mage.game.permanent.Permanent; import mage.game.stack.Spell; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import mage.util.CardUtil; + +import java.util.Objects; +import java.util.UUID; /** - * * @author LevelX2 */ public final class ReflectorMage extends CardImpl { @@ -84,7 +79,7 @@ class ReflectorMageEffect extends OneShotEffect { Permanent targetCreature = game.getPermanent(getTargetPointer().getFirst(game, source)); if (targetCreature != null) { controller.moveCards(targetCreature, Zone.HAND, source, game); - if (!targetCreature.getName().isEmpty()) { // if the creature had no name, no restrict effect will be created + if (!CardUtil.haveEmptyName(targetCreature)) { // if the creature had no name, no restrict effect will be created game.addEffect(new ExclusionRitualReplacementEffect(targetCreature.getName(), targetCreature.getOwnerId()), source); } } @@ -125,7 +120,7 @@ class ExclusionRitualReplacementEffect extends ContinuousRuleModifyingEffectImpl if (spell != null && spell.isFaceDown(game)) { return false; // Face Down cast spell (Morph creature) has no name } - return card.getName().equals(creatureName) && Objects.equals(ownerId, card.getOwnerId()); + return CardUtil.haveSameNames(card.getName(), creatureName) && Objects.equals(ownerId, card.getOwnerId()); } return false; } diff --git a/Mage.Sets/src/mage/cards/r/Reverberation.java b/Mage.Sets/src/mage/cards/r/Reverberation.java new file mode 100644 index 00000000000..0a0768ae700 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/Reverberation.java @@ -0,0 +1,105 @@ + +package mage.cards.r; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.filter.FilterSpell; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.game.events.DamageEvent; +import mage.game.events.GameEvent; +import mage.game.stack.Spell; +import mage.players.Player; +import mage.target.TargetSpell; + +/** + * + * @author L_J + */ +public final class Reverberation extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("sorcery spell"); + + static { + filter.add(new CardTypePredicate(CardType.SORCERY)); + } + + public Reverberation(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U}{U}"); + + // All damage that would be dealt this turn by target sorcery spell is dealt to that spell’s controller instead. + this.getSpellAbility().addEffect(new ReverberationEffect()); + this.getSpellAbility().addTarget(new TargetSpell(filter)); + } + + public Reverberation(final Reverberation card) { + super(card); + } + + @Override + public Reverberation copy() { + return new Reverberation(this); + } +} + +class ReverberationEffect extends ReplacementEffectImpl { + + public ReverberationEffect() { + super(Duration.EndOfTurn, Outcome.RedirectDamage); + staticText = "All damage that would be dealt this turn by target sorcery spell is dealt to that spell’s controller instead"; + } + + public ReverberationEffect(final ReverberationEffect effect) { + super(effect); + } + + @Override + public ReverberationEffect copy() { + return new ReverberationEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGE_CREATURE || + event.getType() == GameEvent.EventType.DAMAGE_PLANESWALKER || + event.getType() == GameEvent.EventType.DAMAGE_PLAYER; + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Player controller = game.getPlayer(source.getControllerId()); + DamageEvent damageEvent = (DamageEvent) event; + if (controller != null) { + Spell targetSpell = game.getStack().getSpell(source.getFirstTarget()); + if (targetSpell != null) { + Player targetsController = game.getPlayer(targetSpell.getControllerId()); + if (targetsController != null) { + targetsController.damage(damageEvent.getAmount(), damageEvent.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), damageEvent.getAppliedEffects()); + return true; + } + } + } + return false; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + DamageEvent damageEvent = (DamageEvent) event; + Spell targetSpell = game.getStack().getSpell(source.getFirstTarget()); + if (targetSpell != null) { + return damageEvent.getAmount() > 0; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RixMaadiReveler.java b/Mage.Sets/src/mage/cards/r/RixMaadiReveler.java new file mode 100644 index 00000000000..82136a1ee75 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RixMaadiReveler.java @@ -0,0 +1,83 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.common.SpectacleCondition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.SpectacleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RixMaadiReveler extends CardImpl { + + public RixMaadiReveler(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Spectacle {2}{B}{R} + this.addAbility(new SpectacleAbility(this, new ManaCostsImpl("{2}{B}{R}"))); + + // When Rix Maadi Reveler enters the battlefield, discard a card, then draw a card. If Rix Maadi Reveler's spectacle cost was paid, instead discard your hand, then draw three cards. + this.addAbility(new EntersBattlefieldTriggeredAbility(new RixMaadiRevelerEffect(), false)); + } + + public RixMaadiReveler(final RixMaadiReveler card) { + super(card); + } + + @Override + public RixMaadiReveler copy() { + return new RixMaadiReveler(this); + } +} + +class RixMaadiRevelerEffect extends OneShotEffect { + + RixMaadiRevelerEffect() { + super(Outcome.Benefit); + staticText = "discard a card, then draw a card. " + + "If {this}'s spectacle cost was paid, " + + "instead discard your hand, then draw three cards."; + } + + private RixMaadiRevelerEffect(final RixMaadiRevelerEffect effect) { + super(effect); + } + + @Override + public RixMaadiRevelerEffect copy() { + return new RixMaadiRevelerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + if (SpectacleCondition.instance.apply(game, source)) { + player.discard(player.getHand().size(), false, source, game); + player.drawCards(3, game); + } else { + player.discard(1, false, source, game); + player.drawCards(1, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SamiteBlessing.java b/Mage.Sets/src/mage/cards/s/SamiteBlessing.java new file mode 100644 index 00000000000..1168cf6606a --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SamiteBlessing.java @@ -0,0 +1,58 @@ +package mage.cards.s; + +import java.util.UUID; +import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.PreventNextDamageFromChosenSourceToTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.constants.Outcome; +import mage.target.TargetPermanent; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; + +/** + * + * @author jeffwadsworth + */ +public final class SamiteBlessing extends CardImpl { + + private static final String rule = "Enchanted creature has \"{T}: The next time a source of your choice would deal damage to target creature this turn, prevent that damage.\""; + + public SamiteBlessing(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Enchanted creature has "{tap}: The next time a source of your choice would deal damage to target creature this turn, prevent that damage." + Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PreventNextDamageFromChosenSourceToTargetEffect(Duration.EndOfTurn), new TapSourceCost()); + ability2.addTarget(new TargetCreaturePermanent()); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(ability2, AttachmentType.AURA, Duration.WhileOnBattlefield, rule))); + + } + + public SamiteBlessing(final SamiteBlessing card) { + super(card); + } + + @Override + public SamiteBlessing copy() { + return new SamiteBlessing(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SearchForSurvivors.java b/Mage.Sets/src/mage/cards/s/SearchForSurvivors.java new file mode 100644 index 00000000000..278beadcfac --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SearchForSurvivors.java @@ -0,0 +1,104 @@ +package mage.cards.s; + +import java.util.Arrays; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; +import mage.util.RandomUtil; + +/** + * + * @author jeffwadsworth + */ + +/* + The card is chosen at random, so the computer just picks a card at random from + the controller's graveyard. Devs, feel free to set up something else... + */ +public final class SearchForSurvivors extends CardImpl { + + public SearchForSurvivors(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}"); + + // Reorder your graveyard at random. An opponent chooses a card at random in your graveyard. If it's a creature card, put it onto the battlefield. Otherwise, exile it. + this.getSpellAbility().addEffect(new SearchForSurvivorsEffect()); + + } + + public SearchForSurvivors(final SearchForSurvivors card) { + super(card); + } + + @Override + public SearchForSurvivors copy() { + return new SearchForSurvivors(this); + } +} + +class SearchForSurvivorsEffect extends OneShotEffect { + + public SearchForSurvivorsEffect() { + super(Outcome.PutCardInPlay); + this.staticText = "Reorder your graveyard at random. " + + "An opponent chooses a card at random in your graveyard. " + + "If it's a creature card, put it onto the battlefield. " + + "Otherwise, exile it"; + } + + public SearchForSurvivorsEffect(final SearchForSurvivorsEffect effect) { + super(effect); + } + + @Override + public SearchForSurvivorsEffect copy() { + return new SearchForSurvivorsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + game.informPlayers("The controller of Search for Survivors will have his or her graveyard randomized. " + + " A card will be chosen at random from the controller's graveyard. " + + " The result is essentially the same as the card rule"); + // randomly arrange the graveyard + UUID[] shuffled = controller.getGraveyard().toArray(new UUID[0]); + for (int n = shuffled.length - 1; n > 0; n--) { + int r = RandomUtil.nextInt(n + 1); + UUID temp = shuffled[r]; + shuffled[r] = shuffled[n]; + shuffled[n] = temp; + } + controller.getGraveyard().clear(); + controller.getGraveyard().addAll(Arrays.asList(shuffled)); + // end of randomize + Cards cards = new CardsImpl(); + controller.getGraveyard().getCards(game).forEach((card) -> { + cards.add(card); + }); + if (!cards.isEmpty()) { + Card card = cards.getRandom(game); + cards.clear(); + cards.add(card); + controller.revealCards(source, cards, game); // reveal the card randomly chosen. + if (card.isCreature()) { + controller.moveCards(card, Zone.BATTLEFIELD, source, game); + } else { + controller.moveCards(card, Zone.EXILED, source, game); + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SearchTheCity.java b/Mage.Sets/src/mage/cards/s/SearchTheCity.java index e1b87380fbc..57ad86e633e 100644 --- a/Mage.Sets/src/mage/cards/s/SearchTheCity.java +++ b/Mage.Sets/src/mage/cards/s/SearchTheCity.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -22,9 +20,11 @@ import mage.game.permanent.Permanent; import mage.game.stack.Spell; import mage.game.turn.TurnMod; import mage.players.Player; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class SearchTheCity extends CardImpl { @@ -157,7 +157,7 @@ class SearchTheCityExiledCardToHandEffect extends OneShotEffect { ExileZone searchTheCityExileZone = game.getExile().getExileZone(source.getSourceId()); if (cardName != null && searchTheCityExileZone != null) { for (Card card : searchTheCityExileZone.getCards(game)) { - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { if (card.moveToZone(Zone.HAND, source.getSourceId(), game, true)) { game.informPlayers("Search the City: put " + card.getName() + " into owner's hand"); } diff --git a/Mage.Sets/src/mage/cards/s/SeverTheBloodline.java b/Mage.Sets/src/mage/cards/s/SeverTheBloodline.java index 3cbbee01a82..dfde359a4f6 100644 --- a/Mage.Sets/src/mage/cards/s/SeverTheBloodline.java +++ b/Mage.Sets/src/mage/cards/s/SeverTheBloodline.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; @@ -19,15 +17,17 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author North */ public final class SeverTheBloodline extends CardImpl { public SeverTheBloodline(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}"); // Exile target creature and all other creatures with the same name as that creature. @@ -69,7 +69,7 @@ class SeverTheBloodlineEffect extends OneShotEffect { Permanent targetPermanent = game.getPermanent(targetPointer.getFirst(game, source)); if (controller != null && targetPermanent != null) { FilterCreaturePermanent filter = new FilterCreaturePermanent(); - if (targetPermanent.getName().isEmpty()) { + if (CardUtil.haveEmptyName(targetPermanent)) { filter.add(new PermanentIdPredicate(targetPermanent.getId())); // if no name (face down creature) only the creature itself is selected } else { filter.add(new NamePredicate(targetPermanent.getName())); diff --git a/Mage.Sets/src/mage/cards/s/ShelteringPrayers.java b/Mage.Sets/src/mage/cards/s/ShelteringPrayers.java new file mode 100644 index 00000000000..7526f97c076 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ShelteringPrayers.java @@ -0,0 +1,98 @@ +package mage.cards.s; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.keyword.ShroudAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.DependencyType; +import mage.constants.Duration; +import mage.constants.Layer; +import static mage.constants.Layer.AbilityAddingRemovingEffects_6; +import mage.constants.Outcome; +import mage.constants.SubLayer; +import mage.constants.Zone; +import mage.filter.common.FilterLandPermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author jeffwadsworth + */ +public final class ShelteringPrayers extends CardImpl { + + public ShelteringPrayers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}"); + + // Basic lands each player controls have shroud as long as that player controls three or fewer lands. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ShelteringPrayersEffect())); + + } + + public ShelteringPrayers(final ShelteringPrayers card) { + super(card); + } + + @Override + public ShelteringPrayers copy() { + return new ShelteringPrayers(this); + } +} + +class ShelteringPrayersEffect extends ContinuousEffectImpl { + + public ShelteringPrayersEffect() { + super(Duration.WhileOnBattlefield, Outcome.AddAbility); + staticText = "Basic lands each player controls have shroud as long as that player controls three or fewer lands."; + dependencyTypes.add(DependencyType.AddingAbility); + + } + + public ShelteringPrayersEffect(final ShelteringPrayersEffect effect) { + super(effect); + } + + @Override + public ShelteringPrayersEffect copy() { + return new ShelteringPrayersEffect(this); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null + && game.getBattlefield().getAllActivePermanents(new FilterLandPermanent(), playerId, game).size() < 4) { + for (Permanent land : game.getBattlefield().getAllActivePermanents(new FilterLandPermanent(), playerId, game)) { + if (land != null + && land.isBasic()) { + switch (layer) { + case AbilityAddingRemovingEffects_6: + if (sublayer == SubLayer.NA) { + land.getAbilities().add(ShroudAbility.getInstance()); + } + break; + } + } + } + } + } + return true; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean hasLayer(Layer layer) { + return Layer.AbilityAddingRemovingEffects_6 == layer; + } + +} diff --git a/Mage.Sets/src/mage/cards/s/SimicManipulator.java b/Mage.Sets/src/mage/cards/s/SimicManipulator.java index 5e74a62d857..c639c7341a1 100644 --- a/Mage.Sets/src/mage/cards/s/SimicManipulator.java +++ b/Mage.Sets/src/mage/cards/s/SimicManipulator.java @@ -6,7 +6,6 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.Cost; import mage.abilities.costs.common.RemoveVariableCountersSourceCost; -import mage.abilities.costs.common.RemoveVariableCountersTargetCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.abilities.keyword.EvolveAbility; @@ -79,8 +78,8 @@ enum SimicManipulatorAdjuster implements TargetAdjuster { if (sourcePermanent != null) { int xValue = 0; for (Cost cost : ability.getCosts()) { - if (cost instanceof RemoveVariableCountersTargetCost) { - xValue = ((RemoveVariableCountersTargetCost) cost).getAmount(); + if (cost instanceof RemoveVariableCountersSourceCost) { + xValue = ((RemoveVariableCountersSourceCost) cost).getAmount(); break; } } diff --git a/Mage.Sets/src/mage/cards/s/SkeletonScavengers.java b/Mage.Sets/src/mage/cards/s/SkeletonScavengers.java new file mode 100644 index 00000000000..c15d68bdd04 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SkeletonScavengers.java @@ -0,0 +1,129 @@ +package mage.cards.s; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.CostImpl; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CountersSourceCount; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.RegenerateSourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author jeffwadsworth + */ +public final class SkeletonScavengers extends CardImpl { + + public SkeletonScavengers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.SKELETON); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // Skeleton Scavengers enters the battlefield with a +1/+1 counter on it. + this.addAbility(new AsEntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()))); + + // Pay {1} for each +1/+1 counter on Skeleton Scavengers: Regenerate Skeleton Scavengers. When it regenerates this way, put a +1/+1 counter on it. + this.addAbility(new SimpleActivatedAbility(new SkeletonScavengersEffect(), new DynamicValueGenericManaCost(new CountersSourceCount(CounterType.P1P1)))); + + } + + public SkeletonScavengers(final SkeletonScavengers card) { + super(card); + } + + @Override + public SkeletonScavengers copy() { + return new SkeletonScavengers(this); + } +} + +class DynamicValueGenericManaCost extends CostImpl { + + DynamicValue amount; + + public DynamicValueGenericManaCost(DynamicValue amount) { + this.amount = amount; + setText(); + } + + public DynamicValueGenericManaCost(DynamicValueGenericManaCost cost) { + super(cost); + this.amount = cost.amount; + } + + @Override + public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { + Player controller = game.getPlayer(controllerId); + if (controller == null) { + return false; + } + int convertedCost = amount.calculate(game, ability, null); + Cost cost = new GenericManaCost(convertedCost); + return cost.canPay(ability, sourceId, controllerId, game); + } + + @Override + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { + Player controller = game.getPlayer(controllerId); + int convertedCost = amount.calculate(game, ability, null); + Cost cost = new GenericManaCost(convertedCost); + if (controller != null) { + paid = cost.pay(ability, game, sourceId, controllerId, noMana); + } + return paid; + } + + @Override + public DynamicValueGenericManaCost copy() { + return new DynamicValueGenericManaCost(this); + } + + private void setText() { + text = ("Pay {1} for each +1/+1 counter on {this}"); + } +} + +class SkeletonScavengersEffect extends OneShotEffect { + + SkeletonScavengersEffect() { + super(Outcome.Benefit); + this.staticText = "Regenerate {this}. When it regenerates this way, put a +1/+1 counter on it"; + } + + SkeletonScavengersEffect(final SkeletonScavengersEffect effect) { + super(effect); + } + + @Override + public SkeletonScavengersEffect copy() { + return new SkeletonScavengersEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent skeletonScavengers = game.getPermanent(source.getSourceId()); + if (skeletonScavengers != null) { + if (new RegenerateSourceEffect().apply(game, source)) { + return new AddCountersSourceEffect(CounterType.P1P1.createInstance()).apply(game, source); + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SoulfireGrandMaster.java b/Mage.Sets/src/mage/cards/s/SoulfireGrandMaster.java index abd70447d89..c7b36889d63 100644 --- a/Mage.Sets/src/mage/cards/s/SoulfireGrandMaster.java +++ b/Mage.Sets/src/mage/cards/s/SoulfireGrandMaster.java @@ -1,14 +1,11 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.GainAbilitySpellsEffect; import mage.abilities.effects.ReplacementEffectImpl; @@ -16,13 +13,7 @@ import mage.abilities.keyword.LifelinkAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.SubLayer; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.FilterCard; import mage.filter.FilterObject; import mage.filter.predicate.Predicates; @@ -30,13 +21,12 @@ import mage.filter.predicate.mageobject.CardTypePredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; -import mage.game.permanent.Permanent; import mage.game.stack.Spell; -import mage.game.stack.StackObject; import mage.players.Player; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SoulfireGrandMaster extends CardImpl { @@ -111,7 +101,7 @@ class SoulfireGrandMasterCastFromHandReplacementEffect extends ReplacementEffect @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { MageObject mageObject = game.getObject(spellId); - if (!(mageObject instanceof Spell) || ((Spell) mageObject).isCopiedSpell()) { + if (!(mageObject instanceof Spell) || ((Spell) mageObject).isCopy()) { return false; } else { Card sourceCard = game.getCard(spellId); diff --git a/Mage.Sets/src/mage/cards/s/SphinxsInsight.java b/Mage.Sets/src/mage/cards/s/SphinxsInsight.java new file mode 100644 index 00000000000..d0c8fb18ad8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SphinxsInsight.java @@ -0,0 +1,40 @@ +package mage.cards.s; + +import mage.abilities.condition.common.MyMainPhaseCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SphinxsInsight extends CardImpl { + + public SphinxsInsight(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}{U}"); + + + // Draw two cards. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(2)); + + // Addendum — If you cast this spell during your main phase, you gain 2 life. + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new GainLifeEffect(2), MyMainPhaseCondition.instance, + "
    Addendum — If you cast this spell during your main phase, you gain 2 life." + )); + } + + private SphinxsInsight(final SphinxsInsight card) { + super(card); + } + + @Override + public SphinxsInsight copy() { + return new SphinxsInsight(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SpinyStarfish.java b/Mage.Sets/src/mage/cards/s/SpinyStarfish.java new file mode 100644 index 00000000000..c2760bd3218 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpinyStarfish.java @@ -0,0 +1,157 @@ +package mage.cards.s; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.Condition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.RegenerateSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.constants.WatcherScope; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.token.StarfishToken; +import mage.watchers.Watcher; + +/** + * @author spike + */ +public final class SpinyStarfish extends CardImpl { + + public SpinyStarfish(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + this.subtype.add(SubType.STARFISH); + this.power = new MageInt(0); + this.toughness = new MageInt(1); + + // {U}: Regenerate Spiny Starfish. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new ManaCostsImpl("{U}"))); + + // At the beginning of each end step, if Spiny Starfish regenerated this turn, create a 0/1 blue Starfish creature token for each time it regenerated this turn. + this.addAbility( + new ConditionalInterveningIfTriggeredAbility( + new BeginningOfEndStepTriggeredAbility( + new CreateTokenEffect( + new StarfishToken(), + new SpinyStarfishDynamicValue()), + TargetController.ANY, + false), + SpinyStarfishCondition.instance, + "At the beginning of each end step, if {this} regenerated this turn, create a 0/1 blue Starfish creature token for each time it regenerated this turn."), + new SpinyStarfishWatcher()); + } + + public SpinyStarfish(final SpinyStarfish card) { + super(card); + } + + @Override + public SpinyStarfish copy() { + return new SpinyStarfish(this); + } +} + +enum SpinyStarfishCondition implements Condition { + + instance; + + @Override + public boolean apply(Game game, Ability source) { + SpinyStarfishWatcher watcher = (SpinyStarfishWatcher) game.getState().getWatchers().get(SpinyStarfishWatcher.class.getSimpleName()); + return watcher != null && watcher.regeneratedCount(source.getSourceId()) != 0; + } + + @Override + public String toString() { + return "if Spiny Starfish regenerated this turn"; + } + +} + +class SpinyStarfishWatcher extends Watcher { + + // Probably dumb to record all regeneration events, could just record this, + // but not sure how to know what source this watcher is attached to. + private final Map regeneratedCount = new HashMap<>(); + + public SpinyStarfishWatcher() { + super(SpinyStarfishWatcher.class.getSimpleName(), WatcherScope.GAME); + } + + public SpinyStarfishWatcher(final SpinyStarfishWatcher watcher) { + super(watcher); + this.regeneratedCount.putAll(watcher.regeneratedCount); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.REGENERATED) { + UUID regeneratedId = event.getTargetId(); + Integer count = regeneratedCount.get(regeneratedId); + if (count == null) { + count = 0; + } + regeneratedCount.put(regeneratedId, ++count); + } + } + + @Override + public void reset() { + super.reset(); + regeneratedCount.clear(); + } + + public int regeneratedCount(UUID sourceId) { + Integer count = regeneratedCount.get(sourceId); + if (count == null) { + return 0; + } + return count; + } + + @Override + public SpinyStarfishWatcher copy() { + return new SpinyStarfishWatcher(this); + } +} + +class SpinyStarfishDynamicValue implements DynamicValue { + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + SpinyStarfishWatcher watcher = (SpinyStarfishWatcher) game.getState().getWatchers().get( + SpinyStarfishWatcher.class.getSimpleName()); + if (watcher != null) { + return watcher.regeneratedCount(sourceAbility.getSourceId()); + } + return 0; + } + + @Override + public SpinyStarfishDynamicValue copy() { + return new SpinyStarfishDynamicValue(); + } + + @Override + public String toString() { + return "1"; + } + + @Override + public String getMessage() { + return "time {this} regenerated this turn"; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SpoilsOfTheVault.java b/Mage.Sets/src/mage/cards/s/SpoilsOfTheVault.java index 622bf0c7f37..153bc570f73 100644 --- a/Mage.Sets/src/mage/cards/s/SpoilsOfTheVault.java +++ b/Mage.Sets/src/mage/cards/s/SpoilsOfTheVault.java @@ -1,23 +1,20 @@ package mage.cards.s; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ChooseACardNameEffect; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; +import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; import mage.players.Player; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author Plopman */ public final class SpoilsOfTheVault extends CardImpl { @@ -71,7 +68,7 @@ class SpoilsOfTheVaultEffect extends OneShotEffect { for (Card card : controller.getLibrary().getCards(game)) { if (card != null) { cardsToReveal.add(card); - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { controller.moveCards(card, Zone.HAND, source, game); break; } else { diff --git a/Mage.Sets/src/mage/cards/s/Subdue.java b/Mage.Sets/src/mage/cards/s/Subdue.java new file mode 100644 index 00000000000..63ac77351e7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/Subdue.java @@ -0,0 +1,39 @@ + +package mage.cards.s; + +import java.util.UUID; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.dynamicvalue.common.TargetConvertedManaCost; +import mage.abilities.effects.common.PreventDamageByTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author L_J + */ +public final class Subdue extends CardImpl { + + public Subdue(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{G}"); + + // Prevent all combat damage that would be dealt by target creature this turn. That creature gets +0/+X until end of turn, where X is its converted mana cost. + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addEffect(new PreventDamageByTargetEffect(Duration.EndOfTurn, true)); + this.getSpellAbility().addEffect(new BoostTargetEffect(new StaticValue(0), new TargetConvertedManaCost(), Duration.EndOfTurn, true) + .setText("That creature gets +0/+X until end of turn, where X is its converted mana cost")); + } + + public Subdue(final Subdue card) { + super(card); + } + + @Override + public Subdue copy() { + return new Subdue(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TeysaEnvoyOfGhosts.java b/Mage.Sets/src/mage/cards/t/TeysaEnvoyOfGhosts.java index af3b6a7f7e9..a5591d5c566 100644 --- a/Mage.Sets/src/mage/cards/t/TeysaEnvoyOfGhosts.java +++ b/Mage.Sets/src/mage/cards/t/TeysaEnvoyOfGhosts.java @@ -1,7 +1,6 @@ package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.common.CreateTokenEffect; @@ -14,16 +13,18 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; import mage.constants.Zone; -import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURES; import mage.game.Game; import mage.game.events.DamagedPlayerEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; -import mage.game.permanent.token.TeysaEnvoyOfGhostsToken; +import mage.game.permanent.token.WhiteBlackSpiritToken; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURES; + /** - * * @author LevelX2 */ public final class TeysaEnvoyOfGhosts extends CardImpl { @@ -60,7 +61,7 @@ class TeysaEnvoyOfGhostsTriggeredAbility extends TriggeredAbilityImpl { public TeysaEnvoyOfGhostsTriggeredAbility() { super(Zone.BATTLEFIELD, new DestroyTargetEffect()); - this.addEffect(new CreateTokenEffect(new TeysaEnvoyOfGhostsToken(), 1)); + this.addEffect(new CreateTokenEffect(new WhiteBlackSpiritToken(), 1)); } diff --git a/Mage.Sets/src/mage/cards/t/TheHauntOfHightower.java b/Mage.Sets/src/mage/cards/t/TheHauntOfHightower.java new file mode 100644 index 00000000000..d759f6d49c9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheHauntOfHightower.java @@ -0,0 +1,57 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.PutCardIntoGraveFromAnywhereAllTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.effects.common.discard.DiscardTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.LifelinkAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheHauntOfHightower extends CardImpl { + + public TheHauntOfHightower(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.VAMPIRE); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + + // Whenever The Haunt of Hightower attacks, defending player discards a card. + this.addAbility(new AttacksTriggeredAbility( + new DiscardTargetEffect(1), false, + "Whenever {this} attacks, defending player discards a card", SetTargetPointer.PLAYER + )); + + // Whenever a card is put into an opponent's graveyard from anywhere, put a +1/+1 counter on The Haunt of Hightower. + this.addAbility(new PutCardIntoGraveFromAnywhereAllTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), + false, TargetController.OPPONENT + )); + } + + public TheHauntOfHightower(final TheHauntOfHightower card) { + super(card); + } + + @Override + public TheHauntOfHightower copy() { + return new TheHauntOfHightower(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/ThoughtHemorrhage.java b/Mage.Sets/src/mage/cards/t/ThoughtHemorrhage.java index bec111276c5..5b0da23fd5e 100644 --- a/Mage.Sets/src/mage/cards/t/ThoughtHemorrhage.java +++ b/Mage.Sets/src/mage/cards/t/ThoughtHemorrhage.java @@ -1,9 +1,5 @@ package mage.cards.t; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -21,9 +17,14 @@ import mage.players.Player; import mage.target.TargetPlayer; import mage.target.common.TargetCardInHand; import mage.target.common.TargetCardInLibrary; +import mage.util.CardUtil; + +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class ThoughtHemorrhage extends CardImpl { @@ -74,7 +75,7 @@ class ThoughtHemorrhageEffect extends OneShotEffect { targetPlayer.revealCards("hand of " + targetPlayer.getName(), targetPlayer.getHand(), game); int cardsFound = 0; for (Card card : targetPlayer.getHand().getCards(game)) { - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { cardsFound++; } } diff --git a/Mage.Sets/src/mage/cards/t/TitheTaker.java b/Mage.Sets/src/mage/cards/t/TitheTaker.java new file mode 100644 index 00000000000..c5f184deb43 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TitheTaker.java @@ -0,0 +1,89 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.abilities.keyword.AfterlifeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TitheTaker extends CardImpl { + + public TitheTaker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // During your turn, spells your opponents cast cost {1} more to cast and abilities your opponents activate cost {1} more to activate unless they're mana abilities. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new TitheTakerCostReductionEffect())); + + // Afterlife 1 + this.addAbility(new AfterlifeAbility(1)); + } + + private TitheTaker(final TitheTaker card) { + super(card); + } + + @Override + public TitheTaker copy() { + return new TitheTaker(this); + } +} + +class TitheTakerCostReductionEffect extends CostModificationEffectImpl { + + TitheTakerCostReductionEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.INCREASE_COST); + staticText = "During your turn, spells your opponents cast cost {1} more to cast " + + "and abilities your opponents activate cost {1} more to activate unless they're mana abilities."; + } + + private TitheTakerCostReductionEffect(TitheTakerCostReductionEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + if (abilityToModify.getAbilityType() == AbilityType.SPELL) { + SpellAbility spellAbility = (SpellAbility) abilityToModify; + CardUtil.adjustCost(spellAbility, -1); + } + if (abilityToModify.getAbilityType() == AbilityType.ACTIVATED) { + CardUtil.increaseCost(abilityToModify, 1); + } + return true; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + if (!MyTurnCondition.instance.apply(game, source)) { + return false; + } + if (!(abilityToModify.getAbilityType() == AbilityType.SPELL) + && !(abilityToModify.getAbilityType() == AbilityType.ACTIVATED)) { + return false; + } + return game.getOpponents(source.getControllerId()).contains(abilityToModify.getControllerId()); + } + + @Override + public TitheTakerCostReductionEffect copy() { + return new TitheTakerCostReductionEffect(this); + } + +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/t/TunnelVision.java b/Mage.Sets/src/mage/cards/t/TunnelVision.java index e7b2e0d9bc2..33b58c266c4 100644 --- a/Mage.Sets/src/mage/cards/t/TunnelVision.java +++ b/Mage.Sets/src/mage/cards/t/TunnelVision.java @@ -1,23 +1,20 @@ package mage.cards.t; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ChooseACardNameEffect; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; +import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) */ public final class TunnelVision extends CardImpl { @@ -76,7 +73,7 @@ class TunnelVisionEffect extends OneShotEffect { for (Card card : targetPlayer.getLibrary().getCards(game)) { cardsToReveal.add(card); - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { namedCard = card; break; } diff --git a/Mage.Sets/src/mage/cards/v/VexingArcanix.java b/Mage.Sets/src/mage/cards/v/VexingArcanix.java index 3ca378b7edd..61ec7710087 100644 --- a/Mage.Sets/src/mage/cards/v/VexingArcanix.java +++ b/Mage.Sets/src/mage/cards/v/VexingArcanix.java @@ -1,7 +1,5 @@ - package mage.cards.v; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -18,9 +16,11 @@ import mage.constants.Zone; import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author BetaSteward_at_googlemail.com & L_J */ public final class VexingArcanix extends CardImpl { @@ -74,7 +74,7 @@ class VexingArcanixEffect extends OneShotEffect { if (card != null) { Cards cards = new CardsImpl(card); player.revealCards(sourceObject.getIdName(), cards, game); - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { player.moveCards(cards, Zone.HAND, source, game); } else { player.moveCards(cards, Zone.GRAVEYARD, source, game); diff --git a/Mage.Sets/src/mage/cards/v/VolrathsDungeon.java b/Mage.Sets/src/mage/cards/v/VolrathsDungeon.java new file mode 100644 index 00000000000..3c0680016d7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VolrathsDungeon.java @@ -0,0 +1,132 @@ +package mage.cards.v; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.ActivatedAbility; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.CostImpl; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DestroySourceEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetPlayer; +import mage.target.common.TargetCardInHand; + +/** + * + * @author jeffwadsworth + */ +public final class VolrathsDungeon extends CardImpl { + + public VolrathsDungeon(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}"); + + // Pay 5 life: Destroy Volrath's Dungeon. Any player may activate this ability but only during his or her turn. + ActivatedAbility ability = new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new DestroySourceEffect().setText("Destroy {this}. Any player may activate this ability but only during his or her turn."), + new PayLifeActivePlayerCost(5)); + ability.setMayActivate(TargetController.ACTIVE); + this.addAbility(ability); + + // Discard a card: Target player puts a card from his or her hand on top of his or her library. Activate this ability only any time you could cast a sorcery. + FilterCard filter = new FilterCard("a card for payment"); + Ability ability2 = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, new VolrathsDungeonEffect(), new DiscardCardCost(filter)); + ability2.addTarget(new TargetPlayer()); + this.addAbility(ability2); + } + + public VolrathsDungeon(final VolrathsDungeon card) { + super(card); + } + + @Override + public VolrathsDungeon copy() { + return new VolrathsDungeon(this); + } +} + +class PayLifeActivePlayerCost extends CostImpl { + + private final DynamicValue amount; + + public PayLifeActivePlayerCost(int amount) { + this.amount = new StaticValue(amount); + this.text = "Pay " + Integer.toString(amount) + " life"; + } + + public PayLifeActivePlayerCost(DynamicValue amount, String text) { + this.amount = amount.copy(); + this.text = "Pay " + text; + } + + public PayLifeActivePlayerCost(PayLifeActivePlayerCost cost) { + super(cost); + this.amount = cost.amount.copy(); + } + + @Override + public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { + int lifeToPayAmount = amount.calculate(game, ability, null); + return game.getPlayer(game.getActivePlayerId()).getLife() >= lifeToPayAmount; + } + + @Override + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { + int lifeToPayAmount = amount.calculate(game, ability, null); + Player activatingPlayer = game.getPlayer(game.getActivePlayerId()); + if (activatingPlayer != null + && activatingPlayer.chooseUse(Outcome.LoseLife, "Do you wish to pay + lifeToPayAmount + life?", ability, game)) { + this.paid = game.getPlayer(game.getActivePlayerId()).loseLife(lifeToPayAmount, game, false) == lifeToPayAmount; + } + return paid; + } + + @Override + public PayLifeActivePlayerCost copy() { + return new PayLifeActivePlayerCost(this); + } +} + +class VolrathsDungeonEffect extends OneShotEffect { + + public VolrathsDungeonEffect() { + super(Outcome.Detriment); + this.staticText = "Target player puts a card from his or her hand on top of his or her library"; + } + + public VolrathsDungeonEffect(final VolrathsDungeonEffect effect) { + super(effect); + } + + @Override + public VolrathsDungeonEffect copy() { + return new VolrathsDungeonEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player targetedPlayer = game.getPlayer(source.getFirstTarget()); + if (targetedPlayer != null) { + TargetCardInHand target = new TargetCardInHand(); + if (targetedPlayer.choose(Outcome.Detriment, targetedPlayer.getHand(), target, game)) { + Card card = game.getCard(target.getFirstTarget()); + return targetedPlayer.putCardOnTopXOfLibrary(card, game, source, 0); + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/w/WalkingDream.java b/Mage.Sets/src/mage/cards/w/WalkingDream.java new file mode 100644 index 00000000000..30cacb3dae8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WalkingDream.java @@ -0,0 +1,59 @@ +package mage.cards.w; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.OpponentControlsPermanentCondition; +import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect; +import mage.abilities.effects.ContinuousRuleModifyingEffect; +import mage.abilities.effects.common.DontUntapInControllersUntapStepSourceEffect; +import mage.abilities.keyword.CantBeBlockedSourceAbility; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; + +/** + * + * @author jeffwadsworth + */ +public final class WalkingDream extends CardImpl { + + private static final String rule = "{this} doesn't untap during your untap step if an opponent controls two or more creatures."; + + public WalkingDream(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); + + this.subtype.add(SubType.ILLUSION); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Walking Dream is unblockable. + this.addAbility(new CantBeBlockedSourceAbility()); + + // Walking Dream doesn't untap during your untap step if an opponent controls two or more creatures. + ContinuousRuleModifyingEffect dontUntap = new DontUntapInControllersUntapStepSourceEffect(false, true); + dontUntap.setText(rule); + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, + new ConditionalContinuousRuleModifyingEffect( + dontUntap, + new OpponentControlsPermanentCondition( + new FilterCreaturePermanent(), + ComparisonType.MORE_THAN, 1))); + this.addAbility(ability); + + } + + public WalkingDream(final WalkingDream card) { + super(card); + } + + @Override + public WalkingDream copy() { + return new WalkingDream(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WallOfTombstones.java b/Mage.Sets/src/mage/cards/w/WallOfTombstones.java new file mode 100644 index 00000000000..16abfc19f7c --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WallOfTombstones.java @@ -0,0 +1,77 @@ + +package mage.cards.w; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.SetToughnessSourceEffect; +import mage.abilities.keyword.DefenderAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubLayer; +import mage.constants.TargetController; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.util.CardUtil; + +/** + * + * @author L_J + */ +public final class WallOfTombstones extends CardImpl { + + public WallOfTombstones(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}"); + this.subtype.add(SubType.WALL); + this.power = new MageInt(0); + this.toughness = new MageInt(1); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + + // At the beginning of your upkeep, change Wall of Tombstones’s base toughness to 1 plus the number of creature cards in your graveyard. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new WallOfTombstonesEffect(), TargetController.YOU, false)); + + } + + public WallOfTombstones(final WallOfTombstones card) { + super(card); + } + + @Override + public WallOfTombstones copy() { + return new WallOfTombstones(this); + } +} + +class WallOfTombstonesEffect extends OneShotEffect { + + public WallOfTombstonesEffect() { + super(Outcome.Detriment); + this.staticText = "change {this}’s base toughness to 1 plus the number of creature cards in your graveyard"; + } + + public WallOfTombstonesEffect(final WallOfTombstonesEffect effect) { + super(effect); + } + + @Override + public WallOfTombstonesEffect copy() { + return new WallOfTombstonesEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + int newToughness = CardUtil.addWithOverflowCheck(1, new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_CREATURE).calculate(game, source, this)); + game.addEffect(new SetToughnessSourceEffect(new StaticValue(newToughness), Duration.Custom, SubLayer.SetPT_7b), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/z/ZeganaUtopianSpeaker.java b/Mage.Sets/src/mage/cards/z/ZeganaUtopianSpeaker.java new file mode 100644 index 00000000000..d373a86a37b --- /dev/null +++ b/Mage.Sets/src/mage/cards/z/ZeganaUtopianSpeaker.java @@ -0,0 +1,81 @@ +package mage.cards.z; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.effects.keyword.AdaptEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.filter.predicate.permanent.CounterPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ZeganaUtopianSpeaker extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); + private static final FilterPermanent filter2 = new FilterControlledCreaturePermanent(); + + static { + filter.add(new CounterPredicate(CounterType.P1P1)); + filter.add(new AnotherPredicate()); + filter2.add(new CounterPredicate(CounterType.P1P1)); + } + + public ZeganaUtopianSpeaker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.MERFOLK); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // When Zegana, Utopian Speaker enters the battlefield, if you control another creature with a +1/+1 counter on it, draw a card. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new EntersBattlefieldTriggeredAbility( + new DrawCardSourceControllerEffect(1), false + ), new PermanentsOnTheBattlefieldCondition(filter), + "When {this} enters the battlefield, " + + "if you control another creature " + + "with a +1/+1 counter on it, draw a card." + )); + + // {4}{G}{U}: Adapt 4. + this.addAbility(new SimpleActivatedAbility( + new AdaptEffect(4), new ManaCostsImpl("{4}{G}{U}") + )); + + // Each creature you control with a +1/+1 counter on it has trample. + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new GainAbilityAllEffect( + TrampleAbility.getInstance(), Duration.WhileOnBattlefield, + filter2, "Each creature you control with a +1/+1 counter on it has trample" + ) + )); + } + + public ZeganaUtopianSpeaker(final ZeganaUtopianSpeaker card) { + super(card); + } + + @Override + public ZeganaUtopianSpeaker copy() { + return new ZeganaUtopianSpeaker(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Alliances.java b/Mage.Sets/src/mage/sets/Alliances.java index e53b14b61d4..7df01628f92 100644 --- a/Mage.Sets/src/mage/sets/Alliances.java +++ b/Mage.Sets/src/mage/sets/Alliances.java @@ -155,6 +155,7 @@ public final class Alliances extends ExpansionSet { cards.add(new SetCardInfo("Soldevi Steam Beast", "133a", Rarity.COMMON, mage.cards.s.SoldeviSteamBeast.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Soldevi Steam Beast", "133b", Rarity.COMMON, mage.cards.s.SoldeviSteamBeast.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Soldier of Fortune", 80, Rarity.UNCOMMON, mage.cards.s.SoldierOfFortune.class)); + cards.add(new SetCardInfo("Spiny Starfish", 35, Rarity.UNCOMMON, mage.cards.s.SpinyStarfish.class)); cards.add(new SetCardInfo("Stench of Decay", "61a", Rarity.COMMON, mage.cards.s.StenchOfDecay.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Stench of Decay", "61b", Rarity.COMMON, mage.cards.s.StenchOfDecay.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Storm Cauldron", 134, Rarity.RARE, mage.cards.s.StormCauldron.class)); diff --git a/Mage.Sets/src/mage/sets/Chronicles.java b/Mage.Sets/src/mage/sets/Chronicles.java index 050f42904b8..66a72016426 100644 --- a/Mage.Sets/src/mage/sets/Chronicles.java +++ b/Mage.Sets/src/mage/sets/Chronicles.java @@ -47,6 +47,7 @@ public final class Chronicles extends ExpansionSet { cards.add(new SetCardInfo("Bog Rats", 2, Rarity.COMMON, mage.cards.b.BogRats.class)); cards.add(new SetCardInfo("Book of Rass", 75, Rarity.RARE, mage.cards.b.BookOfRass.class)); cards.add(new SetCardInfo("Boomerang", 16, Rarity.COMMON, mage.cards.b.Boomerang.class)); + cards.add(new SetCardInfo("Bronze Horse", 76, Rarity.RARE, mage.cards.b.BronzeHorse.class)); cards.add(new SetCardInfo("Cat Warriors", 30, Rarity.COMMON, mage.cards.c.CatWarriors.class)); cards.add(new SetCardInfo("Chromium", 109, Rarity.RARE, mage.cards.c.Chromium.class)); cards.add(new SetCardInfo("City of Brass", 92, Rarity.RARE, mage.cards.c.CityOfBrass.class)); diff --git a/Mage.Sets/src/mage/sets/Conspiracy.java b/Mage.Sets/src/mage/sets/Conspiracy.java index 3e561263f15..bc992d21361 100644 --- a/Mage.Sets/src/mage/sets/Conspiracy.java +++ b/Mage.Sets/src/mage/sets/Conspiracy.java @@ -43,6 +43,7 @@ public final class Conspiracy extends ExpansionSet { cards.add(new SetCardInfo("Brainstorm", 91, Rarity.COMMON, mage.cards.b.Brainstorm.class)); cards.add(new SetCardInfo("Breakthrough", 92, Rarity.UNCOMMON, mage.cards.b.Breakthrough.class)); cards.add(new SetCardInfo("Brimstone Volley", 138, Rarity.COMMON, mage.cards.b.BrimstoneVolley.class)); + cards.add(new SetCardInfo("Canal Dredger", 55, Rarity.RARE, mage.cards.c.CanalDredger.class)); cards.add(new SetCardInfo("Charging Rhino", 159, Rarity.COMMON, mage.cards.c.ChargingRhino.class)); cards.add(new SetCardInfo("Chartooth Cougar", 139, Rarity.COMMON, mage.cards.c.ChartoothCougar.class)); cards.add(new SetCardInfo("Cinder Wall", 140, Rarity.COMMON, mage.cards.c.CinderWall.class)); @@ -57,6 +58,7 @@ public final class Conspiracy extends ExpansionSet { cards.add(new SetCardInfo("Custodi Squire", 18, Rarity.COMMON, mage.cards.c.CustodiSquire.class)); cards.add(new SetCardInfo("Dack Fayden", 42, Rarity.MYTHIC, mage.cards.d.DackFayden.class)); cards.add(new SetCardInfo("Dack's Duplicate", 43, Rarity.RARE, mage.cards.d.DacksDuplicate.class)); + cards.add(new SetCardInfo("Deal Broker", 61, Rarity.RARE, mage.cards.d.DealBroker.class)); cards.add(new SetCardInfo("Deathforge Shaman", 141, Rarity.UNCOMMON, mage.cards.d.DeathforgeShaman.class)); cards.add(new SetCardInfo("Deathreap Ritual", 44, Rarity.UNCOMMON, mage.cards.d.DeathreapRitual.class)); cards.add(new SetCardInfo("Deathrender", 197, Rarity.RARE, mage.cards.d.Deathrender.class)); diff --git a/Mage.Sets/src/mage/sets/Exodus.java b/Mage.Sets/src/mage/sets/Exodus.java index d1091318d43..a7d5dcb6b34 100644 --- a/Mage.Sets/src/mage/sets/Exodus.java +++ b/Mage.Sets/src/mage/sets/Exodus.java @@ -1,165 +1,175 @@ - -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -/** - * - * @author North - */ -public final class Exodus extends ExpansionSet { - - private static final Exodus instance = new Exodus(); - - public static Exodus getInstance() { - return instance; - } - - private Exodus() { - super("Exodus", "EXO", ExpansionSet.buildDate(1998, 6, 15), SetType.EXPANSION); - this.blockName = "Tempest"; - this.parentSet = Tempest.getInstance(); - this.hasBasicLands = false; - this.hasBoosters = true; - this.numBoosterLands = 0; - this.numBoosterCommon = 11; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - cards.add(new SetCardInfo("Allay", 1, Rarity.COMMON, mage.cards.a.Allay.class)); - cards.add(new SetCardInfo("Anarchist", 79, Rarity.COMMON, mage.cards.a.Anarchist.class)); - cards.add(new SetCardInfo("Angelic Blessing", 2, Rarity.COMMON, mage.cards.a.AngelicBlessing.class)); - cards.add(new SetCardInfo("Avenging Druid", 105, Rarity.COMMON, mage.cards.a.AvengingDruid.class)); - cards.add(new SetCardInfo("Bequeathal", 106, Rarity.COMMON, mage.cards.b.Bequeathal.class)); - cards.add(new SetCardInfo("Carnophage", 53, Rarity.COMMON, mage.cards.c.Carnophage.class)); - cards.add(new SetCardInfo("Cartographer", 107, Rarity.UNCOMMON, mage.cards.c.Cartographer.class)); - cards.add(new SetCardInfo("Cataclysm", 3, Rarity.RARE, mage.cards.c.Cataclysm.class)); - cards.add(new SetCardInfo("Cat Burglar", 54, Rarity.COMMON, mage.cards.c.CatBurglar.class)); - cards.add(new SetCardInfo("Charging Paladin", 4, Rarity.COMMON, mage.cards.c.ChargingPaladin.class)); - cards.add(new SetCardInfo("Cinder Crawler", 80, Rarity.COMMON, mage.cards.c.CinderCrawler.class)); - cards.add(new SetCardInfo("City of Traitors", 143, Rarity.RARE, mage.cards.c.CityOfTraitors.class)); - cards.add(new SetCardInfo("Coat of Arms", 131, Rarity.RARE, mage.cards.c.CoatOfArms.class)); - cards.add(new SetCardInfo("Convalescence", 5, Rarity.RARE, mage.cards.c.Convalescence.class)); - cards.add(new SetCardInfo("Crashing Boars", 108, Rarity.UNCOMMON, mage.cards.c.CrashingBoars.class)); - cards.add(new SetCardInfo("Culling the Weak", 55, Rarity.COMMON, mage.cards.c.CullingTheWeak.class)); - cards.add(new SetCardInfo("Curiosity", 29, Rarity.UNCOMMON, mage.cards.c.Curiosity.class)); - cards.add(new SetCardInfo("Cursed Flesh", 56, Rarity.COMMON, mage.cards.c.CursedFlesh.class)); - cards.add(new SetCardInfo("Dauthi Cutthroat", 57, Rarity.UNCOMMON, mage.cards.d.DauthiCutthroat.class)); - cards.add(new SetCardInfo("Dauthi Jackal", 58, Rarity.COMMON, mage.cards.d.DauthiJackal.class)); - cards.add(new SetCardInfo("Dauthi Warlord", 59, Rarity.UNCOMMON, mage.cards.d.DauthiWarlord.class)); - cards.add(new SetCardInfo("Death's Duet", 60, Rarity.COMMON, mage.cards.d.DeathsDuet.class)); - cards.add(new SetCardInfo("Dominating Licid", 30, Rarity.RARE, mage.cards.d.DominatingLicid.class)); - cards.add(new SetCardInfo("Elven Palisade", 109, Rarity.UNCOMMON, mage.cards.e.ElvenPalisade.class)); - cards.add(new SetCardInfo("Elvish Berserker", 110, Rarity.COMMON, mage.cards.e.ElvishBerserker.class)); - cards.add(new SetCardInfo("Entropic Specter", 61, Rarity.RARE, mage.cards.e.EntropicSpecter.class)); - cards.add(new SetCardInfo("Ephemeron", 31, Rarity.RARE, mage.cards.e.Ephemeron.class)); - cards.add(new SetCardInfo("Equilibrium", 32, Rarity.RARE, mage.cards.e.Equilibrium.class)); - cards.add(new SetCardInfo("Erratic Portal", 132, Rarity.RARE, mage.cards.e.ErraticPortal.class)); - cards.add(new SetCardInfo("Ertai, Wizard Adept", 33, Rarity.RARE, mage.cards.e.ErtaiWizardAdept.class)); - cards.add(new SetCardInfo("Exalted Dragon", 6, Rarity.RARE, mage.cards.e.ExaltedDragon.class)); - cards.add(new SetCardInfo("Fade Away", 34, Rarity.COMMON, mage.cards.f.FadeAway.class)); - cards.add(new SetCardInfo("Fighting Chance", 82, Rarity.RARE, mage.cards.f.FightingChance.class)); - cards.add(new SetCardInfo("Flowstone Flood", 83, Rarity.UNCOMMON, mage.cards.f.FlowstoneFlood.class)); - cards.add(new SetCardInfo("Forbid", 35, Rarity.UNCOMMON, mage.cards.f.Forbid.class)); - cards.add(new SetCardInfo("Fugue", 62, Rarity.UNCOMMON, mage.cards.f.Fugue.class)); - cards.add(new SetCardInfo("Furnace Brood", 84, Rarity.COMMON, mage.cards.f.FurnaceBrood.class)); - cards.add(new SetCardInfo("Hatred", 64, Rarity.RARE, mage.cards.h.Hatred.class)); - cards.add(new SetCardInfo("High Ground", 7, Rarity.UNCOMMON, mage.cards.h.HighGround.class)); - cards.add(new SetCardInfo("Jackalope Herd", 111, Rarity.COMMON, mage.cards.j.JackalopeHerd.class)); - cards.add(new SetCardInfo("Keeper of the Beasts", 112, Rarity.UNCOMMON, mage.cards.k.KeeperOfTheBeasts.class)); - cards.add(new SetCardInfo("Keeper of the Dead", 65, Rarity.UNCOMMON, mage.cards.k.KeeperOfTheDead.class)); - cards.add(new SetCardInfo("Keeper of the Light", 8, Rarity.UNCOMMON, mage.cards.k.KeeperOfTheLight.class)); - cards.add(new SetCardInfo("Keeper of the Mind", 36, Rarity.UNCOMMON, mage.cards.k.KeeperOfTheMind.class)); - cards.add(new SetCardInfo("Killer Whale", 37, Rarity.UNCOMMON, mage.cards.k.KillerWhale.class)); - cards.add(new SetCardInfo("Kor Chant", 9, Rarity.COMMON, mage.cards.k.KorChant.class)); - cards.add(new SetCardInfo("Mage il-Vec", 86, Rarity.COMMON, mage.cards.m.MageIlVec.class)); - cards.add(new SetCardInfo("Manabond", 113, Rarity.RARE, mage.cards.m.Manabond.class)); - cards.add(new SetCardInfo("Mana Breach", 38, Rarity.UNCOMMON, mage.cards.m.ManaBreach.class)); - cards.add(new SetCardInfo("Maniacal Rage", 87, Rarity.COMMON, mage.cards.m.ManiacalRage.class)); - cards.add(new SetCardInfo("Medicine Bag", 133, Rarity.UNCOMMON, mage.cards.m.MedicineBag.class)); - cards.add(new SetCardInfo("Memory Crystal", 134, Rarity.RARE, mage.cards.m.MemoryCrystal.class)); - cards.add(new SetCardInfo("Merfolk Looter", 39, Rarity.COMMON, mage.cards.m.MerfolkLooter.class)); - cards.add(new SetCardInfo("Mindless Automaton", 135, Rarity.RARE, mage.cards.m.MindlessAutomaton.class)); - cards.add(new SetCardInfo("Mind Over Matter", 40, Rarity.RARE, mage.cards.m.MindOverMatter.class)); - cards.add(new SetCardInfo("Mirozel", 41, Rarity.UNCOMMON, mage.cards.m.Mirozel.class)); - cards.add(new SetCardInfo("Mirri, Cat Warrior", 114, Rarity.RARE, mage.cards.m.MirriCatWarrior.class)); - cards.add(new SetCardInfo("Mogg Assassin", 88, Rarity.UNCOMMON, mage.cards.m.MoggAssassin.class)); - cards.add(new SetCardInfo("Nausea", 67, Rarity.COMMON, mage.cards.n.Nausea.class)); - cards.add(new SetCardInfo("Necrologia", 68, Rarity.UNCOMMON, mage.cards.n.Necrologia.class)); - cards.add(new SetCardInfo("Null Brooch", 136, Rarity.RARE, mage.cards.n.NullBrooch.class)); - cards.add(new SetCardInfo("Oath of Druids", 115, Rarity.RARE, mage.cards.o.OathOfDruids.class)); - cards.add(new SetCardInfo("Oath of Ghouls", 69, Rarity.RARE, mage.cards.o.OathOfGhouls.class)); - cards.add(new SetCardInfo("Oath of Lieges", 11, Rarity.RARE, mage.cards.o.OathOfLieges.class)); - cards.add(new SetCardInfo("Oath of Mages", 90, Rarity.RARE, mage.cards.o.OathOfMages.class)); - cards.add(new SetCardInfo("Oath of Scholars", 42, Rarity.RARE, mage.cards.o.OathOfScholars.class)); - cards.add(new SetCardInfo("Ogre Shaman", 91, Rarity.RARE, mage.cards.o.OgreShaman.class)); - cards.add(new SetCardInfo("Onslaught", 92, Rarity.COMMON, mage.cards.o.Onslaught.class)); - cards.add(new SetCardInfo("Paladin en-Vec", 12, Rarity.RARE, mage.cards.p.PaladinEnVec.class)); - cards.add(new SetCardInfo("Pandemonium", 93, Rarity.RARE, mage.cards.p.Pandemonium.class)); - cards.add(new SetCardInfo("Peace of Mind", 13, Rarity.UNCOMMON, mage.cards.p.PeaceOfMind.class)); - cards.add(new SetCardInfo("Pegasus Stampede", 14, Rarity.UNCOMMON, mage.cards.p.PegasusStampede.class)); - cards.add(new SetCardInfo("Penance", 15, Rarity.UNCOMMON, mage.cards.p.Penance.class)); - cards.add(new SetCardInfo("Pit Spawn", 70, Rarity.RARE, mage.cards.p.PitSpawn.class)); - cards.add(new SetCardInfo("Plaguebearer", 71, Rarity.RARE, mage.cards.p.Plaguebearer.class)); - cards.add(new SetCardInfo("Plated Rootwalla", 116, Rarity.COMMON, mage.cards.p.PlatedRootwalla.class)); - cards.add(new SetCardInfo("Predatory Hunger", 117, Rarity.COMMON, mage.cards.p.PredatoryHunger.class)); - cards.add(new SetCardInfo("Price of Progress", 95, Rarity.UNCOMMON, mage.cards.p.PriceOfProgress.class)); - cards.add(new SetCardInfo("Pygmy Troll", 118, Rarity.COMMON, mage.cards.p.PygmyTroll.class)); - cards.add(new SetCardInfo("Rabid Wolverines", 119, Rarity.COMMON, mage.cards.r.RabidWolverines.class)); - cards.add(new SetCardInfo("Raging Goblin", 96, Rarity.COMMON, mage.cards.r.RagingGoblin.class)); - cards.add(new SetCardInfo("Ravenous Baboons", 97, Rarity.RARE, mage.cards.r.RavenousBaboons.class)); - cards.add(new SetCardInfo("Reaping the Rewards", 16, Rarity.COMMON, mage.cards.r.ReapingTheRewards.class)); - cards.add(new SetCardInfo("Reckless Ogre", 98, Rarity.COMMON, mage.cards.r.RecklessOgre.class)); - cards.add(new SetCardInfo("Reclaim", 120, Rarity.COMMON, mage.cards.r.Reclaim.class)); - cards.add(new SetCardInfo("Reconnaissance", 17, Rarity.UNCOMMON, mage.cards.r.Reconnaissance.class)); - cards.add(new SetCardInfo("Recurring Nightmare", 72, Rarity.RARE, mage.cards.r.RecurringNightmare.class)); - cards.add(new SetCardInfo("Resuscitate", 121, Rarity.UNCOMMON, mage.cards.r.Resuscitate.class)); - cards.add(new SetCardInfo("Robe of Mirrors", 43, Rarity.COMMON, mage.cards.r.RobeOfMirrors.class)); - cards.add(new SetCardInfo("Rootwater Alligator", 122, Rarity.COMMON, mage.cards.r.RootwaterAlligator.class)); - cards.add(new SetCardInfo("Rootwater Mystic", 44, Rarity.COMMON, mage.cards.r.RootwaterMystic.class)); - cards.add(new SetCardInfo("Sabertooth Wyvern", 99, Rarity.UNCOMMON, mage.cards.s.SabertoothWyvern.class)); - cards.add(new SetCardInfo("Scalding Salamander", 100, Rarity.UNCOMMON, mage.cards.s.ScaldingSalamander.class)); - cards.add(new SetCardInfo("Scare Tactics", 73, Rarity.COMMON, mage.cards.s.ScareTactics.class)); - cards.add(new SetCardInfo("School of Piranha", 45, Rarity.COMMON, mage.cards.s.SchoolOfPiranha.class)); - cards.add(new SetCardInfo("Scrivener", 46, Rarity.UNCOMMON, mage.cards.s.Scrivener.class)); - cards.add(new SetCardInfo("Seismic Assault", 101, Rarity.RARE, mage.cards.s.SeismicAssault.class)); - cards.add(new SetCardInfo("Shackles", 18, Rarity.COMMON, mage.cards.s.Shackles.class)); - cards.add(new SetCardInfo("Shattering Pulse", 102, Rarity.COMMON, mage.cards.s.ShatteringPulse.class)); - cards.add(new SetCardInfo("Shield Mate", 19, Rarity.COMMON, mage.cards.s.ShieldMate.class)); - cards.add(new SetCardInfo("Skyshaper", 137, Rarity.UNCOMMON, mage.cards.s.Skyshaper.class)); - cards.add(new SetCardInfo("Skyshroud Elite", 123, Rarity.UNCOMMON, mage.cards.s.SkyshroudElite.class)); - cards.add(new SetCardInfo("Skyshroud War Beast", 124, Rarity.RARE, mage.cards.s.SkyshroudWarBeast.class)); - cards.add(new SetCardInfo("Slaughter", 74, Rarity.UNCOMMON, mage.cards.s.Slaughter.class)); - cards.add(new SetCardInfo("Soltari Visionary", 20, Rarity.COMMON, mage.cards.s.SoltariVisionary.class)); - cards.add(new SetCardInfo("Song of Serenity", 125, Rarity.UNCOMMON, mage.cards.s.SongOfSerenity.class)); - cards.add(new SetCardInfo("Sonic Burst", 103, Rarity.COMMON, mage.cards.s.SonicBurst.class)); - cards.add(new SetCardInfo("Soul Warden", 21, Rarity.COMMON, mage.cards.s.SoulWarden.class)); - cards.add(new SetCardInfo("Spellbook", 138, Rarity.UNCOMMON, mage.cards.s.Spellbook.class)); - cards.add(new SetCardInfo("Spellshock", 104, Rarity.UNCOMMON, mage.cards.s.Spellshock.class)); - cards.add(new SetCardInfo("Sphere of Resistance", 139, Rarity.RARE, mage.cards.s.SphereOfResistance.class)); - cards.add(new SetCardInfo("Spike Cannibal", 75, Rarity.UNCOMMON, mage.cards.s.SpikeCannibal.class)); - cards.add(new SetCardInfo("Spike Hatcher", 126, Rarity.RARE, mage.cards.s.SpikeHatcher.class)); - cards.add(new SetCardInfo("Spike Rogue", 127, Rarity.UNCOMMON, mage.cards.s.SpikeRogue.class)); - cards.add(new SetCardInfo("Spike Weaver", 128, Rarity.RARE, mage.cards.s.SpikeWeaver.class)); - cards.add(new SetCardInfo("Standing Troops", 22, Rarity.COMMON, mage.cards.s.StandingTroops.class)); - cards.add(new SetCardInfo("Survival of the Fittest", 129, Rarity.RARE, mage.cards.s.SurvivalOfTheFittest.class)); - cards.add(new SetCardInfo("Thalakos Drifters", 47, Rarity.RARE, mage.cards.t.ThalakosDrifters.class)); - cards.add(new SetCardInfo("Thalakos Scout", 48, Rarity.COMMON, mage.cards.t.ThalakosScout.class)); - cards.add(new SetCardInfo("Theft of Dreams", 49, Rarity.COMMON, mage.cards.t.TheftOfDreams.class)); - cards.add(new SetCardInfo("Thopter Squadron", 140, Rarity.RARE, mage.cards.t.ThopterSquadron.class)); - cards.add(new SetCardInfo("Thrull Surgeon", 76, Rarity.COMMON, mage.cards.t.ThrullSurgeon.class)); - cards.add(new SetCardInfo("Transmogrifying Licid", 141, Rarity.UNCOMMON, mage.cards.t.TransmogrifyingLicid.class)); - cards.add(new SetCardInfo("Treasure Hunter", 23, Rarity.UNCOMMON, mage.cards.t.TreasureHunter.class)); - cards.add(new SetCardInfo("Treasure Trove", 50, Rarity.UNCOMMON, mage.cards.t.TreasureTrove.class)); - cards.add(new SetCardInfo("Vampire Hounds", 77, Rarity.COMMON, mage.cards.v.VampireHounds.class)); - cards.add(new SetCardInfo("Wall of Nets", 24, Rarity.RARE, mage.cards.w.WallOfNets.class)); - cards.add(new SetCardInfo("Wayward Soul", 51, Rarity.COMMON, mage.cards.w.WaywardSoul.class)); - cards.add(new SetCardInfo("Welkin Hawk", 25, Rarity.COMMON, mage.cards.w.WelkinHawk.class)); - cards.add(new SetCardInfo("Whiptongue Frog", 52, Rarity.COMMON, mage.cards.w.WhiptongueFrog.class)); - cards.add(new SetCardInfo("Wood Elves", 130, Rarity.COMMON, mage.cards.w.WoodElves.class)); - cards.add(new SetCardInfo("Workhorse", 142, Rarity.RARE, mage.cards.w.Workhorse.class)); - cards.add(new SetCardInfo("Zealots en-Dal", 26, Rarity.UNCOMMON, mage.cards.z.ZealotsEnDal.class)); - } -} + +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * + * @author North + */ +public final class Exodus extends ExpansionSet { + + private static final Exodus instance = new Exodus(); + + public static Exodus getInstance() { + return instance; + } + + private Exodus() { + super("Exodus", "EXO", ExpansionSet.buildDate(1998, 6, 15), SetType.EXPANSION); + this.blockName = "Tempest"; + this.parentSet = Tempest.getInstance(); + this.hasBasicLands = false; + this.hasBoosters = true; + this.numBoosterLands = 0; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + cards.add(new SetCardInfo("Aether Tide", 27, Rarity.COMMON, mage.cards.a.AetherTide.class)); + cards.add(new SetCardInfo("Allay", 1, Rarity.COMMON, mage.cards.a.Allay.class)); + cards.add(new SetCardInfo("Anarchist", 79, Rarity.COMMON, mage.cards.a.Anarchist.class)); + cards.add(new SetCardInfo("Angelic Blessing", 2, Rarity.COMMON, mage.cards.a.AngelicBlessing.class)); + cards.add(new SetCardInfo("Avenging Druid", 105, Rarity.COMMON, mage.cards.a.AvengingDruid.class)); + cards.add(new SetCardInfo("Bequeathal", 106, Rarity.COMMON, mage.cards.b.Bequeathal.class)); + cards.add(new SetCardInfo("Carnophage", 53, Rarity.COMMON, mage.cards.c.Carnophage.class)); + cards.add(new SetCardInfo("Cartographer", 107, Rarity.UNCOMMON, mage.cards.c.Cartographer.class)); + cards.add(new SetCardInfo("Cataclysm", 3, Rarity.RARE, mage.cards.c.Cataclysm.class)); + cards.add(new SetCardInfo("Cat Burglar", 54, Rarity.COMMON, mage.cards.c.CatBurglar.class)); + cards.add(new SetCardInfo("Charging Paladin", 4, Rarity.COMMON, mage.cards.c.ChargingPaladin.class)); + cards.add(new SetCardInfo("Cinder Crawler", 80, Rarity.COMMON, mage.cards.c.CinderCrawler.class)); + cards.add(new SetCardInfo("City of Traitors", 143, Rarity.RARE, mage.cards.c.CityOfTraitors.class)); + cards.add(new SetCardInfo("Coat of Arms", 131, Rarity.RARE, mage.cards.c.CoatOfArms.class)); + cards.add(new SetCardInfo("Convalescence", 5, Rarity.RARE, mage.cards.c.Convalescence.class)); + cards.add(new SetCardInfo("Crashing Boars", 108, Rarity.UNCOMMON, mage.cards.c.CrashingBoars.class)); + cards.add(new SetCardInfo("Culling the Weak", 55, Rarity.COMMON, mage.cards.c.CullingTheWeak.class)); + cards.add(new SetCardInfo("Cunning", 28, Rarity.COMMON, mage.cards.c.Cunning.class)); + cards.add(new SetCardInfo("Curiosity", 29, Rarity.UNCOMMON, mage.cards.c.Curiosity.class)); + cards.add(new SetCardInfo("Cursed Flesh", 56, Rarity.COMMON, mage.cards.c.CursedFlesh.class)); + cards.add(new SetCardInfo("Dauthi Cutthroat", 57, Rarity.UNCOMMON, mage.cards.d.DauthiCutthroat.class)); + cards.add(new SetCardInfo("Dauthi Jackal", 58, Rarity.COMMON, mage.cards.d.DauthiJackal.class)); + cards.add(new SetCardInfo("Dauthi Warlord", 59, Rarity.UNCOMMON, mage.cards.d.DauthiWarlord.class)); + cards.add(new SetCardInfo("Death's Duet", 60, Rarity.COMMON, mage.cards.d.DeathsDuet.class)); + cards.add(new SetCardInfo("Dizzying Gaze", 81, Rarity.COMMON, mage.cards.d.DizzyingGaze.class)); + cards.add(new SetCardInfo("Dominating Licid", 30, Rarity.RARE, mage.cards.d.DominatingLicid.class)); + cards.add(new SetCardInfo("Elven Palisade", 109, Rarity.UNCOMMON, mage.cards.e.ElvenPalisade.class)); + cards.add(new SetCardInfo("Elvish Berserker", 110, Rarity.COMMON, mage.cards.e.ElvishBerserker.class)); + cards.add(new SetCardInfo("Entropic Specter", 61, Rarity.RARE, mage.cards.e.EntropicSpecter.class)); + cards.add(new SetCardInfo("Ephemeron", 31, Rarity.RARE, mage.cards.e.Ephemeron.class)); + cards.add(new SetCardInfo("Equilibrium", 32, Rarity.RARE, mage.cards.e.Equilibrium.class)); + cards.add(new SetCardInfo("Erratic Portal", 132, Rarity.RARE, mage.cards.e.ErraticPortal.class)); + cards.add(new SetCardInfo("Ertai, Wizard Adept", 33, Rarity.RARE, mage.cards.e.ErtaiWizardAdept.class)); + cards.add(new SetCardInfo("Exalted Dragon", 6, Rarity.RARE, mage.cards.e.ExaltedDragon.class)); + cards.add(new SetCardInfo("Fade Away", 34, Rarity.COMMON, mage.cards.f.FadeAway.class)); + cards.add(new SetCardInfo("Fighting Chance", 82, Rarity.RARE, mage.cards.f.FightingChance.class)); + cards.add(new SetCardInfo("Flowstone Flood", 83, Rarity.UNCOMMON, mage.cards.f.FlowstoneFlood.class)); + cards.add(new SetCardInfo("Forbid", 35, Rarity.UNCOMMON, mage.cards.f.Forbid.class)); + cards.add(new SetCardInfo("Fugue", 62, Rarity.UNCOMMON, mage.cards.f.Fugue.class)); + cards.add(new SetCardInfo("Furnace Brood", 84, Rarity.COMMON, mage.cards.f.FurnaceBrood.class)); + cards.add(new SetCardInfo("Grollub", 63, Rarity.COMMON, mage.cards.g.Grollub.class)); + cards.add(new SetCardInfo("Hatred", 64, Rarity.RARE, mage.cards.h.Hatred.class)); + cards.add(new SetCardInfo("High Ground", 7, Rarity.UNCOMMON, mage.cards.h.HighGround.class)); + cards.add(new SetCardInfo("Jackalope Herd", 111, Rarity.COMMON, mage.cards.j.JackalopeHerd.class)); + cards.add(new SetCardInfo("Keeper of the Beasts", 112, Rarity.UNCOMMON, mage.cards.k.KeeperOfTheBeasts.class)); + cards.add(new SetCardInfo("Keeper of the Dead", 65, Rarity.UNCOMMON, mage.cards.k.KeeperOfTheDead.class)); + cards.add(new SetCardInfo("Keeper of the Flame", 85, Rarity.UNCOMMON, mage.cards.k.KeeperOfTheFlame.class)); + cards.add(new SetCardInfo("Keeper of the Light", 8, Rarity.UNCOMMON, mage.cards.k.KeeperOfTheLight.class)); + cards.add(new SetCardInfo("Keeper of the Mind", 36, Rarity.UNCOMMON, mage.cards.k.KeeperOfTheMind.class)); + cards.add(new SetCardInfo("Killer Whale", 37, Rarity.UNCOMMON, mage.cards.k.KillerWhale.class)); + cards.add(new SetCardInfo("Kor Chant", 9, Rarity.COMMON, mage.cards.k.KorChant.class)); + cards.add(new SetCardInfo("Limited Resources", 10, Rarity.RARE, mage.cards.l.LimitedResources.class)); + cards.add(new SetCardInfo("Mage il-Vec", 86, Rarity.COMMON, mage.cards.m.MageIlVec.class)); + cards.add(new SetCardInfo("Manabond", 113, Rarity.RARE, mage.cards.m.Manabond.class)); + cards.add(new SetCardInfo("Mana Breach", 38, Rarity.UNCOMMON, mage.cards.m.ManaBreach.class)); + cards.add(new SetCardInfo("Maniacal Rage", 87, Rarity.COMMON, mage.cards.m.ManiacalRage.class)); + cards.add(new SetCardInfo("Medicine Bag", 133, Rarity.UNCOMMON, mage.cards.m.MedicineBag.class)); + cards.add(new SetCardInfo("Memory Crystal", 134, Rarity.RARE, mage.cards.m.MemoryCrystal.class)); + cards.add(new SetCardInfo("Merfolk Looter", 39, Rarity.COMMON, mage.cards.m.MerfolkLooter.class)); + cards.add(new SetCardInfo("Mind Maggots", 66, Rarity.UNCOMMON, mage.cards.m.MindMaggots.class)); + cards.add(new SetCardInfo("Mindless Automaton", 135, Rarity.RARE, mage.cards.m.MindlessAutomaton.class)); + cards.add(new SetCardInfo("Mind Over Matter", 40, Rarity.RARE, mage.cards.m.MindOverMatter.class)); + cards.add(new SetCardInfo("Mirozel", 41, Rarity.UNCOMMON, mage.cards.m.Mirozel.class)); + cards.add(new SetCardInfo("Mirri, Cat Warrior", 114, Rarity.RARE, mage.cards.m.MirriCatWarrior.class)); + cards.add(new SetCardInfo("Mogg Assassin", 88, Rarity.UNCOMMON, mage.cards.m.MoggAssassin.class)); + cards.add(new SetCardInfo("Monstrous Hound", 89, Rarity.RARE, mage.cards.m.MonstrousHound.class)); + cards.add(new SetCardInfo("Nausea", 67, Rarity.COMMON, mage.cards.n.Nausea.class)); + cards.add(new SetCardInfo("Necrologia", 68, Rarity.UNCOMMON, mage.cards.n.Necrologia.class)); + cards.add(new SetCardInfo("Null Brooch", 136, Rarity.RARE, mage.cards.n.NullBrooch.class)); + cards.add(new SetCardInfo("Oath of Druids", 115, Rarity.RARE, mage.cards.o.OathOfDruids.class)); + cards.add(new SetCardInfo("Oath of Ghouls", 69, Rarity.RARE, mage.cards.o.OathOfGhouls.class)); + cards.add(new SetCardInfo("Oath of Lieges", 11, Rarity.RARE, mage.cards.o.OathOfLieges.class)); + cards.add(new SetCardInfo("Oath of Mages", 90, Rarity.RARE, mage.cards.o.OathOfMages.class)); + cards.add(new SetCardInfo("Oath of Scholars", 42, Rarity.RARE, mage.cards.o.OathOfScholars.class)); + cards.add(new SetCardInfo("Ogre Shaman", 91, Rarity.RARE, mage.cards.o.OgreShaman.class)); + cards.add(new SetCardInfo("Onslaught", 92, Rarity.COMMON, mage.cards.o.Onslaught.class)); + cards.add(new SetCardInfo("Paladin en-Vec", 12, Rarity.RARE, mage.cards.p.PaladinEnVec.class)); + cards.add(new SetCardInfo("Pandemonium", 93, Rarity.RARE, mage.cards.p.Pandemonium.class)); + cards.add(new SetCardInfo("Paroxysm", 94, Rarity.UNCOMMON, mage.cards.p.Paroxysm.class)); + cards.add(new SetCardInfo("Peace of Mind", 13, Rarity.UNCOMMON, mage.cards.p.PeaceOfMind.class)); + cards.add(new SetCardInfo("Pegasus Stampede", 14, Rarity.UNCOMMON, mage.cards.p.PegasusStampede.class)); + cards.add(new SetCardInfo("Penance", 15, Rarity.UNCOMMON, mage.cards.p.Penance.class)); + cards.add(new SetCardInfo("Pit Spawn", 70, Rarity.RARE, mage.cards.p.PitSpawn.class)); + cards.add(new SetCardInfo("Plaguebearer", 71, Rarity.RARE, mage.cards.p.Plaguebearer.class)); + cards.add(new SetCardInfo("Plated Rootwalla", 116, Rarity.COMMON, mage.cards.p.PlatedRootwalla.class)); + cards.add(new SetCardInfo("Predatory Hunger", 117, Rarity.COMMON, mage.cards.p.PredatoryHunger.class)); + cards.add(new SetCardInfo("Price of Progress", 95, Rarity.UNCOMMON, mage.cards.p.PriceOfProgress.class)); + cards.add(new SetCardInfo("Pygmy Troll", 118, Rarity.COMMON, mage.cards.p.PygmyTroll.class)); + cards.add(new SetCardInfo("Rabid Wolverines", 119, Rarity.COMMON, mage.cards.r.RabidWolverines.class)); + cards.add(new SetCardInfo("Raging Goblin", 96, Rarity.COMMON, mage.cards.r.RagingGoblin.class)); + cards.add(new SetCardInfo("Ravenous Baboons", 97, Rarity.RARE, mage.cards.r.RavenousBaboons.class)); + cards.add(new SetCardInfo("Reaping the Rewards", 16, Rarity.COMMON, mage.cards.r.ReapingTheRewards.class)); + cards.add(new SetCardInfo("Reckless Ogre", 98, Rarity.COMMON, mage.cards.r.RecklessOgre.class)); + cards.add(new SetCardInfo("Reclaim", 120, Rarity.COMMON, mage.cards.r.Reclaim.class)); + cards.add(new SetCardInfo("Reconnaissance", 17, Rarity.UNCOMMON, mage.cards.r.Reconnaissance.class)); + cards.add(new SetCardInfo("Recurring Nightmare", 72, Rarity.RARE, mage.cards.r.RecurringNightmare.class)); + cards.add(new SetCardInfo("Resuscitate", 121, Rarity.UNCOMMON, mage.cards.r.Resuscitate.class)); + cards.add(new SetCardInfo("Robe of Mirrors", 43, Rarity.COMMON, mage.cards.r.RobeOfMirrors.class)); + cards.add(new SetCardInfo("Rootwater Alligator", 122, Rarity.COMMON, mage.cards.r.RootwaterAlligator.class)); + cards.add(new SetCardInfo("Rootwater Mystic", 44, Rarity.COMMON, mage.cards.r.RootwaterMystic.class)); + cards.add(new SetCardInfo("Sabertooth Wyvern", 99, Rarity.UNCOMMON, mage.cards.s.SabertoothWyvern.class)); + cards.add(new SetCardInfo("Scalding Salamander", 100, Rarity.UNCOMMON, mage.cards.s.ScaldingSalamander.class)); + cards.add(new SetCardInfo("Scare Tactics", 73, Rarity.COMMON, mage.cards.s.ScareTactics.class)); + cards.add(new SetCardInfo("School of Piranha", 45, Rarity.COMMON, mage.cards.s.SchoolOfPiranha.class)); + cards.add(new SetCardInfo("Scrivener", 46, Rarity.UNCOMMON, mage.cards.s.Scrivener.class)); + cards.add(new SetCardInfo("Seismic Assault", 101, Rarity.RARE, mage.cards.s.SeismicAssault.class)); + cards.add(new SetCardInfo("Shackles", 18, Rarity.COMMON, mage.cards.s.Shackles.class)); + cards.add(new SetCardInfo("Shattering Pulse", 102, Rarity.COMMON, mage.cards.s.ShatteringPulse.class)); + cards.add(new SetCardInfo("Shield Mate", 19, Rarity.COMMON, mage.cards.s.ShieldMate.class)); + cards.add(new SetCardInfo("Skyshaper", 137, Rarity.UNCOMMON, mage.cards.s.Skyshaper.class)); + cards.add(new SetCardInfo("Skyshroud Elite", 123, Rarity.UNCOMMON, mage.cards.s.SkyshroudElite.class)); + cards.add(new SetCardInfo("Skyshroud War Beast", 124, Rarity.RARE, mage.cards.s.SkyshroudWarBeast.class)); + cards.add(new SetCardInfo("Slaughter", 74, Rarity.UNCOMMON, mage.cards.s.Slaughter.class)); + cards.add(new SetCardInfo("Soltari Visionary", 20, Rarity.COMMON, mage.cards.s.SoltariVisionary.class)); + cards.add(new SetCardInfo("Song of Serenity", 125, Rarity.UNCOMMON, mage.cards.s.SongOfSerenity.class)); + cards.add(new SetCardInfo("Sonic Burst", 103, Rarity.COMMON, mage.cards.s.SonicBurst.class)); + cards.add(new SetCardInfo("Soul Warden", 21, Rarity.COMMON, mage.cards.s.SoulWarden.class)); + cards.add(new SetCardInfo("Spellbook", 138, Rarity.UNCOMMON, mage.cards.s.Spellbook.class)); + cards.add(new SetCardInfo("Spellshock", 104, Rarity.UNCOMMON, mage.cards.s.Spellshock.class)); + cards.add(new SetCardInfo("Sphere of Resistance", 139, Rarity.RARE, mage.cards.s.SphereOfResistance.class)); + cards.add(new SetCardInfo("Spike Cannibal", 75, Rarity.UNCOMMON, mage.cards.s.SpikeCannibal.class)); + cards.add(new SetCardInfo("Spike Hatcher", 126, Rarity.RARE, mage.cards.s.SpikeHatcher.class)); + cards.add(new SetCardInfo("Spike Rogue", 127, Rarity.UNCOMMON, mage.cards.s.SpikeRogue.class)); + cards.add(new SetCardInfo("Spike Weaver", 128, Rarity.RARE, mage.cards.s.SpikeWeaver.class)); + cards.add(new SetCardInfo("Standing Troops", 22, Rarity.COMMON, mage.cards.s.StandingTroops.class)); + cards.add(new SetCardInfo("Survival of the Fittest", 129, Rarity.RARE, mage.cards.s.SurvivalOfTheFittest.class)); + cards.add(new SetCardInfo("Thalakos Drifters", 47, Rarity.RARE, mage.cards.t.ThalakosDrifters.class)); + cards.add(new SetCardInfo("Thalakos Scout", 48, Rarity.COMMON, mage.cards.t.ThalakosScout.class)); + cards.add(new SetCardInfo("Theft of Dreams", 49, Rarity.COMMON, mage.cards.t.TheftOfDreams.class)); + cards.add(new SetCardInfo("Thopter Squadron", 140, Rarity.RARE, mage.cards.t.ThopterSquadron.class)); + cards.add(new SetCardInfo("Thrull Surgeon", 76, Rarity.COMMON, mage.cards.t.ThrullSurgeon.class)); + cards.add(new SetCardInfo("Transmogrifying Licid", 141, Rarity.UNCOMMON, mage.cards.t.TransmogrifyingLicid.class)); + cards.add(new SetCardInfo("Treasure Hunter", 23, Rarity.UNCOMMON, mage.cards.t.TreasureHunter.class)); + cards.add(new SetCardInfo("Treasure Trove", 50, Rarity.UNCOMMON, mage.cards.t.TreasureTrove.class)); + cards.add(new SetCardInfo("Vampire Hounds", 77, Rarity.COMMON, mage.cards.v.VampireHounds.class)); + cards.add(new SetCardInfo("Volrath's Dungeon", 78, Rarity.RARE, mage.cards.v.VolrathsDungeon.class)); + cards.add(new SetCardInfo("Wall of Nets", 24, Rarity.RARE, mage.cards.w.WallOfNets.class)); + cards.add(new SetCardInfo("Wayward Soul", 51, Rarity.COMMON, mage.cards.w.WaywardSoul.class)); + cards.add(new SetCardInfo("Welkin Hawk", 25, Rarity.COMMON, mage.cards.w.WelkinHawk.class)); + cards.add(new SetCardInfo("Whiptongue Frog", 52, Rarity.COMMON, mage.cards.w.WhiptongueFrog.class)); + cards.add(new SetCardInfo("Wood Elves", 130, Rarity.COMMON, mage.cards.w.WoodElves.class)); + cards.add(new SetCardInfo("Workhorse", 142, Rarity.RARE, mage.cards.w.Workhorse.class)); + cards.add(new SetCardInfo("Zealots en-Dal", 26, Rarity.UNCOMMON, mage.cards.z.ZealotsEnDal.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/FifthEdition.java b/Mage.Sets/src/mage/sets/FifthEdition.java index fcef5f51232..6d6e93dbc63 100644 --- a/Mage.Sets/src/mage/sets/FifthEdition.java +++ b/Mage.Sets/src/mage/sets/FifthEdition.java @@ -1,465 +1,467 @@ -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -public final class FifthEdition extends ExpansionSet { - - private static final FifthEdition instance = new FifthEdition(); - - public static FifthEdition getInstance() { - return instance; - } - - private FifthEdition() { - super("Fifth Edition", "5ED", ExpansionSet.buildDate(1997, 3, 1), SetType.CORE); - this.hasBoosters = true; - this.numBoosterLands = 0; - this.numBoosterCommon = 11; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - cards.add(new SetCardInfo("Abbey Gargoyles", 1, Rarity.UNCOMMON, mage.cards.a.AbbeyGargoyles.class)); - cards.add(new SetCardInfo("Abyssal Specter", 139, Rarity.UNCOMMON, mage.cards.a.AbyssalSpecter.class)); - cards.add(new SetCardInfo("Adarkar Wastes", 410, Rarity.RARE, mage.cards.a.AdarkarWastes.class)); - cards.add(new SetCardInfo("Aether Storm", 70, Rarity.UNCOMMON, mage.cards.a.AetherStorm.class)); - cards.add(new SetCardInfo("Air Elemental", 71, Rarity.UNCOMMON, mage.cards.a.AirElemental.class)); - cards.add(new SetCardInfo("Akron Legionnaire", 2, Rarity.RARE, mage.cards.a.AkronLegionnaire.class)); - cards.add(new SetCardInfo("Alabaster Potion", 3, Rarity.COMMON, mage.cards.a.AlabasterPotion.class)); - cards.add(new SetCardInfo("Aladdin's Ring", 346, Rarity.RARE, mage.cards.a.AladdinsRing.class)); - cards.add(new SetCardInfo("Ambush Party", 208, Rarity.COMMON, mage.cards.a.AmbushParty.class)); - cards.add(new SetCardInfo("Amulet of Kroog", 347, Rarity.COMMON, mage.cards.a.AmuletOfKroog.class)); - cards.add(new SetCardInfo("An-Havva Constable", 277, Rarity.RARE, mage.cards.a.AnHavvaConstable.class)); - cards.add(new SetCardInfo("Angry Mob", 4, Rarity.UNCOMMON, mage.cards.a.AngryMob.class)); - cards.add(new SetCardInfo("Animate Dead", 140, Rarity.UNCOMMON, mage.cards.a.AnimateDead.class)); - cards.add(new SetCardInfo("Animate Wall", 5, Rarity.RARE, mage.cards.a.AnimateWall.class)); - cards.add(new SetCardInfo("Ankh of Mishra", 348, Rarity.RARE, mage.cards.a.AnkhOfMishra.class)); - cards.add(new SetCardInfo("Anti-Magic Aura", 72, Rarity.UNCOMMON, mage.cards.a.AntiMagicAura.class)); - cards.add(new SetCardInfo("Arenson's Aura", 6, Rarity.UNCOMMON, mage.cards.a.ArensonsAura.class)); - cards.add(new SetCardInfo("Armageddon", 7, Rarity.RARE, mage.cards.a.Armageddon.class)); - cards.add(new SetCardInfo("Armor of Faith", 8, Rarity.COMMON, mage.cards.a.ArmorOfFaith.class)); - cards.add(new SetCardInfo("Ashes to Ashes", 141, Rarity.UNCOMMON, mage.cards.a.AshesToAshes.class)); - cards.add(new SetCardInfo("Ashnod's Altar", 349, Rarity.UNCOMMON, mage.cards.a.AshnodsAltar.class)); - cards.add(new SetCardInfo("Ashnod's Transmogrant", 350, Rarity.COMMON, mage.cards.a.AshnodsTransmogrant.class)); - cards.add(new SetCardInfo("Aspect of Wolf", 278, Rarity.RARE, mage.cards.a.AspectOfWolf.class)); - cards.add(new SetCardInfo("Atog", 209, Rarity.UNCOMMON, mage.cards.a.Atog.class)); - cards.add(new SetCardInfo("Aurochs", 279, Rarity.COMMON, mage.cards.a.Aurochs.class)); - cards.add(new SetCardInfo("Aysen Bureaucrats", 9, Rarity.COMMON, mage.cards.a.AysenBureaucrats.class)); - cards.add(new SetCardInfo("Azure Drake", 73, Rarity.UNCOMMON, mage.cards.a.AzureDrake.class)); - cards.add(new SetCardInfo("Bad Moon", 142, Rarity.RARE, mage.cards.b.BadMoon.class)); - cards.add(new SetCardInfo("Ball Lightning", 210, Rarity.RARE, mage.cards.b.BallLightning.class)); - cards.add(new SetCardInfo("Barbed Sextant", 351, Rarity.COMMON, mage.cards.b.BarbedSextant.class)); - cards.add(new SetCardInfo("Barl's Cage", 352, Rarity.RARE, mage.cards.b.BarlsCage.class)); - cards.add(new SetCardInfo("Battering Ram", 353, Rarity.COMMON, mage.cards.b.BatteringRam.class)); - cards.add(new SetCardInfo("Benalish Hero", 10, Rarity.COMMON, mage.cards.b.BenalishHero.class)); - cards.add(new SetCardInfo("Binding Grasp", 74, Rarity.UNCOMMON, mage.cards.b.BindingGrasp.class)); - cards.add(new SetCardInfo("Bird Maiden", 211, Rarity.COMMON, mage.cards.b.BirdMaiden.class)); - cards.add(new SetCardInfo("Birds of Paradise", 280, Rarity.RARE, mage.cards.b.BirdsOfParadise.class)); - cards.add(new SetCardInfo("Black Knight", 143, Rarity.UNCOMMON, mage.cards.b.BlackKnight.class)); - cards.add(new SetCardInfo("Blessed Wine", 11, Rarity.COMMON, mage.cards.b.BlessedWine.class)); - cards.add(new SetCardInfo("Blight", 144, Rarity.UNCOMMON, mage.cards.b.Blight.class)); - cards.add(new SetCardInfo("Blinking Spirit", 12, Rarity.RARE, mage.cards.b.BlinkingSpirit.class)); - cards.add(new SetCardInfo("Blood Lust", 212, Rarity.COMMON, mage.cards.b.BloodLust.class)); - cards.add(new SetCardInfo("Bog Imp", 145, Rarity.COMMON, mage.cards.b.BogImp.class)); - cards.add(new SetCardInfo("Bog Rats", 146, Rarity.COMMON, mage.cards.b.BogRats.class)); - cards.add(new SetCardInfo("Bog Wraith", 147, Rarity.UNCOMMON, mage.cards.b.BogWraith.class)); - cards.add(new SetCardInfo("Boomerang", 75, Rarity.COMMON, mage.cards.b.Boomerang.class)); - cards.add(new SetCardInfo("Bottle of Suleiman", 354, Rarity.RARE, mage.cards.b.BottleOfSuleiman.class)); - cards.add(new SetCardInfo("Bottomless Vault", 411, Rarity.RARE, mage.cards.b.BottomlessVault.class)); - cards.add(new SetCardInfo("Brainstorm", 76, Rarity.COMMON, mage.cards.b.Brainstorm.class)); - cards.add(new SetCardInfo("Brainwash", 13, Rarity.COMMON, mage.cards.b.Brainwash.class)); - cards.add(new SetCardInfo("Brassclaw Orcs", 213, Rarity.COMMON, mage.cards.b.BrassclawOrcs.class)); - cards.add(new SetCardInfo("Breeding Pit", 148, Rarity.UNCOMMON, mage.cards.b.BreedingPit.class)); - cards.add(new SetCardInfo("Broken Visage", 149, Rarity.RARE, mage.cards.b.BrokenVisage.class)); - cards.add(new SetCardInfo("Brothers of Fire", 214, Rarity.COMMON, mage.cards.b.BrothersOfFire.class)); - cards.add(new SetCardInfo("Brushland", 412, Rarity.RARE, mage.cards.b.Brushland.class)); - cards.add(new SetCardInfo("Carapace", 281, Rarity.COMMON, mage.cards.c.Carapace.class)); - cards.add(new SetCardInfo("Caribou Range", 14, Rarity.RARE, mage.cards.c.CaribouRange.class)); - cards.add(new SetCardInfo("Carrion Ants", 150, Rarity.UNCOMMON, mage.cards.c.CarrionAnts.class)); - cards.add(new SetCardInfo("Castle", 15, Rarity.UNCOMMON, mage.cards.c.Castle.class)); - cards.add(new SetCardInfo("Cat Warriors", 282, Rarity.COMMON, mage.cards.c.CatWarriors.class)); - cards.add(new SetCardInfo("Cave People", 215, Rarity.UNCOMMON, mage.cards.c.CavePeople.class)); - cards.add(new SetCardInfo("Chub Toad", 283, Rarity.COMMON, mage.cards.c.ChubToad.class)); - cards.add(new SetCardInfo("Circle of Protection: Artifacts", 16, Rarity.UNCOMMON, mage.cards.c.CircleOfProtectionArtifacts.class)); - cards.add(new SetCardInfo("Circle of Protection: Black", 17, Rarity.COMMON, mage.cards.c.CircleOfProtectionBlack.class)); - cards.add(new SetCardInfo("Circle of Protection: Blue", 18, Rarity.COMMON, mage.cards.c.CircleOfProtectionBlue.class)); - cards.add(new SetCardInfo("Circle of Protection: Green", 19, Rarity.COMMON, mage.cards.c.CircleOfProtectionGreen.class)); - cards.add(new SetCardInfo("Circle of Protection: Red", 20, Rarity.COMMON, mage.cards.c.CircleOfProtectionRed.class)); - cards.add(new SetCardInfo("Circle of Protection: White", 21, Rarity.COMMON, mage.cards.c.CircleOfProtectionWhite.class)); - cards.add(new SetCardInfo("City of Brass", 413, Rarity.RARE, mage.cards.c.CityOfBrass.class)); - cards.add(new SetCardInfo("Clay Statue", 355, Rarity.COMMON, mage.cards.c.ClayStatue.class)); - cards.add(new SetCardInfo("Clockwork Beast", 356, Rarity.RARE, mage.cards.c.ClockworkBeast.class)); - cards.add(new SetCardInfo("Clockwork Steed", 357, Rarity.UNCOMMON, mage.cards.c.ClockworkSteed.class)); - cards.add(new SetCardInfo("Cockatrice", 284, Rarity.RARE, mage.cards.c.Cockatrice.class)); - cards.add(new SetCardInfo("Colossus of Sardia", 358, Rarity.RARE, mage.cards.c.ColossusOfSardia.class)); - cards.add(new SetCardInfo("Conquer", 216, Rarity.UNCOMMON, mage.cards.c.Conquer.class)); - cards.add(new SetCardInfo("Coral Helm", 359, Rarity.RARE, mage.cards.c.CoralHelm.class)); - cards.add(new SetCardInfo("Counterspell", 77, Rarity.COMMON, mage.cards.c.Counterspell.class)); - cards.add(new SetCardInfo("Craw Giant", 285, Rarity.UNCOMMON, mage.cards.c.CrawGiant.class)); - cards.add(new SetCardInfo("Craw Wurm", 286, Rarity.COMMON, mage.cards.c.CrawWurm.class)); - cards.add(new SetCardInfo("Crimson Manticore", 217, Rarity.RARE, mage.cards.c.CrimsonManticore.class)); - cards.add(new SetCardInfo("Crown of the Ages", 360, Rarity.RARE, mage.cards.c.CrownOfTheAges.class)); - cards.add(new SetCardInfo("Crumble", 287, Rarity.UNCOMMON, mage.cards.c.Crumble.class)); - cards.add(new SetCardInfo("Crusade", 22, Rarity.RARE, mage.cards.c.Crusade.class)); - cards.add(new SetCardInfo("Crystal Rod", 361, Rarity.UNCOMMON, mage.cards.c.CrystalRod.class)); - cards.add(new SetCardInfo("Cursed Land", 152, Rarity.UNCOMMON, mage.cards.c.CursedLand.class)); - cards.add(new SetCardInfo("D'Avenant Archer", 23, Rarity.COMMON, mage.cards.d.DAvenantArcher.class)); - cards.add(new SetCardInfo("Dance of Many", 78, Rarity.RARE, mage.cards.d.DanceOfMany.class)); - cards.add(new SetCardInfo("Dancing Scimitar", 362, Rarity.RARE, mage.cards.d.DancingScimitar.class)); - cards.add(new SetCardInfo("Dandan", 79, Rarity.COMMON, mage.cards.d.Dandan.class)); - cards.add(new SetCardInfo("Dark Maze", 80, Rarity.COMMON, mage.cards.d.DarkMaze.class)); - cards.add(new SetCardInfo("Dark Ritual", 153, Rarity.COMMON, mage.cards.d.DarkRitual.class)); - cards.add(new SetCardInfo("Death Speakers", 24, Rarity.COMMON, mage.cards.d.DeathSpeakers.class)); - cards.add(new SetCardInfo("Death Ward", 25, Rarity.COMMON, mage.cards.d.DeathWard.class)); - cards.add(new SetCardInfo("Deathgrip", 154, Rarity.UNCOMMON, mage.cards.d.Deathgrip.class)); - cards.add(new SetCardInfo("Deflection", 81, Rarity.RARE, mage.cards.d.Deflection.class)); - cards.add(new SetCardInfo("Derelor", 155, Rarity.RARE, mage.cards.d.Derelor.class)); - cards.add(new SetCardInfo("Desert Twister", 288, Rarity.UNCOMMON, mage.cards.d.DesertTwister.class)); - cards.add(new SetCardInfo("Detonate", 218, Rarity.UNCOMMON, mage.cards.d.Detonate.class)); - cards.add(new SetCardInfo("Diabolic Machine", 363, Rarity.UNCOMMON, mage.cards.d.DiabolicMachine.class)); - cards.add(new SetCardInfo("Dingus Egg", 364, Rarity.RARE, mage.cards.d.DingusEgg.class)); - cards.add(new SetCardInfo("Disenchant", 26, Rarity.COMMON, mage.cards.d.Disenchant.class)); - cards.add(new SetCardInfo("Disintegrate", 219, Rarity.COMMON, mage.cards.d.Disintegrate.class)); - cards.add(new SetCardInfo("Disrupting Scepter", 365, Rarity.RARE, mage.cards.d.DisruptingScepter.class)); - cards.add(new SetCardInfo("Divine Offering", 27, Rarity.COMMON, mage.cards.d.DivineOffering.class)); - cards.add(new SetCardInfo("Divine Transformation", 28, Rarity.UNCOMMON, mage.cards.d.DivineTransformation.class)); - cards.add(new SetCardInfo("Dragon Engine", 366, Rarity.RARE, mage.cards.d.DragonEngine.class)); - cards.add(new SetCardInfo("Drain Life", 156, Rarity.COMMON, mage.cards.d.DrainLife.class)); - cards.add(new SetCardInfo("Drain Power", 82, Rarity.RARE, mage.cards.d.DrainPower.class)); - cards.add(new SetCardInfo("Drudge Skeletons", 157, Rarity.COMMON, mage.cards.d.DrudgeSkeletons.class)); - cards.add(new SetCardInfo("Durkwood Boars", 289, Rarity.COMMON, mage.cards.d.DurkwoodBoars.class)); - cards.add(new SetCardInfo("Dust to Dust", 29, Rarity.UNCOMMON, mage.cards.d.DustToDust.class)); - cards.add(new SetCardInfo("Dwarven Catapult", 220, Rarity.UNCOMMON, mage.cards.d.DwarvenCatapult.class)); - cards.add(new SetCardInfo("Dwarven Hold", 414, Rarity.RARE, mage.cards.d.DwarvenHold.class)); - cards.add(new SetCardInfo("Dwarven Ruins", 415, Rarity.UNCOMMON, mage.cards.d.DwarvenRuins.class)); - cards.add(new SetCardInfo("Dwarven Soldier", 221, Rarity.COMMON, mage.cards.d.DwarvenSoldier.class)); - cards.add(new SetCardInfo("Dwarven Warriors", 222, Rarity.COMMON, mage.cards.d.DwarvenWarriors.class)); - cards.add(new SetCardInfo("Earthquake", 223, Rarity.RARE, mage.cards.e.Earthquake.class)); - cards.add(new SetCardInfo("Ebon Stronghold", 416, Rarity.UNCOMMON, mage.cards.e.EbonStronghold.class)); - cards.add(new SetCardInfo("Elder Druid", 290, Rarity.RARE, mage.cards.e.ElderDruid.class)); - cards.add(new SetCardInfo("Elkin Bottle", 367, Rarity.RARE, mage.cards.e.ElkinBottle.class)); - cards.add(new SetCardInfo("Elven Riders", 291, Rarity.UNCOMMON, mage.cards.e.ElvenRiders.class)); - cards.add(new SetCardInfo("Elvish Archers", 292, Rarity.RARE, mage.cards.e.ElvishArchers.class)); - cards.add(new SetCardInfo("Energy Flux", 83, Rarity.UNCOMMON, mage.cards.e.EnergyFlux.class)); - cards.add(new SetCardInfo("Enervate", 84, Rarity.COMMON, mage.cards.e.Enervate.class)); - cards.add(new SetCardInfo("Erg Raiders", 158, Rarity.COMMON, mage.cards.e.ErgRaiders.class)); - cards.add(new SetCardInfo("Errantry", 224, Rarity.COMMON, mage.cards.e.Errantry.class)); - cards.add(new SetCardInfo("Eternal Warrior", 225, Rarity.COMMON, mage.cards.e.EternalWarrior.class)); - cards.add(new SetCardInfo("Evil Eye of Orms-by-Gore", 159, Rarity.UNCOMMON, mage.cards.e.EvilEyeOfOrmsByGore.class)); - cards.add(new SetCardInfo("Evil Presence", 160, Rarity.UNCOMMON, mage.cards.e.EvilPresence.class)); - cards.add(new SetCardInfo("Eye for an Eye", 30, Rarity.RARE, mage.cards.e.EyeForAnEye.class)); - cards.add(new SetCardInfo("Fallen Angel", 161, Rarity.UNCOMMON, mage.cards.f.FallenAngel.class)); - cards.add(new SetCardInfo("Fear", 162, Rarity.COMMON, mage.cards.f.Fear.class)); - cards.add(new SetCardInfo("Feedback", 85, Rarity.UNCOMMON, mage.cards.f.Feedback.class)); - cards.add(new SetCardInfo("Feldon's Cane", 368, Rarity.UNCOMMON, mage.cards.f.FeldonsCane.class)); - cards.add(new SetCardInfo("Fellwar Stone", 369, Rarity.UNCOMMON, mage.cards.f.FellwarStone.class)); - cards.add(new SetCardInfo("Feroz's Ban", 370, Rarity.RARE, mage.cards.f.FerozsBan.class)); - cards.add(new SetCardInfo("Fire Drake", 226, Rarity.UNCOMMON, mage.cards.f.FireDrake.class)); - cards.add(new SetCardInfo("Fireball", 227, Rarity.COMMON, mage.cards.f.Fireball.class)); - cards.add(new SetCardInfo("Firebreathing", 228, Rarity.COMMON, mage.cards.f.Firebreathing.class)); - cards.add(new SetCardInfo("Flame Spirit", 229, Rarity.UNCOMMON, mage.cards.f.FlameSpirit.class)); - cards.add(new SetCardInfo("Flare", 230, Rarity.COMMON, mage.cards.f.Flare.class)); - cards.add(new SetCardInfo("Flashfires", 231, Rarity.UNCOMMON, mage.cards.f.Flashfires.class)); - cards.add(new SetCardInfo("Flight", 86, Rarity.COMMON, mage.cards.f.Flight.class)); - cards.add(new SetCardInfo("Flood", 87, Rarity.COMMON, mage.cards.f.Flood.class)); - cards.add(new SetCardInfo("Flying Carpet", 371, Rarity.RARE, mage.cards.f.FlyingCarpet.class)); - cards.add(new SetCardInfo("Fog", 293, Rarity.COMMON, mage.cards.f.Fog.class)); - cards.add(new SetCardInfo("Force Spike", 88, Rarity.COMMON, mage.cards.f.ForceSpike.class)); - cards.add(new SetCardInfo("Force of Nature", 294, Rarity.RARE, mage.cards.f.ForceOfNature.class)); - cards.add(new SetCardInfo("Forest", 446, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 447, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 448, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 449, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forget", 89, Rarity.RARE, mage.cards.f.Forget.class)); - cards.add(new SetCardInfo("Fountain of Youth", 372, Rarity.UNCOMMON, mage.cards.f.FountainOfYouth.class)); - cards.add(new SetCardInfo("Foxfire", 295, Rarity.COMMON, mage.cards.f.Foxfire.class)); - cards.add(new SetCardInfo("Frozen Shade", 163, Rarity.COMMON, mage.cards.f.FrozenShade.class)); - cards.add(new SetCardInfo("Funeral March", 164, Rarity.COMMON, mage.cards.f.FuneralMarch.class)); - cards.add(new SetCardInfo("Fungusaur", 296, Rarity.RARE, mage.cards.f.Fungusaur.class)); - cards.add(new SetCardInfo("Fyndhorn Elder", 297, Rarity.UNCOMMON, mage.cards.f.FyndhornElder.class)); - cards.add(new SetCardInfo("Game of Chaos", 232, Rarity.RARE, mage.cards.g.GameOfChaos.class)); - cards.add(new SetCardInfo("Gaseous Form", 90, Rarity.COMMON, mage.cards.g.GaseousForm.class)); - cards.add(new SetCardInfo("Gauntlets of Chaos", 373, Rarity.RARE, mage.cards.g.GauntletsOfChaos.class)); - cards.add(new SetCardInfo("Ghazban Ogre", 298, Rarity.COMMON, mage.cards.g.GhazbanOgre.class)); - cards.add(new SetCardInfo("Giant Growth", 299, Rarity.COMMON, mage.cards.g.GiantGrowth.class)); - cards.add(new SetCardInfo("Giant Spider", 300, Rarity.COMMON, mage.cards.g.GiantSpider.class)); - cards.add(new SetCardInfo("Giant Strength", 233, Rarity.COMMON, mage.cards.g.GiantStrength.class)); - cards.add(new SetCardInfo("Glacial Wall", 91, Rarity.UNCOMMON, mage.cards.g.GlacialWall.class)); - cards.add(new SetCardInfo("Glasses of Urza", 374, Rarity.UNCOMMON, mage.cards.g.GlassesOfUrza.class)); - cards.add(new SetCardInfo("Gloom", 165, Rarity.UNCOMMON, mage.cards.g.Gloom.class)); - cards.add(new SetCardInfo("Goblin Digging Team", 234, Rarity.COMMON, mage.cards.g.GoblinDiggingTeam.class)); - cards.add(new SetCardInfo("Goblin Hero", 235, Rarity.COMMON, mage.cards.g.GoblinHero.class)); - cards.add(new SetCardInfo("Goblin King", 236, Rarity.RARE, mage.cards.g.GoblinKing.class)); - cards.add(new SetCardInfo("Goblin War Drums", 237, Rarity.COMMON, mage.cards.g.GoblinWarDrums.class)); - cards.add(new SetCardInfo("Goblin Warrens", 238, Rarity.RARE, mage.cards.g.GoblinWarrens.class)); - cards.add(new SetCardInfo("Grapeshot Catapult", 375, Rarity.COMMON, mage.cards.g.GrapeshotCatapult.class)); - cards.add(new SetCardInfo("Greater Realm of Preservation", 31, Rarity.UNCOMMON, mage.cards.g.GreaterRealmOfPreservation.class)); - cards.add(new SetCardInfo("Greater Werewolf", 166, Rarity.UNCOMMON, mage.cards.g.GreaterWerewolf.class)); - cards.add(new SetCardInfo("Grizzly Bears", 301, Rarity.COMMON, mage.cards.g.GrizzlyBears.class)); - cards.add(new SetCardInfo("Havenwood Battleground", 417, Rarity.UNCOMMON, mage.cards.h.HavenwoodBattleground.class)); - cards.add(new SetCardInfo("Heal", 32, Rarity.COMMON, mage.cards.h.Heal.class)); - cards.add(new SetCardInfo("Healing Salve", 33, Rarity.COMMON, mage.cards.h.HealingSalve.class)); - cards.add(new SetCardInfo("Hecatomb", 167, Rarity.RARE, mage.cards.h.Hecatomb.class)); - cards.add(new SetCardInfo("Helm of Chatzuk", 376, Rarity.RARE, mage.cards.h.HelmOfChatzuk.class)); - cards.add(new SetCardInfo("Hill Giant", 239, Rarity.COMMON, mage.cards.h.HillGiant.class)); - cards.add(new SetCardInfo("Hollow Trees", 418, Rarity.RARE, mage.cards.h.HollowTrees.class)); - cards.add(new SetCardInfo("Holy Strength", 35, Rarity.COMMON, mage.cards.h.HolyStrength.class)); - cards.add(new SetCardInfo("Homarid Warrior", 92, Rarity.COMMON, mage.cards.h.HomaridWarrior.class)); - cards.add(new SetCardInfo("Howl from Beyond", 168, Rarity.COMMON, mage.cards.h.HowlFromBeyond.class)); - cards.add(new SetCardInfo("Howling Mine", 377, Rarity.RARE, mage.cards.h.HowlingMine.class)); - cards.add(new SetCardInfo("Hungry Mist", 302, Rarity.COMMON, mage.cards.h.HungryMist.class)); - cards.add(new SetCardInfo("Hurkyl's Recall", 93, Rarity.RARE, mage.cards.h.HurkylsRecall.class)); - cards.add(new SetCardInfo("Hurloon Minotaur", 240, Rarity.COMMON, mage.cards.h.HurloonMinotaur.class)); - cards.add(new SetCardInfo("Hurricane", 303, Rarity.UNCOMMON, mage.cards.h.Hurricane.class)); - cards.add(new SetCardInfo("Hydroblast", 94, Rarity.UNCOMMON, mage.cards.h.Hydroblast.class)); - cards.add(new SetCardInfo("Icatian Phalanx", 36, Rarity.UNCOMMON, mage.cards.i.IcatianPhalanx.class)); - cards.add(new SetCardInfo("Icatian Scout", 37, Rarity.COMMON, mage.cards.i.IcatianScout.class)); - cards.add(new SetCardInfo("Icatian Store", 419, Rarity.RARE, mage.cards.i.IcatianStore.class)); - cards.add(new SetCardInfo("Icatian Town", 38, Rarity.RARE, mage.cards.i.IcatianTown.class)); - cards.add(new SetCardInfo("Ice Floe", 420, Rarity.UNCOMMON, mage.cards.i.IceFloe.class)); - cards.add(new SetCardInfo("Imposing Visage", 241, Rarity.COMMON, mage.cards.i.ImposingVisage.class)); - cards.add(new SetCardInfo("Incinerate", 242, Rarity.COMMON, mage.cards.i.Incinerate.class)); - cards.add(new SetCardInfo("Inferno", 243, Rarity.RARE, mage.cards.i.Inferno.class)); - cards.add(new SetCardInfo("Infinite Hourglass", 378, Rarity.RARE, mage.cards.i.InfiniteHourglass.class)); - cards.add(new SetCardInfo("Initiates of the Ebon Hand", 169, Rarity.COMMON, mage.cards.i.InitiatesOfTheEbonHand.class)); - cards.add(new SetCardInfo("Instill Energy", 304, Rarity.UNCOMMON, mage.cards.i.InstillEnergy.class)); - cards.add(new SetCardInfo("Iron Star", 379, Rarity.UNCOMMON, mage.cards.i.IronStar.class)); - cards.add(new SetCardInfo("Ironclaw Curse", 244, Rarity.RARE, mage.cards.i.IronclawCurse.class)); - cards.add(new SetCardInfo("Ironclaw Orcs", 245, Rarity.COMMON, mage.cards.i.IronclawOrcs.class)); - cards.add(new SetCardInfo("Ironroot Treefolk", 305, Rarity.COMMON, mage.cards.i.IronrootTreefolk.class)); - cards.add(new SetCardInfo("Island Sanctuary", 39, Rarity.RARE, mage.cards.i.IslandSanctuary.class)); - cards.add(new SetCardInfo("Island", 434, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 435, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 436, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 437, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ivory Cup", 380, Rarity.UNCOMMON, mage.cards.i.IvoryCup.class)); - cards.add(new SetCardInfo("Ivory Guardians", 40, Rarity.UNCOMMON, mage.cards.i.IvoryGuardians.class)); - cards.add(new SetCardInfo("Jade Monolith", 381, Rarity.RARE, mage.cards.j.JadeMonolith.class)); - cards.add(new SetCardInfo("Jalum Tome", 382, Rarity.RARE, mage.cards.j.JalumTome.class)); - cards.add(new SetCardInfo("Jandor's Saddlebags", 383, Rarity.RARE, mage.cards.j.JandorsSaddlebags.class)); - cards.add(new SetCardInfo("Jayemdae Tome", 384, Rarity.RARE, mage.cards.j.JayemdaeTome.class)); - cards.add(new SetCardInfo("Jester's Cap", 385, Rarity.RARE, mage.cards.j.JestersCap.class)); - cards.add(new SetCardInfo("Johtull Wurm", 306, Rarity.UNCOMMON, mage.cards.j.JohtullWurm.class)); - cards.add(new SetCardInfo("Jokulhaups", 246, Rarity.RARE, mage.cards.j.Jokulhaups.class)); - cards.add(new SetCardInfo("Joven's Tools", 386, Rarity.UNCOMMON, mage.cards.j.JovensTools.class)); - cards.add(new SetCardInfo("Justice", 41, Rarity.UNCOMMON, mage.cards.j.Justice.class)); - cards.add(new SetCardInfo("Juxtapose", 95, Rarity.RARE, mage.cards.j.Juxtapose.class)); - cards.add(new SetCardInfo("Karma", 42, Rarity.UNCOMMON, mage.cards.k.Karma.class)); - cards.add(new SetCardInfo("Karplusan Forest", 421, Rarity.RARE, mage.cards.k.KarplusanForest.class)); - cards.add(new SetCardInfo("Keldon Warlord", 247, Rarity.UNCOMMON, mage.cards.k.KeldonWarlord.class)); - cards.add(new SetCardInfo("Killer Bees", 307, Rarity.UNCOMMON, mage.cards.k.KillerBees.class)); - cards.add(new SetCardInfo("Kismet", 43, Rarity.UNCOMMON, mage.cards.k.Kismet.class)); - cards.add(new SetCardInfo("Kjeldoran Dead", 170, Rarity.COMMON, mage.cards.k.KjeldoranDead.class)); - cards.add(new SetCardInfo("Kjeldoran Royal Guard", 44, Rarity.RARE, mage.cards.k.KjeldoranRoyalGuard.class)); - cards.add(new SetCardInfo("Kjeldoran Skycaptain", 45, Rarity.UNCOMMON, mage.cards.k.KjeldoranSkycaptain.class)); - cards.add(new SetCardInfo("Knight of Stromgald", 171, Rarity.UNCOMMON, mage.cards.k.KnightOfStromgald.class)); - cards.add(new SetCardInfo("Krovikan Fetish", 172, Rarity.COMMON, mage.cards.k.KrovikanFetish.class)); - cards.add(new SetCardInfo("Krovikan Sorcerer", 96, Rarity.COMMON, mage.cards.k.KrovikanSorcerer.class)); - cards.add(new SetCardInfo("Labyrinth Minotaur", 97, Rarity.COMMON, mage.cards.l.LabyrinthMinotaur.class)); - cards.add(new SetCardInfo("Leshrac's Rite", 173, Rarity.UNCOMMON, mage.cards.l.LeshracsRite.class)); - cards.add(new SetCardInfo("Leviathan", 98, Rarity.RARE, mage.cards.l.Leviathan.class)); - cards.add(new SetCardInfo("Ley Druid", 308, Rarity.COMMON, mage.cards.l.LeyDruid.class)); - cards.add(new SetCardInfo("Lhurgoyf", 309, Rarity.RARE, mage.cards.l.Lhurgoyf.class)); - cards.add(new SetCardInfo("Library of Leng", 387, Rarity.UNCOMMON, mage.cards.l.LibraryOfLeng.class)); - cards.add(new SetCardInfo("Lifeforce", 310, Rarity.UNCOMMON, mage.cards.l.Lifeforce.class)); - cards.add(new SetCardInfo("Lifetap", 99, Rarity.UNCOMMON, mage.cards.l.Lifetap.class)); - cards.add(new SetCardInfo("Living Artifact", 311, Rarity.RARE, mage.cards.l.LivingArtifact.class)); - cards.add(new SetCardInfo("Living Lands", 312, Rarity.RARE, mage.cards.l.LivingLands.class)); - cards.add(new SetCardInfo("Llanowar Elves", 313, Rarity.COMMON, mage.cards.l.LlanowarElves.class)); - cards.add(new SetCardInfo("Lord of Atlantis", 100, Rarity.RARE, mage.cards.l.LordOfAtlantis.class)); - cards.add(new SetCardInfo("Lord of the Pit", 174, Rarity.RARE, mage.cards.l.LordOfThePit.class)); - cards.add(new SetCardInfo("Lost Soul", 175, Rarity.COMMON, mage.cards.l.LostSoul.class)); - cards.add(new SetCardInfo("Lure", 314, Rarity.UNCOMMON, mage.cards.l.Lure.class)); - cards.add(new SetCardInfo("Magus of the Unseen", 102, Rarity.RARE, mage.cards.m.MagusOfTheUnseen.class)); - cards.add(new SetCardInfo("Mana Clash", 248, Rarity.RARE, mage.cards.m.ManaClash.class)); - cards.add(new SetCardInfo("Mana Flare", 249, Rarity.RARE, mage.cards.m.ManaFlare.class)); - cards.add(new SetCardInfo("Mana Vault", 388, Rarity.RARE, mage.cards.m.ManaVault.class)); - cards.add(new SetCardInfo("Manabarbs", 250, Rarity.RARE, mage.cards.m.Manabarbs.class)); - cards.add(new SetCardInfo("Marsh Viper", 315, Rarity.COMMON, mage.cards.m.MarshViper.class)); - cards.add(new SetCardInfo("Meekstone", 389, Rarity.RARE, mage.cards.m.Meekstone.class)); - cards.add(new SetCardInfo("Memory Lapse", 103, Rarity.COMMON, mage.cards.m.MemoryLapse.class)); - cards.add(new SetCardInfo("Merfolk of the Pearl Trident", 104, Rarity.COMMON, mage.cards.m.MerfolkOfThePearlTrident.class)); - cards.add(new SetCardInfo("Mesa Falcon", 46, Rarity.COMMON, mage.cards.m.MesaFalcon.class)); - cards.add(new SetCardInfo("Mesa Pegasus", 47, Rarity.COMMON, mage.cards.m.MesaPegasus.class)); - cards.add(new SetCardInfo("Millstone", 390, Rarity.RARE, mage.cards.m.Millstone.class)); - cards.add(new SetCardInfo("Mind Bomb", 105, Rarity.UNCOMMON, mage.cards.m.MindBomb.class)); - cards.add(new SetCardInfo("Mind Ravel", 176, Rarity.COMMON, mage.cards.m.MindRavel.class)); - cards.add(new SetCardInfo("Mind Warp", 177, Rarity.UNCOMMON, mage.cards.m.MindWarp.class)); - cards.add(new SetCardInfo("Mindstab Thrull", 178, Rarity.COMMON, mage.cards.m.MindstabThrull.class)); - cards.add(new SetCardInfo("Mole Worms", 179, Rarity.UNCOMMON, mage.cards.m.MoleWorms.class)); - cards.add(new SetCardInfo("Mons's Goblin Raiders", 251, Rarity.COMMON, mage.cards.m.MonssGoblinRaiders.class)); - cards.add(new SetCardInfo("Mountain Goat", 252, Rarity.COMMON, mage.cards.m.MountainGoat.class)); - cards.add(new SetCardInfo("Mountain", 442, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 443, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 444, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 445, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Murk Dwellers", 180, Rarity.COMMON, mage.cards.m.MurkDwellers.class)); - cards.add(new SetCardInfo("Nature's Lore", 316, Rarity.COMMON, mage.cards.n.NaturesLore.class)); - cards.add(new SetCardInfo("Necrite", 181, Rarity.COMMON, mage.cards.n.Necrite.class)); - cards.add(new SetCardInfo("Necropotence", 182, Rarity.RARE, mage.cards.n.Necropotence.class)); - cards.add(new SetCardInfo("Nether Shadow", 183, Rarity.RARE, mage.cards.n.NetherShadow.class)); - cards.add(new SetCardInfo("Nevinyrral's Disk", 391, Rarity.RARE, mage.cards.n.NevinyrralsDisk.class)); - cards.add(new SetCardInfo("Nightmare", 184, Rarity.RARE, mage.cards.n.Nightmare.class)); - cards.add(new SetCardInfo("Obelisk of Undoing", 392, Rarity.RARE, mage.cards.o.ObeliskOfUndoing.class)); - cards.add(new SetCardInfo("Orcish Artillery", 253, Rarity.UNCOMMON, mage.cards.o.OrcishArtillery.class)); - cards.add(new SetCardInfo("Orcish Captain", 254, Rarity.UNCOMMON, mage.cards.o.OrcishCaptain.class)); - cards.add(new SetCardInfo("Orcish Oriflamme", 257, Rarity.UNCOMMON, mage.cards.o.OrcishOriflamme.class)); - cards.add(new SetCardInfo("Orcish Squatters", 258, Rarity.RARE, mage.cards.o.OrcishSquatters.class)); - cards.add(new SetCardInfo("Order of the Sacred Torch", 48, Rarity.RARE, mage.cards.o.OrderOfTheSacredTorch.class)); - cards.add(new SetCardInfo("Order of the White Shield", 49, Rarity.UNCOMMON, mage.cards.o.OrderOfTheWhiteShield.class)); - cards.add(new SetCardInfo("Orgg", 259, Rarity.RARE, mage.cards.o.Orgg.class)); - cards.add(new SetCardInfo("Ornithopter", 393, Rarity.UNCOMMON, mage.cards.o.Ornithopter.class)); - cards.add(new SetCardInfo("Panic", 260, Rarity.COMMON, mage.cards.p.Panic.class)); - cards.add(new SetCardInfo("Paralyze", 185, Rarity.COMMON, mage.cards.p.Paralyze.class)); - cards.add(new SetCardInfo("Pearled Unicorn", 50, Rarity.COMMON, mage.cards.p.PearledUnicorn.class)); - cards.add(new SetCardInfo("Pentagram of the Ages", 394, Rarity.RARE, mage.cards.p.PentagramOfTheAges.class)); - cards.add(new SetCardInfo("Personal Incarnation", 51, Rarity.RARE, mage.cards.p.PersonalIncarnation.class)); - cards.add(new SetCardInfo("Pestilence", 186, Rarity.COMMON, mage.cards.p.Pestilence.class)); - cards.add(new SetCardInfo("Phantasmal Forces", 106, Rarity.UNCOMMON, mage.cards.p.PhantasmalForces.class)); - cards.add(new SetCardInfo("Phantasmal Terrain", 107, Rarity.COMMON, mage.cards.p.PhantasmalTerrain.class)); - cards.add(new SetCardInfo("Phantom Monster", 108, Rarity.UNCOMMON, mage.cards.p.PhantomMonster.class)); - cards.add(new SetCardInfo("Pikemen", 52, Rarity.COMMON, mage.cards.p.Pikemen.class)); - cards.add(new SetCardInfo("Pirate Ship", 109, Rarity.RARE, mage.cards.p.PirateShip.class)); - cards.add(new SetCardInfo("Pit Scorpion", 187, Rarity.COMMON, mage.cards.p.PitScorpion.class)); - cards.add(new SetCardInfo("Plague Rats", 188, Rarity.COMMON, mage.cards.p.PlagueRats.class)); - cards.add(new SetCardInfo("Plains", 430, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 431, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 432, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 433, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Portent", 110, Rarity.COMMON, mage.cards.p.Portent.class)); - cards.add(new SetCardInfo("Power Sink", 111, Rarity.UNCOMMON, mage.cards.p.PowerSink.class)); - cards.add(new SetCardInfo("Pox", 189, Rarity.RARE, mage.cards.p.Pox.class)); - cards.add(new SetCardInfo("Pradesh Gypsies", 317, Rarity.COMMON, mage.cards.p.PradeshGypsies.class)); - cards.add(new SetCardInfo("Primal Clay", 395, Rarity.RARE, mage.cards.p.PrimalClay.class)); - cards.add(new SetCardInfo("Primal Order", 318, Rarity.RARE, mage.cards.p.PrimalOrder.class)); - cards.add(new SetCardInfo("Primordial Ooze", 261, Rarity.UNCOMMON, mage.cards.p.PrimordialOoze.class)); - cards.add(new SetCardInfo("Prismatic Ward", 53, Rarity.COMMON, mage.cards.p.PrismaticWard.class)); - cards.add(new SetCardInfo("Prodigal Sorcerer", 112, Rarity.COMMON, mage.cards.p.ProdigalSorcerer.class)); - cards.add(new SetCardInfo("Psychic Venom", 113, Rarity.COMMON, mage.cards.p.PsychicVenom.class)); - cards.add(new SetCardInfo("Pyroblast", 262, Rarity.UNCOMMON, mage.cards.p.Pyroblast.class)); - cards.add(new SetCardInfo("Pyrotechnics", 263, Rarity.UNCOMMON, mage.cards.p.Pyrotechnics.class)); - cards.add(new SetCardInfo("Rabid Wombat", 319, Rarity.UNCOMMON, mage.cards.r.RabidWombat.class)); - cards.add(new SetCardInfo("Radjan Spirit", 320, Rarity.UNCOMMON, mage.cards.r.RadjanSpirit.class)); - cards.add(new SetCardInfo("Rag Man", 190, Rarity.RARE, mage.cards.r.RagMan.class)); - cards.add(new SetCardInfo("Raise Dead", 191, Rarity.COMMON, mage.cards.r.RaiseDead.class)); - cards.add(new SetCardInfo("Ray of Command", 114, Rarity.COMMON, mage.cards.r.RayOfCommand.class)); - cards.add(new SetCardInfo("Recall", 115, Rarity.RARE, mage.cards.r.Recall.class)); - cards.add(new SetCardInfo("Reef Pirates", 116, Rarity.COMMON, mage.cards.r.ReefPirates.class)); - cards.add(new SetCardInfo("Regeneration", 321, Rarity.COMMON, mage.cards.r.Regeneration.class)); - cards.add(new SetCardInfo("Remove Soul", 117, Rarity.COMMON, mage.cards.r.RemoveSoul.class)); - cards.add(new SetCardInfo("Repentant Blacksmith", 54, Rarity.COMMON, mage.cards.r.RepentantBlacksmith.class)); - cards.add(new SetCardInfo("Reverse Damage", 55, Rarity.RARE, mage.cards.r.ReverseDamage.class)); - cards.add(new SetCardInfo("Righteousness", 56, Rarity.RARE, mage.cards.r.Righteousness.class)); - cards.add(new SetCardInfo("Rod of Ruin", 396, Rarity.UNCOMMON, mage.cards.r.RodOfRuin.class)); - cards.add(new SetCardInfo("Ruins of Trokair", 422, Rarity.UNCOMMON, mage.cards.r.RuinsOfTrokair.class)); - cards.add(new SetCardInfo("Sabretooth Tiger", 264, Rarity.COMMON, mage.cards.s.SabretoothTiger.class)); - cards.add(new SetCardInfo("Samite Healer", 58, Rarity.COMMON, mage.cards.s.SamiteHealer.class)); - cards.add(new SetCardInfo("Sand Silos", 423, Rarity.RARE, mage.cards.s.SandSilos.class)); - cards.add(new SetCardInfo("Scaled Wurm", 322, Rarity.COMMON, mage.cards.s.ScaledWurm.class)); - cards.add(new SetCardInfo("Scathe Zombies", 192, Rarity.COMMON, mage.cards.s.ScatheZombies.class)); - cards.add(new SetCardInfo("Scavenger Folk", 323, Rarity.COMMON, mage.cards.s.ScavengerFolk.class)); - cards.add(new SetCardInfo("Scryb Sprites", 324, Rarity.COMMON, mage.cards.s.ScrybSprites.class)); - cards.add(new SetCardInfo("Sea Serpent", 118, Rarity.COMMON, mage.cards.s.SeaSerpent.class)); - cards.add(new SetCardInfo("Sea Spirit", 119, Rarity.UNCOMMON, mage.cards.s.SeaSpirit.class)); - cards.add(new SetCardInfo("Sea Sprite", 120, Rarity.UNCOMMON, mage.cards.s.SeaSprite.class)); - cards.add(new SetCardInfo("Seasinger", 121, Rarity.UNCOMMON, mage.cards.s.Seasinger.class)); - cards.add(new SetCardInfo("Segovian Leviathan", 122, Rarity.UNCOMMON, mage.cards.s.SegovianLeviathan.class)); - cards.add(new SetCardInfo("Sengir Autocrat", 193, Rarity.RARE, mage.cards.s.SengirAutocrat.class)); - cards.add(new SetCardInfo("Serpent Generator", 397, Rarity.RARE, mage.cards.s.SerpentGenerator.class)); - cards.add(new SetCardInfo("Serra Bestiary", 60, Rarity.UNCOMMON, mage.cards.s.SerraBestiary.class)); - cards.add(new SetCardInfo("Serra Paladin", 61, Rarity.UNCOMMON, mage.cards.s.SerraPaladin.class)); - cards.add(new SetCardInfo("Shanodin Dryads", 325, Rarity.COMMON, mage.cards.s.ShanodinDryads.class)); - cards.add(new SetCardInfo("Shapeshifter", 398, Rarity.UNCOMMON, mage.cards.s.Shapeshifter.class)); - cards.add(new SetCardInfo("Shatter", 265, Rarity.COMMON, mage.cards.s.Shatter.class)); - cards.add(new SetCardInfo("Shatterstorm", 266, Rarity.UNCOMMON, mage.cards.s.Shatterstorm.class)); - cards.add(new SetCardInfo("Shield Bearer", 62, Rarity.COMMON, mage.cards.s.ShieldBearer.class)); - cards.add(new SetCardInfo("Shield Wall", 63, Rarity.COMMON, mage.cards.s.ShieldWall.class)); - cards.add(new SetCardInfo("Shivan Dragon", 267, Rarity.RARE, mage.cards.s.ShivanDragon.class)); - cards.add(new SetCardInfo("Shrink", 326, Rarity.COMMON, mage.cards.s.Shrink.class)); - cards.add(new SetCardInfo("Sibilant Spirit", 123, Rarity.RARE, mage.cards.s.SibilantSpirit.class)); - cards.add(new SetCardInfo("Skull Catapult", 399, Rarity.UNCOMMON, mage.cards.s.SkullCatapult.class)); - cards.add(new SetCardInfo("Smoke", 268, Rarity.RARE, mage.cards.s.Smoke.class)); - cards.add(new SetCardInfo("Sorceress Queen", 194, Rarity.RARE, mage.cards.s.SorceressQueen.class)); - cards.add(new SetCardInfo("Soul Barrier", 125, Rarity.COMMON, mage.cards.s.SoulBarrier.class)); - cards.add(new SetCardInfo("Soul Net", 400, Rarity.UNCOMMON, mage.cards.s.SoulNet.class)); - cards.add(new SetCardInfo("Spell Blast", 126, Rarity.COMMON, mage.cards.s.SpellBlast.class)); - cards.add(new SetCardInfo("Spirit Link", 64, Rarity.UNCOMMON, mage.cards.s.SpiritLink.class)); - cards.add(new SetCardInfo("Stampede", 327, Rarity.RARE, mage.cards.s.Stampede.class)); - cards.add(new SetCardInfo("Stasis", 127, Rarity.RARE, mage.cards.s.Stasis.class)); - cards.add(new SetCardInfo("Steal Artifact", 128, Rarity.UNCOMMON, mage.cards.s.StealArtifact.class)); - cards.add(new SetCardInfo("Stone Giant", 269, Rarity.UNCOMMON, mage.cards.s.StoneGiant.class)); - cards.add(new SetCardInfo("Stone Rain", 270, Rarity.COMMON, mage.cards.s.StoneRain.class)); - cards.add(new SetCardInfo("Stone Spirit", 271, Rarity.UNCOMMON, mage.cards.s.StoneSpirit.class)); - cards.add(new SetCardInfo("Stream of Life", 328, Rarity.COMMON, mage.cards.s.StreamOfLife.class)); - cards.add(new SetCardInfo("Stromgald Cabal", 195, Rarity.RARE, mage.cards.s.StromgaldCabal.class)); - cards.add(new SetCardInfo("Sulfurous Springs", 424, Rarity.RARE, mage.cards.s.SulfurousSprings.class)); - cards.add(new SetCardInfo("Svyelunite Temple", 425, Rarity.UNCOMMON, mage.cards.s.SvyeluniteTemple.class)); - cards.add(new SetCardInfo("Swamp", 438, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 439, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 440, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 441, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Sylvan Library", 329, Rarity.RARE, mage.cards.s.SylvanLibrary.class)); - cards.add(new SetCardInfo("Tarpan", 330, Rarity.COMMON, mage.cards.t.Tarpan.class)); - cards.add(new SetCardInfo("Tawnos's Weaponry", 401, Rarity.UNCOMMON, mage.cards.t.TawnossWeaponry.class)); - cards.add(new SetCardInfo("Terror", 196, Rarity.COMMON, mage.cards.t.Terror.class)); - cards.add(new SetCardInfo("The Brute", 272, Rarity.COMMON, mage.cards.t.TheBrute.class)); - cards.add(new SetCardInfo("The Hive", 402, Rarity.RARE, mage.cards.t.TheHive.class)); - cards.add(new SetCardInfo("The Wretched", 197, Rarity.RARE, mage.cards.t.TheWretched.class)); - cards.add(new SetCardInfo("Thicket Basilisk", 331, Rarity.UNCOMMON, mage.cards.t.ThicketBasilisk.class)); - cards.add(new SetCardInfo("Throne of Bone", 403, Rarity.UNCOMMON, mage.cards.t.ThroneOfBone.class)); - cards.add(new SetCardInfo("Thrull Retainer", 198, Rarity.UNCOMMON, mage.cards.t.ThrullRetainer.class)); - cards.add(new SetCardInfo("Time Bomb", 404, Rarity.RARE, mage.cards.t.TimeBomb.class)); - cards.add(new SetCardInfo("Time Elemental", 129, Rarity.RARE, mage.cards.t.TimeElemental.class)); - cards.add(new SetCardInfo("Titania's Song", 332, Rarity.RARE, mage.cards.t.TitaniasSong.class)); - cards.add(new SetCardInfo("Torture", 199, Rarity.COMMON, mage.cards.t.Torture.class)); - cards.add(new SetCardInfo("Touch of Death", 200, Rarity.COMMON, mage.cards.t.TouchOfDeath.class)); - cards.add(new SetCardInfo("Tranquility", 333, Rarity.COMMON, mage.cards.t.Tranquility.class)); - cards.add(new SetCardInfo("Truce", 65, Rarity.RARE, mage.cards.t.Truce.class)); - cards.add(new SetCardInfo("Tsunami", 334, Rarity.UNCOMMON, mage.cards.t.Tsunami.class)); - cards.add(new SetCardInfo("Tundra Wolves", 66, Rarity.COMMON, mage.cards.t.TundraWolves.class)); - cards.add(new SetCardInfo("Twiddle", 130, Rarity.COMMON, mage.cards.t.Twiddle.class)); - cards.add(new SetCardInfo("Underground River", 426, Rarity.RARE, mage.cards.u.UndergroundRiver.class)); - cards.add(new SetCardInfo("Unholy Strength", 201, Rarity.COMMON, mage.cards.u.UnholyStrength.class)); - cards.add(new SetCardInfo("Unstable Mutation", 131, Rarity.COMMON, mage.cards.u.UnstableMutation.class)); - cards.add(new SetCardInfo("Unsummon", 132, Rarity.COMMON, mage.cards.u.Unsummon.class)); - cards.add(new SetCardInfo("Untamed Wilds", 335, Rarity.UNCOMMON, mage.cards.u.UntamedWilds.class)); - cards.add(new SetCardInfo("Updraft", 133, Rarity.COMMON, mage.cards.u.Updraft.class)); - cards.add(new SetCardInfo("Urza's Avenger", 405, Rarity.RARE, mage.cards.u.UrzasAvenger.class)); - cards.add(new SetCardInfo("Urza's Bauble", 406, Rarity.UNCOMMON, mage.cards.u.UrzasBauble.class)); - cards.add(new SetCardInfo("Urza's Mine", 427, Rarity.COMMON, mage.cards.u.UrzasMine.class)); - cards.add(new SetCardInfo("Urza's Power Plant", 428, Rarity.COMMON, mage.cards.u.UrzasPowerPlant.class)); - cards.add(new SetCardInfo("Urza's Tower", 429, Rarity.COMMON, mage.cards.u.UrzasTower.class)); - cards.add(new SetCardInfo("Vampire Bats", 202, Rarity.COMMON, mage.cards.v.VampireBats.class)); - cards.add(new SetCardInfo("Venom", 336, Rarity.COMMON, mage.cards.v.Venom.class)); - cards.add(new SetCardInfo("Verduran Enchantress", 337, Rarity.RARE, mage.cards.v.VerduranEnchantress.class)); - cards.add(new SetCardInfo("Vodalian Soldiers", 134, Rarity.COMMON, mage.cards.v.VodalianSoldiers.class)); - cards.add(new SetCardInfo("Wall of Air", 135, Rarity.UNCOMMON, mage.cards.w.WallOfAir.class)); - cards.add(new SetCardInfo("Wall of Bone", 203, Rarity.UNCOMMON, mage.cards.w.WallOfBone.class)); - cards.add(new SetCardInfo("Wall of Brambles", 338, Rarity.UNCOMMON, mage.cards.w.WallOfBrambles.class)); - cards.add(new SetCardInfo("Wall of Fire", 273, Rarity.UNCOMMON, mage.cards.w.WallOfFire.class)); - cards.add(new SetCardInfo("Wall of Spears", 407, Rarity.COMMON, mage.cards.w.WallOfSpears.class)); - cards.add(new SetCardInfo("Wall of Stone", 274, Rarity.UNCOMMON, mage.cards.w.WallOfStone.class)); - cards.add(new SetCardInfo("Wall of Swords", 67, Rarity.UNCOMMON, mage.cards.w.WallOfSwords.class)); - cards.add(new SetCardInfo("Wanderlust", 339, Rarity.UNCOMMON, mage.cards.w.Wanderlust.class)); - cards.add(new SetCardInfo("War Mammoth", 340, Rarity.COMMON, mage.cards.w.WarMammoth.class)); - cards.add(new SetCardInfo("Warp Artifact", 204, Rarity.RARE, mage.cards.w.WarpArtifact.class)); - cards.add(new SetCardInfo("Weakness", 205, Rarity.COMMON, mage.cards.w.Weakness.class)); - cards.add(new SetCardInfo("Whirling Dervish", 341, Rarity.UNCOMMON, mage.cards.w.WhirlingDervish.class)); - cards.add(new SetCardInfo("White Knight", 68, Rarity.UNCOMMON, mage.cards.w.WhiteKnight.class)); - cards.add(new SetCardInfo("Wild Growth", 342, Rarity.COMMON, mage.cards.w.WildGrowth.class)); - cards.add(new SetCardInfo("Wind Spirit", 136, Rarity.UNCOMMON, mage.cards.w.WindSpirit.class)); - cards.add(new SetCardInfo("Winds of Change", 275, Rarity.RARE, mage.cards.w.WindsOfChange.class)); - cards.add(new SetCardInfo("Winter Blast", 343, Rarity.UNCOMMON, mage.cards.w.WinterBlast.class)); - cards.add(new SetCardInfo("Winter Orb", 408, Rarity.RARE, mage.cards.w.WinterOrb.class)); - cards.add(new SetCardInfo("Wolverine Pack", 344, Rarity.UNCOMMON, mage.cards.w.WolverinePack.class)); - cards.add(new SetCardInfo("Wooden Sphere", 409, Rarity.UNCOMMON, mage.cards.w.WoodenSphere.class)); - cards.add(new SetCardInfo("Word of Blasting", 276, Rarity.UNCOMMON, mage.cards.w.WordOfBlasting.class)); - cards.add(new SetCardInfo("Wrath of God", 69, Rarity.RARE, mage.cards.w.WrathOfGod.class)); - cards.add(new SetCardInfo("Wyluli Wolf", 345, Rarity.RARE, mage.cards.w.WyluliWolf.class)); - cards.add(new SetCardInfo("Xenic Poltergeist", 206, Rarity.RARE, mage.cards.x.XenicPoltergeist.class)); - cards.add(new SetCardInfo("Zephyr Falcon", 137, Rarity.COMMON, mage.cards.z.ZephyrFalcon.class)); - cards.add(new SetCardInfo("Zombie Master", 207, Rarity.RARE, mage.cards.z.ZombieMaster.class)); - cards.add(new SetCardInfo("Zur's Weirding", 138, Rarity.RARE, mage.cards.z.ZursWeirding.class)); - } -} +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +public final class FifthEdition extends ExpansionSet { + + private static final FifthEdition instance = new FifthEdition(); + + public static FifthEdition getInstance() { + return instance; + } + + private FifthEdition() { + super("Fifth Edition", "5ED", ExpansionSet.buildDate(1997, 3, 1), SetType.CORE); + this.hasBoosters = true; + this.numBoosterLands = 0; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + + cards.add(new SetCardInfo("Abbey Gargoyles", 1, Rarity.UNCOMMON, mage.cards.a.AbbeyGargoyles.class)); + cards.add(new SetCardInfo("Abyssal Specter", 139, Rarity.UNCOMMON, mage.cards.a.AbyssalSpecter.class)); + cards.add(new SetCardInfo("Adarkar Wastes", 410, Rarity.RARE, mage.cards.a.AdarkarWastes.class)); + cards.add(new SetCardInfo("Aether Storm", 70, Rarity.UNCOMMON, mage.cards.a.AetherStorm.class)); + cards.add(new SetCardInfo("Air Elemental", 71, Rarity.UNCOMMON, mage.cards.a.AirElemental.class)); + cards.add(new SetCardInfo("Akron Legionnaire", 2, Rarity.RARE, mage.cards.a.AkronLegionnaire.class)); + cards.add(new SetCardInfo("Alabaster Potion", 3, Rarity.COMMON, mage.cards.a.AlabasterPotion.class)); + cards.add(new SetCardInfo("Aladdin's Ring", 346, Rarity.RARE, mage.cards.a.AladdinsRing.class)); + cards.add(new SetCardInfo("Ambush Party", 208, Rarity.COMMON, mage.cards.a.AmbushParty.class)); + cards.add(new SetCardInfo("Amulet of Kroog", 347, Rarity.COMMON, mage.cards.a.AmuletOfKroog.class)); + cards.add(new SetCardInfo("An-Havva Constable", 277, Rarity.RARE, mage.cards.a.AnHavvaConstable.class)); + cards.add(new SetCardInfo("Angry Mob", 4, Rarity.UNCOMMON, mage.cards.a.AngryMob.class)); + cards.add(new SetCardInfo("Animate Dead", 140, Rarity.UNCOMMON, mage.cards.a.AnimateDead.class)); + cards.add(new SetCardInfo("Animate Wall", 5, Rarity.RARE, mage.cards.a.AnimateWall.class)); + cards.add(new SetCardInfo("Ankh of Mishra", 348, Rarity.RARE, mage.cards.a.AnkhOfMishra.class)); + cards.add(new SetCardInfo("Anti-Magic Aura", 72, Rarity.UNCOMMON, mage.cards.a.AntiMagicAura.class)); + cards.add(new SetCardInfo("Arenson's Aura", 6, Rarity.UNCOMMON, mage.cards.a.ArensonsAura.class)); + cards.add(new SetCardInfo("Armageddon", 7, Rarity.RARE, mage.cards.a.Armageddon.class)); + cards.add(new SetCardInfo("Armor of Faith", 8, Rarity.COMMON, mage.cards.a.ArmorOfFaith.class)); + cards.add(new SetCardInfo("Ashes to Ashes", 141, Rarity.UNCOMMON, mage.cards.a.AshesToAshes.class)); + cards.add(new SetCardInfo("Ashnod's Altar", 349, Rarity.UNCOMMON, mage.cards.a.AshnodsAltar.class)); + cards.add(new SetCardInfo("Ashnod's Transmogrant", 350, Rarity.COMMON, mage.cards.a.AshnodsTransmogrant.class)); + cards.add(new SetCardInfo("Aspect of Wolf", 278, Rarity.RARE, mage.cards.a.AspectOfWolf.class)); + cards.add(new SetCardInfo("Atog", 209, Rarity.UNCOMMON, mage.cards.a.Atog.class)); + cards.add(new SetCardInfo("Aurochs", 279, Rarity.COMMON, mage.cards.a.Aurochs.class)); + cards.add(new SetCardInfo("Aysen Bureaucrats", 9, Rarity.COMMON, mage.cards.a.AysenBureaucrats.class)); + cards.add(new SetCardInfo("Azure Drake", 73, Rarity.UNCOMMON, mage.cards.a.AzureDrake.class)); + cards.add(new SetCardInfo("Bad Moon", 142, Rarity.RARE, mage.cards.b.BadMoon.class)); + cards.add(new SetCardInfo("Ball Lightning", 210, Rarity.RARE, mage.cards.b.BallLightning.class)); + cards.add(new SetCardInfo("Barbed Sextant", 351, Rarity.COMMON, mage.cards.b.BarbedSextant.class)); + cards.add(new SetCardInfo("Barl's Cage", 352, Rarity.RARE, mage.cards.b.BarlsCage.class)); + cards.add(new SetCardInfo("Battering Ram", 353, Rarity.COMMON, mage.cards.b.BatteringRam.class)); + cards.add(new SetCardInfo("Benalish Hero", 10, Rarity.COMMON, mage.cards.b.BenalishHero.class)); + cards.add(new SetCardInfo("Binding Grasp", 74, Rarity.UNCOMMON, mage.cards.b.BindingGrasp.class)); + cards.add(new SetCardInfo("Bird Maiden", 211, Rarity.COMMON, mage.cards.b.BirdMaiden.class)); + cards.add(new SetCardInfo("Birds of Paradise", 280, Rarity.RARE, mage.cards.b.BirdsOfParadise.class)); + cards.add(new SetCardInfo("Black Knight", 143, Rarity.UNCOMMON, mage.cards.b.BlackKnight.class)); + cards.add(new SetCardInfo("Blessed Wine", 11, Rarity.COMMON, mage.cards.b.BlessedWine.class)); + cards.add(new SetCardInfo("Blight", 144, Rarity.UNCOMMON, mage.cards.b.Blight.class)); + cards.add(new SetCardInfo("Blinking Spirit", 12, Rarity.RARE, mage.cards.b.BlinkingSpirit.class)); + cards.add(new SetCardInfo("Blood Lust", 212, Rarity.COMMON, mage.cards.b.BloodLust.class)); + cards.add(new SetCardInfo("Bog Imp", 145, Rarity.COMMON, mage.cards.b.BogImp.class)); + cards.add(new SetCardInfo("Bog Rats", 146, Rarity.COMMON, mage.cards.b.BogRats.class)); + cards.add(new SetCardInfo("Bog Wraith", 147, Rarity.UNCOMMON, mage.cards.b.BogWraith.class)); + cards.add(new SetCardInfo("Boomerang", 75, Rarity.COMMON, mage.cards.b.Boomerang.class)); + cards.add(new SetCardInfo("Bottle of Suleiman", 354, Rarity.RARE, mage.cards.b.BottleOfSuleiman.class)); + cards.add(new SetCardInfo("Bottomless Vault", 411, Rarity.RARE, mage.cards.b.BottomlessVault.class)); + cards.add(new SetCardInfo("Brainstorm", 76, Rarity.COMMON, mage.cards.b.Brainstorm.class)); + cards.add(new SetCardInfo("Brainwash", 13, Rarity.COMMON, mage.cards.b.Brainwash.class)); + cards.add(new SetCardInfo("Brassclaw Orcs", 213, Rarity.COMMON, mage.cards.b.BrassclawOrcs.class)); + cards.add(new SetCardInfo("Breeding Pit", 148, Rarity.UNCOMMON, mage.cards.b.BreedingPit.class)); + cards.add(new SetCardInfo("Broken Visage", 149, Rarity.RARE, mage.cards.b.BrokenVisage.class)); + cards.add(new SetCardInfo("Brothers of Fire", 214, Rarity.COMMON, mage.cards.b.BrothersOfFire.class)); + cards.add(new SetCardInfo("Brushland", 412, Rarity.RARE, mage.cards.b.Brushland.class)); + cards.add(new SetCardInfo("Carapace", 281, Rarity.COMMON, mage.cards.c.Carapace.class)); + cards.add(new SetCardInfo("Caribou Range", 14, Rarity.RARE, mage.cards.c.CaribouRange.class)); + cards.add(new SetCardInfo("Carrion Ants", 150, Rarity.UNCOMMON, mage.cards.c.CarrionAnts.class)); + cards.add(new SetCardInfo("Castle", 15, Rarity.UNCOMMON, mage.cards.c.Castle.class)); + cards.add(new SetCardInfo("Cat Warriors", 282, Rarity.COMMON, mage.cards.c.CatWarriors.class)); + cards.add(new SetCardInfo("Cave People", 215, Rarity.UNCOMMON, mage.cards.c.CavePeople.class)); + cards.add(new SetCardInfo("Chub Toad", 283, Rarity.COMMON, mage.cards.c.ChubToad.class)); + cards.add(new SetCardInfo("Circle of Protection: Artifacts", 16, Rarity.UNCOMMON, mage.cards.c.CircleOfProtectionArtifacts.class)); + cards.add(new SetCardInfo("Circle of Protection: Black", 17, Rarity.COMMON, mage.cards.c.CircleOfProtectionBlack.class)); + cards.add(new SetCardInfo("Circle of Protection: Blue", 18, Rarity.COMMON, mage.cards.c.CircleOfProtectionBlue.class)); + cards.add(new SetCardInfo("Circle of Protection: Green", 19, Rarity.COMMON, mage.cards.c.CircleOfProtectionGreen.class)); + cards.add(new SetCardInfo("Circle of Protection: Red", 20, Rarity.COMMON, mage.cards.c.CircleOfProtectionRed.class)); + cards.add(new SetCardInfo("Circle of Protection: White", 21, Rarity.COMMON, mage.cards.c.CircleOfProtectionWhite.class)); + cards.add(new SetCardInfo("City of Brass", 413, Rarity.RARE, mage.cards.c.CityOfBrass.class)); + cards.add(new SetCardInfo("Clay Statue", 355, Rarity.COMMON, mage.cards.c.ClayStatue.class)); + cards.add(new SetCardInfo("Cloak of Confusion", 151, Rarity.COMMON, mage.cards.c.CloakOfConfusion.class)); + cards.add(new SetCardInfo("Clockwork Beast", 356, Rarity.RARE, mage.cards.c.ClockworkBeast.class)); + cards.add(new SetCardInfo("Clockwork Steed", 357, Rarity.UNCOMMON, mage.cards.c.ClockworkSteed.class)); + cards.add(new SetCardInfo("Cockatrice", 284, Rarity.RARE, mage.cards.c.Cockatrice.class)); + cards.add(new SetCardInfo("Colossus of Sardia", 358, Rarity.RARE, mage.cards.c.ColossusOfSardia.class)); + cards.add(new SetCardInfo("Conquer", 216, Rarity.UNCOMMON, mage.cards.c.Conquer.class)); + cards.add(new SetCardInfo("Coral Helm", 359, Rarity.RARE, mage.cards.c.CoralHelm.class)); + cards.add(new SetCardInfo("Counterspell", 77, Rarity.COMMON, mage.cards.c.Counterspell.class)); + cards.add(new SetCardInfo("Craw Giant", 285, Rarity.UNCOMMON, mage.cards.c.CrawGiant.class)); + cards.add(new SetCardInfo("Craw Wurm", 286, Rarity.COMMON, mage.cards.c.CrawWurm.class)); + cards.add(new SetCardInfo("Crimson Manticore", 217, Rarity.RARE, mage.cards.c.CrimsonManticore.class)); + cards.add(new SetCardInfo("Crown of the Ages", 360, Rarity.RARE, mage.cards.c.CrownOfTheAges.class)); + cards.add(new SetCardInfo("Crumble", 287, Rarity.UNCOMMON, mage.cards.c.Crumble.class)); + cards.add(new SetCardInfo("Crusade", 22, Rarity.RARE, mage.cards.c.Crusade.class)); + cards.add(new SetCardInfo("Crystal Rod", 361, Rarity.UNCOMMON, mage.cards.c.CrystalRod.class)); + cards.add(new SetCardInfo("Cursed Land", 152, Rarity.UNCOMMON, mage.cards.c.CursedLand.class)); + cards.add(new SetCardInfo("D'Avenant Archer", 23, Rarity.COMMON, mage.cards.d.DAvenantArcher.class)); + cards.add(new SetCardInfo("Dance of Many", 78, Rarity.RARE, mage.cards.d.DanceOfMany.class)); + cards.add(new SetCardInfo("Dancing Scimitar", 362, Rarity.RARE, mage.cards.d.DancingScimitar.class)); + cards.add(new SetCardInfo("Dandan", 79, Rarity.COMMON, mage.cards.d.Dandan.class)); + cards.add(new SetCardInfo("Dark Maze", 80, Rarity.COMMON, mage.cards.d.DarkMaze.class)); + cards.add(new SetCardInfo("Dark Ritual", 153, Rarity.COMMON, mage.cards.d.DarkRitual.class)); + cards.add(new SetCardInfo("Death Speakers", 24, Rarity.COMMON, mage.cards.d.DeathSpeakers.class)); + cards.add(new SetCardInfo("Death Ward", 25, Rarity.COMMON, mage.cards.d.DeathWard.class)); + cards.add(new SetCardInfo("Deathgrip", 154, Rarity.UNCOMMON, mage.cards.d.Deathgrip.class)); + cards.add(new SetCardInfo("Deflection", 81, Rarity.RARE, mage.cards.d.Deflection.class)); + cards.add(new SetCardInfo("Derelor", 155, Rarity.RARE, mage.cards.d.Derelor.class)); + cards.add(new SetCardInfo("Desert Twister", 288, Rarity.UNCOMMON, mage.cards.d.DesertTwister.class)); + cards.add(new SetCardInfo("Detonate", 218, Rarity.UNCOMMON, mage.cards.d.Detonate.class)); + cards.add(new SetCardInfo("Diabolic Machine", 363, Rarity.UNCOMMON, mage.cards.d.DiabolicMachine.class)); + cards.add(new SetCardInfo("Dingus Egg", 364, Rarity.RARE, mage.cards.d.DingusEgg.class)); + cards.add(new SetCardInfo("Disenchant", 26, Rarity.COMMON, mage.cards.d.Disenchant.class)); + cards.add(new SetCardInfo("Disintegrate", 219, Rarity.COMMON, mage.cards.d.Disintegrate.class)); + cards.add(new SetCardInfo("Disrupting Scepter", 365, Rarity.RARE, mage.cards.d.DisruptingScepter.class)); + cards.add(new SetCardInfo("Divine Offering", 27, Rarity.COMMON, mage.cards.d.DivineOffering.class)); + cards.add(new SetCardInfo("Divine Transformation", 28, Rarity.UNCOMMON, mage.cards.d.DivineTransformation.class)); + cards.add(new SetCardInfo("Dragon Engine", 366, Rarity.RARE, mage.cards.d.DragonEngine.class)); + cards.add(new SetCardInfo("Drain Life", 156, Rarity.COMMON, mage.cards.d.DrainLife.class)); + cards.add(new SetCardInfo("Drain Power", 82, Rarity.RARE, mage.cards.d.DrainPower.class)); + cards.add(new SetCardInfo("Drudge Skeletons", 157, Rarity.COMMON, mage.cards.d.DrudgeSkeletons.class)); + cards.add(new SetCardInfo("Durkwood Boars", 289, Rarity.COMMON, mage.cards.d.DurkwoodBoars.class)); + cards.add(new SetCardInfo("Dust to Dust", 29, Rarity.UNCOMMON, mage.cards.d.DustToDust.class)); + cards.add(new SetCardInfo("Dwarven Catapult", 220, Rarity.UNCOMMON, mage.cards.d.DwarvenCatapult.class)); + cards.add(new SetCardInfo("Dwarven Hold", 414, Rarity.RARE, mage.cards.d.DwarvenHold.class)); + cards.add(new SetCardInfo("Dwarven Ruins", 415, Rarity.UNCOMMON, mage.cards.d.DwarvenRuins.class)); + cards.add(new SetCardInfo("Dwarven Soldier", 221, Rarity.COMMON, mage.cards.d.DwarvenSoldier.class)); + cards.add(new SetCardInfo("Dwarven Warriors", 222, Rarity.COMMON, mage.cards.d.DwarvenWarriors.class)); + cards.add(new SetCardInfo("Earthquake", 223, Rarity.RARE, mage.cards.e.Earthquake.class)); + cards.add(new SetCardInfo("Ebon Stronghold", 416, Rarity.UNCOMMON, mage.cards.e.EbonStronghold.class)); + cards.add(new SetCardInfo("Elder Druid", 290, Rarity.RARE, mage.cards.e.ElderDruid.class)); + cards.add(new SetCardInfo("Elkin Bottle", 367, Rarity.RARE, mage.cards.e.ElkinBottle.class)); + cards.add(new SetCardInfo("Elven Riders", 291, Rarity.UNCOMMON, mage.cards.e.ElvenRiders.class)); + cards.add(new SetCardInfo("Elvish Archers", 292, Rarity.RARE, mage.cards.e.ElvishArchers.class)); + cards.add(new SetCardInfo("Energy Flux", 83, Rarity.UNCOMMON, mage.cards.e.EnergyFlux.class)); + cards.add(new SetCardInfo("Enervate", 84, Rarity.COMMON, mage.cards.e.Enervate.class)); + cards.add(new SetCardInfo("Erg Raiders", 158, Rarity.COMMON, mage.cards.e.ErgRaiders.class)); + cards.add(new SetCardInfo("Errantry", 224, Rarity.COMMON, mage.cards.e.Errantry.class)); + cards.add(new SetCardInfo("Eternal Warrior", 225, Rarity.COMMON, mage.cards.e.EternalWarrior.class)); + cards.add(new SetCardInfo("Evil Eye of Orms-by-Gore", 159, Rarity.UNCOMMON, mage.cards.e.EvilEyeOfOrmsByGore.class)); + cards.add(new SetCardInfo("Evil Presence", 160, Rarity.UNCOMMON, mage.cards.e.EvilPresence.class)); + cards.add(new SetCardInfo("Eye for an Eye", 30, Rarity.RARE, mage.cards.e.EyeForAnEye.class)); + cards.add(new SetCardInfo("Fallen Angel", 161, Rarity.UNCOMMON, mage.cards.f.FallenAngel.class)); + cards.add(new SetCardInfo("Fear", 162, Rarity.COMMON, mage.cards.f.Fear.class)); + cards.add(new SetCardInfo("Feedback", 85, Rarity.UNCOMMON, mage.cards.f.Feedback.class)); + cards.add(new SetCardInfo("Feldon's Cane", 368, Rarity.UNCOMMON, mage.cards.f.FeldonsCane.class)); + cards.add(new SetCardInfo("Fellwar Stone", 369, Rarity.UNCOMMON, mage.cards.f.FellwarStone.class)); + cards.add(new SetCardInfo("Feroz's Ban", 370, Rarity.RARE, mage.cards.f.FerozsBan.class)); + cards.add(new SetCardInfo("Fire Drake", 226, Rarity.UNCOMMON, mage.cards.f.FireDrake.class)); + cards.add(new SetCardInfo("Fireball", 227, Rarity.COMMON, mage.cards.f.Fireball.class)); + cards.add(new SetCardInfo("Firebreathing", 228, Rarity.COMMON, mage.cards.f.Firebreathing.class)); + cards.add(new SetCardInfo("Flame Spirit", 229, Rarity.UNCOMMON, mage.cards.f.FlameSpirit.class)); + cards.add(new SetCardInfo("Flare", 230, Rarity.COMMON, mage.cards.f.Flare.class)); + cards.add(new SetCardInfo("Flashfires", 231, Rarity.UNCOMMON, mage.cards.f.Flashfires.class)); + cards.add(new SetCardInfo("Flight", 86, Rarity.COMMON, mage.cards.f.Flight.class)); + cards.add(new SetCardInfo("Flood", 87, Rarity.COMMON, mage.cards.f.Flood.class)); + cards.add(new SetCardInfo("Flying Carpet", 371, Rarity.RARE, mage.cards.f.FlyingCarpet.class)); + cards.add(new SetCardInfo("Fog", 293, Rarity.COMMON, mage.cards.f.Fog.class)); + cards.add(new SetCardInfo("Force of Nature", 294, Rarity.RARE, mage.cards.f.ForceOfNature.class)); + cards.add(new SetCardInfo("Force Spike", 88, Rarity.COMMON, mage.cards.f.ForceSpike.class)); + cards.add(new SetCardInfo("Forest", 446, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 447, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 448, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 449, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forget", 89, Rarity.RARE, mage.cards.f.Forget.class)); + cards.add(new SetCardInfo("Fountain of Youth", 372, Rarity.UNCOMMON, mage.cards.f.FountainOfYouth.class)); + cards.add(new SetCardInfo("Foxfire", 295, Rarity.COMMON, mage.cards.f.Foxfire.class)); + cards.add(new SetCardInfo("Frozen Shade", 163, Rarity.COMMON, mage.cards.f.FrozenShade.class)); + cards.add(new SetCardInfo("Funeral March", 164, Rarity.COMMON, mage.cards.f.FuneralMarch.class)); + cards.add(new SetCardInfo("Fungusaur", 296, Rarity.RARE, mage.cards.f.Fungusaur.class)); + cards.add(new SetCardInfo("Fyndhorn Elder", 297, Rarity.UNCOMMON, mage.cards.f.FyndhornElder.class)); + cards.add(new SetCardInfo("Game of Chaos", 232, Rarity.RARE, mage.cards.g.GameOfChaos.class)); + cards.add(new SetCardInfo("Gaseous Form", 90, Rarity.COMMON, mage.cards.g.GaseousForm.class)); + cards.add(new SetCardInfo("Gauntlets of Chaos", 373, Rarity.RARE, mage.cards.g.GauntletsOfChaos.class)); + cards.add(new SetCardInfo("Ghazban Ogre", 298, Rarity.COMMON, mage.cards.g.GhazbanOgre.class)); + cards.add(new SetCardInfo("Giant Growth", 299, Rarity.COMMON, mage.cards.g.GiantGrowth.class)); + cards.add(new SetCardInfo("Giant Spider", 300, Rarity.COMMON, mage.cards.g.GiantSpider.class)); + cards.add(new SetCardInfo("Giant Strength", 233, Rarity.COMMON, mage.cards.g.GiantStrength.class)); + cards.add(new SetCardInfo("Glacial Wall", 91, Rarity.UNCOMMON, mage.cards.g.GlacialWall.class)); + cards.add(new SetCardInfo("Glasses of Urza", 374, Rarity.UNCOMMON, mage.cards.g.GlassesOfUrza.class)); + cards.add(new SetCardInfo("Gloom", 165, Rarity.UNCOMMON, mage.cards.g.Gloom.class)); + cards.add(new SetCardInfo("Goblin Digging Team", 234, Rarity.COMMON, mage.cards.g.GoblinDiggingTeam.class)); + cards.add(new SetCardInfo("Goblin Hero", 235, Rarity.COMMON, mage.cards.g.GoblinHero.class)); + cards.add(new SetCardInfo("Goblin King", 236, Rarity.RARE, mage.cards.g.GoblinKing.class)); + cards.add(new SetCardInfo("Goblin War Drums", 237, Rarity.COMMON, mage.cards.g.GoblinWarDrums.class)); + cards.add(new SetCardInfo("Goblin Warrens", 238, Rarity.RARE, mage.cards.g.GoblinWarrens.class)); + cards.add(new SetCardInfo("Grapeshot Catapult", 375, Rarity.COMMON, mage.cards.g.GrapeshotCatapult.class)); + cards.add(new SetCardInfo("Greater Realm of Preservation", 31, Rarity.UNCOMMON, mage.cards.g.GreaterRealmOfPreservation.class)); + cards.add(new SetCardInfo("Greater Werewolf", 166, Rarity.UNCOMMON, mage.cards.g.GreaterWerewolf.class)); + cards.add(new SetCardInfo("Grizzly Bears", 301, Rarity.COMMON, mage.cards.g.GrizzlyBears.class)); + cards.add(new SetCardInfo("Havenwood Battleground", 417, Rarity.UNCOMMON, mage.cards.h.HavenwoodBattleground.class)); + cards.add(new SetCardInfo("Heal", 32, Rarity.COMMON, mage.cards.h.Heal.class)); + cards.add(new SetCardInfo("Healing Salve", 33, Rarity.COMMON, mage.cards.h.HealingSalve.class)); + cards.add(new SetCardInfo("Hecatomb", 167, Rarity.RARE, mage.cards.h.Hecatomb.class)); + cards.add(new SetCardInfo("Helm of Chatzuk", 376, Rarity.RARE, mage.cards.h.HelmOfChatzuk.class)); + cards.add(new SetCardInfo("Hill Giant", 239, Rarity.COMMON, mage.cards.h.HillGiant.class)); + cards.add(new SetCardInfo("Hollow Trees", 418, Rarity.RARE, mage.cards.h.HollowTrees.class)); + cards.add(new SetCardInfo("Holy Strength", 35, Rarity.COMMON, mage.cards.h.HolyStrength.class)); + cards.add(new SetCardInfo("Homarid Warrior", 92, Rarity.COMMON, mage.cards.h.HomaridWarrior.class)); + cards.add(new SetCardInfo("Howl from Beyond", 168, Rarity.COMMON, mage.cards.h.HowlFromBeyond.class)); + cards.add(new SetCardInfo("Howling Mine", 377, Rarity.RARE, mage.cards.h.HowlingMine.class)); + cards.add(new SetCardInfo("Hungry Mist", 302, Rarity.COMMON, mage.cards.h.HungryMist.class)); + cards.add(new SetCardInfo("Hurkyl's Recall", 93, Rarity.RARE, mage.cards.h.HurkylsRecall.class)); + cards.add(new SetCardInfo("Hurloon Minotaur", 240, Rarity.COMMON, mage.cards.h.HurloonMinotaur.class)); + cards.add(new SetCardInfo("Hurricane", 303, Rarity.UNCOMMON, mage.cards.h.Hurricane.class)); + cards.add(new SetCardInfo("Hydroblast", 94, Rarity.UNCOMMON, mage.cards.h.Hydroblast.class)); + cards.add(new SetCardInfo("Icatian Phalanx", 36, Rarity.UNCOMMON, mage.cards.i.IcatianPhalanx.class)); + cards.add(new SetCardInfo("Icatian Scout", 37, Rarity.COMMON, mage.cards.i.IcatianScout.class)); + cards.add(new SetCardInfo("Icatian Store", 419, Rarity.RARE, mage.cards.i.IcatianStore.class)); + cards.add(new SetCardInfo("Icatian Town", 38, Rarity.RARE, mage.cards.i.IcatianTown.class)); + cards.add(new SetCardInfo("Ice Floe", 420, Rarity.UNCOMMON, mage.cards.i.IceFloe.class)); + cards.add(new SetCardInfo("Imposing Visage", 241, Rarity.COMMON, mage.cards.i.ImposingVisage.class)); + cards.add(new SetCardInfo("Incinerate", 242, Rarity.COMMON, mage.cards.i.Incinerate.class)); + cards.add(new SetCardInfo("Inferno", 243, Rarity.RARE, mage.cards.i.Inferno.class)); + cards.add(new SetCardInfo("Infinite Hourglass", 378, Rarity.RARE, mage.cards.i.InfiniteHourglass.class)); + cards.add(new SetCardInfo("Initiates of the Ebon Hand", 169, Rarity.COMMON, mage.cards.i.InitiatesOfTheEbonHand.class)); + cards.add(new SetCardInfo("Instill Energy", 304, Rarity.UNCOMMON, mage.cards.i.InstillEnergy.class)); + cards.add(new SetCardInfo("Iron Star", 379, Rarity.UNCOMMON, mage.cards.i.IronStar.class)); + cards.add(new SetCardInfo("Ironclaw Curse", 244, Rarity.RARE, mage.cards.i.IronclawCurse.class)); + cards.add(new SetCardInfo("Ironclaw Orcs", 245, Rarity.COMMON, mage.cards.i.IronclawOrcs.class)); + cards.add(new SetCardInfo("Ironroot Treefolk", 305, Rarity.COMMON, mage.cards.i.IronrootTreefolk.class)); + cards.add(new SetCardInfo("Island Sanctuary", 39, Rarity.RARE, mage.cards.i.IslandSanctuary.class)); + cards.add(new SetCardInfo("Island", 434, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 435, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 436, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 437, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ivory Cup", 380, Rarity.UNCOMMON, mage.cards.i.IvoryCup.class)); + cards.add(new SetCardInfo("Ivory Guardians", 40, Rarity.UNCOMMON, mage.cards.i.IvoryGuardians.class)); + cards.add(new SetCardInfo("Jade Monolith", 381, Rarity.RARE, mage.cards.j.JadeMonolith.class)); + cards.add(new SetCardInfo("Jalum Tome", 382, Rarity.RARE, mage.cards.j.JalumTome.class)); + cards.add(new SetCardInfo("Jandor's Saddlebags", 383, Rarity.RARE, mage.cards.j.JandorsSaddlebags.class)); + cards.add(new SetCardInfo("Jayemdae Tome", 384, Rarity.RARE, mage.cards.j.JayemdaeTome.class)); + cards.add(new SetCardInfo("Jester's Cap", 385, Rarity.RARE, mage.cards.j.JestersCap.class)); + cards.add(new SetCardInfo("Johtull Wurm", 306, Rarity.UNCOMMON, mage.cards.j.JohtullWurm.class)); + cards.add(new SetCardInfo("Jokulhaups", 246, Rarity.RARE, mage.cards.j.Jokulhaups.class)); + cards.add(new SetCardInfo("Joven's Tools", 386, Rarity.UNCOMMON, mage.cards.j.JovensTools.class)); + cards.add(new SetCardInfo("Justice", 41, Rarity.UNCOMMON, mage.cards.j.Justice.class)); + cards.add(new SetCardInfo("Juxtapose", 95, Rarity.RARE, mage.cards.j.Juxtapose.class)); + cards.add(new SetCardInfo("Karma", 42, Rarity.UNCOMMON, mage.cards.k.Karma.class)); + cards.add(new SetCardInfo("Karplusan Forest", 421, Rarity.RARE, mage.cards.k.KarplusanForest.class)); + cards.add(new SetCardInfo("Keldon Warlord", 247, Rarity.UNCOMMON, mage.cards.k.KeldonWarlord.class)); + cards.add(new SetCardInfo("Killer Bees", 307, Rarity.UNCOMMON, mage.cards.k.KillerBees.class)); + cards.add(new SetCardInfo("Kismet", 43, Rarity.UNCOMMON, mage.cards.k.Kismet.class)); + cards.add(new SetCardInfo("Kjeldoran Dead", 170, Rarity.COMMON, mage.cards.k.KjeldoranDead.class)); + cards.add(new SetCardInfo("Kjeldoran Royal Guard", 44, Rarity.RARE, mage.cards.k.KjeldoranRoyalGuard.class)); + cards.add(new SetCardInfo("Kjeldoran Skycaptain", 45, Rarity.UNCOMMON, mage.cards.k.KjeldoranSkycaptain.class)); + cards.add(new SetCardInfo("Knight of Stromgald", 171, Rarity.UNCOMMON, mage.cards.k.KnightOfStromgald.class)); + cards.add(new SetCardInfo("Krovikan Fetish", 172, Rarity.COMMON, mage.cards.k.KrovikanFetish.class)); + cards.add(new SetCardInfo("Krovikan Sorcerer", 96, Rarity.COMMON, mage.cards.k.KrovikanSorcerer.class)); + cards.add(new SetCardInfo("Labyrinth Minotaur", 97, Rarity.COMMON, mage.cards.l.LabyrinthMinotaur.class)); + cards.add(new SetCardInfo("Leshrac's Rite", 173, Rarity.UNCOMMON, mage.cards.l.LeshracsRite.class)); + cards.add(new SetCardInfo("Leviathan", 98, Rarity.RARE, mage.cards.l.Leviathan.class)); + cards.add(new SetCardInfo("Ley Druid", 308, Rarity.COMMON, mage.cards.l.LeyDruid.class)); + cards.add(new SetCardInfo("Lhurgoyf", 309, Rarity.RARE, mage.cards.l.Lhurgoyf.class)); + cards.add(new SetCardInfo("Library of Leng", 387, Rarity.UNCOMMON, mage.cards.l.LibraryOfLeng.class)); + cards.add(new SetCardInfo("Lifeforce", 310, Rarity.UNCOMMON, mage.cards.l.Lifeforce.class)); + cards.add(new SetCardInfo("Lifetap", 99, Rarity.UNCOMMON, mage.cards.l.Lifetap.class)); + cards.add(new SetCardInfo("Living Artifact", 311, Rarity.RARE, mage.cards.l.LivingArtifact.class)); + cards.add(new SetCardInfo("Living Lands", 312, Rarity.RARE, mage.cards.l.LivingLands.class)); + cards.add(new SetCardInfo("Llanowar Elves", 313, Rarity.COMMON, mage.cards.l.LlanowarElves.class)); + cards.add(new SetCardInfo("Lord of Atlantis", 100, Rarity.RARE, mage.cards.l.LordOfAtlantis.class)); + cards.add(new SetCardInfo("Lord of the Pit", 174, Rarity.RARE, mage.cards.l.LordOfThePit.class)); + cards.add(new SetCardInfo("Lost Soul", 175, Rarity.COMMON, mage.cards.l.LostSoul.class)); + cards.add(new SetCardInfo("Lure", 314, Rarity.UNCOMMON, mage.cards.l.Lure.class)); + cards.add(new SetCardInfo("Magus of the Unseen", 102, Rarity.RARE, mage.cards.m.MagusOfTheUnseen.class)); + cards.add(new SetCardInfo("Mana Clash", 248, Rarity.RARE, mage.cards.m.ManaClash.class)); + cards.add(new SetCardInfo("Mana Flare", 249, Rarity.RARE, mage.cards.m.ManaFlare.class)); + cards.add(new SetCardInfo("Mana Vault", 388, Rarity.RARE, mage.cards.m.ManaVault.class)); + cards.add(new SetCardInfo("Manabarbs", 250, Rarity.RARE, mage.cards.m.Manabarbs.class)); + cards.add(new SetCardInfo("Marsh Viper", 315, Rarity.COMMON, mage.cards.m.MarshViper.class)); + cards.add(new SetCardInfo("Meekstone", 389, Rarity.RARE, mage.cards.m.Meekstone.class)); + cards.add(new SetCardInfo("Memory Lapse", 103, Rarity.COMMON, mage.cards.m.MemoryLapse.class)); + cards.add(new SetCardInfo("Merfolk of the Pearl Trident", 104, Rarity.COMMON, mage.cards.m.MerfolkOfThePearlTrident.class)); + cards.add(new SetCardInfo("Mesa Falcon", 46, Rarity.COMMON, mage.cards.m.MesaFalcon.class)); + cards.add(new SetCardInfo("Mesa Pegasus", 47, Rarity.COMMON, mage.cards.m.MesaPegasus.class)); + cards.add(new SetCardInfo("Millstone", 390, Rarity.RARE, mage.cards.m.Millstone.class)); + cards.add(new SetCardInfo("Mind Bomb", 105, Rarity.UNCOMMON, mage.cards.m.MindBomb.class)); + cards.add(new SetCardInfo("Mind Ravel", 176, Rarity.COMMON, mage.cards.m.MindRavel.class)); + cards.add(new SetCardInfo("Mind Warp", 177, Rarity.UNCOMMON, mage.cards.m.MindWarp.class)); + cards.add(new SetCardInfo("Mindstab Thrull", 178, Rarity.COMMON, mage.cards.m.MindstabThrull.class)); + cards.add(new SetCardInfo("Mole Worms", 179, Rarity.UNCOMMON, mage.cards.m.MoleWorms.class)); + cards.add(new SetCardInfo("Mons's Goblin Raiders", 251, Rarity.COMMON, mage.cards.m.MonssGoblinRaiders.class)); + cards.add(new SetCardInfo("Mountain Goat", 252, Rarity.COMMON, mage.cards.m.MountainGoat.class)); + cards.add(new SetCardInfo("Mountain", 442, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 443, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 444, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 445, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Murk Dwellers", 180, Rarity.COMMON, mage.cards.m.MurkDwellers.class)); + cards.add(new SetCardInfo("Nature's Lore", 316, Rarity.COMMON, mage.cards.n.NaturesLore.class)); + cards.add(new SetCardInfo("Necrite", 181, Rarity.COMMON, mage.cards.n.Necrite.class)); + cards.add(new SetCardInfo("Necropotence", 182, Rarity.RARE, mage.cards.n.Necropotence.class)); + cards.add(new SetCardInfo("Nether Shadow", 183, Rarity.RARE, mage.cards.n.NetherShadow.class)); + cards.add(new SetCardInfo("Nevinyrral's Disk", 391, Rarity.RARE, mage.cards.n.NevinyrralsDisk.class)); + cards.add(new SetCardInfo("Nightmare", 184, Rarity.RARE, mage.cards.n.Nightmare.class)); + cards.add(new SetCardInfo("Obelisk of Undoing", 392, Rarity.RARE, mage.cards.o.ObeliskOfUndoing.class)); + cards.add(new SetCardInfo("Orcish Artillery", 253, Rarity.UNCOMMON, mage.cards.o.OrcishArtillery.class)); + cards.add(new SetCardInfo("Orcish Captain", 254, Rarity.UNCOMMON, mage.cards.o.OrcishCaptain.class)); + cards.add(new SetCardInfo("Orcish Oriflamme", 257, Rarity.UNCOMMON, mage.cards.o.OrcishOriflamme.class)); + cards.add(new SetCardInfo("Orcish Squatters", 258, Rarity.RARE, mage.cards.o.OrcishSquatters.class)); + cards.add(new SetCardInfo("Order of the Sacred Torch", 48, Rarity.RARE, mage.cards.o.OrderOfTheSacredTorch.class)); + cards.add(new SetCardInfo("Order of the White Shield", 49, Rarity.UNCOMMON, mage.cards.o.OrderOfTheWhiteShield.class)); + cards.add(new SetCardInfo("Orgg", 259, Rarity.RARE, mage.cards.o.Orgg.class)); + cards.add(new SetCardInfo("Ornithopter", 393, Rarity.UNCOMMON, mage.cards.o.Ornithopter.class)); + cards.add(new SetCardInfo("Panic", 260, Rarity.COMMON, mage.cards.p.Panic.class)); + cards.add(new SetCardInfo("Paralyze", 185, Rarity.COMMON, mage.cards.p.Paralyze.class)); + cards.add(new SetCardInfo("Pearled Unicorn", 50, Rarity.COMMON, mage.cards.p.PearledUnicorn.class)); + cards.add(new SetCardInfo("Pentagram of the Ages", 394, Rarity.RARE, mage.cards.p.PentagramOfTheAges.class)); + cards.add(new SetCardInfo("Personal Incarnation", 51, Rarity.RARE, mage.cards.p.PersonalIncarnation.class)); + cards.add(new SetCardInfo("Pestilence", 186, Rarity.COMMON, mage.cards.p.Pestilence.class)); + cards.add(new SetCardInfo("Phantasmal Forces", 106, Rarity.UNCOMMON, mage.cards.p.PhantasmalForces.class)); + cards.add(new SetCardInfo("Phantasmal Terrain", 107, Rarity.COMMON, mage.cards.p.PhantasmalTerrain.class)); + cards.add(new SetCardInfo("Phantom Monster", 108, Rarity.UNCOMMON, mage.cards.p.PhantomMonster.class)); + cards.add(new SetCardInfo("Pikemen", 52, Rarity.COMMON, mage.cards.p.Pikemen.class)); + cards.add(new SetCardInfo("Pirate Ship", 109, Rarity.RARE, mage.cards.p.PirateShip.class)); + cards.add(new SetCardInfo("Pit Scorpion", 187, Rarity.COMMON, mage.cards.p.PitScorpion.class)); + cards.add(new SetCardInfo("Plague Rats", 188, Rarity.COMMON, mage.cards.p.PlagueRats.class)); + cards.add(new SetCardInfo("Plains", 430, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 431, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 432, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 433, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Portent", 110, Rarity.COMMON, mage.cards.p.Portent.class)); + cards.add(new SetCardInfo("Power Sink", 111, Rarity.UNCOMMON, mage.cards.p.PowerSink.class)); + cards.add(new SetCardInfo("Pox", 189, Rarity.RARE, mage.cards.p.Pox.class)); + cards.add(new SetCardInfo("Pradesh Gypsies", 317, Rarity.COMMON, mage.cards.p.PradeshGypsies.class)); + cards.add(new SetCardInfo("Primal Clay", 395, Rarity.RARE, mage.cards.p.PrimalClay.class)); + cards.add(new SetCardInfo("Primal Order", 318, Rarity.RARE, mage.cards.p.PrimalOrder.class)); + cards.add(new SetCardInfo("Primordial Ooze", 261, Rarity.UNCOMMON, mage.cards.p.PrimordialOoze.class)); + cards.add(new SetCardInfo("Prismatic Ward", 53, Rarity.COMMON, mage.cards.p.PrismaticWard.class)); + cards.add(new SetCardInfo("Prodigal Sorcerer", 112, Rarity.COMMON, mage.cards.p.ProdigalSorcerer.class)); + cards.add(new SetCardInfo("Psychic Venom", 113, Rarity.COMMON, mage.cards.p.PsychicVenom.class)); + cards.add(new SetCardInfo("Pyroblast", 262, Rarity.UNCOMMON, mage.cards.p.Pyroblast.class)); + cards.add(new SetCardInfo("Pyrotechnics", 263, Rarity.UNCOMMON, mage.cards.p.Pyrotechnics.class)); + cards.add(new SetCardInfo("Rabid Wombat", 319, Rarity.UNCOMMON, mage.cards.r.RabidWombat.class)); + cards.add(new SetCardInfo("Radjan Spirit", 320, Rarity.UNCOMMON, mage.cards.r.RadjanSpirit.class)); + cards.add(new SetCardInfo("Rag Man", 190, Rarity.RARE, mage.cards.r.RagMan.class)); + cards.add(new SetCardInfo("Raise Dead", 191, Rarity.COMMON, mage.cards.r.RaiseDead.class)); + cards.add(new SetCardInfo("Ray of Command", 114, Rarity.COMMON, mage.cards.r.RayOfCommand.class)); + cards.add(new SetCardInfo("Recall", 115, Rarity.RARE, mage.cards.r.Recall.class)); + cards.add(new SetCardInfo("Reef Pirates", 116, Rarity.COMMON, mage.cards.r.ReefPirates.class)); + cards.add(new SetCardInfo("Regeneration", 321, Rarity.COMMON, mage.cards.r.Regeneration.class)); + cards.add(new SetCardInfo("Remove Soul", 117, Rarity.COMMON, mage.cards.r.RemoveSoul.class)); + cards.add(new SetCardInfo("Repentant Blacksmith", 54, Rarity.COMMON, mage.cards.r.RepentantBlacksmith.class)); + cards.add(new SetCardInfo("Reverse Damage", 55, Rarity.RARE, mage.cards.r.ReverseDamage.class)); + cards.add(new SetCardInfo("Righteousness", 56, Rarity.RARE, mage.cards.r.Righteousness.class)); + cards.add(new SetCardInfo("Rod of Ruin", 396, Rarity.UNCOMMON, mage.cards.r.RodOfRuin.class)); + cards.add(new SetCardInfo("Ruins of Trokair", 422, Rarity.UNCOMMON, mage.cards.r.RuinsOfTrokair.class)); + cards.add(new SetCardInfo("Sabretooth Tiger", 264, Rarity.COMMON, mage.cards.s.SabretoothTiger.class)); + cards.add(new SetCardInfo("Samite Healer", 58, Rarity.COMMON, mage.cards.s.SamiteHealer.class)); + cards.add(new SetCardInfo("Sand Silos", 423, Rarity.RARE, mage.cards.s.SandSilos.class)); + cards.add(new SetCardInfo("Scaled Wurm", 322, Rarity.COMMON, mage.cards.s.ScaledWurm.class)); + cards.add(new SetCardInfo("Scathe Zombies", 192, Rarity.COMMON, mage.cards.s.ScatheZombies.class)); + cards.add(new SetCardInfo("Scavenger Folk", 323, Rarity.COMMON, mage.cards.s.ScavengerFolk.class)); + cards.add(new SetCardInfo("Scryb Sprites", 324, Rarity.COMMON, mage.cards.s.ScrybSprites.class)); + cards.add(new SetCardInfo("Sea Serpent", 118, Rarity.COMMON, mage.cards.s.SeaSerpent.class)); + cards.add(new SetCardInfo("Sea Spirit", 119, Rarity.UNCOMMON, mage.cards.s.SeaSpirit.class)); + cards.add(new SetCardInfo("Sea Sprite", 120, Rarity.UNCOMMON, mage.cards.s.SeaSprite.class)); + cards.add(new SetCardInfo("Seasinger", 121, Rarity.UNCOMMON, mage.cards.s.Seasinger.class)); + cards.add(new SetCardInfo("Segovian Leviathan", 122, Rarity.UNCOMMON, mage.cards.s.SegovianLeviathan.class)); + cards.add(new SetCardInfo("Sengir Autocrat", 193, Rarity.RARE, mage.cards.s.SengirAutocrat.class)); + cards.add(new SetCardInfo("Serpent Generator", 397, Rarity.RARE, mage.cards.s.SerpentGenerator.class)); + cards.add(new SetCardInfo("Serra Bestiary", 60, Rarity.UNCOMMON, mage.cards.s.SerraBestiary.class)); + cards.add(new SetCardInfo("Serra Paladin", 61, Rarity.UNCOMMON, mage.cards.s.SerraPaladin.class)); + cards.add(new SetCardInfo("Shanodin Dryads", 325, Rarity.COMMON, mage.cards.s.ShanodinDryads.class)); + cards.add(new SetCardInfo("Shapeshifter", 398, Rarity.UNCOMMON, mage.cards.s.Shapeshifter.class)); + cards.add(new SetCardInfo("Shatter", 265, Rarity.COMMON, mage.cards.s.Shatter.class)); + cards.add(new SetCardInfo("Shatterstorm", 266, Rarity.UNCOMMON, mage.cards.s.Shatterstorm.class)); + cards.add(new SetCardInfo("Shield Bearer", 62, Rarity.COMMON, mage.cards.s.ShieldBearer.class)); + cards.add(new SetCardInfo("Shield Wall", 63, Rarity.COMMON, mage.cards.s.ShieldWall.class)); + cards.add(new SetCardInfo("Shivan Dragon", 267, Rarity.RARE, mage.cards.s.ShivanDragon.class)); + cards.add(new SetCardInfo("Shrink", 326, Rarity.COMMON, mage.cards.s.Shrink.class)); + cards.add(new SetCardInfo("Sibilant Spirit", 123, Rarity.RARE, mage.cards.s.SibilantSpirit.class)); + cards.add(new SetCardInfo("Skull Catapult", 399, Rarity.UNCOMMON, mage.cards.s.SkullCatapult.class)); + cards.add(new SetCardInfo("Smoke", 268, Rarity.RARE, mage.cards.s.Smoke.class)); + cards.add(new SetCardInfo("Sorceress Queen", 194, Rarity.RARE, mage.cards.s.SorceressQueen.class)); + cards.add(new SetCardInfo("Soul Barrier", 125, Rarity.COMMON, mage.cards.s.SoulBarrier.class)); + cards.add(new SetCardInfo("Soul Net", 400, Rarity.UNCOMMON, mage.cards.s.SoulNet.class)); + cards.add(new SetCardInfo("Spell Blast", 126, Rarity.COMMON, mage.cards.s.SpellBlast.class)); + cards.add(new SetCardInfo("Spirit Link", 64, Rarity.UNCOMMON, mage.cards.s.SpiritLink.class)); + cards.add(new SetCardInfo("Stampede", 327, Rarity.RARE, mage.cards.s.Stampede.class)); + cards.add(new SetCardInfo("Stasis", 127, Rarity.RARE, mage.cards.s.Stasis.class)); + cards.add(new SetCardInfo("Steal Artifact", 128, Rarity.UNCOMMON, mage.cards.s.StealArtifact.class)); + cards.add(new SetCardInfo("Stone Giant", 269, Rarity.UNCOMMON, mage.cards.s.StoneGiant.class)); + cards.add(new SetCardInfo("Stone Rain", 270, Rarity.COMMON, mage.cards.s.StoneRain.class)); + cards.add(new SetCardInfo("Stone Spirit", 271, Rarity.UNCOMMON, mage.cards.s.StoneSpirit.class)); + cards.add(new SetCardInfo("Stream of Life", 328, Rarity.COMMON, mage.cards.s.StreamOfLife.class)); + cards.add(new SetCardInfo("Stromgald Cabal", 195, Rarity.RARE, mage.cards.s.StromgaldCabal.class)); + cards.add(new SetCardInfo("Sulfurous Springs", 424, Rarity.RARE, mage.cards.s.SulfurousSprings.class)); + cards.add(new SetCardInfo("Svyelunite Temple", 425, Rarity.UNCOMMON, mage.cards.s.SvyeluniteTemple.class)); + cards.add(new SetCardInfo("Swamp", 438, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 439, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 440, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 441, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sylvan Library", 329, Rarity.RARE, mage.cards.s.SylvanLibrary.class)); + cards.add(new SetCardInfo("Tarpan", 330, Rarity.COMMON, mage.cards.t.Tarpan.class)); + cards.add(new SetCardInfo("Tawnos's Weaponry", 401, Rarity.UNCOMMON, mage.cards.t.TawnossWeaponry.class)); + cards.add(new SetCardInfo("Terror", 196, Rarity.COMMON, mage.cards.t.Terror.class)); + cards.add(new SetCardInfo("The Brute", 272, Rarity.COMMON, mage.cards.t.TheBrute.class)); + cards.add(new SetCardInfo("The Hive", 402, Rarity.RARE, mage.cards.t.TheHive.class)); + cards.add(new SetCardInfo("The Wretched", 197, Rarity.RARE, mage.cards.t.TheWretched.class)); + cards.add(new SetCardInfo("Thicket Basilisk", 331, Rarity.UNCOMMON, mage.cards.t.ThicketBasilisk.class)); + cards.add(new SetCardInfo("Throne of Bone", 403, Rarity.UNCOMMON, mage.cards.t.ThroneOfBone.class)); + cards.add(new SetCardInfo("Thrull Retainer", 198, Rarity.UNCOMMON, mage.cards.t.ThrullRetainer.class)); + cards.add(new SetCardInfo("Time Bomb", 404, Rarity.RARE, mage.cards.t.TimeBomb.class)); + cards.add(new SetCardInfo("Time Elemental", 129, Rarity.RARE, mage.cards.t.TimeElemental.class)); + cards.add(new SetCardInfo("Titania's Song", 332, Rarity.RARE, mage.cards.t.TitaniasSong.class)); + cards.add(new SetCardInfo("Torture", 199, Rarity.COMMON, mage.cards.t.Torture.class)); + cards.add(new SetCardInfo("Touch of Death", 200, Rarity.COMMON, mage.cards.t.TouchOfDeath.class)); + cards.add(new SetCardInfo("Tranquility", 333, Rarity.COMMON, mage.cards.t.Tranquility.class)); + cards.add(new SetCardInfo("Truce", 65, Rarity.RARE, mage.cards.t.Truce.class)); + cards.add(new SetCardInfo("Tsunami", 334, Rarity.UNCOMMON, mage.cards.t.Tsunami.class)); + cards.add(new SetCardInfo("Tundra Wolves", 66, Rarity.COMMON, mage.cards.t.TundraWolves.class)); + cards.add(new SetCardInfo("Twiddle", 130, Rarity.COMMON, mage.cards.t.Twiddle.class)); + cards.add(new SetCardInfo("Underground River", 426, Rarity.RARE, mage.cards.u.UndergroundRiver.class)); + cards.add(new SetCardInfo("Unholy Strength", 201, Rarity.COMMON, mage.cards.u.UnholyStrength.class)); + cards.add(new SetCardInfo("Unstable Mutation", 131, Rarity.COMMON, mage.cards.u.UnstableMutation.class)); + cards.add(new SetCardInfo("Unsummon", 132, Rarity.COMMON, mage.cards.u.Unsummon.class)); + cards.add(new SetCardInfo("Untamed Wilds", 335, Rarity.UNCOMMON, mage.cards.u.UntamedWilds.class)); + cards.add(new SetCardInfo("Updraft", 133, Rarity.COMMON, mage.cards.u.Updraft.class)); + cards.add(new SetCardInfo("Urza's Avenger", 405, Rarity.RARE, mage.cards.u.UrzasAvenger.class)); + cards.add(new SetCardInfo("Urza's Bauble", 406, Rarity.UNCOMMON, mage.cards.u.UrzasBauble.class)); + cards.add(new SetCardInfo("Urza's Mine", 427, Rarity.COMMON, mage.cards.u.UrzasMine.class)); + cards.add(new SetCardInfo("Urza's Power Plant", 428, Rarity.COMMON, mage.cards.u.UrzasPowerPlant.class)); + cards.add(new SetCardInfo("Urza's Tower", 429, Rarity.COMMON, mage.cards.u.UrzasTower.class)); + cards.add(new SetCardInfo("Vampire Bats", 202, Rarity.COMMON, mage.cards.v.VampireBats.class)); + cards.add(new SetCardInfo("Venom", 336, Rarity.COMMON, mage.cards.v.Venom.class)); + cards.add(new SetCardInfo("Verduran Enchantress", 337, Rarity.RARE, mage.cards.v.VerduranEnchantress.class)); + cards.add(new SetCardInfo("Vodalian Soldiers", 134, Rarity.COMMON, mage.cards.v.VodalianSoldiers.class)); + cards.add(new SetCardInfo("Wall of Air", 135, Rarity.UNCOMMON, mage.cards.w.WallOfAir.class)); + cards.add(new SetCardInfo("Wall of Bone", 203, Rarity.UNCOMMON, mage.cards.w.WallOfBone.class)); + cards.add(new SetCardInfo("Wall of Brambles", 338, Rarity.UNCOMMON, mage.cards.w.WallOfBrambles.class)); + cards.add(new SetCardInfo("Wall of Fire", 273, Rarity.UNCOMMON, mage.cards.w.WallOfFire.class)); + cards.add(new SetCardInfo("Wall of Spears", 407, Rarity.COMMON, mage.cards.w.WallOfSpears.class)); + cards.add(new SetCardInfo("Wall of Stone", 274, Rarity.UNCOMMON, mage.cards.w.WallOfStone.class)); + cards.add(new SetCardInfo("Wall of Swords", 67, Rarity.UNCOMMON, mage.cards.w.WallOfSwords.class)); + cards.add(new SetCardInfo("Wanderlust", 339, Rarity.UNCOMMON, mage.cards.w.Wanderlust.class)); + cards.add(new SetCardInfo("War Mammoth", 340, Rarity.COMMON, mage.cards.w.WarMammoth.class)); + cards.add(new SetCardInfo("Warp Artifact", 204, Rarity.RARE, mage.cards.w.WarpArtifact.class)); + cards.add(new SetCardInfo("Weakness", 205, Rarity.COMMON, mage.cards.w.Weakness.class)); + cards.add(new SetCardInfo("Whirling Dervish", 341, Rarity.UNCOMMON, mage.cards.w.WhirlingDervish.class)); + cards.add(new SetCardInfo("White Knight", 68, Rarity.UNCOMMON, mage.cards.w.WhiteKnight.class)); + cards.add(new SetCardInfo("Wild Growth", 342, Rarity.COMMON, mage.cards.w.WildGrowth.class)); + cards.add(new SetCardInfo("Wind Spirit", 136, Rarity.UNCOMMON, mage.cards.w.WindSpirit.class)); + cards.add(new SetCardInfo("Winds of Change", 275, Rarity.RARE, mage.cards.w.WindsOfChange.class)); + cards.add(new SetCardInfo("Winter Blast", 343, Rarity.UNCOMMON, mage.cards.w.WinterBlast.class)); + cards.add(new SetCardInfo("Winter Orb", 408, Rarity.RARE, mage.cards.w.WinterOrb.class)); + cards.add(new SetCardInfo("Wolverine Pack", 344, Rarity.UNCOMMON, mage.cards.w.WolverinePack.class)); + cards.add(new SetCardInfo("Wooden Sphere", 409, Rarity.UNCOMMON, mage.cards.w.WoodenSphere.class)); + cards.add(new SetCardInfo("Word of Blasting", 276, Rarity.UNCOMMON, mage.cards.w.WordOfBlasting.class)); + cards.add(new SetCardInfo("Wrath of God", 69, Rarity.RARE, mage.cards.w.WrathOfGod.class)); + cards.add(new SetCardInfo("Wyluli Wolf", 345, Rarity.RARE, mage.cards.w.WyluliWolf.class)); + cards.add(new SetCardInfo("Xenic Poltergeist", 206, Rarity.RARE, mage.cards.x.XenicPoltergeist.class)); + cards.add(new SetCardInfo("Zephyr Falcon", 137, Rarity.COMMON, mage.cards.z.ZephyrFalcon.class)); + cards.add(new SetCardInfo("Zombie Master", 207, Rarity.RARE, mage.cards.z.ZombieMaster.class)); + cards.add(new SetCardInfo("Zur's Weirding", 138, Rarity.RARE, mage.cards.z.ZursWeirding.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/GuildsOfRavnica.java b/Mage.Sets/src/mage/sets/GuildsOfRavnica.java index 0c9ee0fd14f..6cf884943b1 100644 --- a/Mage.Sets/src/mage/sets/GuildsOfRavnica.java +++ b/Mage.Sets/src/mage/sets/GuildsOfRavnica.java @@ -86,7 +86,7 @@ public final class GuildsOfRavnica extends ExpansionSet { cards.add(new SetCardInfo("Deadly Visit", 68, Rarity.COMMON, mage.cards.d.DeadlyVisit.class)); cards.add(new SetCardInfo("Deafening Clarion", 165, Rarity.RARE, mage.cards.d.DeafeningClarion.class)); cards.add(new SetCardInfo("Demotion", 9, Rarity.UNCOMMON, mage.cards.d.Demotion.class)); - cards.add(new SetCardInfo("Devious Cover-up", 35, Rarity.COMMON, mage.cards.d.DeviousCoverUp.class)); + cards.add(new SetCardInfo("Devious Cover-Up", 35, Rarity.COMMON, mage.cards.d.DeviousCoverUp.class)); cards.add(new SetCardInfo("Devkarin Dissident", 127, Rarity.COMMON, mage.cards.d.DevkarinDissident.class)); cards.add(new SetCardInfo("Dimir Guildgate", 245, Rarity.COMMON, mage.cards.d.DimirGuildgate.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dimir Guildgate", 246, Rarity.COMMON, mage.cards.d.DimirGuildgate.class, NON_FULL_USE_VARIOUS)); diff --git a/Mage.Sets/src/mage/sets/IceAge.java b/Mage.Sets/src/mage/sets/IceAge.java index 2112294e3b5..a56bfb0d143 100644 --- a/Mage.Sets/src/mage/sets/IceAge.java +++ b/Mage.Sets/src/mage/sets/IceAge.java @@ -1,357 +1,359 @@ -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -/** - * - * @author North - */ -public final class IceAge extends ExpansionSet { - - private static final IceAge instance = new IceAge(); - - public static IceAge getInstance() { - return instance; - } - - private IceAge() { - super("Ice Age", "ICE", ExpansionSet.buildDate(1995, 5, 1), SetType.EXPANSION); - this.blockName = "Ice Age"; - this.hasBoosters = true; - this.numBoosterLands = 0; - this.numBoosterCommon = 11; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - cards.add(new SetCardInfo("Abyssal Specter", 113, Rarity.UNCOMMON, mage.cards.a.AbyssalSpecter.class)); - cards.add(new SetCardInfo("Adarkar Sentinel", 306, Rarity.UNCOMMON, mage.cards.a.AdarkarSentinel.class)); - cards.add(new SetCardInfo("Adarkar Wastes", 351, Rarity.RARE, mage.cards.a.AdarkarWastes.class)); - cards.add(new SetCardInfo("Aegis of the Meek", 307, Rarity.RARE, mage.cards.a.AegisOfTheMeek.class)); - cards.add(new SetCardInfo("Altar of Bone", 281, Rarity.RARE, mage.cards.a.AltarOfBone.class)); - cards.add(new SetCardInfo("Anarchy", 170, Rarity.UNCOMMON, mage.cards.a.Anarchy.class)); - cards.add(new SetCardInfo("Arenson's Aura", 3, Rarity.COMMON, mage.cards.a.ArensonsAura.class)); - cards.add(new SetCardInfo("Armor of Faith", 4, Rarity.COMMON, mage.cards.a.ArmorOfFaith.class)); - cards.add(new SetCardInfo("Arnjlot's Ascent", 57, Rarity.COMMON, mage.cards.a.ArnjlotsAscent.class)); - cards.add(new SetCardInfo("Ashen Ghoul", 114, Rarity.UNCOMMON, mage.cards.a.AshenGhoul.class)); - cards.add(new SetCardInfo("Aurochs", 225, Rarity.COMMON, mage.cards.a.Aurochs.class)); - cards.add(new SetCardInfo("Avalanche", 171, Rarity.UNCOMMON, mage.cards.a.Avalanche.class)); - cards.add(new SetCardInfo("Balduvian Barbarians", 172, Rarity.COMMON, mage.cards.b.BalduvianBarbarians.class)); - cards.add(new SetCardInfo("Balduvian Bears", 226, Rarity.COMMON, mage.cards.b.BalduvianBears.class)); - cards.add(new SetCardInfo("Balduvian Conjurer", 58, Rarity.UNCOMMON, mage.cards.b.BalduvianConjurer.class)); - cards.add(new SetCardInfo("Balduvian Hydra", 173, Rarity.RARE, mage.cards.b.BalduvianHydra.class)); - cards.add(new SetCardInfo("Barbed Sextant", 312, Rarity.COMMON, mage.cards.b.BarbedSextant.class)); - cards.add(new SetCardInfo("Baton of Morale", 313, Rarity.UNCOMMON, mage.cards.b.BatonOfMorale.class)); - cards.add(new SetCardInfo("Battle Cry", 5, Rarity.UNCOMMON, mage.cards.b.BattleCry.class)); - cards.add(new SetCardInfo("Battle Frenzy", 175, Rarity.COMMON, mage.cards.b.BattleFrenzy.class)); - cards.add(new SetCardInfo("Binding Grasp", 60, Rarity.UNCOMMON, mage.cards.b.BindingGrasp.class)); - cards.add(new SetCardInfo("Black Scarab", 6, Rarity.UNCOMMON, mage.cards.b.BlackScarab.class)); - cards.add(new SetCardInfo("Blessed Wine", 7, Rarity.COMMON, mage.cards.b.BlessedWine.class)); - cards.add(new SetCardInfo("Blinking Spirit", 8, Rarity.RARE, mage.cards.b.BlinkingSpirit.class)); - cards.add(new SetCardInfo("Blizzard", 227, Rarity.RARE, mage.cards.b.Blizzard.class)); - cards.add(new SetCardInfo("Blue Scarab", 9, Rarity.UNCOMMON, mage.cards.b.BlueScarab.class)); - cards.add(new SetCardInfo("Brainstorm", 61, Rarity.COMMON, mage.cards.b.Brainstorm.class)); - cards.add(new SetCardInfo("Brand of Ill Omen", 177, Rarity.RARE, mage.cards.b.BrandOfIllOmen.class)); - cards.add(new SetCardInfo("Breath of Dreams", 62, Rarity.UNCOMMON, mage.cards.b.BreathOfDreams.class)); - cards.add(new SetCardInfo("Brine Shaman", 115, Rarity.COMMON, mage.cards.b.BrineShaman.class)); - cards.add(new SetCardInfo("Brown Ouphe", 228, Rarity.COMMON, mage.cards.b.BrownOuphe.class)); - cards.add(new SetCardInfo("Brushland", 352, Rarity.RARE, mage.cards.b.Brushland.class)); - cards.add(new SetCardInfo("Burnt Offering", 116, Rarity.COMMON, mage.cards.b.BurntOffering.class)); - cards.add(new SetCardInfo("Call to Arms", 10, Rarity.RARE, mage.cards.c.CallToArms.class)); - cards.add(new SetCardInfo("Caribou Range", 11, Rarity.RARE, mage.cards.c.CaribouRange.class)); - cards.add(new SetCardInfo("Celestial Sword", 314, Rarity.RARE, mage.cards.c.CelestialSword.class)); - cards.add(new SetCardInfo("Centaur Archer", 282, Rarity.UNCOMMON, mage.cards.c.CentaurArcher.class)); - cards.add(new SetCardInfo("Chaos Moon", 179, Rarity.RARE, mage.cards.c.ChaosMoon.class)); - cards.add(new SetCardInfo("Chub Toad", 229, Rarity.COMMON, mage.cards.c.ChubToad.class)); - cards.add(new SetCardInfo("Circle of Protection: Black", 12, Rarity.COMMON, mage.cards.c.CircleOfProtectionBlack.class)); - cards.add(new SetCardInfo("Circle of Protection: Blue", 13, Rarity.COMMON, mage.cards.c.CircleOfProtectionBlue.class)); - cards.add(new SetCardInfo("Circle of Protection: Green", 14, Rarity.COMMON, mage.cards.c.CircleOfProtectionGreen.class)); - cards.add(new SetCardInfo("Circle of Protection: Red", 15, Rarity.COMMON, mage.cards.c.CircleOfProtectionRed.class)); - cards.add(new SetCardInfo("Circle of Protection: White", 16, Rarity.COMMON, mage.cards.c.CircleOfProtectionWhite.class)); - cards.add(new SetCardInfo("Clairvoyance", 63, Rarity.COMMON, mage.cards.c.Clairvoyance.class)); - cards.add(new SetCardInfo("Cold Snap", 17, Rarity.UNCOMMON, mage.cards.c.ColdSnap.class)); - cards.add(new SetCardInfo("Conquer", 180, Rarity.UNCOMMON, mage.cards.c.Conquer.class)); - cards.add(new SetCardInfo("Cooperation", 18, Rarity.COMMON, mage.cards.c.Cooperation.class)); - cards.add(new SetCardInfo("Counterspell", 64, Rarity.COMMON, mage.cards.c.Counterspell.class)); - cards.add(new SetCardInfo("Crown of the Ages", 315, Rarity.RARE, mage.cards.c.CrownOfTheAges.class)); - cards.add(new SetCardInfo("Curse of Marit Lage", 181, Rarity.RARE, mage.cards.c.CurseOfMaritLage.class)); - cards.add(new SetCardInfo("Dance of the Dead", 118, Rarity.UNCOMMON, mage.cards.d.DanceOfTheDead.class)); - cards.add(new SetCardInfo("Dark Banishing", 119, Rarity.COMMON, mage.cards.d.DarkBanishing.class)); - cards.add(new SetCardInfo("Dark Ritual", 120, Rarity.COMMON, mage.cards.d.DarkRitual.class)); - cards.add(new SetCardInfo("Death Ward", 19, Rarity.COMMON, mage.cards.d.DeathWard.class)); - cards.add(new SetCardInfo("Deflection", 65, Rarity.RARE, mage.cards.d.Deflection.class)); - cards.add(new SetCardInfo("Demonic Consultation", 121, Rarity.UNCOMMON, mage.cards.d.DemonicConsultation.class)); - cards.add(new SetCardInfo("Despotic Scepter", 316, Rarity.RARE, mage.cards.d.DespoticScepter.class)); - cards.add(new SetCardInfo("Diabolic Vision", 284, Rarity.UNCOMMON, mage.cards.d.DiabolicVision.class)); - cards.add(new SetCardInfo("Dire Wolves", 230, Rarity.COMMON, mage.cards.d.DireWolves.class)); - cards.add(new SetCardInfo("Disenchant", 20, Rarity.COMMON, mage.cards.d.Disenchant.class)); - cards.add(new SetCardInfo("Dreams of the Dead", 66, Rarity.UNCOMMON, mage.cards.d.DreamsOfTheDead.class)); - cards.add(new SetCardInfo("Drift of the Dead", 123, Rarity.UNCOMMON, mage.cards.d.DriftOfTheDead.class)); - cards.add(new SetCardInfo("Drought", 21, Rarity.UNCOMMON, mage.cards.d.Drought.class)); - cards.add(new SetCardInfo("Dwarven Armory", 182, Rarity.RARE, mage.cards.d.DwarvenArmory.class)); - cards.add(new SetCardInfo("Earthlink", 285, Rarity.RARE, mage.cards.e.Earthlink.class)); - cards.add(new SetCardInfo("Earthlore", 231, Rarity.COMMON, mage.cards.e.Earthlore.class)); - cards.add(new SetCardInfo("Elder Druid", 232, Rarity.RARE, mage.cards.e.ElderDruid.class)); - cards.add(new SetCardInfo("Elemental Augury", 286, Rarity.RARE, mage.cards.e.ElementalAugury.class)); - cards.add(new SetCardInfo("Elkin Bottle", 317, Rarity.RARE, mage.cards.e.ElkinBottle.class)); - cards.add(new SetCardInfo("Enduring Renewal", 23, Rarity.RARE, mage.cards.e.EnduringRenewal.class)); - cards.add(new SetCardInfo("Energy Storm", 24, Rarity.RARE, mage.cards.e.EnergyStorm.class)); - cards.add(new SetCardInfo("Enervate", 67, Rarity.COMMON, mage.cards.e.Enervate.class)); - cards.add(new SetCardInfo("Errantry", 183, Rarity.COMMON, mage.cards.e.Errantry.class)); - cards.add(new SetCardInfo("Essence Filter", 233, Rarity.COMMON, mage.cards.e.EssenceFilter.class)); - cards.add(new SetCardInfo("Essence Flare", 69, Rarity.COMMON, mage.cards.e.EssenceFlare.class)); - cards.add(new SetCardInfo("Fanatical Fever", 234, Rarity.UNCOMMON, mage.cards.f.FanaticalFever.class)); - cards.add(new SetCardInfo("Fear", 124, Rarity.COMMON, mage.cards.f.Fear.class)); - cards.add(new SetCardInfo("Fiery Justice", 288, Rarity.RARE, mage.cards.f.FieryJustice.class)); - cards.add(new SetCardInfo("Fire Covenant", 289, Rarity.UNCOMMON, mage.cards.f.FireCovenant.class)); - cards.add(new SetCardInfo("Flame Spirit", 184, Rarity.UNCOMMON, mage.cards.f.FlameSpirit.class)); - cards.add(new SetCardInfo("Flare", 185, Rarity.COMMON, mage.cards.f.Flare.class)); - cards.add(new SetCardInfo("Flooded Woodlands", 290, Rarity.RARE, mage.cards.f.FloodedWoodlands.class)); - cards.add(new SetCardInfo("Flow of Maggots", 125, Rarity.RARE, mage.cards.f.FlowOfMaggots.class)); - cards.add(new SetCardInfo("Folk of the Pines", 235, Rarity.COMMON, mage.cards.f.FolkOfThePines.class)); - cards.add(new SetCardInfo("Forbidden Lore", 236, Rarity.RARE, mage.cards.f.ForbiddenLore.class)); - cards.add(new SetCardInfo("Force Void", 70, Rarity.UNCOMMON, mage.cards.f.ForceVoid.class)); - cards.add(new SetCardInfo("Forest", 380, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 381, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 382, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forgotten Lore", 237, Rarity.UNCOMMON, mage.cards.f.ForgottenLore.class)); - cards.add(new SetCardInfo("Formation", 25, Rarity.RARE, mage.cards.f.Formation.class)); - cards.add(new SetCardInfo("Foul Familiar", 126, Rarity.COMMON, mage.cards.f.FoulFamiliar.class)); - cards.add(new SetCardInfo("Foxfire", 238, Rarity.COMMON, mage.cards.f.Foxfire.class)); - cards.add(new SetCardInfo("Freyalise's Charm", 240, Rarity.UNCOMMON, mage.cards.f.FreyalisesCharm.class)); - cards.add(new SetCardInfo("Fumarole", 291, Rarity.UNCOMMON, mage.cards.f.Fumarole.class)); - cards.add(new SetCardInfo("Fyndhorn Bow", 318, Rarity.UNCOMMON, mage.cards.f.FyndhornBow.class)); - cards.add(new SetCardInfo("Fyndhorn Brownie", 242, Rarity.COMMON, mage.cards.f.FyndhornBrownie.class)); - cards.add(new SetCardInfo("Fyndhorn Elder", 243, Rarity.UNCOMMON, mage.cards.f.FyndhornElder.class)); - cards.add(new SetCardInfo("Fyndhorn Elves", 244, Rarity.COMMON, mage.cards.f.FyndhornElves.class)); - cards.add(new SetCardInfo("Fyndhorn Pollen", 245, Rarity.RARE, mage.cards.f.FyndhornPollen.class)); - cards.add(new SetCardInfo("Game of Chaos", 186, Rarity.RARE, mage.cards.g.GameOfChaos.class)); - cards.add(new SetCardInfo("Gangrenous Zombies", 127, Rarity.COMMON, mage.cards.g.GangrenousZombies.class)); - cards.add(new SetCardInfo("General Jarkeld", 27, Rarity.RARE, mage.cards.g.GeneralJarkeld.class)); - cards.add(new SetCardInfo("Giant Growth", 246, Rarity.COMMON, mage.cards.g.GiantGrowth.class)); - cards.add(new SetCardInfo("Giant Trap Door Spider", 293, Rarity.UNCOMMON, mage.cards.g.GiantTrapDoorSpider.class)); - cards.add(new SetCardInfo("Glacial Chasm", 353, Rarity.UNCOMMON, mage.cards.g.GlacialChasm.class)); - cards.add(new SetCardInfo("Glacial Crevasses", 187, Rarity.RARE, mage.cards.g.GlacialCrevasses.class)); - cards.add(new SetCardInfo("Glacial Wall", 71, Rarity.UNCOMMON, mage.cards.g.GlacialWall.class)); - cards.add(new SetCardInfo("Goblin Lyre", 319, Rarity.RARE, mage.cards.g.GoblinLyre.class)); - cards.add(new SetCardInfo("Goblin Mutant", 188, Rarity.UNCOMMON, mage.cards.g.GoblinMutant.class)); - cards.add(new SetCardInfo("Goblin Snowman", 191, Rarity.UNCOMMON, mage.cards.g.GoblinSnowman.class)); - cards.add(new SetCardInfo("Gorilla Pack", 247, Rarity.COMMON, mage.cards.g.GorillaPack.class)); - cards.add(new SetCardInfo("Gravebind", 129, Rarity.RARE, mage.cards.g.Gravebind.class)); - cards.add(new SetCardInfo("Green Scarab", 28, Rarity.UNCOMMON, mage.cards.g.GreenScarab.class)); - cards.add(new SetCardInfo("Hallowed Ground", 29, Rarity.UNCOMMON, mage.cards.h.HallowedGround.class)); - cards.add(new SetCardInfo("Halls of Mist", 354, Rarity.RARE, mage.cards.h.HallsOfMist.class)); - cards.add(new SetCardInfo("Heal", 30, Rarity.COMMON, mage.cards.h.Heal.class)); - cards.add(new SetCardInfo("Hecatomb", 130, Rarity.RARE, mage.cards.h.Hecatomb.class)); - cards.add(new SetCardInfo("Hematite Talisman", 320, Rarity.UNCOMMON, mage.cards.h.HematiteTalisman.class)); - cards.add(new SetCardInfo("Hoar Shade", 131, Rarity.COMMON, mage.cards.h.HoarShade.class)); - cards.add(new SetCardInfo("Hot Springs", 248, Rarity.RARE, mage.cards.h.HotSprings.class)); - cards.add(new SetCardInfo("Howl from Beyond", 132, Rarity.COMMON, mage.cards.h.HowlFromBeyond.class)); - cards.add(new SetCardInfo("Hurricane", 249, Rarity.UNCOMMON, mage.cards.h.Hurricane.class)); - cards.add(new SetCardInfo("Hyalopterous Lemure", 133, Rarity.UNCOMMON, mage.cards.h.HyalopterousLemure.class)); - cards.add(new SetCardInfo("Hydroblast", 72, Rarity.COMMON, mage.cards.h.Hydroblast.class)); - cards.add(new SetCardInfo("Hymn of Rebirth", 295, Rarity.UNCOMMON, mage.cards.h.HymnOfRebirth.class)); - cards.add(new SetCardInfo("Ice Cauldron", 321, Rarity.RARE, mage.cards.i.IceCauldron.class)); - cards.add(new SetCardInfo("Ice Floe", 355, Rarity.UNCOMMON, mage.cards.i.IceFloe.class)); - cards.add(new SetCardInfo("Iceberg", 73, Rarity.UNCOMMON, mage.cards.i.Iceberg.class)); - cards.add(new SetCardInfo("Icequake", 134, Rarity.UNCOMMON, mage.cards.i.Icequake.class)); - cards.add(new SetCardInfo("Icy Manipulator", 322, Rarity.UNCOMMON, mage.cards.i.IcyManipulator.class)); - cards.add(new SetCardInfo("Icy Prison", 74, Rarity.RARE, mage.cards.i.IcyPrison.class)); - cards.add(new SetCardInfo("Illusionary Forces", 75, Rarity.COMMON, mage.cards.i.IllusionaryForces.class)); - cards.add(new SetCardInfo("Illusionary Wall", 78, Rarity.COMMON, mage.cards.i.IllusionaryWall.class)); - cards.add(new SetCardInfo("Illusions of Grandeur", 79, Rarity.RARE, mage.cards.i.IllusionsOfGrandeur.class)); - cards.add(new SetCardInfo("Imposing Visage", 193, Rarity.COMMON, mage.cards.i.ImposingVisage.class)); - cards.add(new SetCardInfo("Incinerate", 194, Rarity.COMMON, mage.cards.i.Incinerate.class)); - cards.add(new SetCardInfo("Infernal Darkness", 135, Rarity.RARE, mage.cards.i.InfernalDarkness.class)); - cards.add(new SetCardInfo("Infernal Denizen", 136, Rarity.RARE, mage.cards.i.InfernalDenizen.class)); - cards.add(new SetCardInfo("Infinite Hourglass", 323, Rarity.RARE, mage.cards.i.InfiniteHourglass.class)); - cards.add(new SetCardInfo("Infuse", 80, Rarity.COMMON, mage.cards.i.Infuse.class)); - cards.add(new SetCardInfo("Island", 368, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 369, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 370, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Jester's Cap", 324, Rarity.RARE, mage.cards.j.JestersCap.class)); - cards.add(new SetCardInfo("Jester's Mask", 325, Rarity.RARE, mage.cards.j.JestersMask.class)); - cards.add(new SetCardInfo("Jeweled Amulet", 326, Rarity.UNCOMMON, mage.cards.j.JeweledAmulet.class)); - cards.add(new SetCardInfo("Johtull Wurm", 250, Rarity.UNCOMMON, mage.cards.j.JohtullWurm.class)); - cards.add(new SetCardInfo("Jokulhaups", 195, Rarity.RARE, mage.cards.j.Jokulhaups.class)); - cards.add(new SetCardInfo("Juniper Order Druid", 251, Rarity.COMMON, mage.cards.j.JuniperOrderDruid.class)); - cards.add(new SetCardInfo("Justice", 32, Rarity.UNCOMMON, mage.cards.j.Justice.class)); - cards.add(new SetCardInfo("Karplusan Forest", 356, Rarity.RARE, mage.cards.k.KarplusanForest.class)); - cards.add(new SetCardInfo("Karplusan Giant", 196, Rarity.UNCOMMON, mage.cards.k.KarplusanGiant.class)); - cards.add(new SetCardInfo("Karplusan Yeti", 197, Rarity.RARE, mage.cards.k.KarplusanYeti.class)); - cards.add(new SetCardInfo("Kelsinko Ranger", 33, Rarity.COMMON, mage.cards.k.KelsinkoRanger.class)); - cards.add(new SetCardInfo("Kjeldoran Dead", 137, Rarity.COMMON, mage.cards.k.KjeldoranDead.class)); - cards.add(new SetCardInfo("Kjeldoran Frostbeast", 296, Rarity.UNCOMMON, mage.cards.k.KjeldoranFrostbeast.class)); - cards.add(new SetCardInfo("Kjeldoran Knight", 36, Rarity.RARE, mage.cards.k.KjeldoranKnight.class)); - cards.add(new SetCardInfo("Kjeldoran Phalanx", 37, Rarity.RARE, mage.cards.k.KjeldoranPhalanx.class)); - cards.add(new SetCardInfo("Kjeldoran Royal Guard", 38, Rarity.RARE, mage.cards.k.KjeldoranRoyalGuard.class)); - cards.add(new SetCardInfo("Kjeldoran Skycaptain", 39, Rarity.UNCOMMON, mage.cards.k.KjeldoranSkycaptain.class)); - cards.add(new SetCardInfo("Kjeldoran Skyknight", 40, Rarity.COMMON, mage.cards.k.KjeldoranSkyknight.class)); - cards.add(new SetCardInfo("Kjeldoran Warrior", 41, Rarity.COMMON, mage.cards.k.KjeldoranWarrior.class)); - cards.add(new SetCardInfo("Knight of Stromgald", 138, Rarity.UNCOMMON, mage.cards.k.KnightOfStromgald.class)); - cards.add(new SetCardInfo("Krovikan Elementalist", 139, Rarity.UNCOMMON, mage.cards.k.KrovikanElementalist.class)); - cards.add(new SetCardInfo("Krovikan Fetish", 140, Rarity.COMMON, mage.cards.k.KrovikanFetish.class)); - cards.add(new SetCardInfo("Krovikan Sorcerer", 81, Rarity.COMMON, mage.cards.k.KrovikanSorcerer.class)); - cards.add(new SetCardInfo("Land Cap", 357, Rarity.RARE, mage.cards.l.LandCap.class)); - cards.add(new SetCardInfo("Lapis Lazuli Talisman", 327, Rarity.UNCOMMON, mage.cards.l.LapisLazuliTalisman.class)); - cards.add(new SetCardInfo("Lava Tubes", 358, Rarity.RARE, mage.cards.l.LavaTubes.class)); - cards.add(new SetCardInfo("Legions of Lim-Dul", 142, Rarity.COMMON, mage.cards.l.LegionsOfLimDul.class)); - cards.add(new SetCardInfo("Leshrac's Rite", 143, Rarity.UNCOMMON, mage.cards.l.LeshracsRite.class)); - cards.add(new SetCardInfo("Leshrac's Sigil", 144, Rarity.UNCOMMON, mage.cards.l.LeshracsSigil.class)); - cards.add(new SetCardInfo("Lhurgoyf", 252, Rarity.RARE, mage.cards.l.Lhurgoyf.class)); - cards.add(new SetCardInfo("Lightning Blow", 42, Rarity.RARE, mage.cards.l.LightningBlow.class)); - cards.add(new SetCardInfo("Lim-Dul's Hex", 146, Rarity.UNCOMMON, mage.cards.l.LimDulsHex.class)); - cards.add(new SetCardInfo("Lure", 253, Rarity.UNCOMMON, mage.cards.l.Lure.class)); - cards.add(new SetCardInfo("Magus of the Unseen", 82, Rarity.RARE, mage.cards.m.MagusOfTheUnseen.class)); - cards.add(new SetCardInfo("Malachite Talisman", 328, Rarity.UNCOMMON, mage.cards.m.MalachiteTalisman.class)); - cards.add(new SetCardInfo("Marton Stromgald", 204, Rarity.RARE, mage.cards.m.MartonStromgald.class)); - cards.add(new SetCardInfo("Melee", 199, Rarity.UNCOMMON, mage.cards.m.Melee.class)); - cards.add(new SetCardInfo("Melting", 200, Rarity.UNCOMMON, mage.cards.m.Melting.class)); - cards.add(new SetCardInfo("Merieke Ri Berit", 297, Rarity.RARE, mage.cards.m.MeriekeRiBerit.class)); - cards.add(new SetCardInfo("Mesmeric Trance", 83, Rarity.RARE, mage.cards.m.MesmericTrance.class)); - cards.add(new SetCardInfo("Meteor Shower", 201, Rarity.COMMON, mage.cards.m.MeteorShower.class)); - cards.add(new SetCardInfo("Mind Ravel", 147, Rarity.COMMON, mage.cards.m.MindRavel.class)); - cards.add(new SetCardInfo("Mind Warp", 148, Rarity.UNCOMMON, mage.cards.m.MindWarp.class)); - cards.add(new SetCardInfo("Minion of Leshrac", 150, Rarity.RARE, mage.cards.m.MinionOfLeshrac.class)); - cards.add(new SetCardInfo("Minion of Tevesh Szat", 151, Rarity.RARE, mage.cards.m.MinionOfTeveshSzat.class)); - cards.add(new SetCardInfo("Mistfolk", 84, Rarity.COMMON, mage.cards.m.Mistfolk.class)); - cards.add(new SetCardInfo("Mole Worms", 152, Rarity.UNCOMMON, mage.cards.m.MoleWorms.class)); - cards.add(new SetCardInfo("Monsoon", 298, Rarity.RARE, mage.cards.m.Monsoon.class)); - cards.add(new SetCardInfo("Moor Fiend", 153, Rarity.COMMON, mage.cards.m.MoorFiend.class)); - cards.add(new SetCardInfo("Mountain Goat", 202, Rarity.COMMON, mage.cards.m.MountainGoat.class)); - cards.add(new SetCardInfo("Mountain Titan", 299, Rarity.RARE, mage.cards.m.MountainTitan.class)); - cards.add(new SetCardInfo("Mountain", 376, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 377, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 378, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mudslide", 203, Rarity.RARE, mage.cards.m.Mudslide.class)); - cards.add(new SetCardInfo("Mystic Might", 86, Rarity.RARE, mage.cards.m.MysticMight.class)); - cards.add(new SetCardInfo("Mystic Remora", 87, Rarity.COMMON, mage.cards.m.MysticRemora.class)); - cards.add(new SetCardInfo("Nacre Talisman", 329, Rarity.UNCOMMON, mage.cards.n.NacreTalisman.class)); - cards.add(new SetCardInfo("Naked Singularity", 330, Rarity.RARE, mage.cards.n.NakedSingularity.class)); - cards.add(new SetCardInfo("Nature's Lore", 255, Rarity.UNCOMMON, mage.cards.n.NaturesLore.class)); - cards.add(new SetCardInfo("Necropotence", 154, Rarity.RARE, mage.cards.n.Necropotence.class)); - cards.add(new SetCardInfo("Norritt", 155, Rarity.COMMON, mage.cards.n.Norritt.class)); - cards.add(new SetCardInfo("Onyx Talisman", 331, Rarity.UNCOMMON, mage.cards.o.OnyxTalisman.class)); - cards.add(new SetCardInfo("Orcish Cannoneers", 205, Rarity.UNCOMMON, mage.cards.o.OrcishCannoneers.class)); - cards.add(new SetCardInfo("Orcish Healer", 208, Rarity.UNCOMMON, mage.cards.o.OrcishHealer.class)); - cards.add(new SetCardInfo("Orcish Librarian", 209, Rarity.RARE, mage.cards.o.OrcishLibrarian.class)); - cards.add(new SetCardInfo("Orcish Lumberjack", 210, Rarity.COMMON, mage.cards.o.OrcishLumberjack.class)); - cards.add(new SetCardInfo("Orcish Squatters", 211, Rarity.RARE, mage.cards.o.OrcishSquatters.class)); - cards.add(new SetCardInfo("Order of the Sacred Torch", 45, Rarity.RARE, mage.cards.o.OrderOfTheSacredTorch.class)); - cards.add(new SetCardInfo("Order of the White Shield", 46, Rarity.UNCOMMON, mage.cards.o.OrderOfTheWhiteShield.class)); - cards.add(new SetCardInfo("Pale Bears", 256, Rarity.RARE, mage.cards.p.PaleBears.class)); - cards.add(new SetCardInfo("Panic", 212, Rarity.COMMON, mage.cards.p.Panic.class)); - cards.add(new SetCardInfo("Pentagram of the Ages", 332, Rarity.RARE, mage.cards.p.PentagramOfTheAges.class)); - cards.add(new SetCardInfo("Pestilence Rats", 157, Rarity.COMMON, mage.cards.p.PestilenceRats.class)); - cards.add(new SetCardInfo("Pit Trap", 333, Rarity.UNCOMMON, mage.cards.p.PitTrap.class)); - cards.add(new SetCardInfo("Plains", 364, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 365, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 366, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Polar Kraken", 89, Rarity.RARE, mage.cards.p.PolarKraken.class)); - cards.add(new SetCardInfo("Portent", 90, Rarity.COMMON, mage.cards.p.Portent.class)); - cards.add(new SetCardInfo("Power Sink", 91, Rarity.COMMON, mage.cards.p.PowerSink.class)); - cards.add(new SetCardInfo("Pox", 158, Rarity.RARE, mage.cards.p.Pox.class)); - cards.add(new SetCardInfo("Prismatic Ward", 47, Rarity.COMMON, mage.cards.p.PrismaticWard.class)); - cards.add(new SetCardInfo("Pygmy Allosaurus", 257, Rarity.RARE, mage.cards.p.PygmyAllosaurus.class)); - cards.add(new SetCardInfo("Pyknite", 258, Rarity.COMMON, mage.cards.p.Pyknite.class)); - cards.add(new SetCardInfo("Pyroblast", 213, Rarity.COMMON, mage.cards.p.Pyroblast.class)); - cards.add(new SetCardInfo("Pyroclasm", 214, Rarity.UNCOMMON, mage.cards.p.Pyroclasm.class)); - cards.add(new SetCardInfo("Rally", 48, Rarity.COMMON, mage.cards.r.Rally.class)); - cards.add(new SetCardInfo("Ray of Command", 92, Rarity.COMMON, mage.cards.r.RayOfCommand.class)); - cards.add(new SetCardInfo("Ray of Erasure", 93, Rarity.COMMON, mage.cards.r.RayOfErasure.class)); - cards.add(new SetCardInfo("Reality Twist", 94, Rarity.RARE, mage.cards.r.RealityTwist.class)); - cards.add(new SetCardInfo("Reclamation", 300, Rarity.RARE, mage.cards.r.Reclamation.class)); - cards.add(new SetCardInfo("Red Scarab", 49, Rarity.UNCOMMON, mage.cards.r.RedScarab.class)); - cards.add(new SetCardInfo("Regeneration", 259, Rarity.COMMON, mage.cards.r.Regeneration.class)); - cards.add(new SetCardInfo("Rime Dryad", 260, Rarity.COMMON, mage.cards.r.RimeDryad.class)); - cards.add(new SetCardInfo("Ritual of Subdual", 261, Rarity.RARE, mage.cards.r.RitualOfSubdual.class)); - cards.add(new SetCardInfo("River Delta", 359, Rarity.RARE, mage.cards.r.RiverDelta.class)); - cards.add(new SetCardInfo("Runed Arch", 334, Rarity.RARE, mage.cards.r.RunedArch.class)); - cards.add(new SetCardInfo("Sabretooth Tiger", 215, Rarity.COMMON, mage.cards.s.SabretoothTiger.class)); - cards.add(new SetCardInfo("Scaled Wurm", 262, Rarity.COMMON, mage.cards.s.ScaledWurm.class)); - cards.add(new SetCardInfo("Sea Spirit", 95, Rarity.UNCOMMON, mage.cards.s.SeaSpirit.class)); - cards.add(new SetCardInfo("Seizures", 159, Rarity.COMMON, mage.cards.s.Seizures.class)); - cards.add(new SetCardInfo("Shambling Strider", 263, Rarity.COMMON, mage.cards.s.ShamblingStrider.class)); - cards.add(new SetCardInfo("Shatter", 216, Rarity.COMMON, mage.cards.s.Shatter.class)); - cards.add(new SetCardInfo("Shield Bearer", 52, Rarity.COMMON, mage.cards.s.ShieldBearer.class)); - cards.add(new SetCardInfo("Shield of the Ages", 335, Rarity.UNCOMMON, mage.cards.s.ShieldOfTheAges.class)); - cards.add(new SetCardInfo("Shyft", 96, Rarity.RARE, mage.cards.s.Shyft.class)); - cards.add(new SetCardInfo("Sibilant Spirit", 97, Rarity.RARE, mage.cards.s.SibilantSpirit.class)); - cards.add(new SetCardInfo("Silver Erne", 98, Rarity.UNCOMMON, mage.cards.s.SilverErne.class)); - cards.add(new SetCardInfo("Skeleton Ship", 301, Rarity.RARE, mage.cards.s.SkeletonShip.class)); - cards.add(new SetCardInfo("Skull Catapult", 336, Rarity.UNCOMMON, mage.cards.s.SkullCatapult.class)); - cards.add(new SetCardInfo("Snow Fortress", 337, Rarity.RARE, mage.cards.s.SnowFortress.class)); - cards.add(new SetCardInfo("Snow Hound", 53, Rarity.UNCOMMON, mage.cards.s.SnowHound.class)); - cards.add(new SetCardInfo("Snow-Covered Forest", 383, Rarity.LAND, mage.cards.s.SnowCoveredForest.class)); - cards.add(new SetCardInfo("Snow-Covered Island", 371, Rarity.LAND, mage.cards.s.SnowCoveredIsland.class)); - cards.add(new SetCardInfo("Snow-Covered Mountain", 379, Rarity.LAND, mage.cards.s.SnowCoveredMountain.class)); - cards.add(new SetCardInfo("Snow-Covered Plains", 367, Rarity.LAND, mage.cards.s.SnowCoveredPlains.class)); - cards.add(new SetCardInfo("Snow-Covered Swamp", 372, Rarity.LAND, mage.cards.s.SnowCoveredSwamp.class)); - cards.add(new SetCardInfo("Soldevi Golem", 338, Rarity.RARE, mage.cards.s.SoldeviGolem.class)); - cards.add(new SetCardInfo("Soldevi Machinist", 102, Rarity.UNCOMMON, mage.cards.s.SoldeviMachinist.class)); - cards.add(new SetCardInfo("Soldevi Simulacrum", 339, Rarity.UNCOMMON, mage.cards.s.SoldeviSimulacrum.class)); - cards.add(new SetCardInfo("Songs of the Damned", 160, Rarity.COMMON, mage.cards.s.SongsOfTheDamned.class)); - cards.add(new SetCardInfo("Soul Barrier", 103, Rarity.UNCOMMON, mage.cards.s.SoulBarrier.class)); - cards.add(new SetCardInfo("Soul Burn", 161, Rarity.COMMON, mage.cards.s.SoulBurn.class)); - cards.add(new SetCardInfo("Soul Kiss", 162, Rarity.COMMON, mage.cards.s.SoulKiss.class)); - cards.add(new SetCardInfo("Spoils of Evil", 163, Rarity.RARE, mage.cards.s.SpoilsOfEvil.class)); - cards.add(new SetCardInfo("Staff of the Ages", 340, Rarity.RARE, mage.cards.s.StaffOfTheAges.class)); - cards.add(new SetCardInfo("Stampede", 265, Rarity.RARE, mage.cards.s.Stampede.class)); - cards.add(new SetCardInfo("Stone Rain", 217, Rarity.COMMON, mage.cards.s.StoneRain.class)); - cards.add(new SetCardInfo("Stone Spirit", 218, Rarity.UNCOMMON, mage.cards.s.StoneSpirit.class)); - cards.add(new SetCardInfo("Stonehands", 219, Rarity.COMMON, mage.cards.s.Stonehands.class)); - cards.add(new SetCardInfo("Storm Spirit", 303, Rarity.RARE, mage.cards.s.StormSpirit.class)); - cards.add(new SetCardInfo("Stormbind", 304, Rarity.RARE, mage.cards.s.Stormbind.class)); - cards.add(new SetCardInfo("Stromgald Cabal", 166, Rarity.RARE, mage.cards.s.StromgaldCabal.class)); - cards.add(new SetCardInfo("Stunted Growth", 266, Rarity.RARE, mage.cards.s.StuntedGrowth.class)); - cards.add(new SetCardInfo("Sulfurous Springs", 360, Rarity.RARE, mage.cards.s.SulfurousSprings.class)); - cards.add(new SetCardInfo("Sunstone", 341, Rarity.UNCOMMON, mage.cards.s.Sunstone.class)); - cards.add(new SetCardInfo("Swamp", 373, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 374, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 375, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swords to Plowshares", 54, Rarity.UNCOMMON, mage.cards.s.SwordsToPlowshares.class)); - cards.add(new SetCardInfo("Tarpan", 267, Rarity.COMMON, mage.cards.t.Tarpan.class)); - cards.add(new SetCardInfo("Thermokarst", 268, Rarity.UNCOMMON, mage.cards.t.Thermokarst.class)); - cards.add(new SetCardInfo("Thoughtleech", 269, Rarity.UNCOMMON, mage.cards.t.Thoughtleech.class)); - cards.add(new SetCardInfo("Thunder Wall", 104, Rarity.UNCOMMON, mage.cards.t.ThunderWall.class)); - cards.add(new SetCardInfo("Timberline Ridge", 361, Rarity.RARE, mage.cards.t.TimberlineRidge.class)); - cards.add(new SetCardInfo("Time Bomb", 342, Rarity.RARE, mage.cards.t.TimeBomb.class)); - cards.add(new SetCardInfo("Tinder Wall", 270, Rarity.COMMON, mage.cards.t.TinderWall.class)); - cards.add(new SetCardInfo("Tor Giant", 220, Rarity.COMMON, mage.cards.t.TorGiant.class)); - cards.add(new SetCardInfo("Total War", 221, Rarity.RARE, mage.cards.t.TotalWar.class)); - cards.add(new SetCardInfo("Touch of Death", 167, Rarity.COMMON, mage.cards.t.TouchOfDeath.class)); - cards.add(new SetCardInfo("Trailblazer", 272, Rarity.RARE, mage.cards.t.Trailblazer.class)); - cards.add(new SetCardInfo("Underground River", 362, Rarity.RARE, mage.cards.u.UndergroundRiver.class)); - cards.add(new SetCardInfo("Updraft", 105, Rarity.UNCOMMON, mage.cards.u.Updraft.class)); - cards.add(new SetCardInfo("Urza's Bauble", 343, Rarity.UNCOMMON, mage.cards.u.UrzasBauble.class)); - cards.add(new SetCardInfo("Veldt", 363, Rarity.RARE, mage.cards.v.Veldt.class)); - cards.add(new SetCardInfo("Venomous Breath", 273, Rarity.UNCOMMON, mage.cards.v.VenomousBreath.class)); - cards.add(new SetCardInfo("Vertigo", 222, Rarity.UNCOMMON, mage.cards.v.Vertigo.class)); - cards.add(new SetCardInfo("Vexing Arcanix", 344, Rarity.RARE, mage.cards.v.VexingArcanix.class)); - cards.add(new SetCardInfo("Vibrating Sphere", 345, Rarity.RARE, mage.cards.v.VibratingSphere.class)); - cards.add(new SetCardInfo("Walking Wall", 346, Rarity.UNCOMMON, mage.cards.w.WalkingWall.class)); - cards.add(new SetCardInfo("Wall of Lava", 223, Rarity.UNCOMMON, mage.cards.w.WallOfLava.class)); - cards.add(new SetCardInfo("Wall of Pine Needles", 274, Rarity.UNCOMMON, mage.cards.w.WallOfPineNeedles.class)); - cards.add(new SetCardInfo("Wall of Shields", 347, Rarity.UNCOMMON, mage.cards.w.WallOfShields.class)); - cards.add(new SetCardInfo("War Chariot", 348, Rarity.UNCOMMON, mage.cards.w.WarChariot.class)); - cards.add(new SetCardInfo("Warning", 55, Rarity.COMMON, mage.cards.w.Warning.class)); - cards.add(new SetCardInfo("Whalebone Glider", 349, Rarity.UNCOMMON, mage.cards.w.WhaleboneGlider.class)); - cards.add(new SetCardInfo("White Scarab", 56, Rarity.UNCOMMON, mage.cards.w.WhiteScarab.class)); - cards.add(new SetCardInfo("Whiteout", 275, Rarity.UNCOMMON, mage.cards.w.Whiteout.class)); - cards.add(new SetCardInfo("Wild Growth", 277, Rarity.COMMON, mage.cards.w.WildGrowth.class)); - cards.add(new SetCardInfo("Wind Spirit", 106, Rarity.UNCOMMON, mage.cards.w.WindSpirit.class)); - cards.add(new SetCardInfo("Wings of Aesthir", 305, Rarity.UNCOMMON, mage.cards.w.WingsOfAesthir.class)); - cards.add(new SetCardInfo("Withering Wisps", 168, Rarity.UNCOMMON, mage.cards.w.WitheringWisps.class)); - cards.add(new SetCardInfo("Woolly Mammoths", 278, Rarity.COMMON, mage.cards.w.WoollyMammoths.class)); - cards.add(new SetCardInfo("Woolly Spider", 279, Rarity.COMMON, mage.cards.w.WoollySpider.class)); - cards.add(new SetCardInfo("Word of Blasting", 224, Rarity.UNCOMMON, mage.cards.w.WordOfBlasting.class)); - cards.add(new SetCardInfo("Word of Undoing", 108, Rarity.COMMON, mage.cards.w.WordOfUndoing.class)); - cards.add(new SetCardInfo("Wrath of Marit Lage", 109, Rarity.RARE, mage.cards.w.WrathOfMaritLage.class)); - cards.add(new SetCardInfo("Yavimaya Gnats", 280, Rarity.UNCOMMON, mage.cards.y.YavimayaGnats.class)); - cards.add(new SetCardInfo("Zur's Weirding", 110, Rarity.RARE, mage.cards.z.ZursWeirding.class)); - cards.add(new SetCardInfo("Zuran Enchanter", 111, Rarity.COMMON, mage.cards.z.ZuranEnchanter.class)); - cards.add(new SetCardInfo("Zuran Orb", 350, Rarity.UNCOMMON, mage.cards.z.ZuranOrb.class)); - cards.add(new SetCardInfo("Zuran Spellcaster", 112, Rarity.COMMON, mage.cards.z.ZuranSpellcaster.class)); - } -} +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author North + */ +public final class IceAge extends ExpansionSet { + + private static final IceAge instance = new IceAge(); + + public static IceAge getInstance() { + return instance; + } + + private IceAge() { + super("Ice Age", "ICE", ExpansionSet.buildDate(1995, 5, 1), SetType.EXPANSION); + this.blockName = "Ice Age"; + this.hasBoosters = true; + this.numBoosterLands = 0; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + + cards.add(new SetCardInfo("Abyssal Specter", 113, Rarity.UNCOMMON, mage.cards.a.AbyssalSpecter.class)); + cards.add(new SetCardInfo("Adarkar Sentinel", 306, Rarity.UNCOMMON, mage.cards.a.AdarkarSentinel.class)); + cards.add(new SetCardInfo("Adarkar Wastes", 351, Rarity.RARE, mage.cards.a.AdarkarWastes.class)); + cards.add(new SetCardInfo("Aegis of the Meek", 307, Rarity.RARE, mage.cards.a.AegisOfTheMeek.class)); + cards.add(new SetCardInfo("Altar of Bone", 281, Rarity.RARE, mage.cards.a.AltarOfBone.class)); + cards.add(new SetCardInfo("Anarchy", 170, Rarity.UNCOMMON, mage.cards.a.Anarchy.class)); + cards.add(new SetCardInfo("Arenson's Aura", 3, Rarity.COMMON, mage.cards.a.ArensonsAura.class)); + cards.add(new SetCardInfo("Armor of Faith", 4, Rarity.COMMON, mage.cards.a.ArmorOfFaith.class)); + cards.add(new SetCardInfo("Arnjlot's Ascent", 57, Rarity.COMMON, mage.cards.a.ArnjlotsAscent.class)); + cards.add(new SetCardInfo("Ashen Ghoul", 114, Rarity.UNCOMMON, mage.cards.a.AshenGhoul.class)); + cards.add(new SetCardInfo("Aurochs", 225, Rarity.COMMON, mage.cards.a.Aurochs.class)); + cards.add(new SetCardInfo("Avalanche", 171, Rarity.UNCOMMON, mage.cards.a.Avalanche.class)); + cards.add(new SetCardInfo("Balduvian Barbarians", 172, Rarity.COMMON, mage.cards.b.BalduvianBarbarians.class)); + cards.add(new SetCardInfo("Balduvian Bears", 226, Rarity.COMMON, mage.cards.b.BalduvianBears.class)); + cards.add(new SetCardInfo("Balduvian Conjurer", 58, Rarity.UNCOMMON, mage.cards.b.BalduvianConjurer.class)); + cards.add(new SetCardInfo("Balduvian Hydra", 173, Rarity.RARE, mage.cards.b.BalduvianHydra.class)); + cards.add(new SetCardInfo("Barbed Sextant", 312, Rarity.COMMON, mage.cards.b.BarbedSextant.class)); + cards.add(new SetCardInfo("Baton of Morale", 313, Rarity.UNCOMMON, mage.cards.b.BatonOfMorale.class)); + cards.add(new SetCardInfo("Battle Cry", 5, Rarity.UNCOMMON, mage.cards.b.BattleCry.class)); + cards.add(new SetCardInfo("Battle Frenzy", 175, Rarity.COMMON, mage.cards.b.BattleFrenzy.class)); + cards.add(new SetCardInfo("Binding Grasp", 60, Rarity.UNCOMMON, mage.cards.b.BindingGrasp.class)); + cards.add(new SetCardInfo("Black Scarab", 6, Rarity.UNCOMMON, mage.cards.b.BlackScarab.class)); + cards.add(new SetCardInfo("Blessed Wine", 7, Rarity.COMMON, mage.cards.b.BlessedWine.class)); + cards.add(new SetCardInfo("Blinking Spirit", 8, Rarity.RARE, mage.cards.b.BlinkingSpirit.class)); + cards.add(new SetCardInfo("Blizzard", 227, Rarity.RARE, mage.cards.b.Blizzard.class)); + cards.add(new SetCardInfo("Blue Scarab", 9, Rarity.UNCOMMON, mage.cards.b.BlueScarab.class)); + cards.add(new SetCardInfo("Brainstorm", 61, Rarity.COMMON, mage.cards.b.Brainstorm.class)); + cards.add(new SetCardInfo("Brand of Ill Omen", 177, Rarity.RARE, mage.cards.b.BrandOfIllOmen.class)); + cards.add(new SetCardInfo("Breath of Dreams", 62, Rarity.UNCOMMON, mage.cards.b.BreathOfDreams.class)); + cards.add(new SetCardInfo("Brine Shaman", 115, Rarity.COMMON, mage.cards.b.BrineShaman.class)); + cards.add(new SetCardInfo("Brown Ouphe", 228, Rarity.COMMON, mage.cards.b.BrownOuphe.class)); + cards.add(new SetCardInfo("Brushland", 352, Rarity.RARE, mage.cards.b.Brushland.class)); + cards.add(new SetCardInfo("Burnt Offering", 116, Rarity.COMMON, mage.cards.b.BurntOffering.class)); + cards.add(new SetCardInfo("Call to Arms", 10, Rarity.RARE, mage.cards.c.CallToArms.class)); + cards.add(new SetCardInfo("Caribou Range", 11, Rarity.RARE, mage.cards.c.CaribouRange.class)); + cards.add(new SetCardInfo("Celestial Sword", 314, Rarity.RARE, mage.cards.c.CelestialSword.class)); + cards.add(new SetCardInfo("Centaur Archer", 282, Rarity.UNCOMMON, mage.cards.c.CentaurArcher.class)); + cards.add(new SetCardInfo("Chaos Moon", 179, Rarity.RARE, mage.cards.c.ChaosMoon.class)); + cards.add(new SetCardInfo("Chub Toad", 229, Rarity.COMMON, mage.cards.c.ChubToad.class)); + cards.add(new SetCardInfo("Circle of Protection: Black", 12, Rarity.COMMON, mage.cards.c.CircleOfProtectionBlack.class)); + cards.add(new SetCardInfo("Circle of Protection: Blue", 13, Rarity.COMMON, mage.cards.c.CircleOfProtectionBlue.class)); + cards.add(new SetCardInfo("Circle of Protection: Green", 14, Rarity.COMMON, mage.cards.c.CircleOfProtectionGreen.class)); + cards.add(new SetCardInfo("Circle of Protection: Red", 15, Rarity.COMMON, mage.cards.c.CircleOfProtectionRed.class)); + cards.add(new SetCardInfo("Circle of Protection: White", 16, Rarity.COMMON, mage.cards.c.CircleOfProtectionWhite.class)); + cards.add(new SetCardInfo("Clairvoyance", 63, Rarity.COMMON, mage.cards.c.Clairvoyance.class)); + cards.add(new SetCardInfo("Cloak of Confusion", 117, Rarity.COMMON, mage.cards.c.CloakOfConfusion.class)); + cards.add(new SetCardInfo("Cold Snap", 17, Rarity.UNCOMMON, mage.cards.c.ColdSnap.class)); + cards.add(new SetCardInfo("Conquer", 180, Rarity.UNCOMMON, mage.cards.c.Conquer.class)); + cards.add(new SetCardInfo("Cooperation", 18, Rarity.COMMON, mage.cards.c.Cooperation.class)); + cards.add(new SetCardInfo("Counterspell", 64, Rarity.COMMON, mage.cards.c.Counterspell.class)); + cards.add(new SetCardInfo("Crown of the Ages", 315, Rarity.RARE, mage.cards.c.CrownOfTheAges.class)); + cards.add(new SetCardInfo("Curse of Marit Lage", 181, Rarity.RARE, mage.cards.c.CurseOfMaritLage.class)); + cards.add(new SetCardInfo("Dance of the Dead", 118, Rarity.UNCOMMON, mage.cards.d.DanceOfTheDead.class)); + cards.add(new SetCardInfo("Dark Banishing", 119, Rarity.COMMON, mage.cards.d.DarkBanishing.class)); + cards.add(new SetCardInfo("Dark Ritual", 120, Rarity.COMMON, mage.cards.d.DarkRitual.class)); + cards.add(new SetCardInfo("Death Ward", 19, Rarity.COMMON, mage.cards.d.DeathWard.class)); + cards.add(new SetCardInfo("Deflection", 65, Rarity.RARE, mage.cards.d.Deflection.class)); + cards.add(new SetCardInfo("Demonic Consultation", 121, Rarity.UNCOMMON, mage.cards.d.DemonicConsultation.class)); + cards.add(new SetCardInfo("Despotic Scepter", 316, Rarity.RARE, mage.cards.d.DespoticScepter.class)); + cards.add(new SetCardInfo("Diabolic Vision", 284, Rarity.UNCOMMON, mage.cards.d.DiabolicVision.class)); + cards.add(new SetCardInfo("Dire Wolves", 230, Rarity.COMMON, mage.cards.d.DireWolves.class)); + cards.add(new SetCardInfo("Disenchant", 20, Rarity.COMMON, mage.cards.d.Disenchant.class)); + cards.add(new SetCardInfo("Dread Wight", 122, Rarity.RARE, mage.cards.d.DreadWight.class)); + cards.add(new SetCardInfo("Dreams of the Dead", 66, Rarity.UNCOMMON, mage.cards.d.DreamsOfTheDead.class)); + cards.add(new SetCardInfo("Drift of the Dead", 123, Rarity.UNCOMMON, mage.cards.d.DriftOfTheDead.class)); + cards.add(new SetCardInfo("Drought", 21, Rarity.UNCOMMON, mage.cards.d.Drought.class)); + cards.add(new SetCardInfo("Dwarven Armory", 182, Rarity.RARE, mage.cards.d.DwarvenArmory.class)); + cards.add(new SetCardInfo("Earthlink", 285, Rarity.RARE, mage.cards.e.Earthlink.class)); + cards.add(new SetCardInfo("Earthlore", 231, Rarity.COMMON, mage.cards.e.Earthlore.class)); + cards.add(new SetCardInfo("Elder Druid", 232, Rarity.RARE, mage.cards.e.ElderDruid.class)); + cards.add(new SetCardInfo("Elemental Augury", 286, Rarity.RARE, mage.cards.e.ElementalAugury.class)); + cards.add(new SetCardInfo("Elkin Bottle", 317, Rarity.RARE, mage.cards.e.ElkinBottle.class)); + cards.add(new SetCardInfo("Enduring Renewal", 23, Rarity.RARE, mage.cards.e.EnduringRenewal.class)); + cards.add(new SetCardInfo("Energy Storm", 24, Rarity.RARE, mage.cards.e.EnergyStorm.class)); + cards.add(new SetCardInfo("Enervate", 67, Rarity.COMMON, mage.cards.e.Enervate.class)); + cards.add(new SetCardInfo("Errantry", 183, Rarity.COMMON, mage.cards.e.Errantry.class)); + cards.add(new SetCardInfo("Essence Filter", 233, Rarity.COMMON, mage.cards.e.EssenceFilter.class)); + cards.add(new SetCardInfo("Essence Flare", 69, Rarity.COMMON, mage.cards.e.EssenceFlare.class)); + cards.add(new SetCardInfo("Fanatical Fever", 234, Rarity.UNCOMMON, mage.cards.f.FanaticalFever.class)); + cards.add(new SetCardInfo("Fear", 124, Rarity.COMMON, mage.cards.f.Fear.class)); + cards.add(new SetCardInfo("Fiery Justice", 288, Rarity.RARE, mage.cards.f.FieryJustice.class)); + cards.add(new SetCardInfo("Fire Covenant", 289, Rarity.UNCOMMON, mage.cards.f.FireCovenant.class)); + cards.add(new SetCardInfo("Flame Spirit", 184, Rarity.UNCOMMON, mage.cards.f.FlameSpirit.class)); + cards.add(new SetCardInfo("Flare", 185, Rarity.COMMON, mage.cards.f.Flare.class)); + cards.add(new SetCardInfo("Flooded Woodlands", 290, Rarity.RARE, mage.cards.f.FloodedWoodlands.class)); + cards.add(new SetCardInfo("Flow of Maggots", 125, Rarity.RARE, mage.cards.f.FlowOfMaggots.class)); + cards.add(new SetCardInfo("Folk of the Pines", 235, Rarity.COMMON, mage.cards.f.FolkOfThePines.class)); + cards.add(new SetCardInfo("Forbidden Lore", 236, Rarity.RARE, mage.cards.f.ForbiddenLore.class)); + cards.add(new SetCardInfo("Force Void", 70, Rarity.UNCOMMON, mage.cards.f.ForceVoid.class)); + cards.add(new SetCardInfo("Forest", 380, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 381, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 382, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forgotten Lore", 237, Rarity.UNCOMMON, mage.cards.f.ForgottenLore.class)); + cards.add(new SetCardInfo("Formation", 25, Rarity.RARE, mage.cards.f.Formation.class)); + cards.add(new SetCardInfo("Foul Familiar", 126, Rarity.COMMON, mage.cards.f.FoulFamiliar.class)); + cards.add(new SetCardInfo("Foxfire", 238, Rarity.COMMON, mage.cards.f.Foxfire.class)); + cards.add(new SetCardInfo("Freyalise's Charm", 240, Rarity.UNCOMMON, mage.cards.f.FreyalisesCharm.class)); + cards.add(new SetCardInfo("Fumarole", 291, Rarity.UNCOMMON, mage.cards.f.Fumarole.class)); + cards.add(new SetCardInfo("Fyndhorn Bow", 318, Rarity.UNCOMMON, mage.cards.f.FyndhornBow.class)); + cards.add(new SetCardInfo("Fyndhorn Brownie", 242, Rarity.COMMON, mage.cards.f.FyndhornBrownie.class)); + cards.add(new SetCardInfo("Fyndhorn Elder", 243, Rarity.UNCOMMON, mage.cards.f.FyndhornElder.class)); + cards.add(new SetCardInfo("Fyndhorn Elves", 244, Rarity.COMMON, mage.cards.f.FyndhornElves.class)); + cards.add(new SetCardInfo("Fyndhorn Pollen", 245, Rarity.RARE, mage.cards.f.FyndhornPollen.class)); + cards.add(new SetCardInfo("Game of Chaos", 186, Rarity.RARE, mage.cards.g.GameOfChaos.class)); + cards.add(new SetCardInfo("Gangrenous Zombies", 127, Rarity.COMMON, mage.cards.g.GangrenousZombies.class)); + cards.add(new SetCardInfo("General Jarkeld", 27, Rarity.RARE, mage.cards.g.GeneralJarkeld.class)); + cards.add(new SetCardInfo("Giant Growth", 246, Rarity.COMMON, mage.cards.g.GiantGrowth.class)); + cards.add(new SetCardInfo("Giant Trap Door Spider", 293, Rarity.UNCOMMON, mage.cards.g.GiantTrapDoorSpider.class)); + cards.add(new SetCardInfo("Glacial Chasm", 353, Rarity.UNCOMMON, mage.cards.g.GlacialChasm.class)); + cards.add(new SetCardInfo("Glacial Crevasses", 187, Rarity.RARE, mage.cards.g.GlacialCrevasses.class)); + cards.add(new SetCardInfo("Glacial Wall", 71, Rarity.UNCOMMON, mage.cards.g.GlacialWall.class)); + cards.add(new SetCardInfo("Goblin Lyre", 319, Rarity.RARE, mage.cards.g.GoblinLyre.class)); + cards.add(new SetCardInfo("Goblin Mutant", 188, Rarity.UNCOMMON, mage.cards.g.GoblinMutant.class)); + cards.add(new SetCardInfo("Goblin Snowman", 191, Rarity.UNCOMMON, mage.cards.g.GoblinSnowman.class)); + cards.add(new SetCardInfo("Gorilla Pack", 247, Rarity.COMMON, mage.cards.g.GorillaPack.class)); + cards.add(new SetCardInfo("Gravebind", 129, Rarity.RARE, mage.cards.g.Gravebind.class)); + cards.add(new SetCardInfo("Green Scarab", 28, Rarity.UNCOMMON, mage.cards.g.GreenScarab.class)); + cards.add(new SetCardInfo("Hallowed Ground", 29, Rarity.UNCOMMON, mage.cards.h.HallowedGround.class)); + cards.add(new SetCardInfo("Halls of Mist", 354, Rarity.RARE, mage.cards.h.HallsOfMist.class)); + cards.add(new SetCardInfo("Heal", 30, Rarity.COMMON, mage.cards.h.Heal.class)); + cards.add(new SetCardInfo("Hecatomb", 130, Rarity.RARE, mage.cards.h.Hecatomb.class)); + cards.add(new SetCardInfo("Hematite Talisman", 320, Rarity.UNCOMMON, mage.cards.h.HematiteTalisman.class)); + cards.add(new SetCardInfo("Hoar Shade", 131, Rarity.COMMON, mage.cards.h.HoarShade.class)); + cards.add(new SetCardInfo("Hot Springs", 248, Rarity.RARE, mage.cards.h.HotSprings.class)); + cards.add(new SetCardInfo("Howl from Beyond", 132, Rarity.COMMON, mage.cards.h.HowlFromBeyond.class)); + cards.add(new SetCardInfo("Hurricane", 249, Rarity.UNCOMMON, mage.cards.h.Hurricane.class)); + cards.add(new SetCardInfo("Hyalopterous Lemure", 133, Rarity.UNCOMMON, mage.cards.h.HyalopterousLemure.class)); + cards.add(new SetCardInfo("Hydroblast", 72, Rarity.COMMON, mage.cards.h.Hydroblast.class)); + cards.add(new SetCardInfo("Hymn of Rebirth", 295, Rarity.UNCOMMON, mage.cards.h.HymnOfRebirth.class)); + cards.add(new SetCardInfo("Ice Cauldron", 321, Rarity.RARE, mage.cards.i.IceCauldron.class)); + cards.add(new SetCardInfo("Ice Floe", 355, Rarity.UNCOMMON, mage.cards.i.IceFloe.class)); + cards.add(new SetCardInfo("Iceberg", 73, Rarity.UNCOMMON, mage.cards.i.Iceberg.class)); + cards.add(new SetCardInfo("Icequake", 134, Rarity.UNCOMMON, mage.cards.i.Icequake.class)); + cards.add(new SetCardInfo("Icy Manipulator", 322, Rarity.UNCOMMON, mage.cards.i.IcyManipulator.class)); + cards.add(new SetCardInfo("Icy Prison", 74, Rarity.RARE, mage.cards.i.IcyPrison.class)); + cards.add(new SetCardInfo("Illusionary Forces", 75, Rarity.COMMON, mage.cards.i.IllusionaryForces.class)); + cards.add(new SetCardInfo("Illusionary Wall", 78, Rarity.COMMON, mage.cards.i.IllusionaryWall.class)); + cards.add(new SetCardInfo("Illusions of Grandeur", 79, Rarity.RARE, mage.cards.i.IllusionsOfGrandeur.class)); + cards.add(new SetCardInfo("Imposing Visage", 193, Rarity.COMMON, mage.cards.i.ImposingVisage.class)); + cards.add(new SetCardInfo("Incinerate", 194, Rarity.COMMON, mage.cards.i.Incinerate.class)); + cards.add(new SetCardInfo("Infernal Darkness", 135, Rarity.RARE, mage.cards.i.InfernalDarkness.class)); + cards.add(new SetCardInfo("Infernal Denizen", 136, Rarity.RARE, mage.cards.i.InfernalDenizen.class)); + cards.add(new SetCardInfo("Infinite Hourglass", 323, Rarity.RARE, mage.cards.i.InfiniteHourglass.class)); + cards.add(new SetCardInfo("Infuse", 80, Rarity.COMMON, mage.cards.i.Infuse.class)); + cards.add(new SetCardInfo("Island", 368, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 369, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 370, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jester's Cap", 324, Rarity.RARE, mage.cards.j.JestersCap.class)); + cards.add(new SetCardInfo("Jester's Mask", 325, Rarity.RARE, mage.cards.j.JestersMask.class)); + cards.add(new SetCardInfo("Jeweled Amulet", 326, Rarity.UNCOMMON, mage.cards.j.JeweledAmulet.class)); + cards.add(new SetCardInfo("Johtull Wurm", 250, Rarity.UNCOMMON, mage.cards.j.JohtullWurm.class)); + cards.add(new SetCardInfo("Jokulhaups", 195, Rarity.RARE, mage.cards.j.Jokulhaups.class)); + cards.add(new SetCardInfo("Juniper Order Druid", 251, Rarity.COMMON, mage.cards.j.JuniperOrderDruid.class)); + cards.add(new SetCardInfo("Justice", 32, Rarity.UNCOMMON, mage.cards.j.Justice.class)); + cards.add(new SetCardInfo("Karplusan Forest", 356, Rarity.RARE, mage.cards.k.KarplusanForest.class)); + cards.add(new SetCardInfo("Karplusan Giant", 196, Rarity.UNCOMMON, mage.cards.k.KarplusanGiant.class)); + cards.add(new SetCardInfo("Karplusan Yeti", 197, Rarity.RARE, mage.cards.k.KarplusanYeti.class)); + cards.add(new SetCardInfo("Kelsinko Ranger", 33, Rarity.COMMON, mage.cards.k.KelsinkoRanger.class)); + cards.add(new SetCardInfo("Kjeldoran Dead", 137, Rarity.COMMON, mage.cards.k.KjeldoranDead.class)); + cards.add(new SetCardInfo("Kjeldoran Frostbeast", 296, Rarity.UNCOMMON, mage.cards.k.KjeldoranFrostbeast.class)); + cards.add(new SetCardInfo("Kjeldoran Knight", 36, Rarity.RARE, mage.cards.k.KjeldoranKnight.class)); + cards.add(new SetCardInfo("Kjeldoran Phalanx", 37, Rarity.RARE, mage.cards.k.KjeldoranPhalanx.class)); + cards.add(new SetCardInfo("Kjeldoran Royal Guard", 38, Rarity.RARE, mage.cards.k.KjeldoranRoyalGuard.class)); + cards.add(new SetCardInfo("Kjeldoran Skycaptain", 39, Rarity.UNCOMMON, mage.cards.k.KjeldoranSkycaptain.class)); + cards.add(new SetCardInfo("Kjeldoran Skyknight", 40, Rarity.COMMON, mage.cards.k.KjeldoranSkyknight.class)); + cards.add(new SetCardInfo("Kjeldoran Warrior", 41, Rarity.COMMON, mage.cards.k.KjeldoranWarrior.class)); + cards.add(new SetCardInfo("Knight of Stromgald", 138, Rarity.UNCOMMON, mage.cards.k.KnightOfStromgald.class)); + cards.add(new SetCardInfo("Krovikan Elementalist", 139, Rarity.UNCOMMON, mage.cards.k.KrovikanElementalist.class)); + cards.add(new SetCardInfo("Krovikan Fetish", 140, Rarity.COMMON, mage.cards.k.KrovikanFetish.class)); + cards.add(new SetCardInfo("Krovikan Sorcerer", 81, Rarity.COMMON, mage.cards.k.KrovikanSorcerer.class)); + cards.add(new SetCardInfo("Land Cap", 357, Rarity.RARE, mage.cards.l.LandCap.class)); + cards.add(new SetCardInfo("Lapis Lazuli Talisman", 327, Rarity.UNCOMMON, mage.cards.l.LapisLazuliTalisman.class)); + cards.add(new SetCardInfo("Lava Tubes", 358, Rarity.RARE, mage.cards.l.LavaTubes.class)); + cards.add(new SetCardInfo("Legions of Lim-Dul", 142, Rarity.COMMON, mage.cards.l.LegionsOfLimDul.class)); + cards.add(new SetCardInfo("Leshrac's Rite", 143, Rarity.UNCOMMON, mage.cards.l.LeshracsRite.class)); + cards.add(new SetCardInfo("Leshrac's Sigil", 144, Rarity.UNCOMMON, mage.cards.l.LeshracsSigil.class)); + cards.add(new SetCardInfo("Lhurgoyf", 252, Rarity.RARE, mage.cards.l.Lhurgoyf.class)); + cards.add(new SetCardInfo("Lightning Blow", 42, Rarity.RARE, mage.cards.l.LightningBlow.class)); + cards.add(new SetCardInfo("Lim-Dul's Hex", 146, Rarity.UNCOMMON, mage.cards.l.LimDulsHex.class)); + cards.add(new SetCardInfo("Lure", 253, Rarity.UNCOMMON, mage.cards.l.Lure.class)); + cards.add(new SetCardInfo("Magus of the Unseen", 82, Rarity.RARE, mage.cards.m.MagusOfTheUnseen.class)); + cards.add(new SetCardInfo("Malachite Talisman", 328, Rarity.UNCOMMON, mage.cards.m.MalachiteTalisman.class)); + cards.add(new SetCardInfo("Marton Stromgald", 199, Rarity.RARE, mage.cards.m.MartonStromgald.class)); + cards.add(new SetCardInfo("Melee", 200, Rarity.UNCOMMON, mage.cards.m.Melee.class)); + cards.add(new SetCardInfo("Melting", 201, Rarity.UNCOMMON, mage.cards.m.Melting.class)); + cards.add(new SetCardInfo("Merieke Ri Berit", 297, Rarity.RARE, mage.cards.m.MeriekeRiBerit.class)); + cards.add(new SetCardInfo("Mesmeric Trance", 83, Rarity.RARE, mage.cards.m.MesmericTrance.class)); + cards.add(new SetCardInfo("Meteor Shower", 202, Rarity.COMMON, mage.cards.m.MeteorShower.class)); + cards.add(new SetCardInfo("Mind Ravel", 147, Rarity.COMMON, mage.cards.m.MindRavel.class)); + cards.add(new SetCardInfo("Mind Warp", 148, Rarity.UNCOMMON, mage.cards.m.MindWarp.class)); + cards.add(new SetCardInfo("Minion of Leshrac", 150, Rarity.RARE, mage.cards.m.MinionOfLeshrac.class)); + cards.add(new SetCardInfo("Minion of Tevesh Szat", 151, Rarity.RARE, mage.cards.m.MinionOfTeveshSzat.class)); + cards.add(new SetCardInfo("Mistfolk", 84, Rarity.COMMON, mage.cards.m.Mistfolk.class)); + cards.add(new SetCardInfo("Mole Worms", 152, Rarity.UNCOMMON, mage.cards.m.MoleWorms.class)); + cards.add(new SetCardInfo("Monsoon", 298, Rarity.RARE, mage.cards.m.Monsoon.class)); + cards.add(new SetCardInfo("Moor Fiend", 153, Rarity.COMMON, mage.cards.m.MoorFiend.class)); + cards.add(new SetCardInfo("Mountain Goat", 203, Rarity.COMMON, mage.cards.m.MountainGoat.class)); + cards.add(new SetCardInfo("Mountain Titan", 299, Rarity.RARE, mage.cards.m.MountainTitan.class)); + cards.add(new SetCardInfo("Mountain", 376, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 377, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 378, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mudslide", 204, Rarity.RARE, mage.cards.m.Mudslide.class)); + cards.add(new SetCardInfo("Mystic Might", 86, Rarity.RARE, mage.cards.m.MysticMight.class)); + cards.add(new SetCardInfo("Mystic Remora", 87, Rarity.COMMON, mage.cards.m.MysticRemora.class)); + cards.add(new SetCardInfo("Nacre Talisman", 329, Rarity.UNCOMMON, mage.cards.n.NacreTalisman.class)); + cards.add(new SetCardInfo("Naked Singularity", 330, Rarity.RARE, mage.cards.n.NakedSingularity.class)); + cards.add(new SetCardInfo("Nature's Lore", 255, Rarity.UNCOMMON, mage.cards.n.NaturesLore.class)); + cards.add(new SetCardInfo("Necropotence", 154, Rarity.RARE, mage.cards.n.Necropotence.class)); + cards.add(new SetCardInfo("Norritt", 155, Rarity.COMMON, mage.cards.n.Norritt.class)); + cards.add(new SetCardInfo("Onyx Talisman", 331, Rarity.UNCOMMON, mage.cards.o.OnyxTalisman.class)); + cards.add(new SetCardInfo("Orcish Cannoneers", 205, Rarity.UNCOMMON, mage.cards.o.OrcishCannoneers.class)); + cards.add(new SetCardInfo("Orcish Healer", 208, Rarity.UNCOMMON, mage.cards.o.OrcishHealer.class)); + cards.add(new SetCardInfo("Orcish Librarian", 209, Rarity.RARE, mage.cards.o.OrcishLibrarian.class)); + cards.add(new SetCardInfo("Orcish Lumberjack", 210, Rarity.COMMON, mage.cards.o.OrcishLumberjack.class)); + cards.add(new SetCardInfo("Orcish Squatters", 211, Rarity.RARE, mage.cards.o.OrcishSquatters.class)); + cards.add(new SetCardInfo("Order of the Sacred Torch", 45, Rarity.RARE, mage.cards.o.OrderOfTheSacredTorch.class)); + cards.add(new SetCardInfo("Order of the White Shield", 46, Rarity.UNCOMMON, mage.cards.o.OrderOfTheWhiteShield.class)); + cards.add(new SetCardInfo("Pale Bears", 256, Rarity.RARE, mage.cards.p.PaleBears.class)); + cards.add(new SetCardInfo("Panic", 212, Rarity.COMMON, mage.cards.p.Panic.class)); + cards.add(new SetCardInfo("Pentagram of the Ages", 332, Rarity.RARE, mage.cards.p.PentagramOfTheAges.class)); + cards.add(new SetCardInfo("Pestilence Rats", 157, Rarity.COMMON, mage.cards.p.PestilenceRats.class)); + cards.add(new SetCardInfo("Pit Trap", 333, Rarity.UNCOMMON, mage.cards.p.PitTrap.class)); + cards.add(new SetCardInfo("Plains", 364, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 365, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 366, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Polar Kraken", 89, Rarity.RARE, mage.cards.p.PolarKraken.class)); + cards.add(new SetCardInfo("Portent", 90, Rarity.COMMON, mage.cards.p.Portent.class)); + cards.add(new SetCardInfo("Power Sink", 91, Rarity.COMMON, mage.cards.p.PowerSink.class)); + cards.add(new SetCardInfo("Pox", 158, Rarity.RARE, mage.cards.p.Pox.class)); + cards.add(new SetCardInfo("Prismatic Ward", 47, Rarity.COMMON, mage.cards.p.PrismaticWard.class)); + cards.add(new SetCardInfo("Pygmy Allosaurus", 257, Rarity.RARE, mage.cards.p.PygmyAllosaurus.class)); + cards.add(new SetCardInfo("Pyknite", 258, Rarity.COMMON, mage.cards.p.Pyknite.class)); + cards.add(new SetCardInfo("Pyroblast", 213, Rarity.COMMON, mage.cards.p.Pyroblast.class)); + cards.add(new SetCardInfo("Pyroclasm", 214, Rarity.UNCOMMON, mage.cards.p.Pyroclasm.class)); + cards.add(new SetCardInfo("Rally", 48, Rarity.COMMON, mage.cards.r.Rally.class)); + cards.add(new SetCardInfo("Ray of Command", 92, Rarity.COMMON, mage.cards.r.RayOfCommand.class)); + cards.add(new SetCardInfo("Ray of Erasure", 93, Rarity.COMMON, mage.cards.r.RayOfErasure.class)); + cards.add(new SetCardInfo("Reality Twist", 94, Rarity.RARE, mage.cards.r.RealityTwist.class)); + cards.add(new SetCardInfo("Reclamation", 300, Rarity.RARE, mage.cards.r.Reclamation.class)); + cards.add(new SetCardInfo("Red Scarab", 49, Rarity.UNCOMMON, mage.cards.r.RedScarab.class)); + cards.add(new SetCardInfo("Regeneration", 259, Rarity.COMMON, mage.cards.r.Regeneration.class)); + cards.add(new SetCardInfo("Rime Dryad", 260, Rarity.COMMON, mage.cards.r.RimeDryad.class)); + cards.add(new SetCardInfo("Ritual of Subdual", 261, Rarity.RARE, mage.cards.r.RitualOfSubdual.class)); + cards.add(new SetCardInfo("River Delta", 359, Rarity.RARE, mage.cards.r.RiverDelta.class)); + cards.add(new SetCardInfo("Runed Arch", 334, Rarity.RARE, mage.cards.r.RunedArch.class)); + cards.add(new SetCardInfo("Sabretooth Tiger", 215, Rarity.COMMON, mage.cards.s.SabretoothTiger.class)); + cards.add(new SetCardInfo("Scaled Wurm", 262, Rarity.COMMON, mage.cards.s.ScaledWurm.class)); + cards.add(new SetCardInfo("Sea Spirit", 95, Rarity.UNCOMMON, mage.cards.s.SeaSpirit.class)); + cards.add(new SetCardInfo("Seizures", 159, Rarity.COMMON, mage.cards.s.Seizures.class)); + cards.add(new SetCardInfo("Shambling Strider", 263, Rarity.COMMON, mage.cards.s.ShamblingStrider.class)); + cards.add(new SetCardInfo("Shatter", 216, Rarity.COMMON, mage.cards.s.Shatter.class)); + cards.add(new SetCardInfo("Shield Bearer", 52, Rarity.COMMON, mage.cards.s.ShieldBearer.class)); + cards.add(new SetCardInfo("Shield of the Ages", 335, Rarity.UNCOMMON, mage.cards.s.ShieldOfTheAges.class)); + cards.add(new SetCardInfo("Shyft", 96, Rarity.RARE, mage.cards.s.Shyft.class)); + cards.add(new SetCardInfo("Sibilant Spirit", 97, Rarity.RARE, mage.cards.s.SibilantSpirit.class)); + cards.add(new SetCardInfo("Silver Erne", 98, Rarity.UNCOMMON, mage.cards.s.SilverErne.class)); + cards.add(new SetCardInfo("Skeleton Ship", 301, Rarity.RARE, mage.cards.s.SkeletonShip.class)); + cards.add(new SetCardInfo("Skull Catapult", 336, Rarity.UNCOMMON, mage.cards.s.SkullCatapult.class)); + cards.add(new SetCardInfo("Snow Fortress", 337, Rarity.RARE, mage.cards.s.SnowFortress.class)); + cards.add(new SetCardInfo("Snow Hound", 53, Rarity.UNCOMMON, mage.cards.s.SnowHound.class)); + cards.add(new SetCardInfo("Snow-Covered Forest", 383, Rarity.LAND, mage.cards.s.SnowCoveredForest.class)); + cards.add(new SetCardInfo("Snow-Covered Island", 371, Rarity.LAND, mage.cards.s.SnowCoveredIsland.class)); + cards.add(new SetCardInfo("Snow-Covered Mountain", 379, Rarity.LAND, mage.cards.s.SnowCoveredMountain.class)); + cards.add(new SetCardInfo("Snow-Covered Plains", 367, Rarity.LAND, mage.cards.s.SnowCoveredPlains.class)); + cards.add(new SetCardInfo("Snow-Covered Swamp", 372, Rarity.LAND, mage.cards.s.SnowCoveredSwamp.class)); + cards.add(new SetCardInfo("Soldevi Golem", 338, Rarity.RARE, mage.cards.s.SoldeviGolem.class)); + cards.add(new SetCardInfo("Soldevi Machinist", 102, Rarity.UNCOMMON, mage.cards.s.SoldeviMachinist.class)); + cards.add(new SetCardInfo("Soldevi Simulacrum", 339, Rarity.UNCOMMON, mage.cards.s.SoldeviSimulacrum.class)); + cards.add(new SetCardInfo("Songs of the Damned", 160, Rarity.COMMON, mage.cards.s.SongsOfTheDamned.class)); + cards.add(new SetCardInfo("Soul Barrier", 103, Rarity.UNCOMMON, mage.cards.s.SoulBarrier.class)); + cards.add(new SetCardInfo("Soul Burn", 161, Rarity.COMMON, mage.cards.s.SoulBurn.class)); + cards.add(new SetCardInfo("Soul Kiss", 162, Rarity.COMMON, mage.cards.s.SoulKiss.class)); + cards.add(new SetCardInfo("Spoils of Evil", 163, Rarity.RARE, mage.cards.s.SpoilsOfEvil.class)); + cards.add(new SetCardInfo("Staff of the Ages", 340, Rarity.RARE, mage.cards.s.StaffOfTheAges.class)); + cards.add(new SetCardInfo("Stampede", 265, Rarity.RARE, mage.cards.s.Stampede.class)); + cards.add(new SetCardInfo("Stone Rain", 217, Rarity.COMMON, mage.cards.s.StoneRain.class)); + cards.add(new SetCardInfo("Stone Spirit", 218, Rarity.UNCOMMON, mage.cards.s.StoneSpirit.class)); + cards.add(new SetCardInfo("Stonehands", 219, Rarity.COMMON, mage.cards.s.Stonehands.class)); + cards.add(new SetCardInfo("Storm Spirit", 303, Rarity.RARE, mage.cards.s.StormSpirit.class)); + cards.add(new SetCardInfo("Stormbind", 304, Rarity.RARE, mage.cards.s.Stormbind.class)); + cards.add(new SetCardInfo("Stromgald Cabal", 166, Rarity.RARE, mage.cards.s.StromgaldCabal.class)); + cards.add(new SetCardInfo("Stunted Growth", 266, Rarity.RARE, mage.cards.s.StuntedGrowth.class)); + cards.add(new SetCardInfo("Sulfurous Springs", 360, Rarity.RARE, mage.cards.s.SulfurousSprings.class)); + cards.add(new SetCardInfo("Sunstone", 341, Rarity.UNCOMMON, mage.cards.s.Sunstone.class)); + cards.add(new SetCardInfo("Swamp", 373, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 374, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 375, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swords to Plowshares", 54, Rarity.UNCOMMON, mage.cards.s.SwordsToPlowshares.class)); + cards.add(new SetCardInfo("Tarpan", 267, Rarity.COMMON, mage.cards.t.Tarpan.class)); + cards.add(new SetCardInfo("Thermokarst", 268, Rarity.UNCOMMON, mage.cards.t.Thermokarst.class)); + cards.add(new SetCardInfo("Thoughtleech", 269, Rarity.UNCOMMON, mage.cards.t.Thoughtleech.class)); + cards.add(new SetCardInfo("Thunder Wall", 104, Rarity.UNCOMMON, mage.cards.t.ThunderWall.class)); + cards.add(new SetCardInfo("Timberline Ridge", 361, Rarity.RARE, mage.cards.t.TimberlineRidge.class)); + cards.add(new SetCardInfo("Time Bomb", 342, Rarity.RARE, mage.cards.t.TimeBomb.class)); + cards.add(new SetCardInfo("Tinder Wall", 270, Rarity.COMMON, mage.cards.t.TinderWall.class)); + cards.add(new SetCardInfo("Tor Giant", 220, Rarity.COMMON, mage.cards.t.TorGiant.class)); + cards.add(new SetCardInfo("Total War", 221, Rarity.RARE, mage.cards.t.TotalWar.class)); + cards.add(new SetCardInfo("Touch of Death", 167, Rarity.COMMON, mage.cards.t.TouchOfDeath.class)); + cards.add(new SetCardInfo("Trailblazer", 272, Rarity.RARE, mage.cards.t.Trailblazer.class)); + cards.add(new SetCardInfo("Underground River", 362, Rarity.RARE, mage.cards.u.UndergroundRiver.class)); + cards.add(new SetCardInfo("Updraft", 105, Rarity.UNCOMMON, mage.cards.u.Updraft.class)); + cards.add(new SetCardInfo("Urza's Bauble", 343, Rarity.UNCOMMON, mage.cards.u.UrzasBauble.class)); + cards.add(new SetCardInfo("Veldt", 363, Rarity.RARE, mage.cards.v.Veldt.class)); + cards.add(new SetCardInfo("Venomous Breath", 273, Rarity.UNCOMMON, mage.cards.v.VenomousBreath.class)); + cards.add(new SetCardInfo("Vertigo", 222, Rarity.UNCOMMON, mage.cards.v.Vertigo.class)); + cards.add(new SetCardInfo("Vexing Arcanix", 344, Rarity.RARE, mage.cards.v.VexingArcanix.class)); + cards.add(new SetCardInfo("Vibrating Sphere", 345, Rarity.RARE, mage.cards.v.VibratingSphere.class)); + cards.add(new SetCardInfo("Walking Wall", 346, Rarity.UNCOMMON, mage.cards.w.WalkingWall.class)); + cards.add(new SetCardInfo("Wall of Lava", 223, Rarity.UNCOMMON, mage.cards.w.WallOfLava.class)); + cards.add(new SetCardInfo("Wall of Pine Needles", 274, Rarity.UNCOMMON, mage.cards.w.WallOfPineNeedles.class)); + cards.add(new SetCardInfo("Wall of Shields", 347, Rarity.UNCOMMON, mage.cards.w.WallOfShields.class)); + cards.add(new SetCardInfo("War Chariot", 348, Rarity.UNCOMMON, mage.cards.w.WarChariot.class)); + cards.add(new SetCardInfo("Warning", 55, Rarity.COMMON, mage.cards.w.Warning.class)); + cards.add(new SetCardInfo("Whalebone Glider", 349, Rarity.UNCOMMON, mage.cards.w.WhaleboneGlider.class)); + cards.add(new SetCardInfo("White Scarab", 56, Rarity.UNCOMMON, mage.cards.w.WhiteScarab.class)); + cards.add(new SetCardInfo("Whiteout", 275, Rarity.UNCOMMON, mage.cards.w.Whiteout.class)); + cards.add(new SetCardInfo("Wild Growth", 277, Rarity.COMMON, mage.cards.w.WildGrowth.class)); + cards.add(new SetCardInfo("Wind Spirit", 106, Rarity.UNCOMMON, mage.cards.w.WindSpirit.class)); + cards.add(new SetCardInfo("Wings of Aesthir", 305, Rarity.UNCOMMON, mage.cards.w.WingsOfAesthir.class)); + cards.add(new SetCardInfo("Withering Wisps", 168, Rarity.UNCOMMON, mage.cards.w.WitheringWisps.class)); + cards.add(new SetCardInfo("Woolly Mammoths", 278, Rarity.COMMON, mage.cards.w.WoollyMammoths.class)); + cards.add(new SetCardInfo("Woolly Spider", 279, Rarity.COMMON, mage.cards.w.WoollySpider.class)); + cards.add(new SetCardInfo("Word of Blasting", 224, Rarity.UNCOMMON, mage.cards.w.WordOfBlasting.class)); + cards.add(new SetCardInfo("Word of Undoing", 108, Rarity.COMMON, mage.cards.w.WordOfUndoing.class)); + cards.add(new SetCardInfo("Wrath of Marit Lage", 109, Rarity.RARE, mage.cards.w.WrathOfMaritLage.class)); + cards.add(new SetCardInfo("Yavimaya Gnats", 280, Rarity.UNCOMMON, mage.cards.y.YavimayaGnats.class)); + cards.add(new SetCardInfo("Zur's Weirding", 110, Rarity.RARE, mage.cards.z.ZursWeirding.class)); + cards.add(new SetCardInfo("Zuran Enchanter", 111, Rarity.COMMON, mage.cards.z.ZuranEnchanter.class)); + cards.add(new SetCardInfo("Zuran Orb", 350, Rarity.UNCOMMON, mage.cards.z.ZuranOrb.class)); + cards.add(new SetCardInfo("Zuran Spellcaster", 112, Rarity.COMMON, mage.cards.z.ZuranSpellcaster.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/Legends.java b/Mage.Sets/src/mage/sets/Legends.java index 68a33d49747..134bb3b75cb 100644 --- a/Mage.Sets/src/mage/sets/Legends.java +++ b/Mage.Sets/src/mage/sets/Legends.java @@ -29,6 +29,7 @@ public final class Legends extends ExpansionSet { cards.add(new SetCardInfo("Acid Rain", 44, Rarity.RARE, mage.cards.a.AcidRain.class)); cards.add(new SetCardInfo("Active Volcano", 130, Rarity.COMMON, mage.cards.a.ActiveVolcano.class)); cards.add(new SetCardInfo("Adun Oakenshield", 216, Rarity.RARE, mage.cards.a.AdunOakenshield.class)); + cards.add(new SetCardInfo("Adventurers' Guildhouse", 300, Rarity.UNCOMMON, mage.cards.a.AdventurersGuildhouse.class)); cards.add(new SetCardInfo("Aerathi Berserker", 131, Rarity.UNCOMMON, mage.cards.a.AerathiBerserker.class)); cards.add(new SetCardInfo("Aisling Leprechaun", 173, Rarity.COMMON, mage.cards.a.AislingLeprechaun.class)); cards.add(new SetCardInfo("Akron Legionnaire", 1, Rarity.RARE, mage.cards.a.AkronLegionnaire.class)); @@ -58,8 +59,10 @@ public final class Legends extends ExpansionSet { cards.add(new SetCardInfo("Blue Mana Battery", 275, Rarity.UNCOMMON, mage.cards.b.BlueManaBattery.class)); cards.add(new SetCardInfo("Boomerang", 48, Rarity.COMMON, mage.cards.b.Boomerang.class)); cards.add(new SetCardInfo("Boris Devilboon", 223, Rarity.RARE, mage.cards.b.BorisDevilboon.class)); + cards.add(new SetCardInfo("Bronze Horse", 276, Rarity.RARE, mage.cards.b.BronzeHorse.class)); cards.add(new SetCardInfo("Carrion Ants", 90, Rarity.RARE, mage.cards.c.CarrionAnts.class)); cards.add(new SetCardInfo("Cat Warriors", 177, Rarity.COMMON, mage.cards.c.CatWarriors.class)); + cards.add(new SetCardInfo("Cathedral of Serra", 301, Rarity.UNCOMMON, mage.cards.c.CathedralOfSerra.class)); cards.add(new SetCardInfo("Caverns of Despair", 136, Rarity.RARE, mage.cards.c.CavernsOfDespair.class)); cards.add(new SetCardInfo("Chain Lightning", 137, Rarity.COMMON, mage.cards.c.ChainLightning.class)); cards.add(new SetCardInfo("Chains of Mephistopheles", 91, Rarity.RARE, mage.cards.c.ChainsOfMephistopheles.class)); @@ -88,8 +91,10 @@ public final class Legends extends ExpansionSet { cards.add(new SetCardInfo("Durkwood Boars", 182, Rarity.COMMON, mage.cards.d.DurkwoodBoars.class)); cards.add(new SetCardInfo("Dwarven Song", 143, Rarity.UNCOMMON, mage.cards.d.DwarvenSong.class)); cards.add(new SetCardInfo("Elder Land Wurm", 11, Rarity.RARE, mage.cards.e.ElderLandWurm.class)); + cards.add(new SetCardInfo("Elder Spawn", 52, Rarity.RARE, mage.cards.e.ElderSpawn.class)); cards.add(new SetCardInfo("Elven Riders", 183, Rarity.RARE, mage.cards.e.ElvenRiders.class)); cards.add(new SetCardInfo("Emerald Dragonfly", 184, Rarity.COMMON, mage.cards.e.EmeraldDragonfly.class)); + cards.add(new SetCardInfo("Enchanted Being", 12, Rarity.COMMON, mage.cards.e.EnchantedBeing.class)); cards.add(new SetCardInfo("Enchantment Alteration", 53, Rarity.COMMON, mage.cards.e.EnchantmentAlteration.class)); cards.add(new SetCardInfo("Energy Tap", 54, Rarity.COMMON, mage.cards.e.EnergyTap.class)); cards.add(new SetCardInfo("Eternal Warrior", 144, Rarity.UNCOMMON, mage.cards.e.EternalWarrior.class)); @@ -102,6 +107,7 @@ public final class Legends extends ExpansionSet { cards.add(new SetCardInfo("Flash Flood", 57, Rarity.COMMON, mage.cards.f.FlashFlood.class)); cards.add(new SetCardInfo("Floral Spuzzem", 187, Rarity.UNCOMMON, mage.cards.f.FloralSpuzzem.class)); cards.add(new SetCardInfo("Force Spike", 58, Rarity.COMMON, mage.cards.f.ForceSpike.class)); + cards.add(new SetCardInfo("Forethought Amulet", 277, Rarity.RARE, mage.cards.f.ForethoughtAmulet.class)); cards.add(new SetCardInfo("Fortified Area", 14, Rarity.UNCOMMON, mage.cards.f.FortifiedArea.class)); cards.add(new SetCardInfo("Frost Giant", 148, Rarity.UNCOMMON, mage.cards.f.FrostGiant.class)); cards.add(new SetCardInfo("Gabriel Angelfire", 226, Rarity.RARE, mage.cards.g.GabrielAngelfire.class)); @@ -159,6 +165,7 @@ public final class Legends extends ExpansionSet { cards.add(new SetCardInfo("Kobold Overlord", 155, Rarity.RARE, mage.cards.k.KoboldOverlord.class)); cards.add(new SetCardInfo("Kobold Taskmaster", 156, Rarity.UNCOMMON, mage.cards.k.KoboldTaskmaster.class)); cards.add(new SetCardInfo("Kobolds of Kher Keep", 157, Rarity.COMMON, mage.cards.k.KoboldsOfKherKeep.class)); + cards.add(new SetCardInfo("Kry Shield", 282, Rarity.UNCOMMON, mage.cards.k.KryShield.class)); cards.add(new SetCardInfo("Lady Caleria", 239, Rarity.RARE, mage.cards.l.LadyCaleria.class)); cards.add(new SetCardInfo("Lady Evangela", 240, Rarity.RARE, mage.cards.l.LadyEvangela.class)); cards.add(new SetCardInfo("Lady Orca", 241, Rarity.UNCOMMON, mage.cards.l.LadyOrca.class)); @@ -175,10 +182,12 @@ public final class Legends extends ExpansionSet { cards.add(new SetCardInfo("Mana Matrix", 285, Rarity.RARE, mage.cards.m.ManaMatrix.class)); cards.add(new SetCardInfo("Marble Priest", 286, Rarity.UNCOMMON, mage.cards.m.MarblePriest.class)); cards.add(new SetCardInfo("Marhault Elsdragon", 244, Rarity.UNCOMMON, mage.cards.m.MarhaultElsdragon.class)); + cards.add(new SetCardInfo("Master of the Hunt", 194, Rarity.RARE, mage.cards.m.MasterOfTheHunt.class)); cards.add(new SetCardInfo("Mirror Universe", 287, Rarity.RARE, mage.cards.m.MirrorUniverse.class)); cards.add(new SetCardInfo("Moat", 28, Rarity.RARE, mage.cards.m.Moat.class)); cards.add(new SetCardInfo("Mold Demon", 112, Rarity.RARE, mage.cards.m.MoldDemon.class)); cards.add(new SetCardInfo("Moss Monster", 195, Rarity.COMMON, mage.cards.m.MossMonster.class)); + cards.add(new SetCardInfo("Mountain Stronghold", 304, Rarity.UNCOMMON, mage.cards.m.MountainStronghold.class)); cards.add(new SetCardInfo("Mountain Yeti", 159, Rarity.UNCOMMON, mage.cards.m.MountainYeti.class)); cards.add(new SetCardInfo("Nebuchadnezzar", 245, Rarity.RARE, mage.cards.n.Nebuchadnezzar.class)); cards.add(new SetCardInfo("Nether Void", 113, Rarity.RARE, mage.cards.n.NetherVoid.class)); @@ -217,6 +226,7 @@ public final class Legends extends ExpansionSet { cards.add(new SetCardInfo("Remove Soul", 72, Rarity.COMMON, mage.cards.r.RemoveSoul.class)); cards.add(new SetCardInfo("Reset", 73, Rarity.UNCOMMON, mage.cards.r.Reset.class)); cards.add(new SetCardInfo("Revelation", 202, Rarity.RARE, mage.cards.r.Revelation.class)); + cards.add(new SetCardInfo("Reverberation", 74, Rarity.RARE, mage.cards.r.Reverberation.class)); cards.add(new SetCardInfo("Righteous Avengers", 34, Rarity.UNCOMMON, mage.cards.r.RighteousAvengers.class)); cards.add(new SetCardInfo("Ring of Immortals", 293, Rarity.RARE, mage.cards.r.RingOfImmortals.class)); cards.add(new SetCardInfo("Riven Turnbull", 254, Rarity.UNCOMMON, mage.cards.r.RivenTurnbull.class)); @@ -224,10 +234,12 @@ public final class Legends extends ExpansionSet { cards.add(new SetCardInfo("Rubinia Soulsinger", 256, Rarity.RARE, mage.cards.r.RubiniaSoulsinger.class)); cards.add(new SetCardInfo("Rust", 203, Rarity.COMMON, mage.cards.r.Rust.class)); cards.add(new SetCardInfo("Sea Kings' Blessing", 75, Rarity.UNCOMMON, mage.cards.s.SeaKingsBlessing.class)); + cards.add(new SetCardInfo("Seafarer's Quay", 306, Rarity.UNCOMMON, mage.cards.s.SeafarersQuay.class)); cards.add(new SetCardInfo("Seeker", 35, Rarity.UNCOMMON, mage.cards.s.Seeker.class)); cards.add(new SetCardInfo("Segovian Leviathan", 76, Rarity.UNCOMMON, mage.cards.s.SegovianLeviathan.class)); cards.add(new SetCardInfo("Sentinel", 294, Rarity.RARE, mage.cards.s.Sentinel.class)); cards.add(new SetCardInfo("Serpent Generator", 295, Rarity.RARE, mage.cards.s.SerpentGenerator.class)); + cards.add(new SetCardInfo("Shelkin Brownie", 204, Rarity.COMMON, mage.cards.s.ShelkinBrownie.class)); cards.add(new SetCardInfo("Shield Wall", 36, Rarity.UNCOMMON, mage.cards.s.ShieldWall.class)); cards.add(new SetCardInfo("Shimian Night Stalker", 116, Rarity.UNCOMMON, mage.cards.s.ShimianNightStalker.class)); cards.add(new SetCardInfo("Sir Shandlar of Eberyn", 257, Rarity.UNCOMMON, mage.cards.s.SirShandlarOfEberyn.class)); @@ -241,6 +253,7 @@ public final class Legends extends ExpansionSet { cards.add(new SetCardInfo("Stangg", 260, Rarity.RARE, mage.cards.s.Stangg.class)); cards.add(new SetCardInfo("Storm Seeker", 205, Rarity.UNCOMMON, mage.cards.s.StormSeeker.class)); cards.add(new SetCardInfo("Storm World", 165, Rarity.RARE, mage.cards.s.StormWorld.class)); + cards.add(new SetCardInfo("Subdue", 206, Rarity.COMMON, mage.cards.s.Subdue.class)); cards.add(new SetCardInfo("Sunastian Falconer", 261, Rarity.UNCOMMON, mage.cards.s.SunastianFalconer.class)); cards.add(new SetCardInfo("Sword of the Ages", 296, Rarity.RARE, mage.cards.s.SwordOfTheAges.class)); cards.add(new SetCardInfo("Sylvan Library", 207, Rarity.UNCOMMON, mage.cards.s.SylvanLibrary.class)); @@ -257,6 +270,7 @@ public final class Legends extends ExpansionSet { cards.add(new SetCardInfo("Thunder Spirit", 39, Rarity.RARE, mage.cards.t.ThunderSpirit.class)); cards.add(new SetCardInfo("Time Elemental", 81, Rarity.RARE, mage.cards.t.TimeElemental.class)); cards.add(new SetCardInfo("Tobias Andrion", 264, Rarity.UNCOMMON, mage.cards.t.TobiasAndrion.class)); + cards.add(new SetCardInfo("Tolaria", 308, Rarity.UNCOMMON, mage.cards.t.Tolaria.class)); cards.add(new SetCardInfo("Tor Wauki", 265, Rarity.UNCOMMON, mage.cards.t.TorWauki.class)); cards.add(new SetCardInfo("Torsten Von Ursus", 266, Rarity.UNCOMMON, mage.cards.t.TorstenVonUrsus.class)); cards.add(new SetCardInfo("Touch of Darkness", 122, Rarity.UNCOMMON, mage.cards.t.TouchOfDarkness.class)); @@ -266,6 +280,7 @@ public final class Legends extends ExpansionSet { cards.add(new SetCardInfo("Tundra Wolves", 40, Rarity.COMMON, mage.cards.t.TundraWolves.class)); cards.add(new SetCardInfo("Typhoon", 209, Rarity.RARE, mage.cards.t.Typhoon.class)); cards.add(new SetCardInfo("Undertow", 82, Rarity.UNCOMMON, mage.cards.u.Undertow.class)); + cards.add(new SetCardInfo("Unholy Citadel", 309, Rarity.UNCOMMON, mage.cards.u.UnholyCitadel.class)); cards.add(new SetCardInfo("Underworld Dreams", 124, Rarity.UNCOMMON, mage.cards.u.UnderworldDreams.class)); cards.add(new SetCardInfo("Untamed Wilds", 210, Rarity.UNCOMMON, mage.cards.u.UntamedWilds.class)); cards.add(new SetCardInfo("Ur-Drago", 268, Rarity.RARE, mage.cards.u.UrDrago.class)); @@ -281,6 +296,7 @@ public final class Legends extends ExpansionSet { cards.add(new SetCardInfo("Wall of Light", 43, Rarity.UNCOMMON, mage.cards.w.WallOfLight.class)); cards.add(new SetCardInfo("Wall of Opposition", 171, Rarity.RARE, mage.cards.w.WallOfOpposition.class)); cards.add(new SetCardInfo("Wall of Putrid Flesh", 127, Rarity.UNCOMMON, mage.cards.w.WallOfPutridFlesh.class)); + cards.add(new SetCardInfo("Wall of Tombstones", 129, Rarity.UNCOMMON, mage.cards.w.WallOfTombstones.class)); cards.add(new SetCardInfo("Wall of Vapor", 84, Rarity.COMMON, mage.cards.w.WallOfVapor.class)); cards.add(new SetCardInfo("Wall of Wonder", 85, Rarity.UNCOMMON, mage.cards.w.WallOfWonder.class)); cards.add(new SetCardInfo("Whirling Dervish", 211, Rarity.UNCOMMON, mage.cards.w.WhirlingDervish.class)); diff --git a/Mage.Sets/src/mage/sets/MastersEditionII.java b/Mage.Sets/src/mage/sets/MastersEditionII.java index 7002dff323a..00bafb192f1 100644 --- a/Mage.Sets/src/mage/sets/MastersEditionII.java +++ b/Mage.Sets/src/mage/sets/MastersEditionII.java @@ -1,258 +1,259 @@ - -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -/** - * @author LevelX2 - */ -public final class MastersEditionII extends ExpansionSet { - - private static final MastersEditionII instance = new MastersEditionII(); - - public static MastersEditionII getInstance() { - return instance; - } - - private MastersEditionII() { - super("Masters Edition II", "ME2", ExpansionSet.buildDate(2008, 9, 22), SetType.MAGIC_ONLINE); - this.hasBasicLands = true; - this.hasBoosters = true; - this.numBoosterLands = 1; - this.numBoosterCommon = 10; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - - cards.add(new SetCardInfo("Abbey Gargoyles", 1, Rarity.UNCOMMON, mage.cards.a.AbbeyGargoyles.class)); - cards.add(new SetCardInfo("Adarkar Sentinel", 201, Rarity.COMMON, mage.cards.a.AdarkarSentinel.class)); - cards.add(new SetCardInfo("Aeolipile", 202, Rarity.COMMON, mage.cards.a.Aeolipile.class)); - cards.add(new SetCardInfo("Aether Storm", 39, Rarity.UNCOMMON, mage.cards.a.AetherStorm.class)); - cards.add(new SetCardInfo("Ambush Party", 115, Rarity.COMMON, mage.cards.a.AmbushParty.class)); - cards.add(new SetCardInfo("An-Zerrin Ruins", 117, Rarity.RARE, mage.cards.a.AnZerrinRuins.class)); - cards.add(new SetCardInfo("Anarchy", 116, Rarity.RARE, mage.cards.a.Anarchy.class)); - cards.add(new SetCardInfo("Angel of Fury", 2, Rarity.RARE, mage.cards.a.AngelOfFury.class)); - cards.add(new SetCardInfo("Angel of Light", 3, Rarity.UNCOMMON, mage.cards.a.AngelOfLight.class)); - cards.add(new SetCardInfo("Armor of Faith", 4, Rarity.COMMON, mage.cards.a.ArmorOfFaith.class)); - cards.add(new SetCardInfo("Armor Thrull", 77, Rarity.COMMON, mage.cards.a.ArmorThrull.class)); - cards.add(new SetCardInfo("Armored Griffin", 5, Rarity.COMMON, mage.cards.a.ArmoredGriffin.class)); - cards.add(new SetCardInfo("Ashen Ghoul", 78, Rarity.UNCOMMON, mage.cards.a.AshenGhoul.class)); - cards.add(new SetCardInfo("Ashnod's Cylix", 203, Rarity.RARE, mage.cards.a.AshnodsCylix.class)); - cards.add(new SetCardInfo("Aurochs", 153, Rarity.COMMON, mage.cards.a.Aurochs.class)); - cards.add(new SetCardInfo("Aysen Bureaucrats", 6, Rarity.COMMON, mage.cards.a.AysenBureaucrats.class)); - cards.add(new SetCardInfo("Aysen Crusader", 7, Rarity.UNCOMMON, mage.cards.a.AysenCrusader.class)); - cards.add(new SetCardInfo("Badlands", 225, Rarity.RARE, mage.cards.b.Badlands.class)); - cards.add(new SetCardInfo("Balduvian Conjurer", 40, Rarity.COMMON, mage.cards.b.BalduvianConjurer.class)); - cards.add(new SetCardInfo("Balduvian Dead", 79, Rarity.UNCOMMON, mage.cards.b.BalduvianDead.class)); - cards.add(new SetCardInfo("Balduvian Hydra", 118, Rarity.RARE, mage.cards.b.BalduvianHydra.class)); - cards.add(new SetCardInfo("Balduvian Trading Post", 226, Rarity.RARE, mage.cards.b.BalduvianTradingPost.class)); - cards.add(new SetCardInfo("Barbed Sextant", 204, Rarity.COMMON, mage.cards.b.BarbedSextant.class)); - cards.add(new SetCardInfo("Binding Grasp", 41, Rarity.RARE, mage.cards.b.BindingGrasp.class)); - cards.add(new SetCardInfo("Bounty of the Hunt", 154, Rarity.RARE, mage.cards.b.BountyOfTheHunt.class)); - cards.add(new SetCardInfo("Brainstorm", 42, Rarity.COMMON, mage.cards.b.Brainstorm.class)); - cards.add(new SetCardInfo("Brassclaw Orcs", 119, Rarity.COMMON, mage.cards.b.BrassclawOrcs.class)); - cards.add(new SetCardInfo("Brimstone Dragon", 120, Rarity.RARE, mage.cards.b.BrimstoneDragon.class)); - cards.add(new SetCardInfo("Brine Shaman", 80, Rarity.COMMON, mage.cards.b.BrineShaman.class)); - cards.add(new SetCardInfo("Broken Visage", 81, Rarity.UNCOMMON, mage.cards.b.BrokenVisage.class)); - cards.add(new SetCardInfo("Browse", 43, Rarity.UNCOMMON, mage.cards.b.Browse.class)); - cards.add(new SetCardInfo("Burnout", 121, Rarity.UNCOMMON, mage.cards.b.Burnout.class)); - cards.add(new SetCardInfo("Carapace", 155, Rarity.COMMON, mage.cards.c.Carapace.class)); - cards.add(new SetCardInfo("Caribou Range", 8, Rarity.RARE, mage.cards.c.CaribouRange.class)); - cards.add(new SetCardInfo("Clockwork Steed", 205, Rarity.UNCOMMON, mage.cards.c.ClockworkSteed.class)); - cards.add(new SetCardInfo("Combat Medic", 9, Rarity.COMMON, mage.cards.c.CombatMedic.class)); - cards.add(new SetCardInfo("Conquer", 122, Rarity.UNCOMMON, mage.cards.c.Conquer.class)); - cards.add(new SetCardInfo("Counterspell", 44, Rarity.UNCOMMON, mage.cards.c.Counterspell.class)); - cards.add(new SetCardInfo("Dance of the Dead", 83, Rarity.UNCOMMON, mage.cards.d.DanceOfTheDead.class)); - cards.add(new SetCardInfo("Dark Banishing", 84, Rarity.COMMON, mage.cards.d.DarkBanishing.class)); - cards.add(new SetCardInfo("Death Spark", 123, Rarity.COMMON, mage.cards.d.DeathSpark.class)); - cards.add(new SetCardInfo("Deep Spawn", 45, Rarity.RARE, mage.cards.d.DeepSpawn.class)); - cards.add(new SetCardInfo("Demonic Consultation", 85, Rarity.UNCOMMON, mage.cards.d.DemonicConsultation.class)); - cards.add(new SetCardInfo("Despotic Scepter", 206, Rarity.RARE, mage.cards.d.DespoticScepter.class)); - cards.add(new SetCardInfo("Diabolic Vision", 191, Rarity.UNCOMMON, mage.cards.d.DiabolicVision.class)); - cards.add(new SetCardInfo("Disenchant", 10, Rarity.COMMON, mage.cards.d.Disenchant.class)); - cards.add(new SetCardInfo("Dreams of the Dead", 46, Rarity.RARE, mage.cards.d.DreamsOfTheDead.class)); - cards.add(new SetCardInfo("Drift of the Dead", 86, Rarity.COMMON, mage.cards.d.DriftOfTheDead.class)); - cards.add(new SetCardInfo("Dry Spell", 87, Rarity.COMMON, mage.cards.d.DrySpell.class)); - cards.add(new SetCardInfo("Dwarven Ruins", 227, Rarity.UNCOMMON, mage.cards.d.DwarvenRuins.class)); - cards.add(new SetCardInfo("Dystopia", 88, Rarity.RARE, mage.cards.d.Dystopia.class)); - cards.add(new SetCardInfo("Earthlink", 192, Rarity.RARE, mage.cards.e.Earthlink.class)); - cards.add(new SetCardInfo("Ebon Praetor", 89, Rarity.RARE, mage.cards.e.EbonPraetor.class)); - cards.add(new SetCardInfo("Ebon Stronghold", 228, Rarity.UNCOMMON, mage.cards.e.EbonStronghold.class)); - cards.add(new SetCardInfo("Elemental Augury", 193, Rarity.RARE, mage.cards.e.ElementalAugury.class)); - cards.add(new SetCardInfo("Elkin Bottle", 207, Rarity.RARE, mage.cards.e.ElkinBottle.class)); - cards.add(new SetCardInfo("Elven Lyre", 208, Rarity.COMMON, mage.cards.e.ElvenLyre.class)); - cards.add(new SetCardInfo("Elvish Farmer", 156, Rarity.RARE, mage.cards.e.ElvishFarmer.class)); - cards.add(new SetCardInfo("Elvish Hunter", 157, Rarity.COMMON, mage.cards.e.ElvishHunter.class)); - cards.add(new SetCardInfo("Elvish Ranger", 158, Rarity.COMMON, mage.cards.e.ElvishRanger.class)); - cards.add(new SetCardInfo("Elvish Spirit Guide", 159, Rarity.UNCOMMON, mage.cards.e.ElvishSpiritGuide.class)); - cards.add(new SetCardInfo("Energy Storm", 11, Rarity.RARE, mage.cards.e.EnergyStorm.class)); - cards.add(new SetCardInfo("Enervate", 47, Rarity.COMMON, mage.cards.e.Enervate.class)); - cards.add(new SetCardInfo("Errand of Duty", 12, Rarity.UNCOMMON, mage.cards.e.ErrandOfDuty.class)); - cards.add(new SetCardInfo("Errantry", 124, Rarity.COMMON, mage.cards.e.Errantry.class)); - cards.add(new SetCardInfo("Essence Filter", 160, Rarity.UNCOMMON, mage.cards.e.EssenceFilter.class)); - cards.add(new SetCardInfo("Essence Flare", 48, Rarity.COMMON, mage.cards.e.EssenceFlare.class)); - cards.add(new SetCardInfo("Farrel's Mantle", 13, Rarity.UNCOMMON, mage.cards.f.FarrelsMantle.class)); - cards.add(new SetCardInfo("Farrel's Zealot", 14, Rarity.UNCOMMON, mage.cards.f.FarrelsZealot.class)); - cards.add(new SetCardInfo("Feral Thallid", 161, Rarity.COMMON, mage.cards.f.FeralThallid.class)); - cards.add(new SetCardInfo("Fire Dragon", 125, Rarity.RARE, mage.cards.f.FireDragon.class)); - cards.add(new SetCardInfo("Flame Spirit", 126, Rarity.UNCOMMON, mage.cards.f.FlameSpirit.class)); - cards.add(new SetCardInfo("Folk of the Pines", 162, Rarity.COMMON, mage.cards.f.FolkOfThePines.class)); - cards.add(new SetCardInfo("Forbidden Lore", 163, Rarity.UNCOMMON, mage.cards.f.ForbiddenLore.class)); - cards.add(new SetCardInfo("Forgotten Lore", 164, Rarity.UNCOMMON, mage.cards.f.ForgottenLore.class)); - cards.add(new SetCardInfo("Foul Familiar", 90, Rarity.COMMON, mage.cards.f.FoulFamiliar.class)); - cards.add(new SetCardInfo("Fumarole", 194, Rarity.UNCOMMON, mage.cards.f.Fumarole.class)); - cards.add(new SetCardInfo("Funeral March", 91, Rarity.COMMON, mage.cards.f.FuneralMarch.class)); - cards.add(new SetCardInfo("Fungal Bloom", 165, Rarity.RARE, mage.cards.f.FungalBloom.class)); - cards.add(new SetCardInfo("Fyndhorn Pollen", 166, Rarity.RARE, mage.cards.f.FyndhornPollen.class)); - cards.add(new SetCardInfo("Gangrenous Zombies", 92, Rarity.COMMON, mage.cards.g.GangrenousZombies.class)); - cards.add(new SetCardInfo("Giant Growth", 167, Rarity.COMMON, mage.cards.g.GiantGrowth.class)); - cards.add(new SetCardInfo("Giant Trap Door Spider", 195, Rarity.UNCOMMON, mage.cards.g.GiantTrapDoorSpider.class)); - cards.add(new SetCardInfo("Glacial Chasm", 229, Rarity.RARE, mage.cards.g.GlacialChasm.class)); - cards.add(new SetCardInfo("Glacial Crevasses", 127, Rarity.RARE, mage.cards.g.GlacialCrevasses.class)); - cards.add(new SetCardInfo("Gorilla Shaman", 129, Rarity.UNCOMMON, mage.cards.g.GorillaShaman.class)); - cards.add(new SetCardInfo("Grandmother Sengir", 93, Rarity.RARE, mage.cards.g.GrandmotherSengir.class)); - cards.add(new SetCardInfo("Havenwood Battleground", 230, Rarity.UNCOMMON, mage.cards.h.HavenwoodBattleground.class)); - cards.add(new SetCardInfo("Heart of Yavimaya", 231, Rarity.RARE, mage.cards.h.HeartOfYavimaya.class)); - cards.add(new SetCardInfo("Helm of Obedience", 210, Rarity.RARE, mage.cards.h.HelmOfObedience.class)); - cards.add(new SetCardInfo("Icatian Javelineers", 15, Rarity.COMMON, mage.cards.i.IcatianJavelineers.class)); - cards.add(new SetCardInfo("Icatian Phalanx", 16, Rarity.COMMON, mage.cards.i.IcatianPhalanx.class)); - cards.add(new SetCardInfo("Icatian Scout", 17, Rarity.COMMON, mage.cards.i.IcatianScout.class)); - cards.add(new SetCardInfo("Ice Floe", 232, Rarity.UNCOMMON, mage.cards.i.IceFloe.class)); - cards.add(new SetCardInfo("Iceberg", 49, Rarity.UNCOMMON, mage.cards.i.Iceberg.class)); - cards.add(new SetCardInfo("Icequake", 94, Rarity.COMMON, mage.cards.i.Icequake.class)); - cards.add(new SetCardInfo("Icy Prison", 50, Rarity.COMMON, mage.cards.i.IcyPrison.class)); - cards.add(new SetCardInfo("Ihsan's Shade", 95, Rarity.RARE, mage.cards.i.IhsansShade.class)); - cards.add(new SetCardInfo("Imperial Recruiter", 130, Rarity.RARE, mage.cards.i.ImperialRecruiter.class)); - cards.add(new SetCardInfo("Imperial Seal", 96, Rarity.RARE, mage.cards.i.ImperialSeal.class)); - cards.add(new SetCardInfo("Incinerate", 131, Rarity.COMMON, mage.cards.i.Incinerate.class)); - cards.add(new SetCardInfo("Infernal Darkness", 97, Rarity.RARE, mage.cards.i.InfernalDarkness.class)); - cards.add(new SetCardInfo("Inheritance", 18, Rarity.UNCOMMON, mage.cards.i.Inheritance.class)); - cards.add(new SetCardInfo("Ironclaw Orcs", 132, Rarity.COMMON, mage.cards.i.IronclawOrcs.class)); - cards.add(new SetCardInfo("Ivory Gargoyle", 19, Rarity.RARE, mage.cards.i.IvoryGargoyle.class)); - cards.add(new SetCardInfo("Jester's Mask", 211, Rarity.RARE, mage.cards.j.JestersMask.class)); - cards.add(new SetCardInfo("Jeweled Amulet", 212, Rarity.UNCOMMON, mage.cards.j.JeweledAmulet.class)); - cards.add(new SetCardInfo("Johtull Wurm", 168, Rarity.UNCOMMON, mage.cards.j.JohtullWurm.class)); - cards.add(new SetCardInfo("Joven's Ferrets", 169, Rarity.UNCOMMON, mage.cards.j.JovensFerrets.class)); - cards.add(new SetCardInfo("Juniper Order Advocate", 20, Rarity.UNCOMMON, mage.cards.j.JuniperOrderAdvocate.class)); - cards.add(new SetCardInfo("Karplusan Giant", 133, Rarity.UNCOMMON, mage.cards.k.KarplusanGiant.class)); - cards.add(new SetCardInfo("Kaysa", 170, Rarity.RARE, mage.cards.k.Kaysa.class)); - cards.add(new SetCardInfo("Kjeldoran Dead", 98, Rarity.COMMON, mage.cards.k.KjeldoranDead.class)); - cards.add(new SetCardInfo("Kjeldoran Home Guard", 22, Rarity.UNCOMMON, mage.cards.k.KjeldoranHomeGuard.class)); - cards.add(new SetCardInfo("Kjeldoran Outpost", 233, Rarity.RARE, mage.cards.k.KjeldoranOutpost.class)); - cards.add(new SetCardInfo("Kjeldoran Skycaptain", 23, Rarity.COMMON, mage.cards.k.KjeldoranSkycaptain.class)); - cards.add(new SetCardInfo("Knight of Stromgald", 99, Rarity.UNCOMMON, mage.cards.k.KnightOfStromgald.class)); - cards.add(new SetCardInfo("Krovikan Fetish", 100, Rarity.COMMON, mage.cards.k.KrovikanFetish.class)); - cards.add(new SetCardInfo("Krovikan Horror", 101, Rarity.RARE, mage.cards.k.KrovikanHorror.class)); - cards.add(new SetCardInfo("Krovikan Sorcerer", 51, Rarity.COMMON, mage.cards.k.KrovikanSorcerer.class)); - cards.add(new SetCardInfo("Lat-Nam's Legacy", 52, Rarity.COMMON, mage.cards.l.LatNamsLegacy.class)); - cards.add(new SetCardInfo("Leaping Lizard", 171, Rarity.COMMON, mage.cards.l.LeapingLizard.class)); - cards.add(new SetCardInfo("Lim-Dul's High Guard", 103, Rarity.UNCOMMON, mage.cards.l.LimDulsHighGuard.class)); - cards.add(new SetCardInfo("Lodestone Bauble", 213, Rarity.RARE, mage.cards.l.LodestoneBauble.class)); - cards.add(new SetCardInfo("Magus of the Unseen", 53, Rarity.RARE, mage.cards.m.MagusOfTheUnseen.class)); - cards.add(new SetCardInfo("Mana Crypt", 214, Rarity.RARE, mage.cards.m.ManaCrypt.class)); - cards.add(new SetCardInfo("Marjhan", 54, Rarity.RARE, mage.cards.m.Marjhan.class)); - cards.add(new SetCardInfo("Mesmeric Trance", 55, Rarity.RARE, mage.cards.m.MesmericTrance.class)); - cards.add(new SetCardInfo("Meteor Shower", 135, Rarity.COMMON, mage.cards.m.MeteorShower.class)); - cards.add(new SetCardInfo("Minion of Leshrac", 104, Rarity.RARE, mage.cards.m.MinionOfLeshrac.class)); - cards.add(new SetCardInfo("Mishra's Groundbreaker", 215, Rarity.UNCOMMON, mage.cards.m.MishrasGroundbreaker.class)); - cards.add(new SetCardInfo("Misinformation", 105, Rarity.UNCOMMON, mage.cards.m.Misinformation.class)); - cards.add(new SetCardInfo("Mudslide", 136, Rarity.RARE, mage.cards.m.Mudslide.class)); - cards.add(new SetCardInfo("Narwhal", 57, Rarity.UNCOMMON, mage.cards.n.Narwhal.class)); - cards.add(new SetCardInfo("Nature's Blessing", 196, Rarity.UNCOMMON, mage.cards.n.NaturesBlessing.class)); - cards.add(new SetCardInfo("Nature's Wrath", 172, Rarity.RARE, mage.cards.n.NaturesWrath.class)); - cards.add(new SetCardInfo("Necrite", 106, Rarity.COMMON, mage.cards.n.Necrite.class)); - cards.add(new SetCardInfo("Necropotence", 107, Rarity.RARE, mage.cards.n.Necropotence.class)); - cards.add(new SetCardInfo("Night Soil", 173, Rarity.UNCOMMON, mage.cards.n.NightSoil.class)); - cards.add(new SetCardInfo("Orc General", 137, Rarity.UNCOMMON, mage.cards.o.OrcGeneral.class)); - cards.add(new SetCardInfo("Orcish Cannoneers", 138, Rarity.UNCOMMON, mage.cards.o.OrcishCannoneers.class)); - cards.add(new SetCardInfo("Orcish Captain", 139, Rarity.UNCOMMON, mage.cards.o.OrcishCaptain.class)); - cards.add(new SetCardInfo("Orcish Lumberjack", 142, Rarity.COMMON, mage.cards.o.OrcishLumberjack.class)); - cards.add(new SetCardInfo("Orcish Squatters", 143, Rarity.RARE, mage.cards.o.OrcishSquatters.class)); - cards.add(new SetCardInfo("Orcish Veteran", 144, Rarity.COMMON, mage.cards.o.OrcishVeteran.class)); - cards.add(new SetCardInfo("Order of the Sacred Torch", 25, Rarity.RARE, mage.cards.o.OrderOfTheSacredTorch.class)); - cards.add(new SetCardInfo("Order of the White Shield", 26, Rarity.UNCOMMON, mage.cards.o.OrderOfTheWhiteShield.class)); - cards.add(new SetCardInfo("Panic", 145, Rarity.COMMON, mage.cards.p.Panic.class)); - cards.add(new SetCardInfo("Personal Tutor", 58, Rarity.UNCOMMON, mage.cards.p.PersonalTutor.class)); - cards.add(new SetCardInfo("Phantasmal Fiend", 108, Rarity.COMMON, mage.cards.p.PhantasmalFiend.class)); - cards.add(new SetCardInfo("Phyrexian Devourer", 216, Rarity.UNCOMMON, mage.cards.p.PhyrexianDevourer.class)); - cards.add(new SetCardInfo("Pillage", 146, Rarity.UNCOMMON, mage.cards.p.Pillage.class)); - cards.add(new SetCardInfo("Portent", 60, Rarity.COMMON, mage.cards.p.Portent.class)); - cards.add(new SetCardInfo("Pyrokinesis", 147, Rarity.RARE, mage.cards.p.Pyrokinesis.class)); - cards.add(new SetCardInfo("Ravages of War", 27, Rarity.RARE, mage.cards.r.RavagesOfWar.class)); - cards.add(new SetCardInfo("Ray of Command", 61, Rarity.UNCOMMON, mage.cards.r.RayOfCommand.class)); - cards.add(new SetCardInfo("Red Cliffs Armada", 62, Rarity.COMMON, mage.cards.r.RedCliffsArmada.class)); - cards.add(new SetCardInfo("Reinforcements", 28, Rarity.COMMON, mage.cards.r.Reinforcements.class)); - cards.add(new SetCardInfo("Reprisal", 29, Rarity.COMMON, mage.cards.r.Reprisal.class)); - cards.add(new SetCardInfo("Retribution", 148, Rarity.UNCOMMON, mage.cards.r.Retribution.class)); - cards.add(new SetCardInfo("Righteous Fury", 30, Rarity.RARE, mage.cards.r.RighteousFury.class)); - cards.add(new SetCardInfo("Ritual of Subdual", 174, Rarity.RARE, mage.cards.r.RitualOfSubdual.class)); - cards.add(new SetCardInfo("Ritual of the Machine", 109, Rarity.RARE, mage.cards.r.RitualOfTheMachine.class)); - cards.add(new SetCardInfo("Roterothopter", 218, Rarity.COMMON, mage.cards.r.Roterothopter.class)); - cards.add(new SetCardInfo("Royal Decree", 31, Rarity.RARE, mage.cards.r.RoyalDecree.class)); - cards.add(new SetCardInfo("Royal Trooper", 32, Rarity.COMMON, mage.cards.r.RoyalTrooper.class)); - cards.add(new SetCardInfo("Ruins of Trokair", 234, Rarity.UNCOMMON, mage.cards.r.RuinsOfTrokair.class)); - cards.add(new SetCardInfo("Savannah", 235, Rarity.RARE, mage.cards.s.Savannah.class)); - cards.add(new SetCardInfo("Screeching Drake", 63, Rarity.COMMON, mage.cards.s.ScreechingDrake.class)); - cards.add(new SetCardInfo("Sea Drake", 64, Rarity.RARE, mage.cards.s.SeaDrake.class)); - cards.add(new SetCardInfo("Sea Spirit", 65, Rarity.UNCOMMON, mage.cards.s.SeaSpirit.class)); - cards.add(new SetCardInfo("Shield Bearer", 35, Rarity.COMMON, mage.cards.s.ShieldBearer.class)); - cards.add(new SetCardInfo("Shrink", 175, Rarity.COMMON, mage.cards.s.Shrink.class)); - cards.add(new SetCardInfo("Shyft", 66, Rarity.COMMON, mage.cards.s.Shyft.class)); - cards.add(new SetCardInfo("Sibilant Spirit", 67, Rarity.RARE, mage.cards.s.SibilantSpirit.class)); - cards.add(new SetCardInfo("Skeleton Ship", 197, Rarity.RARE, mage.cards.s.SkeletonShip.class)); - cards.add(new SetCardInfo("Skull Catapult", 219, Rarity.UNCOMMON, mage.cards.s.SkullCatapult.class)); - cards.add(new SetCardInfo("Snow Fortress", 220, Rarity.UNCOMMON, mage.cards.s.SnowFortress.class)); - cards.add(new SetCardInfo("Snow-Covered Forest", 245, Rarity.LAND, mage.cards.s.SnowCoveredForest.class)); - cards.add(new SetCardInfo("Snow-Covered Island", 242, Rarity.LAND, mage.cards.s.SnowCoveredIsland.class)); - cards.add(new SetCardInfo("Snow-Covered Mountain", 244, Rarity.LAND, mage.cards.s.SnowCoveredMountain.class)); - cards.add(new SetCardInfo("Snow-Covered Plains", 241, Rarity.LAND, mage.cards.s.SnowCoveredPlains.class)); - cards.add(new SetCardInfo("Snow-Covered Swamp", 243, Rarity.LAND, mage.cards.s.SnowCoveredSwamp.class)); - cards.add(new SetCardInfo("Soldevi Digger", 221, Rarity.UNCOMMON, mage.cards.s.SoldeviDigger.class)); - cards.add(new SetCardInfo("Soldevi Excavations", 236, Rarity.RARE, mage.cards.s.SoldeviExcavations.class)); - cards.add(new SetCardInfo("Soldevi Simulacrum", 222, Rarity.UNCOMMON, mage.cards.s.SoldeviSimulacrum.class)); - cards.add(new SetCardInfo("Songs of the Damned", 110, Rarity.COMMON, mage.cards.s.SongsOfTheDamned.class)); - cards.add(new SetCardInfo("Soul Exchange", 111, Rarity.UNCOMMON, mage.cards.s.SoulExchange.class)); - cards.add(new SetCardInfo("Soul Kiss", 112, Rarity.UNCOMMON, mage.cards.s.SoulKiss.class)); - cards.add(new SetCardInfo("Spore Cloud", 176, Rarity.UNCOMMON, mage.cards.s.SporeCloud.class)); - cards.add(new SetCardInfo("Spore Flower", 177, Rarity.UNCOMMON, mage.cards.s.SporeFlower.class)); - cards.add(new SetCardInfo("Stampede", 178, Rarity.UNCOMMON, mage.cards.s.Stampede.class)); - cards.add(new SetCardInfo("Stone Spirit", 150, Rarity.UNCOMMON, mage.cards.s.StoneSpirit.class)); - cards.add(new SetCardInfo("Stonehands", 151, Rarity.COMMON, mage.cards.s.Stonehands.class)); - cards.add(new SetCardInfo("Storm Spirit", 198, Rarity.RARE, mage.cards.s.StormSpirit.class)); - cards.add(new SetCardInfo("Stromgald Cabal", 113, Rarity.RARE, mage.cards.s.StromgaldCabal.class)); - cards.add(new SetCardInfo("Stunted Growth", 179, Rarity.RARE, mage.cards.s.StuntedGrowth.class)); - cards.add(new SetCardInfo("Sustaining Spirit", 36, Rarity.RARE, mage.cards.s.SustainingSpirit.class)); - cards.add(new SetCardInfo("Svyelunite Temple", 237, Rarity.UNCOMMON, mage.cards.s.SvyeluniteTemple.class)); - cards.add(new SetCardInfo("Swords to Plowshares", 37, Rarity.UNCOMMON, mage.cards.s.SwordsToPlowshares.class)); - cards.add(new SetCardInfo("Taiga", 238, Rarity.RARE, mage.cards.t.Taiga.class)); - cards.add(new SetCardInfo("Temporal Manipulation", 69, Rarity.RARE, mage.cards.t.TemporalManipulation.class)); - cards.add(new SetCardInfo("Thallid Devourer", 181, Rarity.COMMON, mage.cards.t.ThallidDevourer.class)); - cards.add(new SetCardInfo("Thallid", 180, Rarity.COMMON, mage.cards.t.Thallid.class)); - cards.add(new SetCardInfo("Thelonite Druid", 182, Rarity.RARE, mage.cards.t.TheloniteDruid.class)); - cards.add(new SetCardInfo("Thermokarst", 183, Rarity.COMMON, mage.cards.t.Thermokarst.class)); - cards.add(new SetCardInfo("Thought Lash", 70, Rarity.RARE, mage.cards.t.ThoughtLash.class)); - cards.add(new SetCardInfo("Thunder Wall", 71, Rarity.UNCOMMON, mage.cards.t.ThunderWall.class)); - cards.add(new SetCardInfo("Time Bomb", 223, Rarity.RARE, mage.cards.t.TimeBomb.class)); - cards.add(new SetCardInfo("Tinder Wall", 184, Rarity.COMMON, mage.cards.t.TinderWall.class)); - cards.add(new SetCardInfo("Tundra", 239, Rarity.RARE, mage.cards.t.Tundra.class)); - cards.add(new SetCardInfo("Underground Sea", 240, Rarity.RARE, mage.cards.u.UndergroundSea.class)); - cards.add(new SetCardInfo("Varchild's Crusader", 152, Rarity.COMMON, mage.cards.v.VarchildsCrusader.class)); - cards.add(new SetCardInfo("Viscerid Armor", 72, Rarity.COMMON, mage.cards.v.VisceridArmor.class)); - cards.add(new SetCardInfo("Viscerid Drone", 73, Rarity.UNCOMMON, mage.cards.v.VisceridDrone.class)); - cards.add(new SetCardInfo("Wall of Kelp", 74, Rarity.COMMON, mage.cards.w.WallOfKelp.class)); - cards.add(new SetCardInfo("Warning", 38, Rarity.COMMON, mage.cards.w.Warning.class)); - cards.add(new SetCardInfo("Whirling Catapult", 224, Rarity.UNCOMMON, mage.cards.w.WhirlingCatapult.class)); - cards.add(new SetCardInfo("Whiteout", 185, Rarity.COMMON, mage.cards.w.Whiteout.class)); - cards.add(new SetCardInfo("Wind Spirit", 75, Rarity.UNCOMMON, mage.cards.w.WindSpirit.class)); - cards.add(new SetCardInfo("Wings of Aesthir", 199, Rarity.UNCOMMON, mage.cards.w.WingsOfAesthir.class)); - cards.add(new SetCardInfo("Winter's Night", 200, Rarity.RARE, mage.cards.w.WintersNight.class)); - cards.add(new SetCardInfo("Withering Wisps", 114, Rarity.UNCOMMON, mage.cards.w.WitheringWisps.class)); - cards.add(new SetCardInfo("Wolf Pack", 187, Rarity.RARE, mage.cards.w.WolfPack.class)); - cards.add(new SetCardInfo("Woolly Mammoths", 188, Rarity.COMMON, mage.cards.w.WoollyMammoths.class)); - cards.add(new SetCardInfo("Woolly Spider", 189, Rarity.UNCOMMON, mage.cards.w.WoollySpider.class)); - cards.add(new SetCardInfo("Yavimaya Ancients", 190, Rarity.UNCOMMON, mage.cards.y.YavimayaAncients.class)); - cards.add(new SetCardInfo("Zuran Spellcaster", 76, Rarity.COMMON, mage.cards.z.ZuranSpellcaster.class)); - } -} + +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author LevelX2 + */ +public final class MastersEditionII extends ExpansionSet { + + private static final MastersEditionII instance = new MastersEditionII(); + + public static MastersEditionII getInstance() { + return instance; + } + + private MastersEditionII() { + super("Masters Edition II", "ME2", ExpansionSet.buildDate(2008, 9, 22), SetType.MAGIC_ONLINE); + this.hasBasicLands = true; + this.hasBoosters = true; + this.numBoosterLands = 1; + this.numBoosterCommon = 10; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + + cards.add(new SetCardInfo("Abbey Gargoyles", 1, Rarity.UNCOMMON, mage.cards.a.AbbeyGargoyles.class)); + cards.add(new SetCardInfo("Adarkar Sentinel", 201, Rarity.COMMON, mage.cards.a.AdarkarSentinel.class)); + cards.add(new SetCardInfo("Aeolipile", 202, Rarity.COMMON, mage.cards.a.Aeolipile.class)); + cards.add(new SetCardInfo("Aether Storm", 39, Rarity.UNCOMMON, mage.cards.a.AetherStorm.class)); + cards.add(new SetCardInfo("Ambush Party", 115, Rarity.COMMON, mage.cards.a.AmbushParty.class)); + cards.add(new SetCardInfo("An-Zerrin Ruins", 117, Rarity.RARE, mage.cards.a.AnZerrinRuins.class)); + cards.add(new SetCardInfo("Anarchy", 116, Rarity.RARE, mage.cards.a.Anarchy.class)); + cards.add(new SetCardInfo("Angel of Fury", 2, Rarity.RARE, mage.cards.a.AngelOfFury.class)); + cards.add(new SetCardInfo("Angel of Light", 3, Rarity.UNCOMMON, mage.cards.a.AngelOfLight.class)); + cards.add(new SetCardInfo("Armor of Faith", 4, Rarity.COMMON, mage.cards.a.ArmorOfFaith.class)); + cards.add(new SetCardInfo("Armor Thrull", 77, Rarity.COMMON, mage.cards.a.ArmorThrull.class)); + cards.add(new SetCardInfo("Armored Griffin", 5, Rarity.COMMON, mage.cards.a.ArmoredGriffin.class)); + cards.add(new SetCardInfo("Ashen Ghoul", 78, Rarity.UNCOMMON, mage.cards.a.AshenGhoul.class)); + cards.add(new SetCardInfo("Ashnod's Cylix", 203, Rarity.RARE, mage.cards.a.AshnodsCylix.class)); + cards.add(new SetCardInfo("Aurochs", 153, Rarity.COMMON, mage.cards.a.Aurochs.class)); + cards.add(new SetCardInfo("Aysen Bureaucrats", 6, Rarity.COMMON, mage.cards.a.AysenBureaucrats.class)); + cards.add(new SetCardInfo("Aysen Crusader", 7, Rarity.UNCOMMON, mage.cards.a.AysenCrusader.class)); + cards.add(new SetCardInfo("Badlands", 225, Rarity.RARE, mage.cards.b.Badlands.class)); + cards.add(new SetCardInfo("Balduvian Conjurer", 40, Rarity.COMMON, mage.cards.b.BalduvianConjurer.class)); + cards.add(new SetCardInfo("Balduvian Dead", 79, Rarity.UNCOMMON, mage.cards.b.BalduvianDead.class)); + cards.add(new SetCardInfo("Balduvian Hydra", 118, Rarity.RARE, mage.cards.b.BalduvianHydra.class)); + cards.add(new SetCardInfo("Balduvian Trading Post", 226, Rarity.RARE, mage.cards.b.BalduvianTradingPost.class)); + cards.add(new SetCardInfo("Barbed Sextant", 204, Rarity.COMMON, mage.cards.b.BarbedSextant.class)); + cards.add(new SetCardInfo("Binding Grasp", 41, Rarity.RARE, mage.cards.b.BindingGrasp.class)); + cards.add(new SetCardInfo("Bounty of the Hunt", 154, Rarity.RARE, mage.cards.b.BountyOfTheHunt.class)); + cards.add(new SetCardInfo("Brainstorm", 42, Rarity.COMMON, mage.cards.b.Brainstorm.class)); + cards.add(new SetCardInfo("Brassclaw Orcs", 119, Rarity.COMMON, mage.cards.b.BrassclawOrcs.class)); + cards.add(new SetCardInfo("Brimstone Dragon", 120, Rarity.RARE, mage.cards.b.BrimstoneDragon.class)); + cards.add(new SetCardInfo("Brine Shaman", 80, Rarity.COMMON, mage.cards.b.BrineShaman.class)); + cards.add(new SetCardInfo("Broken Visage", 81, Rarity.UNCOMMON, mage.cards.b.BrokenVisage.class)); + cards.add(new SetCardInfo("Browse", 43, Rarity.UNCOMMON, mage.cards.b.Browse.class)); + cards.add(new SetCardInfo("Burnout", 121, Rarity.UNCOMMON, mage.cards.b.Burnout.class)); + cards.add(new SetCardInfo("Carapace", 155, Rarity.COMMON, mage.cards.c.Carapace.class)); + cards.add(new SetCardInfo("Caribou Range", 8, Rarity.RARE, mage.cards.c.CaribouRange.class)); + cards.add(new SetCardInfo("Cloak of Confusion", 82, Rarity.COMMON, mage.cards.c.CloakOfConfusion.class)); + cards.add(new SetCardInfo("Clockwork Steed", 205, Rarity.UNCOMMON, mage.cards.c.ClockworkSteed.class)); + cards.add(new SetCardInfo("Combat Medic", 9, Rarity.COMMON, mage.cards.c.CombatMedic.class)); + cards.add(new SetCardInfo("Conquer", 122, Rarity.UNCOMMON, mage.cards.c.Conquer.class)); + cards.add(new SetCardInfo("Counterspell", 44, Rarity.UNCOMMON, mage.cards.c.Counterspell.class)); + cards.add(new SetCardInfo("Dance of the Dead", 83, Rarity.UNCOMMON, mage.cards.d.DanceOfTheDead.class)); + cards.add(new SetCardInfo("Dark Banishing", 84, Rarity.COMMON, mage.cards.d.DarkBanishing.class)); + cards.add(new SetCardInfo("Death Spark", 123, Rarity.COMMON, mage.cards.d.DeathSpark.class)); + cards.add(new SetCardInfo("Deep Spawn", 45, Rarity.RARE, mage.cards.d.DeepSpawn.class)); + cards.add(new SetCardInfo("Demonic Consultation", 85, Rarity.UNCOMMON, mage.cards.d.DemonicConsultation.class)); + cards.add(new SetCardInfo("Despotic Scepter", 206, Rarity.RARE, mage.cards.d.DespoticScepter.class)); + cards.add(new SetCardInfo("Diabolic Vision", 191, Rarity.UNCOMMON, mage.cards.d.DiabolicVision.class)); + cards.add(new SetCardInfo("Disenchant", 10, Rarity.COMMON, mage.cards.d.Disenchant.class)); + cards.add(new SetCardInfo("Dreams of the Dead", 46, Rarity.RARE, mage.cards.d.DreamsOfTheDead.class)); + cards.add(new SetCardInfo("Drift of the Dead", 86, Rarity.COMMON, mage.cards.d.DriftOfTheDead.class)); + cards.add(new SetCardInfo("Dry Spell", 87, Rarity.COMMON, mage.cards.d.DrySpell.class)); + cards.add(new SetCardInfo("Dwarven Ruins", 227, Rarity.UNCOMMON, mage.cards.d.DwarvenRuins.class)); + cards.add(new SetCardInfo("Dystopia", 88, Rarity.RARE, mage.cards.d.Dystopia.class)); + cards.add(new SetCardInfo("Earthlink", 192, Rarity.RARE, mage.cards.e.Earthlink.class)); + cards.add(new SetCardInfo("Ebon Praetor", 89, Rarity.RARE, mage.cards.e.EbonPraetor.class)); + cards.add(new SetCardInfo("Ebon Stronghold", 228, Rarity.UNCOMMON, mage.cards.e.EbonStronghold.class)); + cards.add(new SetCardInfo("Elemental Augury", 193, Rarity.RARE, mage.cards.e.ElementalAugury.class)); + cards.add(new SetCardInfo("Elkin Bottle", 207, Rarity.RARE, mage.cards.e.ElkinBottle.class)); + cards.add(new SetCardInfo("Elven Lyre", 208, Rarity.COMMON, mage.cards.e.ElvenLyre.class)); + cards.add(new SetCardInfo("Elvish Farmer", 156, Rarity.RARE, mage.cards.e.ElvishFarmer.class)); + cards.add(new SetCardInfo("Elvish Hunter", 157, Rarity.COMMON, mage.cards.e.ElvishHunter.class)); + cards.add(new SetCardInfo("Elvish Ranger", 158, Rarity.COMMON, mage.cards.e.ElvishRanger.class)); + cards.add(new SetCardInfo("Elvish Spirit Guide", 159, Rarity.UNCOMMON, mage.cards.e.ElvishSpiritGuide.class)); + cards.add(new SetCardInfo("Energy Storm", 11, Rarity.RARE, mage.cards.e.EnergyStorm.class)); + cards.add(new SetCardInfo("Enervate", 47, Rarity.COMMON, mage.cards.e.Enervate.class)); + cards.add(new SetCardInfo("Errand of Duty", 12, Rarity.UNCOMMON, mage.cards.e.ErrandOfDuty.class)); + cards.add(new SetCardInfo("Errantry", 124, Rarity.COMMON, mage.cards.e.Errantry.class)); + cards.add(new SetCardInfo("Essence Filter", 160, Rarity.UNCOMMON, mage.cards.e.EssenceFilter.class)); + cards.add(new SetCardInfo("Essence Flare", 48, Rarity.COMMON, mage.cards.e.EssenceFlare.class)); + cards.add(new SetCardInfo("Farrel's Mantle", 13, Rarity.UNCOMMON, mage.cards.f.FarrelsMantle.class)); + cards.add(new SetCardInfo("Farrel's Zealot", 14, Rarity.UNCOMMON, mage.cards.f.FarrelsZealot.class)); + cards.add(new SetCardInfo("Feral Thallid", 161, Rarity.COMMON, mage.cards.f.FeralThallid.class)); + cards.add(new SetCardInfo("Fire Dragon", 125, Rarity.RARE, mage.cards.f.FireDragon.class)); + cards.add(new SetCardInfo("Flame Spirit", 126, Rarity.UNCOMMON, mage.cards.f.FlameSpirit.class)); + cards.add(new SetCardInfo("Folk of the Pines", 162, Rarity.COMMON, mage.cards.f.FolkOfThePines.class)); + cards.add(new SetCardInfo("Forbidden Lore", 163, Rarity.UNCOMMON, mage.cards.f.ForbiddenLore.class)); + cards.add(new SetCardInfo("Forgotten Lore", 164, Rarity.UNCOMMON, mage.cards.f.ForgottenLore.class)); + cards.add(new SetCardInfo("Foul Familiar", 90, Rarity.COMMON, mage.cards.f.FoulFamiliar.class)); + cards.add(new SetCardInfo("Fumarole", 194, Rarity.UNCOMMON, mage.cards.f.Fumarole.class)); + cards.add(new SetCardInfo("Funeral March", 91, Rarity.COMMON, mage.cards.f.FuneralMarch.class)); + cards.add(new SetCardInfo("Fungal Bloom", 165, Rarity.RARE, mage.cards.f.FungalBloom.class)); + cards.add(new SetCardInfo("Fyndhorn Pollen", 166, Rarity.RARE, mage.cards.f.FyndhornPollen.class)); + cards.add(new SetCardInfo("Gangrenous Zombies", 92, Rarity.COMMON, mage.cards.g.GangrenousZombies.class)); + cards.add(new SetCardInfo("Giant Growth", 167, Rarity.COMMON, mage.cards.g.GiantGrowth.class)); + cards.add(new SetCardInfo("Giant Trap Door Spider", 195, Rarity.UNCOMMON, mage.cards.g.GiantTrapDoorSpider.class)); + cards.add(new SetCardInfo("Glacial Chasm", 229, Rarity.RARE, mage.cards.g.GlacialChasm.class)); + cards.add(new SetCardInfo("Glacial Crevasses", 127, Rarity.RARE, mage.cards.g.GlacialCrevasses.class)); + cards.add(new SetCardInfo("Gorilla Shaman", 129, Rarity.UNCOMMON, mage.cards.g.GorillaShaman.class)); + cards.add(new SetCardInfo("Grandmother Sengir", 93, Rarity.RARE, mage.cards.g.GrandmotherSengir.class)); + cards.add(new SetCardInfo("Havenwood Battleground", 230, Rarity.UNCOMMON, mage.cards.h.HavenwoodBattleground.class)); + cards.add(new SetCardInfo("Heart of Yavimaya", 231, Rarity.RARE, mage.cards.h.HeartOfYavimaya.class)); + cards.add(new SetCardInfo("Helm of Obedience", 210, Rarity.RARE, mage.cards.h.HelmOfObedience.class)); + cards.add(new SetCardInfo("Icatian Javelineers", 15, Rarity.COMMON, mage.cards.i.IcatianJavelineers.class)); + cards.add(new SetCardInfo("Icatian Phalanx", 16, Rarity.COMMON, mage.cards.i.IcatianPhalanx.class)); + cards.add(new SetCardInfo("Icatian Scout", 17, Rarity.COMMON, mage.cards.i.IcatianScout.class)); + cards.add(new SetCardInfo("Ice Floe", 232, Rarity.UNCOMMON, mage.cards.i.IceFloe.class)); + cards.add(new SetCardInfo("Iceberg", 49, Rarity.UNCOMMON, mage.cards.i.Iceberg.class)); + cards.add(new SetCardInfo("Icequake", 94, Rarity.COMMON, mage.cards.i.Icequake.class)); + cards.add(new SetCardInfo("Icy Prison", 50, Rarity.COMMON, mage.cards.i.IcyPrison.class)); + cards.add(new SetCardInfo("Ihsan's Shade", 95, Rarity.RARE, mage.cards.i.IhsansShade.class)); + cards.add(new SetCardInfo("Imperial Recruiter", 130, Rarity.RARE, mage.cards.i.ImperialRecruiter.class)); + cards.add(new SetCardInfo("Imperial Seal", 96, Rarity.RARE, mage.cards.i.ImperialSeal.class)); + cards.add(new SetCardInfo("Incinerate", 131, Rarity.COMMON, mage.cards.i.Incinerate.class)); + cards.add(new SetCardInfo("Infernal Darkness", 97, Rarity.RARE, mage.cards.i.InfernalDarkness.class)); + cards.add(new SetCardInfo("Inheritance", 18, Rarity.UNCOMMON, mage.cards.i.Inheritance.class)); + cards.add(new SetCardInfo("Ironclaw Orcs", 132, Rarity.COMMON, mage.cards.i.IronclawOrcs.class)); + cards.add(new SetCardInfo("Ivory Gargoyle", 19, Rarity.RARE, mage.cards.i.IvoryGargoyle.class)); + cards.add(new SetCardInfo("Jester's Mask", 211, Rarity.RARE, mage.cards.j.JestersMask.class)); + cards.add(new SetCardInfo("Jeweled Amulet", 212, Rarity.UNCOMMON, mage.cards.j.JeweledAmulet.class)); + cards.add(new SetCardInfo("Johtull Wurm", 168, Rarity.UNCOMMON, mage.cards.j.JohtullWurm.class)); + cards.add(new SetCardInfo("Joven's Ferrets", 169, Rarity.UNCOMMON, mage.cards.j.JovensFerrets.class)); + cards.add(new SetCardInfo("Juniper Order Advocate", 20, Rarity.UNCOMMON, mage.cards.j.JuniperOrderAdvocate.class)); + cards.add(new SetCardInfo("Karplusan Giant", 133, Rarity.UNCOMMON, mage.cards.k.KarplusanGiant.class)); + cards.add(new SetCardInfo("Kaysa", 170, Rarity.RARE, mage.cards.k.Kaysa.class)); + cards.add(new SetCardInfo("Kjeldoran Dead", 98, Rarity.COMMON, mage.cards.k.KjeldoranDead.class)); + cards.add(new SetCardInfo("Kjeldoran Home Guard", 22, Rarity.UNCOMMON, mage.cards.k.KjeldoranHomeGuard.class)); + cards.add(new SetCardInfo("Kjeldoran Outpost", 233, Rarity.RARE, mage.cards.k.KjeldoranOutpost.class)); + cards.add(new SetCardInfo("Kjeldoran Skycaptain", 23, Rarity.COMMON, mage.cards.k.KjeldoranSkycaptain.class)); + cards.add(new SetCardInfo("Knight of Stromgald", 99, Rarity.UNCOMMON, mage.cards.k.KnightOfStromgald.class)); + cards.add(new SetCardInfo("Krovikan Fetish", 100, Rarity.COMMON, mage.cards.k.KrovikanFetish.class)); + cards.add(new SetCardInfo("Krovikan Horror", 101, Rarity.RARE, mage.cards.k.KrovikanHorror.class)); + cards.add(new SetCardInfo("Krovikan Sorcerer", 51, Rarity.COMMON, mage.cards.k.KrovikanSorcerer.class)); + cards.add(new SetCardInfo("Lat-Nam's Legacy", 52, Rarity.COMMON, mage.cards.l.LatNamsLegacy.class)); + cards.add(new SetCardInfo("Leaping Lizard", 171, Rarity.COMMON, mage.cards.l.LeapingLizard.class)); + cards.add(new SetCardInfo("Lim-Dul's High Guard", 103, Rarity.UNCOMMON, mage.cards.l.LimDulsHighGuard.class)); + cards.add(new SetCardInfo("Lodestone Bauble", 213, Rarity.RARE, mage.cards.l.LodestoneBauble.class)); + cards.add(new SetCardInfo("Magus of the Unseen", 53, Rarity.RARE, mage.cards.m.MagusOfTheUnseen.class)); + cards.add(new SetCardInfo("Mana Crypt", 214, Rarity.RARE, mage.cards.m.ManaCrypt.class)); + cards.add(new SetCardInfo("Marjhan", 54, Rarity.RARE, mage.cards.m.Marjhan.class)); + cards.add(new SetCardInfo("Mesmeric Trance", 55, Rarity.RARE, mage.cards.m.MesmericTrance.class)); + cards.add(new SetCardInfo("Meteor Shower", 135, Rarity.COMMON, mage.cards.m.MeteorShower.class)); + cards.add(new SetCardInfo("Minion of Leshrac", 104, Rarity.RARE, mage.cards.m.MinionOfLeshrac.class)); + cards.add(new SetCardInfo("Mishra's Groundbreaker", 215, Rarity.UNCOMMON, mage.cards.m.MishrasGroundbreaker.class)); + cards.add(new SetCardInfo("Misinformation", 105, Rarity.UNCOMMON, mage.cards.m.Misinformation.class)); + cards.add(new SetCardInfo("Mudslide", 136, Rarity.RARE, mage.cards.m.Mudslide.class)); + cards.add(new SetCardInfo("Narwhal", 57, Rarity.UNCOMMON, mage.cards.n.Narwhal.class)); + cards.add(new SetCardInfo("Nature's Blessing", 196, Rarity.UNCOMMON, mage.cards.n.NaturesBlessing.class)); + cards.add(new SetCardInfo("Nature's Wrath", 172, Rarity.RARE, mage.cards.n.NaturesWrath.class)); + cards.add(new SetCardInfo("Necrite", 106, Rarity.COMMON, mage.cards.n.Necrite.class)); + cards.add(new SetCardInfo("Necropotence", 107, Rarity.RARE, mage.cards.n.Necropotence.class)); + cards.add(new SetCardInfo("Night Soil", 173, Rarity.UNCOMMON, mage.cards.n.NightSoil.class)); + cards.add(new SetCardInfo("Orc General", 137, Rarity.UNCOMMON, mage.cards.o.OrcGeneral.class)); + cards.add(new SetCardInfo("Orcish Cannoneers", 138, Rarity.UNCOMMON, mage.cards.o.OrcishCannoneers.class)); + cards.add(new SetCardInfo("Orcish Captain", 139, Rarity.UNCOMMON, mage.cards.o.OrcishCaptain.class)); + cards.add(new SetCardInfo("Orcish Lumberjack", 142, Rarity.COMMON, mage.cards.o.OrcishLumberjack.class)); + cards.add(new SetCardInfo("Orcish Squatters", 143, Rarity.RARE, mage.cards.o.OrcishSquatters.class)); + cards.add(new SetCardInfo("Orcish Veteran", 144, Rarity.COMMON, mage.cards.o.OrcishVeteran.class)); + cards.add(new SetCardInfo("Order of the Sacred Torch", 25, Rarity.RARE, mage.cards.o.OrderOfTheSacredTorch.class)); + cards.add(new SetCardInfo("Order of the White Shield", 26, Rarity.UNCOMMON, mage.cards.o.OrderOfTheWhiteShield.class)); + cards.add(new SetCardInfo("Panic", 145, Rarity.COMMON, mage.cards.p.Panic.class)); + cards.add(new SetCardInfo("Personal Tutor", 58, Rarity.UNCOMMON, mage.cards.p.PersonalTutor.class)); + cards.add(new SetCardInfo("Phantasmal Fiend", 108, Rarity.COMMON, mage.cards.p.PhantasmalFiend.class)); + cards.add(new SetCardInfo("Phyrexian Devourer", 216, Rarity.UNCOMMON, mage.cards.p.PhyrexianDevourer.class)); + cards.add(new SetCardInfo("Pillage", 146, Rarity.UNCOMMON, mage.cards.p.Pillage.class)); + cards.add(new SetCardInfo("Portent", 60, Rarity.COMMON, mage.cards.p.Portent.class)); + cards.add(new SetCardInfo("Pyrokinesis", 147, Rarity.RARE, mage.cards.p.Pyrokinesis.class)); + cards.add(new SetCardInfo("Ravages of War", 27, Rarity.RARE, mage.cards.r.RavagesOfWar.class)); + cards.add(new SetCardInfo("Ray of Command", 61, Rarity.UNCOMMON, mage.cards.r.RayOfCommand.class)); + cards.add(new SetCardInfo("Red Cliffs Armada", 62, Rarity.COMMON, mage.cards.r.RedCliffsArmada.class)); + cards.add(new SetCardInfo("Reinforcements", 28, Rarity.COMMON, mage.cards.r.Reinforcements.class)); + cards.add(new SetCardInfo("Reprisal", 29, Rarity.COMMON, mage.cards.r.Reprisal.class)); + cards.add(new SetCardInfo("Retribution", 148, Rarity.UNCOMMON, mage.cards.r.Retribution.class)); + cards.add(new SetCardInfo("Righteous Fury", 30, Rarity.RARE, mage.cards.r.RighteousFury.class)); + cards.add(new SetCardInfo("Ritual of Subdual", 174, Rarity.RARE, mage.cards.r.RitualOfSubdual.class)); + cards.add(new SetCardInfo("Ritual of the Machine", 109, Rarity.RARE, mage.cards.r.RitualOfTheMachine.class)); + cards.add(new SetCardInfo("Roterothopter", 218, Rarity.COMMON, mage.cards.r.Roterothopter.class)); + cards.add(new SetCardInfo("Royal Decree", 31, Rarity.RARE, mage.cards.r.RoyalDecree.class)); + cards.add(new SetCardInfo("Royal Trooper", 32, Rarity.COMMON, mage.cards.r.RoyalTrooper.class)); + cards.add(new SetCardInfo("Ruins of Trokair", 234, Rarity.UNCOMMON, mage.cards.r.RuinsOfTrokair.class)); + cards.add(new SetCardInfo("Savannah", 235, Rarity.RARE, mage.cards.s.Savannah.class)); + cards.add(new SetCardInfo("Screeching Drake", 63, Rarity.COMMON, mage.cards.s.ScreechingDrake.class)); + cards.add(new SetCardInfo("Sea Drake", 64, Rarity.RARE, mage.cards.s.SeaDrake.class)); + cards.add(new SetCardInfo("Sea Spirit", 65, Rarity.UNCOMMON, mage.cards.s.SeaSpirit.class)); + cards.add(new SetCardInfo("Shield Bearer", 35, Rarity.COMMON, mage.cards.s.ShieldBearer.class)); + cards.add(new SetCardInfo("Shrink", 175, Rarity.COMMON, mage.cards.s.Shrink.class)); + cards.add(new SetCardInfo("Shyft", 66, Rarity.COMMON, mage.cards.s.Shyft.class)); + cards.add(new SetCardInfo("Sibilant Spirit", 67, Rarity.RARE, mage.cards.s.SibilantSpirit.class)); + cards.add(new SetCardInfo("Skeleton Ship", 197, Rarity.RARE, mage.cards.s.SkeletonShip.class)); + cards.add(new SetCardInfo("Skull Catapult", 219, Rarity.UNCOMMON, mage.cards.s.SkullCatapult.class)); + cards.add(new SetCardInfo("Snow Fortress", 220, Rarity.UNCOMMON, mage.cards.s.SnowFortress.class)); + cards.add(new SetCardInfo("Snow-Covered Forest", 245, Rarity.LAND, mage.cards.s.SnowCoveredForest.class)); + cards.add(new SetCardInfo("Snow-Covered Island", 242, Rarity.LAND, mage.cards.s.SnowCoveredIsland.class)); + cards.add(new SetCardInfo("Snow-Covered Mountain", 244, Rarity.LAND, mage.cards.s.SnowCoveredMountain.class)); + cards.add(new SetCardInfo("Snow-Covered Plains", 241, Rarity.LAND, mage.cards.s.SnowCoveredPlains.class)); + cards.add(new SetCardInfo("Snow-Covered Swamp", 243, Rarity.LAND, mage.cards.s.SnowCoveredSwamp.class)); + cards.add(new SetCardInfo("Soldevi Digger", 221, Rarity.UNCOMMON, mage.cards.s.SoldeviDigger.class)); + cards.add(new SetCardInfo("Soldevi Excavations", 236, Rarity.RARE, mage.cards.s.SoldeviExcavations.class)); + cards.add(new SetCardInfo("Soldevi Simulacrum", 222, Rarity.UNCOMMON, mage.cards.s.SoldeviSimulacrum.class)); + cards.add(new SetCardInfo("Songs of the Damned", 110, Rarity.COMMON, mage.cards.s.SongsOfTheDamned.class)); + cards.add(new SetCardInfo("Soul Exchange", 111, Rarity.UNCOMMON, mage.cards.s.SoulExchange.class)); + cards.add(new SetCardInfo("Soul Kiss", 112, Rarity.UNCOMMON, mage.cards.s.SoulKiss.class)); + cards.add(new SetCardInfo("Spore Cloud", 176, Rarity.UNCOMMON, mage.cards.s.SporeCloud.class)); + cards.add(new SetCardInfo("Spore Flower", 177, Rarity.UNCOMMON, mage.cards.s.SporeFlower.class)); + cards.add(new SetCardInfo("Stampede", 178, Rarity.UNCOMMON, mage.cards.s.Stampede.class)); + cards.add(new SetCardInfo("Stone Spirit", 150, Rarity.UNCOMMON, mage.cards.s.StoneSpirit.class)); + cards.add(new SetCardInfo("Stonehands", 151, Rarity.COMMON, mage.cards.s.Stonehands.class)); + cards.add(new SetCardInfo("Storm Spirit", 198, Rarity.RARE, mage.cards.s.StormSpirit.class)); + cards.add(new SetCardInfo("Stromgald Cabal", 113, Rarity.RARE, mage.cards.s.StromgaldCabal.class)); + cards.add(new SetCardInfo("Stunted Growth", 179, Rarity.RARE, mage.cards.s.StuntedGrowth.class)); + cards.add(new SetCardInfo("Sustaining Spirit", 36, Rarity.RARE, mage.cards.s.SustainingSpirit.class)); + cards.add(new SetCardInfo("Svyelunite Temple", 237, Rarity.UNCOMMON, mage.cards.s.SvyeluniteTemple.class)); + cards.add(new SetCardInfo("Swords to Plowshares", 37, Rarity.UNCOMMON, mage.cards.s.SwordsToPlowshares.class)); + cards.add(new SetCardInfo("Taiga", 238, Rarity.RARE, mage.cards.t.Taiga.class)); + cards.add(new SetCardInfo("Temporal Manipulation", 69, Rarity.RARE, mage.cards.t.TemporalManipulation.class)); + cards.add(new SetCardInfo("Thallid Devourer", 181, Rarity.COMMON, mage.cards.t.ThallidDevourer.class)); + cards.add(new SetCardInfo("Thallid", 180, Rarity.COMMON, mage.cards.t.Thallid.class)); + cards.add(new SetCardInfo("Thelonite Druid", 182, Rarity.RARE, mage.cards.t.TheloniteDruid.class)); + cards.add(new SetCardInfo("Thermokarst", 183, Rarity.COMMON, mage.cards.t.Thermokarst.class)); + cards.add(new SetCardInfo("Thought Lash", 70, Rarity.RARE, mage.cards.t.ThoughtLash.class)); + cards.add(new SetCardInfo("Thunder Wall", 71, Rarity.UNCOMMON, mage.cards.t.ThunderWall.class)); + cards.add(new SetCardInfo("Time Bomb", 223, Rarity.RARE, mage.cards.t.TimeBomb.class)); + cards.add(new SetCardInfo("Tinder Wall", 184, Rarity.COMMON, mage.cards.t.TinderWall.class)); + cards.add(new SetCardInfo("Tundra", 239, Rarity.RARE, mage.cards.t.Tundra.class)); + cards.add(new SetCardInfo("Underground Sea", 240, Rarity.RARE, mage.cards.u.UndergroundSea.class)); + cards.add(new SetCardInfo("Varchild's Crusader", 152, Rarity.COMMON, mage.cards.v.VarchildsCrusader.class)); + cards.add(new SetCardInfo("Viscerid Armor", 72, Rarity.COMMON, mage.cards.v.VisceridArmor.class)); + cards.add(new SetCardInfo("Viscerid Drone", 73, Rarity.UNCOMMON, mage.cards.v.VisceridDrone.class)); + cards.add(new SetCardInfo("Wall of Kelp", 74, Rarity.COMMON, mage.cards.w.WallOfKelp.class)); + cards.add(new SetCardInfo("Warning", 38, Rarity.COMMON, mage.cards.w.Warning.class)); + cards.add(new SetCardInfo("Whirling Catapult", 224, Rarity.UNCOMMON, mage.cards.w.WhirlingCatapult.class)); + cards.add(new SetCardInfo("Whiteout", 185, Rarity.COMMON, mage.cards.w.Whiteout.class)); + cards.add(new SetCardInfo("Wind Spirit", 75, Rarity.UNCOMMON, mage.cards.w.WindSpirit.class)); + cards.add(new SetCardInfo("Wings of Aesthir", 199, Rarity.UNCOMMON, mage.cards.w.WingsOfAesthir.class)); + cards.add(new SetCardInfo("Winter's Night", 200, Rarity.RARE, mage.cards.w.WintersNight.class)); + cards.add(new SetCardInfo("Withering Wisps", 114, Rarity.UNCOMMON, mage.cards.w.WitheringWisps.class)); + cards.add(new SetCardInfo("Wolf Pack", 187, Rarity.RARE, mage.cards.w.WolfPack.class)); + cards.add(new SetCardInfo("Woolly Mammoths", 188, Rarity.COMMON, mage.cards.w.WoollyMammoths.class)); + cards.add(new SetCardInfo("Woolly Spider", 189, Rarity.UNCOMMON, mage.cards.w.WoollySpider.class)); + cards.add(new SetCardInfo("Yavimaya Ancients", 190, Rarity.UNCOMMON, mage.cards.y.YavimayaAncients.class)); + cards.add(new SetCardInfo("Zuran Spellcaster", 76, Rarity.COMMON, mage.cards.z.ZuranSpellcaster.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/MastersEditionIV.java b/Mage.Sets/src/mage/sets/MastersEditionIV.java index ba6d2eb7e95..3d2c86d822d 100644 --- a/Mage.Sets/src/mage/sets/MastersEditionIV.java +++ b/Mage.Sets/src/mage/sets/MastersEditionIV.java @@ -1,318 +1,319 @@ - -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.cards.repository.CardCriteria; -import mage.cards.repository.CardInfo; -import mage.cards.repository.CardRepository; -import mage.constants.Rarity; -import mage.constants.SetType; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author LevelX2 - */ -public final class MastersEditionIV extends ExpansionSet { - - private static final MastersEditionIV instance = new MastersEditionIV(); - - public static MastersEditionIV getInstance() { - return instance; - } - - protected final List savedSpecialLand = new ArrayList<>(); - - private MastersEditionIV() { - super("Masters Edition IV", "ME4", ExpansionSet.buildDate(2011, 1, 10), SetType.MAGIC_ONLINE); - this.hasBasicLands = false; - this.hasBoosters = true; - this.numBoosterLands = 1; - this.numBoosterCommon = 10; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - this.ratioBoosterSpecialLand = 1; // replace all basic lands - - cards.add(new SetCardInfo("Acid Rain", 36, Rarity.RARE, mage.cards.a.AcidRain.class)); - cards.add(new SetCardInfo("Aesthir Glider", 176, Rarity.COMMON, mage.cards.a.AesthirGlider.class)); - cards.add(new SetCardInfo("Air Elemental", 37, Rarity.UNCOMMON, mage.cards.a.AirElemental.class)); - cards.add(new SetCardInfo("Al-abara's Carpet", 177, Rarity.RARE, mage.cards.a.AlAbarasCarpet.class)); - cards.add(new SetCardInfo("Alaborn Musketeer", 1, Rarity.COMMON, mage.cards.a.AlabornMusketeer.class)); - cards.add(new SetCardInfo("Alaborn Trooper", 2, Rarity.COMMON, mage.cards.a.AlabornTrooper.class)); - cards.add(new SetCardInfo("Aladdin", 106, Rarity.RARE, mage.cards.a.Aladdin.class)); - cards.add(new SetCardInfo("Alchor's Tomb", 178, Rarity.RARE, mage.cards.a.AlchorsTomb.class)); - cards.add(new SetCardInfo("Ali from Cairo", 107, Rarity.RARE, mage.cards.a.AliFromCairo.class)); - cards.add(new SetCardInfo("Alluring Scent", 141, Rarity.COMMON, mage.cards.a.AlluringScent.class)); - cards.add(new SetCardInfo("Amulet of Kroog", 179, Rarity.COMMON, mage.cards.a.AmuletOfKroog.class)); - cards.add(new SetCardInfo("Angelic Voices", 3, Rarity.UNCOMMON, mage.cards.a.AngelicVoices.class)); - cards.add(new SetCardInfo("Animate Artifact", 38, Rarity.UNCOMMON, mage.cards.a.AnimateArtifact.class)); - cards.add(new SetCardInfo("Argivian Blacksmith", 4, Rarity.UNCOMMON, mage.cards.a.ArgivianBlacksmith.class)); - cards.add(new SetCardInfo("Argothian Pixies", 142, Rarity.COMMON, mage.cards.a.ArgothianPixies.class)); - cards.add(new SetCardInfo("Argothian Treefolk", 143, Rarity.UNCOMMON, mage.cards.a.ArgothianTreefolk.class)); - cards.add(new SetCardInfo("Armageddon Clock", 180, Rarity.RARE, mage.cards.a.ArmageddonClock.class)); - cards.add(new SetCardInfo("Armageddon", 5, Rarity.RARE, mage.cards.a.Armageddon.class)); - cards.add(new SetCardInfo("Artifact Blast", 108, Rarity.COMMON, mage.cards.a.ArtifactBlast.class)); - cards.add(new SetCardInfo("Ashnod's Altar", 181, Rarity.RARE, mage.cards.a.AshnodsAltar.class)); - cards.add(new SetCardInfo("Atog", 109, Rarity.COMMON, mage.cards.a.Atog.class)); - cards.add(new SetCardInfo("Badlands", 241, Rarity.RARE, mage.cards.b.Badlands.class)); - cards.add(new SetCardInfo("Balance", 6, Rarity.RARE, mage.cards.b.Balance.class)); - cards.add(new SetCardInfo("Basalt Monolith", 182, Rarity.UNCOMMON, mage.cards.b.BasaltMonolith.class)); - cards.add(new SetCardInfo("Bayou", 242, Rarity.RARE, mage.cards.b.Bayou.class)); - cards.add(new SetCardInfo("Bee Sting", 144, Rarity.UNCOMMON, mage.cards.b.BeeSting.class)); - cards.add(new SetCardInfo("Bird Maiden", 110, Rarity.COMMON, mage.cards.b.BirdMaiden.class)); - cards.add(new SetCardInfo("Black Knight", 71, Rarity.UNCOMMON, mage.cards.b.BlackKnight.class)); - cards.add(new SetCardInfo("Blaze of Glory", 7, Rarity.UNCOMMON, mage.cards.b.BlazeOfGlory.class)); - cards.add(new SetCardInfo("Blue Elemental Blast", 39, Rarity.UNCOMMON, mage.cards.b.BlueElementalBlast.class)); - cards.add(new SetCardInfo("Book of Rass", 183, Rarity.UNCOMMON, mage.cards.b.BookOfRass.class)); - cards.add(new SetCardInfo("Bottle of Suleiman", 184, Rarity.RARE, mage.cards.b.BottleOfSuleiman.class)); - cards.add(new SetCardInfo("Braingeyser", 40, Rarity.RARE, mage.cards.b.Braingeyser.class)); - cards.add(new SetCardInfo("Brass Man", 185, Rarity.COMMON, mage.cards.b.BrassMan.class)); - cards.add(new SetCardInfo("Candelabra of Tawnos", 187, Rarity.RARE, mage.cards.c.CandelabraOfTawnos.class)); - cards.add(new SetCardInfo("Celestial Sword", 188, Rarity.UNCOMMON, mage.cards.c.CelestialSword.class)); - cards.add(new SetCardInfo("Champion Lancer", 8, Rarity.RARE, mage.cards.c.ChampionLancer.class)); - cards.add(new SetCardInfo("Channel", 145, Rarity.RARE, mage.cards.c.Channel.class)); - cards.add(new SetCardInfo("Citanul Druid", 146, Rarity.COMMON, mage.cards.c.CitanulDruid.class)); - cards.add(new SetCardInfo("City of Brass", 243, Rarity.RARE, mage.cards.c.CityOfBrass.class)); - cards.add(new SetCardInfo("Clay Statue", 189, Rarity.UNCOMMON, mage.cards.c.ClayStatue.class)); - cards.add(new SetCardInfo("Clockwork Avian", 190, Rarity.UNCOMMON, mage.cards.c.ClockworkAvian.class)); - cards.add(new SetCardInfo("Clockwork Gnomes", 191, Rarity.UNCOMMON, mage.cards.c.ClockworkGnomes.class)); - cards.add(new SetCardInfo("Clockwork Swarm", 192, Rarity.COMMON, mage.cards.c.ClockworkSwarm.class)); - cards.add(new SetCardInfo("Cloud Dragon", 41, Rarity.RARE, mage.cards.c.CloudDragon.class)); - cards.add(new SetCardInfo("Cloud Spirit", 42, Rarity.COMMON, mage.cards.c.CloudSpirit.class)); - cards.add(new SetCardInfo("Colossus of Sardia", 193, Rarity.RARE, mage.cards.c.ColossusOfSardia.class)); - cards.add(new SetCardInfo("Control Magic", 43, Rarity.RARE, mage.cards.c.ControlMagic.class)); - cards.add(new SetCardInfo("Conversion", 9, Rarity.RARE, mage.cards.c.Conversion.class)); - cards.add(new SetCardInfo("Copy Artifact", 44, Rarity.RARE, mage.cards.c.CopyArtifact.class)); - cards.add(new SetCardInfo("Coral Helm", 194, Rarity.UNCOMMON, mage.cards.c.CoralHelm.class)); - cards.add(new SetCardInfo("Counterspell", 45, Rarity.COMMON, mage.cards.c.Counterspell.class)); - cards.add(new SetCardInfo("Crumble", 147, Rarity.COMMON, mage.cards.c.Crumble.class)); - cards.add(new SetCardInfo("Cyclone", 148, Rarity.RARE, mage.cards.c.Cyclone.class)); - cards.add(new SetCardInfo("Cyclopean Mummy", 72, Rarity.COMMON, mage.cards.c.CyclopeanMummy.class)); - cards.add(new SetCardInfo("Cyclopean Tomb", 195, Rarity.RARE, mage.cards.c.CyclopeanTomb.class)); - cards.add(new SetCardInfo("Dakmor Plague", 73, Rarity.UNCOMMON, mage.cards.d.DakmorPlague.class)); - cards.add(new SetCardInfo("Dark Ritual", 74, Rarity.COMMON, mage.cards.d.DarkRitual.class)); - cards.add(new SetCardInfo("Deathcoil Wurm", 149, Rarity.RARE, mage.cards.d.DeathcoilWurm.class)); - cards.add(new SetCardInfo("Deathgrip", 75, Rarity.RARE, mage.cards.d.Deathgrip.class)); - cards.add(new SetCardInfo("Demonic Hordes", 76, Rarity.RARE, mage.cards.d.DemonicHordes.class)); - cards.add(new SetCardInfo("Demonic Tutor", 77, Rarity.RARE, mage.cards.d.DemonicTutor.class)); - cards.add(new SetCardInfo("Detonate", 111, Rarity.UNCOMMON, mage.cards.d.Detonate.class)); - cards.add(new SetCardInfo("Devastation", 112, Rarity.RARE, mage.cards.d.Devastation.class)); - cards.add(new SetCardInfo("Diabolic Machine", 196, Rarity.UNCOMMON, mage.cards.d.DiabolicMachine.class)); - cards.add(new SetCardInfo("Divine Offering", 10, Rarity.COMMON, mage.cards.d.DivineOffering.class)); - cards.add(new SetCardInfo("Dragon Engine", 197, Rarity.COMMON, mage.cards.d.DragonEngine.class)); - cards.add(new SetCardInfo("Drain Power", 46, Rarity.RARE, mage.cards.d.DrainPower.class)); - cards.add(new SetCardInfo("Dread Reaper", 78, Rarity.RARE, mage.cards.d.DreadReaper.class)); - cards.add(new SetCardInfo("Drop of Honey", 150, Rarity.RARE, mage.cards.d.DropOfHoney.class)); - cards.add(new SetCardInfo("Drowned", 47, Rarity.COMMON, mage.cards.d.Drowned.class)); - cards.add(new SetCardInfo("Dust to Dust", 11, Rarity.UNCOMMON, mage.cards.d.DustToDust.class)); - cards.add(new SetCardInfo("Ebon Dragon", 80, Rarity.RARE, mage.cards.e.EbonDragon.class)); - cards.add(new SetCardInfo("Ebony Horse", 198, Rarity.COMMON, mage.cards.e.EbonyHorse.class)); - cards.add(new SetCardInfo("Ebony Rhino", 199, Rarity.COMMON, mage.cards.e.EbonyRhino.class)); - cards.add(new SetCardInfo("Elephant Graveyard", 244, Rarity.UNCOMMON, mage.cards.e.ElephantGraveyard.class)); - cards.add(new SetCardInfo("Elite Cat Warrior", 151, Rarity.COMMON, mage.cards.e.EliteCatWarrior.class)); - cards.add(new SetCardInfo("Energy Flux", 48, Rarity.UNCOMMON, mage.cards.e.EnergyFlux.class)); - cards.add(new SetCardInfo("Eye for an Eye", 12, Rarity.RARE, mage.cards.e.EyeForAnEye.class)); - cards.add(new SetCardInfo("False Summoning", 49, Rarity.COMMON, mage.cards.f.FalseSummoning.class)); - cards.add(new SetCardInfo("Fastbond", 152, Rarity.RARE, mage.cards.f.Fastbond.class)); - cards.add(new SetCardInfo("Fire Imp", 113, Rarity.UNCOMMON, mage.cards.f.FireImp.class)); - cards.add(new SetCardInfo("Fire Tempest", 114, Rarity.RARE, mage.cards.f.FireTempest.class)); - cards.add(new SetCardInfo("Fireball", 115, Rarity.UNCOMMON, mage.cards.f.Fireball.class)); - cards.add(new SetCardInfo("Floodwater Dam", 200, Rarity.RARE, mage.cards.f.FloodwaterDam.class)); - cards.add(new SetCardInfo("Flying Carpet", 201, Rarity.COMMON, mage.cards.f.FlyingCarpet.class)); - cards.add(new SetCardInfo("Fog", 153, Rarity.COMMON, mage.cards.f.Fog.class)); - cards.add(new SetCardInfo("Force of Nature", 154, Rarity.RARE, mage.cards.f.ForceOfNature.class)); - cards.add(new SetCardInfo("Fork", 116, Rarity.RARE, mage.cards.f.Fork.class)); - cards.add(new SetCardInfo("Foul Spirit", 81, Rarity.COMMON, mage.cards.f.FoulSpirit.class)); - cards.add(new SetCardInfo("Gaea's Avenger", 155, Rarity.UNCOMMON, mage.cards.g.GaeasAvenger.class)); - cards.add(new SetCardInfo("Gate to Phyrexia", 82, Rarity.UNCOMMON, mage.cards.g.GateToPhyrexia.class)); - cards.add(new SetCardInfo("Gauntlet of Might", 202, Rarity.RARE, mage.cards.g.GauntletOfMight.class)); - cards.add(new SetCardInfo("Giant Growth", 156, Rarity.COMMON, mage.cards.g.GiantGrowth.class)); - cards.add(new SetCardInfo("Giant Tortoise", 50, Rarity.COMMON, mage.cards.g.GiantTortoise.class)); - cards.add(new SetCardInfo("Glasses of Urza", 203, Rarity.COMMON, mage.cards.g.GlassesOfUrza.class)); - cards.add(new SetCardInfo("Gloom", 83, Rarity.RARE, mage.cards.g.Gloom.class)); - cards.add(new SetCardInfo("Goblin Bully", 117, Rarity.COMMON, mage.cards.g.GoblinBully.class)); - cards.add(new SetCardInfo("Goblin Cavaliers", 118, Rarity.COMMON, mage.cards.g.GoblinCavaliers.class)); - cards.add(new SetCardInfo("Goblin Caves", 119, Rarity.COMMON, mage.cards.g.GoblinCaves.class)); - cards.add(new SetCardInfo("Goblin Firestarter", 120, Rarity.COMMON, mage.cards.g.GoblinFirestarter.class)); - cards.add(new SetCardInfo("Goblin General", 121, Rarity.UNCOMMON, mage.cards.g.GoblinGeneral.class)); - cards.add(new SetCardInfo("Goblin Shrine", 122, Rarity.COMMON, mage.cards.g.GoblinShrine.class)); - cards.add(new SetCardInfo("Goblin Warrens", 123, Rarity.UNCOMMON, mage.cards.g.GoblinWarrens.class)); - cards.add(new SetCardInfo("Gorilla War Cry", 124, Rarity.COMMON, mage.cards.g.GorillaWarCry.class)); - cards.add(new SetCardInfo("Grapeshot Catapult", 204, Rarity.UNCOMMON, mage.cards.g.GrapeshotCatapult.class)); - cards.add(new SetCardInfo("Gravebind", 84, Rarity.COMMON, mage.cards.g.Gravebind.class)); - cards.add(new SetCardInfo("Guardian Beast", 85, Rarity.RARE, mage.cards.g.GuardianBeast.class)); - cards.add(new SetCardInfo("Harsh Justice", 13, Rarity.RARE, mage.cards.h.HarshJustice.class)); - cards.add(new SetCardInfo("Hasran Ogress", 86, Rarity.COMMON, mage.cards.h.HasranOgress.class)); - cards.add(new SetCardInfo("Healing Salve", 14, Rarity.COMMON, mage.cards.h.HealingSalve.class)); - cards.add(new SetCardInfo("Horn of Deafening", 205, Rarity.UNCOMMON, mage.cards.h.HornOfDeafening.class)); - cards.add(new SetCardInfo("Howl from Beyond", 87, Rarity.COMMON, mage.cards.h.HowlFromBeyond.class)); - cards.add(new SetCardInfo("Ice Cauldron", 206, Rarity.RARE, mage.cards.i.IceCauldron.class)); - cards.add(new SetCardInfo("Icy Manipulator", 207, Rarity.UNCOMMON, mage.cards.i.IcyManipulator.class)); - cards.add(new SetCardInfo("In the Eye of Chaos", 51, Rarity.RARE, mage.cards.i.InTheEyeOfChaos.class)); - cards.add(new SetCardInfo("Instill Energy", 157, Rarity.UNCOMMON, mage.cards.i.InstillEnergy.class)); - cards.add(new SetCardInfo("Ironhoof Ox", 158, Rarity.COMMON, mage.cards.i.IronhoofOx.class)); - cards.add(new SetCardInfo("Island Sanctuary", 15, Rarity.RARE, mage.cards.i.IslandSanctuary.class)); - cards.add(new SetCardInfo("Jade Monolith", 208, Rarity.RARE, mage.cards.j.JadeMonolith.class)); - cards.add(new SetCardInfo("Juggernaut", 209, Rarity.UNCOMMON, mage.cards.j.Juggernaut.class)); - cards.add(new SetCardInfo("Junun Efreet", 88, Rarity.UNCOMMON, mage.cards.j.JununEfreet.class)); - cards.add(new SetCardInfo("Just Fate", 16, Rarity.COMMON, mage.cards.j.JustFate.class)); - cards.add(new SetCardInfo("Kismet", 17, Rarity.RARE, mage.cards.k.Kismet.class)); - cards.add(new SetCardInfo("Kormus Bell", 210, Rarity.RARE, mage.cards.k.KormusBell.class)); - cards.add(new SetCardInfo("Kudzu", 159, Rarity.UNCOMMON, mage.cards.k.Kudzu.class)); - cards.add(new SetCardInfo("Last Chance", 125, Rarity.RARE, mage.cards.l.LastChance.class)); - cards.add(new SetCardInfo("Lava Flow", 126, Rarity.COMMON, mage.cards.l.LavaFlow.class)); - cards.add(new SetCardInfo("Leeches", 18, Rarity.RARE, mage.cards.l.Leeches.class)); - cards.add(new SetCardInfo("Library of Alexandria", 245, Rarity.RARE, mage.cards.l.LibraryOfAlexandria.class)); - cards.add(new SetCardInfo("Library of Leng", 211, Rarity.COMMON, mage.cards.l.LibraryOfLeng.class)); - cards.add(new SetCardInfo("Lich", 89, Rarity.RARE, mage.cards.l.Lich.class)); - cards.add(new SetCardInfo("Lifeforce", 160, Rarity.RARE, mage.cards.l.Lifeforce.class)); - cards.add(new SetCardInfo("Living Lands", 161, Rarity.RARE, mage.cards.l.LivingLands.class)); - cards.add(new SetCardInfo("Living Wall", 212, Rarity.UNCOMMON, mage.cards.l.LivingWall.class)); - cards.add(new SetCardInfo("Mahamoti Djinn", 52, Rarity.RARE, mage.cards.m.MahamotiDjinn.class)); - cards.add(new SetCardInfo("Mana Matrix", 213, Rarity.RARE, mage.cards.m.ManaMatrix.class)); - cards.add(new SetCardInfo("Mana Vault", 214, Rarity.RARE, mage.cards.m.ManaVault.class)); - cards.add(new SetCardInfo("Martyr's Cry", 19, Rarity.RARE, mage.cards.m.MartyrsCry.class)); - cards.add(new SetCardInfo("Martyrs of Korlis", 20, Rarity.UNCOMMON, mage.cards.m.MartyrsOfKorlis.class)); - cards.add(new SetCardInfo("Maze of Ith", 246, Rarity.RARE, mage.cards.m.MazeOfIth.class)); - cards.add(new SetCardInfo("Mightstone", 215, Rarity.COMMON, mage.cards.m.Mightstone.class)); - cards.add(new SetCardInfo("Mijae Djinn", 127, Rarity.RARE, mage.cards.m.MijaeDjinn.class)); - cards.add(new SetCardInfo("Minion of Tevesh Szat", 91, Rarity.RARE, mage.cards.m.MinionOfTeveshSzat.class)); - cards.add(new SetCardInfo("Mishra's Workshop", 247, Rarity.RARE, mage.cards.m.MishrasWorkshop.class)); - cards.add(new SetCardInfo("Mystic Decree", 53, Rarity.UNCOMMON, mage.cards.m.MysticDecree.class)); - cards.add(new SetCardInfo("Naked Singularity", 216, Rarity.RARE, mage.cards.n.NakedSingularity.class)); - cards.add(new SetCardInfo("Oasis", 248, Rarity.COMMON, mage.cards.o.Oasis.class)); - cards.add(new SetCardInfo("Obelisk of Undoing", 217, Rarity.RARE, mage.cards.o.ObeliskOfUndoing.class)); - cards.add(new SetCardInfo("Obsianus Golem", 218, Rarity.COMMON, mage.cards.o.ObsianusGolem.class)); - cards.add(new SetCardInfo("Ogre Taskmaster", 128, Rarity.COMMON, mage.cards.o.OgreTaskmaster.class)); - cards.add(new SetCardInfo("Onulet", 219, Rarity.COMMON, mage.cards.o.Onulet.class)); - cards.add(new SetCardInfo("Orcish Mechanics", 129, Rarity.UNCOMMON, mage.cards.o.OrcishMechanics.class)); - cards.add(new SetCardInfo("Osai Vultures", 21, Rarity.COMMON, mage.cards.o.OsaiVultures.class)); - cards.add(new SetCardInfo("Overwhelming Forces", 92, Rarity.RARE, mage.cards.o.OverwhelmingForces.class)); - cards.add(new SetCardInfo("Owl Familiar", 54, Rarity.COMMON, mage.cards.o.OwlFamiliar.class)); - cards.add(new SetCardInfo("Pentagram of the Ages", 220, Rarity.UNCOMMON, mage.cards.p.PentagramOfTheAges.class)); - cards.add(new SetCardInfo("Personal Incarnation", 22, Rarity.RARE, mage.cards.p.PersonalIncarnation.class)); - cards.add(new SetCardInfo("Phantasmal Forces", 55, Rarity.COMMON, mage.cards.p.PhantasmalForces.class)); - cards.add(new SetCardInfo("Phantasmal Terrain", 56, Rarity.COMMON, mage.cards.p.PhantasmalTerrain.class)); - cards.add(new SetCardInfo("Planar Gate", 221, Rarity.UNCOMMON, mage.cards.p.PlanarGate.class)); - cards.add(new SetCardInfo("Plateau", 249, Rarity.RARE, mage.cards.p.Plateau.class)); - cards.add(new SetCardInfo("Power Artifact", 57, Rarity.RARE, mage.cards.p.PowerArtifact.class)); - cards.add(new SetCardInfo("Primal Clay", 222, Rarity.COMMON, mage.cards.p.PrimalClay.class)); - cards.add(new SetCardInfo("Prodigal Sorcerer", 58, Rarity.UNCOMMON, mage.cards.p.ProdigalSorcerer.class)); - cards.add(new SetCardInfo("Prowling Nightstalker", 93, Rarity.COMMON, mage.cards.p.ProwlingNightstalker.class)); - cards.add(new SetCardInfo("Radjan Spirit", 162, Rarity.UNCOMMON, mage.cards.r.RadjanSpirit.class)); - cards.add(new SetCardInfo("Rain of Daggers", 94, Rarity.RARE, mage.cards.r.RainOfDaggers.class)); - cards.add(new SetCardInfo("Rakalite", 223, Rarity.RARE, mage.cards.r.Rakalite.class)); - cards.add(new SetCardInfo("Reconstruction", 59, Rarity.COMMON, mage.cards.r.Reconstruction.class)); - cards.add(new SetCardInfo("Red Elemental Blast", 131, Rarity.UNCOMMON, mage.cards.r.RedElementalBlast.class)); - cards.add(new SetCardInfo("Regrowth", 163, Rarity.RARE, mage.cards.r.Regrowth.class)); - cards.add(new SetCardInfo("Righteous Charge", 23, Rarity.COMMON, mage.cards.r.RighteousCharge.class)); - cards.add(new SetCardInfo("Ring of Renewal", 224, Rarity.RARE, mage.cards.r.RingOfRenewal.class)); - cards.add(new SetCardInfo("Roc of Kher Ridges", 132, Rarity.UNCOMMON, mage.cards.r.RocOfKherRidges.class)); - cards.add(new SetCardInfo("Rock Hydra", 133, Rarity.RARE, mage.cards.r.RockHydra.class)); - cards.add(new SetCardInfo("Rockslide Ambush", 134, Rarity.COMMON, mage.cards.r.RockslideAmbush.class)); - cards.add(new SetCardInfo("Sandstorm", 164, Rarity.COMMON, mage.cards.s.Sandstorm.class)); - cards.add(new SetCardInfo("Savannah Lions", 24, Rarity.UNCOMMON, mage.cards.s.SavannahLions.class)); - cards.add(new SetCardInfo("Savannah", 250, Rarity.RARE, mage.cards.s.Savannah.class)); - cards.add(new SetCardInfo("Scarecrow", 225, Rarity.UNCOMMON, mage.cards.s.Scarecrow.class)); - cards.add(new SetCardInfo("Scarwood Bandits", 165, Rarity.RARE, mage.cards.s.ScarwoodBandits.class)); - cards.add(new SetCardInfo("Scavenger Folk", 166, Rarity.COMMON, mage.cards.s.ScavengerFolk.class)); - cards.add(new SetCardInfo("Scavenging Ghoul", 95, Rarity.UNCOMMON, mage.cards.s.ScavengingGhoul.class)); - cards.add(new SetCardInfo("Scrubland", 251, Rarity.RARE, mage.cards.s.Scrubland.class)); - cards.add(new SetCardInfo("Sea Serpent", 60, Rarity.COMMON, mage.cards.s.SeaSerpent.class)); - cards.add(new SetCardInfo("Sedge Troll", 135, Rarity.RARE, mage.cards.s.SedgeTroll.class)); - cards.add(new SetCardInfo("Sengir Vampire", 96, Rarity.UNCOMMON, mage.cards.s.SengirVampire.class)); - cards.add(new SetCardInfo("Serendib Djinn", 61, Rarity.RARE, mage.cards.s.SerendibDjinn.class)); - cards.add(new SetCardInfo("Serra Angel", 25, Rarity.UNCOMMON, mage.cards.s.SerraAngel.class)); - cards.add(new SetCardInfo("Serra Aviary", 26, Rarity.UNCOMMON, mage.cards.s.SerraAviary.class)); - cards.add(new SetCardInfo("Serra Bestiary", 27, Rarity.COMMON, mage.cards.s.SerraBestiary.class)); - cards.add(new SetCardInfo("Shapeshifter", 226, Rarity.UNCOMMON, mage.cards.s.Shapeshifter.class)); - cards.add(new SetCardInfo("Shivan Dragon", 136, Rarity.RARE, mage.cards.s.ShivanDragon.class)); - cards.add(new SetCardInfo("Sinkhole", 97, Rarity.RARE, mage.cards.s.Sinkhole.class)); - cards.add(new SetCardInfo("Sleight of Hand", 62, Rarity.COMMON, mage.cards.s.SleightOfHand.class)); - cards.add(new SetCardInfo("Smoke", 137, Rarity.RARE, mage.cards.s.Smoke.class)); - cards.add(new SetCardInfo("Sol Ring", 227, Rarity.RARE, mage.cards.s.SolRing.class)); - cards.add(new SetCardInfo("Soldevi Golem", 228, Rarity.UNCOMMON, mage.cards.s.SoldeviGolem.class)); - cards.add(new SetCardInfo("Soldevi Machinist", 63, Rarity.UNCOMMON, mage.cards.s.SoldeviMachinist.class)); - cards.add(new SetCardInfo("Soul Shred", 98, Rarity.COMMON, mage.cards.s.SoulShred.class)); - cards.add(new SetCardInfo("Southern Elephant", 167, Rarity.COMMON, mage.cards.s.SouthernElephant.class)); - cards.add(new SetCardInfo("Spotted Griffin", 28, Rarity.COMMON, mage.cards.s.SpottedGriffin.class)); - cards.add(new SetCardInfo("Squall", 168, Rarity.UNCOMMON, mage.cards.s.Squall.class)); - cards.add(new SetCardInfo("Staff of Zegon", 229, Rarity.COMMON, mage.cards.s.StaffOfZegon.class)); - cards.add(new SetCardInfo("Stasis", 64, Rarity.RARE, mage.cards.s.Stasis.class)); - cards.add(new SetCardInfo("Steam Catapult", 29, Rarity.RARE, mage.cards.s.SteamCatapult.class)); - cards.add(new SetCardInfo("Strip Mine", 252, Rarity.RARE, mage.cards.s.StripMine.class)); - cards.add(new SetCardInfo("Swords to Plowshares", 30, Rarity.UNCOMMON, mage.cards.s.SwordsToPlowshares.class)); - cards.add(new SetCardInfo("Sylvan Tutor", 169, Rarity.UNCOMMON, mage.cards.s.SylvanTutor.class)); - cards.add(new SetCardInfo("Symbol of Unsummoning", 65, Rarity.COMMON, mage.cards.s.SymbolOfUnsummoning.class)); - cards.add(new SetCardInfo("Tablet of Epityr", 230, Rarity.COMMON, mage.cards.t.TabletOfEpityr.class)); - cards.add(new SetCardInfo("Taiga", 253, Rarity.RARE, mage.cards.t.Taiga.class)); - cards.add(new SetCardInfo("Talas Researcher", 66, Rarity.UNCOMMON, mage.cards.t.TalasResearcher.class)); - cards.add(new SetCardInfo("Tawnos's Wand", 231, Rarity.COMMON, mage.cards.t.TawnossWand.class)); - cards.add(new SetCardInfo("Tawnos's Weaponry", 232, Rarity.UNCOMMON, mage.cards.t.TawnossWeaponry.class)); - cards.add(new SetCardInfo("Temple Acolyte", 31, Rarity.COMMON, mage.cards.t.TempleAcolyte.class)); - cards.add(new SetCardInfo("Terror", 99, Rarity.COMMON, mage.cards.t.Terror.class)); - cards.add(new SetCardInfo("Tetravus", 233, Rarity.RARE, mage.cards.t.Tetravus.class)); - cards.add(new SetCardInfo("Theft of Dreams", 67, Rarity.UNCOMMON, mage.cards.t.TheftOfDreams.class)); - cards.add(new SetCardInfo("Thing from the Deep", 68, Rarity.RARE, mage.cards.t.ThingFromTheDeep.class)); - cards.add(new SetCardInfo("Thunder Dragon", 138, Rarity.RARE, mage.cards.t.ThunderDragon.class)); - cards.add(new SetCardInfo("Time Vault", 234, Rarity.RARE, mage.cards.t.TimeVault.class)); - cards.add(new SetCardInfo("Titania's Song", 170, Rarity.RARE, mage.cards.t.TitaniasSong.class)); - cards.add(new SetCardInfo("Transmute Artifact", 69, Rarity.RARE, mage.cards.t.TransmuteArtifact.class)); - cards.add(new SetCardInfo("Triassic Egg", 235, Rarity.RARE, mage.cards.t.TriassicEgg.class)); - cards.add(new SetCardInfo("Tropical Island", 254, Rarity.RARE, mage.cards.t.TropicalIsland.class)); - cards.add(new SetCardInfo("Tsunami", 171, Rarity.RARE, mage.cards.t.Tsunami.class)); - cards.add(new SetCardInfo("Tundra", 255, Rarity.RARE, mage.cards.t.Tundra.class)); - cards.add(new SetCardInfo("Two-Headed Giant of Foriys", 139, Rarity.UNCOMMON, mage.cards.t.TwoHeadedGiantOfForiys.class)); - cards.add(new SetCardInfo("Underground Sea", 256, Rarity.RARE, mage.cards.u.UndergroundSea.class)); - cards.add(new SetCardInfo("Urza's Chalice", 236, Rarity.COMMON, mage.cards.u.UrzasChalice.class)); - cards.add(new SetCardInfo("Urza's Mine", "257a", Rarity.COMMON, mage.cards.u.UrzasMine.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Mine", "257b", Rarity.COMMON, mage.cards.u.UrzasMine.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Mine", "257c", Rarity.COMMON, mage.cards.u.UrzasMine.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Mine", "257d", Rarity.COMMON, mage.cards.u.UrzasMine.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Miter", 237, Rarity.RARE, mage.cards.u.UrzasMiter.class)); - cards.add(new SetCardInfo("Urza's Power Plant", "258a", Rarity.COMMON, mage.cards.u.UrzasPowerPlant.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Power Plant", "258b", Rarity.COMMON, mage.cards.u.UrzasPowerPlant.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Power Plant", "258c", Rarity.COMMON, mage.cards.u.UrzasPowerPlant.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Power Plant", "258d", Rarity.COMMON, mage.cards.u.UrzasPowerPlant.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Tower", "259a", Rarity.COMMON, mage.cards.u.UrzasTower.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Tower", "259b", Rarity.COMMON, mage.cards.u.UrzasTower.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Tower", "259c", Rarity.COMMON, mage.cards.u.UrzasTower.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Tower", "259d", Rarity.COMMON, mage.cards.u.UrzasTower.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Veteran Bodyguard", 32, Rarity.RARE, mage.cards.v.VeteranBodyguard.class)); - cards.add(new SetCardInfo("Vibrating Sphere", 238, Rarity.RARE, mage.cards.v.VibratingSphere.class)); - cards.add(new SetCardInfo("Volcanic Island", 260, Rarity.RARE, mage.cards.v.VolcanicIsland.class)); - cards.add(new SetCardInfo("War Mammoth", 172, Rarity.COMMON, mage.cards.w.WarMammoth.class)); - cards.add(new SetCardInfo("Warp Artifact", 100, Rarity.COMMON, mage.cards.w.WarpArtifact.class)); - cards.add(new SetCardInfo("Water Elemental", 70, Rarity.UNCOMMON, mage.cards.w.WaterElemental.class)); - cards.add(new SetCardInfo("Weakness", 101, Rarity.COMMON, mage.cards.w.Weakness.class)); - cards.add(new SetCardInfo("Weakstone", 239, Rarity.UNCOMMON, mage.cards.w.Weakstone.class)); - cards.add(new SetCardInfo("Wheel of Fortune", 140, Rarity.RARE, mage.cards.w.WheelOfFortune.class)); - cards.add(new SetCardInfo("Whiptail Wurm", 173, Rarity.UNCOMMON, mage.cards.w.WhiptailWurm.class)); - cards.add(new SetCardInfo("White Knight", 33, Rarity.UNCOMMON, mage.cards.w.WhiteKnight.class)); - cards.add(new SetCardInfo("Wicked Pact", 102, Rarity.UNCOMMON, mage.cards.w.WickedPact.class)); - cards.add(new SetCardInfo("Wild Aesthir", 34, Rarity.COMMON, mage.cards.w.WildAesthir.class)); - cards.add(new SetCardInfo("Wild Griffin", 35, Rarity.COMMON, mage.cards.w.WildGriffin.class)); - cards.add(new SetCardInfo("Wild Ox", 174, Rarity.UNCOMMON, mage.cards.w.WildOx.class)); - cards.add(new SetCardInfo("Wood Elemental", 175, Rarity.RARE, mage.cards.w.WoodElemental.class)); - cards.add(new SetCardInfo("Word of Command", 103, Rarity.RARE, mage.cards.w.WordOfCommand.class)); - cards.add(new SetCardInfo("Xenic Poltergeist", 104, Rarity.UNCOMMON, mage.cards.x.XenicPoltergeist.class)); - cards.add(new SetCardInfo("Yotian Soldier", 240, Rarity.COMMON, mage.cards.y.YotianSoldier.class)); - cards.add(new SetCardInfo("Zombie Master", 105, Rarity.UNCOMMON, mage.cards.z.ZombieMaster.class)); - } - - @Override - public List getSpecialLand() { - // ME4 replace all basic lands with special (1 per booster) - // https://mtg.gamepedia.com/Masters_Edition_IV - - if (savedSpecialLand.isEmpty()) { - savedSpecialLand.addAll(CardRepository.instance.findCards(new CardCriteria().setCodes(this.code).name("Urza's Mine"))); - savedSpecialLand.addAll(CardRepository.instance.findCards(new CardCriteria().setCodes(this.code).name("Urza's Power Plant"))); - savedSpecialLand.addAll(CardRepository.instance.findCards(new CardCriteria().setCodes(this.code).name("Urza's Tower"))); - } - - return new ArrayList<>(savedSpecialLand); - } + +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.cards.repository.CardCriteria; +import mage.cards.repository.CardInfo; +import mage.cards.repository.CardRepository; +import mage.constants.Rarity; +import mage.constants.SetType; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author LevelX2 + */ +public final class MastersEditionIV extends ExpansionSet { + + private static final MastersEditionIV instance = new MastersEditionIV(); + + public static MastersEditionIV getInstance() { + return instance; + } + + protected final List savedSpecialLand = new ArrayList<>(); + + private MastersEditionIV() { + super("Masters Edition IV", "ME4", ExpansionSet.buildDate(2011, 1, 10), SetType.MAGIC_ONLINE); + this.hasBasicLands = false; + this.hasBoosters = true; + this.numBoosterLands = 1; + this.numBoosterCommon = 10; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + this.ratioBoosterSpecialLand = 1; // replace all basic lands + + cards.add(new SetCardInfo("Acid Rain", 36, Rarity.RARE, mage.cards.a.AcidRain.class)); + cards.add(new SetCardInfo("Aesthir Glider", 176, Rarity.COMMON, mage.cards.a.AesthirGlider.class)); + cards.add(new SetCardInfo("Air Elemental", 37, Rarity.UNCOMMON, mage.cards.a.AirElemental.class)); + cards.add(new SetCardInfo("Al-abara's Carpet", 177, Rarity.RARE, mage.cards.a.AlAbarasCarpet.class)); + cards.add(new SetCardInfo("Alaborn Musketeer", 1, Rarity.COMMON, mage.cards.a.AlabornMusketeer.class)); + cards.add(new SetCardInfo("Alaborn Trooper", 2, Rarity.COMMON, mage.cards.a.AlabornTrooper.class)); + cards.add(new SetCardInfo("Aladdin", 106, Rarity.RARE, mage.cards.a.Aladdin.class)); + cards.add(new SetCardInfo("Alchor's Tomb", 178, Rarity.RARE, mage.cards.a.AlchorsTomb.class)); + cards.add(new SetCardInfo("Ali from Cairo", 107, Rarity.RARE, mage.cards.a.AliFromCairo.class)); + cards.add(new SetCardInfo("Alluring Scent", 141, Rarity.COMMON, mage.cards.a.AlluringScent.class)); + cards.add(new SetCardInfo("Amulet of Kroog", 179, Rarity.COMMON, mage.cards.a.AmuletOfKroog.class)); + cards.add(new SetCardInfo("Angelic Voices", 3, Rarity.UNCOMMON, mage.cards.a.AngelicVoices.class)); + cards.add(new SetCardInfo("Animate Artifact", 38, Rarity.UNCOMMON, mage.cards.a.AnimateArtifact.class)); + cards.add(new SetCardInfo("Argivian Blacksmith", 4, Rarity.UNCOMMON, mage.cards.a.ArgivianBlacksmith.class)); + cards.add(new SetCardInfo("Argothian Pixies", 142, Rarity.COMMON, mage.cards.a.ArgothianPixies.class)); + cards.add(new SetCardInfo("Argothian Treefolk", 143, Rarity.UNCOMMON, mage.cards.a.ArgothianTreefolk.class)); + cards.add(new SetCardInfo("Armageddon Clock", 180, Rarity.RARE, mage.cards.a.ArmageddonClock.class)); + cards.add(new SetCardInfo("Armageddon", 5, Rarity.RARE, mage.cards.a.Armageddon.class)); + cards.add(new SetCardInfo("Artifact Blast", 108, Rarity.COMMON, mage.cards.a.ArtifactBlast.class)); + cards.add(new SetCardInfo("Ashnod's Altar", 181, Rarity.RARE, mage.cards.a.AshnodsAltar.class)); + cards.add(new SetCardInfo("Atog", 109, Rarity.COMMON, mage.cards.a.Atog.class)); + cards.add(new SetCardInfo("Badlands", 241, Rarity.RARE, mage.cards.b.Badlands.class)); + cards.add(new SetCardInfo("Balance", 6, Rarity.RARE, mage.cards.b.Balance.class)); + cards.add(new SetCardInfo("Basalt Monolith", 182, Rarity.UNCOMMON, mage.cards.b.BasaltMonolith.class)); + cards.add(new SetCardInfo("Bayou", 242, Rarity.RARE, mage.cards.b.Bayou.class)); + cards.add(new SetCardInfo("Bee Sting", 144, Rarity.UNCOMMON, mage.cards.b.BeeSting.class)); + cards.add(new SetCardInfo("Bird Maiden", 110, Rarity.COMMON, mage.cards.b.BirdMaiden.class)); + cards.add(new SetCardInfo("Black Knight", 71, Rarity.UNCOMMON, mage.cards.b.BlackKnight.class)); + cards.add(new SetCardInfo("Blaze of Glory", 7, Rarity.UNCOMMON, mage.cards.b.BlazeOfGlory.class)); + cards.add(new SetCardInfo("Blue Elemental Blast", 39, Rarity.UNCOMMON, mage.cards.b.BlueElementalBlast.class)); + cards.add(new SetCardInfo("Book of Rass", 183, Rarity.UNCOMMON, mage.cards.b.BookOfRass.class)); + cards.add(new SetCardInfo("Bottle of Suleiman", 184, Rarity.RARE, mage.cards.b.BottleOfSuleiman.class)); + cards.add(new SetCardInfo("Braingeyser", 40, Rarity.RARE, mage.cards.b.Braingeyser.class)); + cards.add(new SetCardInfo("Brass Man", 185, Rarity.COMMON, mage.cards.b.BrassMan.class)); + cards.add(new SetCardInfo("Candelabra of Tawnos", 187, Rarity.RARE, mage.cards.c.CandelabraOfTawnos.class)); + cards.add(new SetCardInfo("Celestial Sword", 188, Rarity.UNCOMMON, mage.cards.c.CelestialSword.class)); + cards.add(new SetCardInfo("Champion Lancer", 8, Rarity.RARE, mage.cards.c.ChampionLancer.class)); + cards.add(new SetCardInfo("Channel", 145, Rarity.RARE, mage.cards.c.Channel.class)); + cards.add(new SetCardInfo("Citanul Druid", 146, Rarity.COMMON, mage.cards.c.CitanulDruid.class)); + cards.add(new SetCardInfo("City of Brass", 243, Rarity.RARE, mage.cards.c.CityOfBrass.class)); + cards.add(new SetCardInfo("Clay Statue", 189, Rarity.UNCOMMON, mage.cards.c.ClayStatue.class)); + cards.add(new SetCardInfo("Clockwork Avian", 190, Rarity.UNCOMMON, mage.cards.c.ClockworkAvian.class)); + cards.add(new SetCardInfo("Clockwork Gnomes", 191, Rarity.UNCOMMON, mage.cards.c.ClockworkGnomes.class)); + cards.add(new SetCardInfo("Clockwork Swarm", 192, Rarity.COMMON, mage.cards.c.ClockworkSwarm.class)); + cards.add(new SetCardInfo("Cloud Dragon", 41, Rarity.RARE, mage.cards.c.CloudDragon.class)); + cards.add(new SetCardInfo("Cloud Spirit", 42, Rarity.COMMON, mage.cards.c.CloudSpirit.class)); + cards.add(new SetCardInfo("Colossus of Sardia", 193, Rarity.RARE, mage.cards.c.ColossusOfSardia.class)); + cards.add(new SetCardInfo("Control Magic", 43, Rarity.RARE, mage.cards.c.ControlMagic.class)); + cards.add(new SetCardInfo("Conversion", 9, Rarity.RARE, mage.cards.c.Conversion.class)); + cards.add(new SetCardInfo("Copy Artifact", 44, Rarity.RARE, mage.cards.c.CopyArtifact.class)); + cards.add(new SetCardInfo("Coral Helm", 194, Rarity.UNCOMMON, mage.cards.c.CoralHelm.class)); + cards.add(new SetCardInfo("Counterspell", 45, Rarity.COMMON, mage.cards.c.Counterspell.class)); + cards.add(new SetCardInfo("Crumble", 147, Rarity.COMMON, mage.cards.c.Crumble.class)); + cards.add(new SetCardInfo("Cyclone", 148, Rarity.RARE, mage.cards.c.Cyclone.class)); + cards.add(new SetCardInfo("Cyclopean Mummy", 72, Rarity.COMMON, mage.cards.c.CyclopeanMummy.class)); + cards.add(new SetCardInfo("Cyclopean Tomb", 195, Rarity.RARE, mage.cards.c.CyclopeanTomb.class)); + cards.add(new SetCardInfo("Dakmor Plague", 73, Rarity.UNCOMMON, mage.cards.d.DakmorPlague.class)); + cards.add(new SetCardInfo("Dark Ritual", 74, Rarity.COMMON, mage.cards.d.DarkRitual.class)); + cards.add(new SetCardInfo("Deathcoil Wurm", 149, Rarity.RARE, mage.cards.d.DeathcoilWurm.class)); + cards.add(new SetCardInfo("Deathgrip", 75, Rarity.RARE, mage.cards.d.Deathgrip.class)); + cards.add(new SetCardInfo("Demonic Hordes", 76, Rarity.RARE, mage.cards.d.DemonicHordes.class)); + cards.add(new SetCardInfo("Demonic Tutor", 77, Rarity.RARE, mage.cards.d.DemonicTutor.class)); + cards.add(new SetCardInfo("Detonate", 111, Rarity.UNCOMMON, mage.cards.d.Detonate.class)); + cards.add(new SetCardInfo("Devastation", 112, Rarity.RARE, mage.cards.d.Devastation.class)); + cards.add(new SetCardInfo("Diabolic Machine", 196, Rarity.UNCOMMON, mage.cards.d.DiabolicMachine.class)); + cards.add(new SetCardInfo("Divine Offering", 10, Rarity.COMMON, mage.cards.d.DivineOffering.class)); + cards.add(new SetCardInfo("Dragon Engine", 197, Rarity.COMMON, mage.cards.d.DragonEngine.class)); + cards.add(new SetCardInfo("Drain Power", 46, Rarity.RARE, mage.cards.d.DrainPower.class)); + cards.add(new SetCardInfo("Dread Reaper", 78, Rarity.RARE, mage.cards.d.DreadReaper.class)); + cards.add(new SetCardInfo("Dread Wight", 79, Rarity.UNCOMMON, mage.cards.d.DreadWight.class)); + cards.add(new SetCardInfo("Drop of Honey", 150, Rarity.RARE, mage.cards.d.DropOfHoney.class)); + cards.add(new SetCardInfo("Drowned", 47, Rarity.COMMON, mage.cards.d.Drowned.class)); + cards.add(new SetCardInfo("Dust to Dust", 11, Rarity.UNCOMMON, mage.cards.d.DustToDust.class)); + cards.add(new SetCardInfo("Ebon Dragon", 80, Rarity.RARE, mage.cards.e.EbonDragon.class)); + cards.add(new SetCardInfo("Ebony Horse", 198, Rarity.COMMON, mage.cards.e.EbonyHorse.class)); + cards.add(new SetCardInfo("Ebony Rhino", 199, Rarity.COMMON, mage.cards.e.EbonyRhino.class)); + cards.add(new SetCardInfo("Elephant Graveyard", 244, Rarity.UNCOMMON, mage.cards.e.ElephantGraveyard.class)); + cards.add(new SetCardInfo("Elite Cat Warrior", 151, Rarity.COMMON, mage.cards.e.EliteCatWarrior.class)); + cards.add(new SetCardInfo("Energy Flux", 48, Rarity.UNCOMMON, mage.cards.e.EnergyFlux.class)); + cards.add(new SetCardInfo("Eye for an Eye", 12, Rarity.RARE, mage.cards.e.EyeForAnEye.class)); + cards.add(new SetCardInfo("False Summoning", 49, Rarity.COMMON, mage.cards.f.FalseSummoning.class)); + cards.add(new SetCardInfo("Fastbond", 152, Rarity.RARE, mage.cards.f.Fastbond.class)); + cards.add(new SetCardInfo("Fire Imp", 113, Rarity.UNCOMMON, mage.cards.f.FireImp.class)); + cards.add(new SetCardInfo("Fire Tempest", 114, Rarity.RARE, mage.cards.f.FireTempest.class)); + cards.add(new SetCardInfo("Fireball", 115, Rarity.UNCOMMON, mage.cards.f.Fireball.class)); + cards.add(new SetCardInfo("Floodwater Dam", 200, Rarity.RARE, mage.cards.f.FloodwaterDam.class)); + cards.add(new SetCardInfo("Flying Carpet", 201, Rarity.COMMON, mage.cards.f.FlyingCarpet.class)); + cards.add(new SetCardInfo("Fog", 153, Rarity.COMMON, mage.cards.f.Fog.class)); + cards.add(new SetCardInfo("Force of Nature", 154, Rarity.RARE, mage.cards.f.ForceOfNature.class)); + cards.add(new SetCardInfo("Fork", 116, Rarity.RARE, mage.cards.f.Fork.class)); + cards.add(new SetCardInfo("Foul Spirit", 81, Rarity.COMMON, mage.cards.f.FoulSpirit.class)); + cards.add(new SetCardInfo("Gaea's Avenger", 155, Rarity.UNCOMMON, mage.cards.g.GaeasAvenger.class)); + cards.add(new SetCardInfo("Gate to Phyrexia", 82, Rarity.UNCOMMON, mage.cards.g.GateToPhyrexia.class)); + cards.add(new SetCardInfo("Gauntlet of Might", 202, Rarity.RARE, mage.cards.g.GauntletOfMight.class)); + cards.add(new SetCardInfo("Giant Growth", 156, Rarity.COMMON, mage.cards.g.GiantGrowth.class)); + cards.add(new SetCardInfo("Giant Tortoise", 50, Rarity.COMMON, mage.cards.g.GiantTortoise.class)); + cards.add(new SetCardInfo("Glasses of Urza", 203, Rarity.COMMON, mage.cards.g.GlassesOfUrza.class)); + cards.add(new SetCardInfo("Gloom", 83, Rarity.RARE, mage.cards.g.Gloom.class)); + cards.add(new SetCardInfo("Goblin Bully", 117, Rarity.COMMON, mage.cards.g.GoblinBully.class)); + cards.add(new SetCardInfo("Goblin Cavaliers", 118, Rarity.COMMON, mage.cards.g.GoblinCavaliers.class)); + cards.add(new SetCardInfo("Goblin Caves", 119, Rarity.COMMON, mage.cards.g.GoblinCaves.class)); + cards.add(new SetCardInfo("Goblin Firestarter", 120, Rarity.COMMON, mage.cards.g.GoblinFirestarter.class)); + cards.add(new SetCardInfo("Goblin General", 121, Rarity.UNCOMMON, mage.cards.g.GoblinGeneral.class)); + cards.add(new SetCardInfo("Goblin Shrine", 122, Rarity.COMMON, mage.cards.g.GoblinShrine.class)); + cards.add(new SetCardInfo("Goblin Warrens", 123, Rarity.UNCOMMON, mage.cards.g.GoblinWarrens.class)); + cards.add(new SetCardInfo("Gorilla War Cry", 124, Rarity.COMMON, mage.cards.g.GorillaWarCry.class)); + cards.add(new SetCardInfo("Grapeshot Catapult", 204, Rarity.UNCOMMON, mage.cards.g.GrapeshotCatapult.class)); + cards.add(new SetCardInfo("Gravebind", 84, Rarity.COMMON, mage.cards.g.Gravebind.class)); + cards.add(new SetCardInfo("Guardian Beast", 85, Rarity.RARE, mage.cards.g.GuardianBeast.class)); + cards.add(new SetCardInfo("Harsh Justice", 13, Rarity.RARE, mage.cards.h.HarshJustice.class)); + cards.add(new SetCardInfo("Hasran Ogress", 86, Rarity.COMMON, mage.cards.h.HasranOgress.class)); + cards.add(new SetCardInfo("Healing Salve", 14, Rarity.COMMON, mage.cards.h.HealingSalve.class)); + cards.add(new SetCardInfo("Horn of Deafening", 205, Rarity.UNCOMMON, mage.cards.h.HornOfDeafening.class)); + cards.add(new SetCardInfo("Howl from Beyond", 87, Rarity.COMMON, mage.cards.h.HowlFromBeyond.class)); + cards.add(new SetCardInfo("Ice Cauldron", 206, Rarity.RARE, mage.cards.i.IceCauldron.class)); + cards.add(new SetCardInfo("Icy Manipulator", 207, Rarity.UNCOMMON, mage.cards.i.IcyManipulator.class)); + cards.add(new SetCardInfo("In the Eye of Chaos", 51, Rarity.RARE, mage.cards.i.InTheEyeOfChaos.class)); + cards.add(new SetCardInfo("Instill Energy", 157, Rarity.UNCOMMON, mage.cards.i.InstillEnergy.class)); + cards.add(new SetCardInfo("Ironhoof Ox", 158, Rarity.COMMON, mage.cards.i.IronhoofOx.class)); + cards.add(new SetCardInfo("Island Sanctuary", 15, Rarity.RARE, mage.cards.i.IslandSanctuary.class)); + cards.add(new SetCardInfo("Jade Monolith", 208, Rarity.RARE, mage.cards.j.JadeMonolith.class)); + cards.add(new SetCardInfo("Juggernaut", 209, Rarity.UNCOMMON, mage.cards.j.Juggernaut.class)); + cards.add(new SetCardInfo("Junun Efreet", 88, Rarity.UNCOMMON, mage.cards.j.JununEfreet.class)); + cards.add(new SetCardInfo("Just Fate", 16, Rarity.COMMON, mage.cards.j.JustFate.class)); + cards.add(new SetCardInfo("Kismet", 17, Rarity.RARE, mage.cards.k.Kismet.class)); + cards.add(new SetCardInfo("Kormus Bell", 210, Rarity.RARE, mage.cards.k.KormusBell.class)); + cards.add(new SetCardInfo("Kudzu", 159, Rarity.UNCOMMON, mage.cards.k.Kudzu.class)); + cards.add(new SetCardInfo("Last Chance", 125, Rarity.RARE, mage.cards.l.LastChance.class)); + cards.add(new SetCardInfo("Lava Flow", 126, Rarity.COMMON, mage.cards.l.LavaFlow.class)); + cards.add(new SetCardInfo("Leeches", 18, Rarity.RARE, mage.cards.l.Leeches.class)); + cards.add(new SetCardInfo("Library of Alexandria", 245, Rarity.RARE, mage.cards.l.LibraryOfAlexandria.class)); + cards.add(new SetCardInfo("Library of Leng", 211, Rarity.COMMON, mage.cards.l.LibraryOfLeng.class)); + cards.add(new SetCardInfo("Lich", 89, Rarity.RARE, mage.cards.l.Lich.class)); + cards.add(new SetCardInfo("Lifeforce", 160, Rarity.RARE, mage.cards.l.Lifeforce.class)); + cards.add(new SetCardInfo("Living Lands", 161, Rarity.RARE, mage.cards.l.LivingLands.class)); + cards.add(new SetCardInfo("Living Wall", 212, Rarity.UNCOMMON, mage.cards.l.LivingWall.class)); + cards.add(new SetCardInfo("Mahamoti Djinn", 52, Rarity.RARE, mage.cards.m.MahamotiDjinn.class)); + cards.add(new SetCardInfo("Mana Matrix", 213, Rarity.RARE, mage.cards.m.ManaMatrix.class)); + cards.add(new SetCardInfo("Mana Vault", 214, Rarity.RARE, mage.cards.m.ManaVault.class)); + cards.add(new SetCardInfo("Martyr's Cry", 19, Rarity.RARE, mage.cards.m.MartyrsCry.class)); + cards.add(new SetCardInfo("Martyrs of Korlis", 20, Rarity.UNCOMMON, mage.cards.m.MartyrsOfKorlis.class)); + cards.add(new SetCardInfo("Maze of Ith", 246, Rarity.RARE, mage.cards.m.MazeOfIth.class)); + cards.add(new SetCardInfo("Mightstone", 215, Rarity.COMMON, mage.cards.m.Mightstone.class)); + cards.add(new SetCardInfo("Mijae Djinn", 127, Rarity.RARE, mage.cards.m.MijaeDjinn.class)); + cards.add(new SetCardInfo("Minion of Tevesh Szat", 91, Rarity.RARE, mage.cards.m.MinionOfTeveshSzat.class)); + cards.add(new SetCardInfo("Mishra's Workshop", 247, Rarity.RARE, mage.cards.m.MishrasWorkshop.class)); + cards.add(new SetCardInfo("Mystic Decree", 53, Rarity.UNCOMMON, mage.cards.m.MysticDecree.class)); + cards.add(new SetCardInfo("Naked Singularity", 216, Rarity.RARE, mage.cards.n.NakedSingularity.class)); + cards.add(new SetCardInfo("Oasis", 248, Rarity.COMMON, mage.cards.o.Oasis.class)); + cards.add(new SetCardInfo("Obelisk of Undoing", 217, Rarity.RARE, mage.cards.o.ObeliskOfUndoing.class)); + cards.add(new SetCardInfo("Obsianus Golem", 218, Rarity.COMMON, mage.cards.o.ObsianusGolem.class)); + cards.add(new SetCardInfo("Ogre Taskmaster", 128, Rarity.COMMON, mage.cards.o.OgreTaskmaster.class)); + cards.add(new SetCardInfo("Onulet", 219, Rarity.COMMON, mage.cards.o.Onulet.class)); + cards.add(new SetCardInfo("Orcish Mechanics", 129, Rarity.UNCOMMON, mage.cards.o.OrcishMechanics.class)); + cards.add(new SetCardInfo("Osai Vultures", 21, Rarity.COMMON, mage.cards.o.OsaiVultures.class)); + cards.add(new SetCardInfo("Overwhelming Forces", 92, Rarity.RARE, mage.cards.o.OverwhelmingForces.class)); + cards.add(new SetCardInfo("Owl Familiar", 54, Rarity.COMMON, mage.cards.o.OwlFamiliar.class)); + cards.add(new SetCardInfo("Pentagram of the Ages", 220, Rarity.UNCOMMON, mage.cards.p.PentagramOfTheAges.class)); + cards.add(new SetCardInfo("Personal Incarnation", 22, Rarity.RARE, mage.cards.p.PersonalIncarnation.class)); + cards.add(new SetCardInfo("Phantasmal Forces", 55, Rarity.COMMON, mage.cards.p.PhantasmalForces.class)); + cards.add(new SetCardInfo("Phantasmal Terrain", 56, Rarity.COMMON, mage.cards.p.PhantasmalTerrain.class)); + cards.add(new SetCardInfo("Planar Gate", 221, Rarity.UNCOMMON, mage.cards.p.PlanarGate.class)); + cards.add(new SetCardInfo("Plateau", 249, Rarity.RARE, mage.cards.p.Plateau.class)); + cards.add(new SetCardInfo("Power Artifact", 57, Rarity.RARE, mage.cards.p.PowerArtifact.class)); + cards.add(new SetCardInfo("Primal Clay", 222, Rarity.COMMON, mage.cards.p.PrimalClay.class)); + cards.add(new SetCardInfo("Prodigal Sorcerer", 58, Rarity.UNCOMMON, mage.cards.p.ProdigalSorcerer.class)); + cards.add(new SetCardInfo("Prowling Nightstalker", 93, Rarity.COMMON, mage.cards.p.ProwlingNightstalker.class)); + cards.add(new SetCardInfo("Radjan Spirit", 162, Rarity.UNCOMMON, mage.cards.r.RadjanSpirit.class)); + cards.add(new SetCardInfo("Rain of Daggers", 94, Rarity.RARE, mage.cards.r.RainOfDaggers.class)); + cards.add(new SetCardInfo("Rakalite", 223, Rarity.RARE, mage.cards.r.Rakalite.class)); + cards.add(new SetCardInfo("Reconstruction", 59, Rarity.COMMON, mage.cards.r.Reconstruction.class)); + cards.add(new SetCardInfo("Red Elemental Blast", 131, Rarity.UNCOMMON, mage.cards.r.RedElementalBlast.class)); + cards.add(new SetCardInfo("Regrowth", 163, Rarity.RARE, mage.cards.r.Regrowth.class)); + cards.add(new SetCardInfo("Righteous Charge", 23, Rarity.COMMON, mage.cards.r.RighteousCharge.class)); + cards.add(new SetCardInfo("Ring of Renewal", 224, Rarity.RARE, mage.cards.r.RingOfRenewal.class)); + cards.add(new SetCardInfo("Roc of Kher Ridges", 132, Rarity.UNCOMMON, mage.cards.r.RocOfKherRidges.class)); + cards.add(new SetCardInfo("Rock Hydra", 133, Rarity.RARE, mage.cards.r.RockHydra.class)); + cards.add(new SetCardInfo("Rockslide Ambush", 134, Rarity.COMMON, mage.cards.r.RockslideAmbush.class)); + cards.add(new SetCardInfo("Sandstorm", 164, Rarity.COMMON, mage.cards.s.Sandstorm.class)); + cards.add(new SetCardInfo("Savannah Lions", 24, Rarity.UNCOMMON, mage.cards.s.SavannahLions.class)); + cards.add(new SetCardInfo("Savannah", 250, Rarity.RARE, mage.cards.s.Savannah.class)); + cards.add(new SetCardInfo("Scarecrow", 225, Rarity.UNCOMMON, mage.cards.s.Scarecrow.class)); + cards.add(new SetCardInfo("Scarwood Bandits", 165, Rarity.RARE, mage.cards.s.ScarwoodBandits.class)); + cards.add(new SetCardInfo("Scavenger Folk", 166, Rarity.COMMON, mage.cards.s.ScavengerFolk.class)); + cards.add(new SetCardInfo("Scavenging Ghoul", 95, Rarity.UNCOMMON, mage.cards.s.ScavengingGhoul.class)); + cards.add(new SetCardInfo("Scrubland", 251, Rarity.RARE, mage.cards.s.Scrubland.class)); + cards.add(new SetCardInfo("Sea Serpent", 60, Rarity.COMMON, mage.cards.s.SeaSerpent.class)); + cards.add(new SetCardInfo("Sedge Troll", 135, Rarity.RARE, mage.cards.s.SedgeTroll.class)); + cards.add(new SetCardInfo("Sengir Vampire", 96, Rarity.UNCOMMON, mage.cards.s.SengirVampire.class)); + cards.add(new SetCardInfo("Serendib Djinn", 61, Rarity.RARE, mage.cards.s.SerendibDjinn.class)); + cards.add(new SetCardInfo("Serra Angel", 25, Rarity.UNCOMMON, mage.cards.s.SerraAngel.class)); + cards.add(new SetCardInfo("Serra Aviary", 26, Rarity.UNCOMMON, mage.cards.s.SerraAviary.class)); + cards.add(new SetCardInfo("Serra Bestiary", 27, Rarity.COMMON, mage.cards.s.SerraBestiary.class)); + cards.add(new SetCardInfo("Shapeshifter", 226, Rarity.UNCOMMON, mage.cards.s.Shapeshifter.class)); + cards.add(new SetCardInfo("Shivan Dragon", 136, Rarity.RARE, mage.cards.s.ShivanDragon.class)); + cards.add(new SetCardInfo("Sinkhole", 97, Rarity.RARE, mage.cards.s.Sinkhole.class)); + cards.add(new SetCardInfo("Sleight of Hand", 62, Rarity.COMMON, mage.cards.s.SleightOfHand.class)); + cards.add(new SetCardInfo("Smoke", 137, Rarity.RARE, mage.cards.s.Smoke.class)); + cards.add(new SetCardInfo("Sol Ring", 227, Rarity.RARE, mage.cards.s.SolRing.class)); + cards.add(new SetCardInfo("Soldevi Golem", 228, Rarity.UNCOMMON, mage.cards.s.SoldeviGolem.class)); + cards.add(new SetCardInfo("Soldevi Machinist", 63, Rarity.UNCOMMON, mage.cards.s.SoldeviMachinist.class)); + cards.add(new SetCardInfo("Soul Shred", 98, Rarity.COMMON, mage.cards.s.SoulShred.class)); + cards.add(new SetCardInfo("Southern Elephant", 167, Rarity.COMMON, mage.cards.s.SouthernElephant.class)); + cards.add(new SetCardInfo("Spotted Griffin", 28, Rarity.COMMON, mage.cards.s.SpottedGriffin.class)); + cards.add(new SetCardInfo("Squall", 168, Rarity.UNCOMMON, mage.cards.s.Squall.class)); + cards.add(new SetCardInfo("Staff of Zegon", 229, Rarity.COMMON, mage.cards.s.StaffOfZegon.class)); + cards.add(new SetCardInfo("Stasis", 64, Rarity.RARE, mage.cards.s.Stasis.class)); + cards.add(new SetCardInfo("Steam Catapult", 29, Rarity.RARE, mage.cards.s.SteamCatapult.class)); + cards.add(new SetCardInfo("Strip Mine", 252, Rarity.RARE, mage.cards.s.StripMine.class)); + cards.add(new SetCardInfo("Swords to Plowshares", 30, Rarity.UNCOMMON, mage.cards.s.SwordsToPlowshares.class)); + cards.add(new SetCardInfo("Sylvan Tutor", 169, Rarity.UNCOMMON, mage.cards.s.SylvanTutor.class)); + cards.add(new SetCardInfo("Symbol of Unsummoning", 65, Rarity.COMMON, mage.cards.s.SymbolOfUnsummoning.class)); + cards.add(new SetCardInfo("Tablet of Epityr", 230, Rarity.COMMON, mage.cards.t.TabletOfEpityr.class)); + cards.add(new SetCardInfo("Taiga", 253, Rarity.RARE, mage.cards.t.Taiga.class)); + cards.add(new SetCardInfo("Talas Researcher", 66, Rarity.UNCOMMON, mage.cards.t.TalasResearcher.class)); + cards.add(new SetCardInfo("Tawnos's Wand", 231, Rarity.COMMON, mage.cards.t.TawnossWand.class)); + cards.add(new SetCardInfo("Tawnos's Weaponry", 232, Rarity.UNCOMMON, mage.cards.t.TawnossWeaponry.class)); + cards.add(new SetCardInfo("Temple Acolyte", 31, Rarity.COMMON, mage.cards.t.TempleAcolyte.class)); + cards.add(new SetCardInfo("Terror", 99, Rarity.COMMON, mage.cards.t.Terror.class)); + cards.add(new SetCardInfo("Tetravus", 233, Rarity.RARE, mage.cards.t.Tetravus.class)); + cards.add(new SetCardInfo("Theft of Dreams", 67, Rarity.UNCOMMON, mage.cards.t.TheftOfDreams.class)); + cards.add(new SetCardInfo("Thing from the Deep", 68, Rarity.RARE, mage.cards.t.ThingFromTheDeep.class)); + cards.add(new SetCardInfo("Thunder Dragon", 138, Rarity.RARE, mage.cards.t.ThunderDragon.class)); + cards.add(new SetCardInfo("Time Vault", 234, Rarity.RARE, mage.cards.t.TimeVault.class)); + cards.add(new SetCardInfo("Titania's Song", 170, Rarity.RARE, mage.cards.t.TitaniasSong.class)); + cards.add(new SetCardInfo("Transmute Artifact", 69, Rarity.RARE, mage.cards.t.TransmuteArtifact.class)); + cards.add(new SetCardInfo("Triassic Egg", 235, Rarity.RARE, mage.cards.t.TriassicEgg.class)); + cards.add(new SetCardInfo("Tropical Island", 254, Rarity.RARE, mage.cards.t.TropicalIsland.class)); + cards.add(new SetCardInfo("Tsunami", 171, Rarity.RARE, mage.cards.t.Tsunami.class)); + cards.add(new SetCardInfo("Tundra", 255, Rarity.RARE, mage.cards.t.Tundra.class)); + cards.add(new SetCardInfo("Two-Headed Giant of Foriys", 139, Rarity.UNCOMMON, mage.cards.t.TwoHeadedGiantOfForiys.class)); + cards.add(new SetCardInfo("Underground Sea", 256, Rarity.RARE, mage.cards.u.UndergroundSea.class)); + cards.add(new SetCardInfo("Urza's Chalice", 236, Rarity.COMMON, mage.cards.u.UrzasChalice.class)); + cards.add(new SetCardInfo("Urza's Mine", "257a", Rarity.COMMON, mage.cards.u.UrzasMine.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Mine", "257b", Rarity.COMMON, mage.cards.u.UrzasMine.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Mine", "257c", Rarity.COMMON, mage.cards.u.UrzasMine.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Mine", "257d", Rarity.COMMON, mage.cards.u.UrzasMine.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Miter", 237, Rarity.RARE, mage.cards.u.UrzasMiter.class)); + cards.add(new SetCardInfo("Urza's Power Plant", "258a", Rarity.COMMON, mage.cards.u.UrzasPowerPlant.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Power Plant", "258b", Rarity.COMMON, mage.cards.u.UrzasPowerPlant.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Power Plant", "258c", Rarity.COMMON, mage.cards.u.UrzasPowerPlant.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Power Plant", "258d", Rarity.COMMON, mage.cards.u.UrzasPowerPlant.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Tower", "259a", Rarity.COMMON, mage.cards.u.UrzasTower.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Tower", "259b", Rarity.COMMON, mage.cards.u.UrzasTower.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Tower", "259c", Rarity.COMMON, mage.cards.u.UrzasTower.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Tower", "259d", Rarity.COMMON, mage.cards.u.UrzasTower.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Veteran Bodyguard", 32, Rarity.RARE, mage.cards.v.VeteranBodyguard.class)); + cards.add(new SetCardInfo("Vibrating Sphere", 238, Rarity.RARE, mage.cards.v.VibratingSphere.class)); + cards.add(new SetCardInfo("Volcanic Island", 260, Rarity.RARE, mage.cards.v.VolcanicIsland.class)); + cards.add(new SetCardInfo("War Mammoth", 172, Rarity.COMMON, mage.cards.w.WarMammoth.class)); + cards.add(new SetCardInfo("Warp Artifact", 100, Rarity.COMMON, mage.cards.w.WarpArtifact.class)); + cards.add(new SetCardInfo("Water Elemental", 70, Rarity.UNCOMMON, mage.cards.w.WaterElemental.class)); + cards.add(new SetCardInfo("Weakness", 101, Rarity.COMMON, mage.cards.w.Weakness.class)); + cards.add(new SetCardInfo("Weakstone", 239, Rarity.UNCOMMON, mage.cards.w.Weakstone.class)); + cards.add(new SetCardInfo("Wheel of Fortune", 140, Rarity.RARE, mage.cards.w.WheelOfFortune.class)); + cards.add(new SetCardInfo("Whiptail Wurm", 173, Rarity.UNCOMMON, mage.cards.w.WhiptailWurm.class)); + cards.add(new SetCardInfo("White Knight", 33, Rarity.UNCOMMON, mage.cards.w.WhiteKnight.class)); + cards.add(new SetCardInfo("Wicked Pact", 102, Rarity.UNCOMMON, mage.cards.w.WickedPact.class)); + cards.add(new SetCardInfo("Wild Aesthir", 34, Rarity.COMMON, mage.cards.w.WildAesthir.class)); + cards.add(new SetCardInfo("Wild Griffin", 35, Rarity.COMMON, mage.cards.w.WildGriffin.class)); + cards.add(new SetCardInfo("Wild Ox", 174, Rarity.UNCOMMON, mage.cards.w.WildOx.class)); + cards.add(new SetCardInfo("Wood Elemental", 175, Rarity.RARE, mage.cards.w.WoodElemental.class)); + cards.add(new SetCardInfo("Word of Command", 103, Rarity.RARE, mage.cards.w.WordOfCommand.class)); + cards.add(new SetCardInfo("Xenic Poltergeist", 104, Rarity.UNCOMMON, mage.cards.x.XenicPoltergeist.class)); + cards.add(new SetCardInfo("Yotian Soldier", 240, Rarity.COMMON, mage.cards.y.YotianSoldier.class)); + cards.add(new SetCardInfo("Zombie Master", 105, Rarity.UNCOMMON, mage.cards.z.ZombieMaster.class)); + } + + @Override + public List getSpecialLand() { + // ME4 replace all basic lands with special (1 per booster) + // https://mtg.gamepedia.com/Masters_Edition_IV + + if (savedSpecialLand.isEmpty()) { + savedSpecialLand.addAll(CardRepository.instance.findCards(new CardCriteria().setCodes(this.code).name("Urza's Mine"))); + savedSpecialLand.addAll(CardRepository.instance.findCards(new CardCriteria().setCodes(this.code).name("Urza's Power Plant"))); + savedSpecialLand.addAll(CardRepository.instance.findCards(new CardCriteria().setCodes(this.code).name("Urza's Tower"))); + } + + return new ArrayList<>(savedSpecialLand); + } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/Prophecy.java b/Mage.Sets/src/mage/sets/Prophecy.java index 66b0ea67afb..9ff9dde2a77 100644 --- a/Mage.Sets/src/mage/sets/Prophecy.java +++ b/Mage.Sets/src/mage/sets/Prophecy.java @@ -1,173 +1,175 @@ - -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -/** - * - * @author North - */ -public final class Prophecy extends ExpansionSet { - - private static final Prophecy instance = new Prophecy(); - - public static Prophecy getInstance() { - return instance; - } - - private Prophecy() { - super("Prophecy", "PCY", ExpansionSet.buildDate(2000, 4, 27), SetType.EXPANSION); - this.blockName = "Masques"; - this.parentSet = MercadianMasques.getInstance(); - this.hasBasicLands = false; - this.hasBoosters = true; - this.numBoosterLands = 0; - this.numBoosterCommon = 11; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - cards.add(new SetCardInfo("Abolish", 1, Rarity.UNCOMMON, mage.cards.a.Abolish.class)); - cards.add(new SetCardInfo("Agent of Shauku", 55, Rarity.COMMON, mage.cards.a.AgentOfShauku.class)); - cards.add(new SetCardInfo("Alexi's Cloak", 29, Rarity.COMMON, mage.cards.a.AlexisCloak.class)); - cards.add(new SetCardInfo("Alexi, Zephyr Mage", 28, Rarity.RARE, mage.cards.a.AlexiZephyrMage.class)); - cards.add(new SetCardInfo("Aura Fracture", 2, Rarity.COMMON, mage.cards.a.AuraFracture.class)); - cards.add(new SetCardInfo("Avatar of Fury", 82, Rarity.RARE, mage.cards.a.AvatarOfFury.class)); - cards.add(new SetCardInfo("Avatar of Hope", 3, Rarity.RARE, mage.cards.a.AvatarOfHope.class)); - cards.add(new SetCardInfo("Avatar of Might", 109, Rarity.RARE, mage.cards.a.AvatarOfMight.class)); - cards.add(new SetCardInfo("Avatar of Will", 30, Rarity.RARE, mage.cards.a.AvatarOfWill.class)); - cards.add(new SetCardInfo("Avatar of Woe", 56, Rarity.RARE, mage.cards.a.AvatarOfWoe.class)); - cards.add(new SetCardInfo("Barbed Field", 83, Rarity.UNCOMMON, mage.cards.b.BarbedField.class)); - cards.add(new SetCardInfo("Blessed Wind", 4, Rarity.RARE, mage.cards.b.BlessedWind.class)); - cards.add(new SetCardInfo("Bog Elemental", 57, Rarity.RARE, mage.cards.b.BogElemental.class)); - cards.add(new SetCardInfo("Bog Glider", 58, Rarity.COMMON, mage.cards.b.BogGlider.class)); - cards.add(new SetCardInfo("Branded Brawlers", 84, Rarity.COMMON, mage.cards.b.BrandedBrawlers.class)); - cards.add(new SetCardInfo("Brutal Suppression", 85, Rarity.UNCOMMON, mage.cards.b.BrutalSuppression.class)); - cards.add(new SetCardInfo("Calming Verse", 110, Rarity.COMMON, mage.cards.c.CalmingVerse.class)); - cards.add(new SetCardInfo("Celestial Convergence", 5, Rarity.RARE, mage.cards.c.CelestialConvergence.class)); - cards.add(new SetCardInfo("Chilling Apparition", 59, Rarity.UNCOMMON, mage.cards.c.ChillingApparition.class)); - cards.add(new SetCardInfo("Chimeric Idol", 136, Rarity.UNCOMMON, mage.cards.c.ChimericIdol.class)); - cards.add(new SetCardInfo("Citadel of Pain", 86, Rarity.UNCOMMON, mage.cards.c.CitadelOfPain.class)); - cards.add(new SetCardInfo("Coastal Hornclaw", 31, Rarity.COMMON, mage.cards.c.CoastalHornclaw.class)); - cards.add(new SetCardInfo("Coffin Puppets", 60, Rarity.RARE, mage.cards.c.CoffinPuppets.class)); - cards.add(new SetCardInfo("Copper-Leaf Angel", 137, Rarity.RARE, mage.cards.c.CopperLeafAngel.class)); - cards.add(new SetCardInfo("Darba", 111, Rarity.UNCOMMON, mage.cards.d.Darba.class)); - cards.add(new SetCardInfo("Death Charmer", 61, Rarity.COMMON, mage.cards.d.DeathCharmer.class)); - cards.add(new SetCardInfo("Denying Wind", 32, Rarity.RARE, mage.cards.d.DenyingWind.class)); - cards.add(new SetCardInfo("Despoil", 62, Rarity.COMMON, mage.cards.d.Despoil.class)); - cards.add(new SetCardInfo("Devastate", 87, Rarity.COMMON, mage.cards.d.Devastate.class)); - cards.add(new SetCardInfo("Diving Griffin", 6, Rarity.COMMON, mage.cards.d.DivingGriffin.class)); - cards.add(new SetCardInfo("Dual Nature", 112, Rarity.RARE, mage.cards.d.DualNature.class)); - cards.add(new SetCardInfo("Elephant Resurgence", 113, Rarity.RARE, mage.cards.e.ElephantResurgence.class)); - cards.add(new SetCardInfo("Endbringer's Revel", 63, Rarity.UNCOMMON, mage.cards.e.EndbringersRevel.class)); - cards.add(new SetCardInfo("Entangler", 7, Rarity.UNCOMMON, mage.cards.e.Entangler.class)); - cards.add(new SetCardInfo("Excavation", 33, Rarity.UNCOMMON, mage.cards.e.Excavation.class)); - cards.add(new SetCardInfo("Excise", 8, Rarity.COMMON, mage.cards.e.Excise.class)); - cards.add(new SetCardInfo("Fault Riders", 88, Rarity.COMMON, mage.cards.f.FaultRiders.class)); - cards.add(new SetCardInfo("Fen Stalker", 64, Rarity.COMMON, mage.cards.f.FenStalker.class)); - cards.add(new SetCardInfo("Fickle Efreet", 89, Rarity.RARE, mage.cards.f.FickleEfreet.class)); - cards.add(new SetCardInfo("Flameshot", 90, Rarity.UNCOMMON, mage.cards.f.Flameshot.class)); - cards.add(new SetCardInfo("Flay", 65, Rarity.COMMON, mage.cards.f.Flay.class)); - cards.add(new SetCardInfo("Flowering Field", 9, Rarity.UNCOMMON, mage.cards.f.FloweringField.class)); - cards.add(new SetCardInfo("Foil", 34, Rarity.UNCOMMON, mage.cards.f.Foil.class)); - cards.add(new SetCardInfo("Forgotten Harvest", 114, Rarity.RARE, mage.cards.f.ForgottenHarvest.class)); - cards.add(new SetCardInfo("Glittering Lion", 10, Rarity.UNCOMMON, mage.cards.g.GlitteringLion.class)); - cards.add(new SetCardInfo("Glittering Lynx", 11, Rarity.COMMON, mage.cards.g.GlitteringLynx.class)); - cards.add(new SetCardInfo("Greel's Caress", 67, Rarity.COMMON, mage.cards.g.GreelsCaress.class)); - cards.add(new SetCardInfo("Greel, Mind Raker", 66, Rarity.RARE, mage.cards.g.GreelMindRaker.class)); - cards.add(new SetCardInfo("Gulf Squid", 35, Rarity.COMMON, mage.cards.g.GulfSquid.class)); - cards.add(new SetCardInfo("Hazy Homunculus", 36, Rarity.COMMON, mage.cards.h.HazyHomunculus.class)); - cards.add(new SetCardInfo("Heightened Awareness", 37, Rarity.RARE, mage.cards.h.HeightenedAwareness.class)); - cards.add(new SetCardInfo("Hollow Warrior", 138, Rarity.UNCOMMON, mage.cards.h.HollowWarrior.class)); - cards.add(new SetCardInfo("Infernal Genesis", 68, Rarity.RARE, mage.cards.i.InfernalGenesis.class)); - cards.add(new SetCardInfo("Inflame", 91, Rarity.COMMON, mage.cards.i.Inflame.class)); - cards.add(new SetCardInfo("Jeweled Spirit", 12, Rarity.RARE, mage.cards.j.JeweledSpirit.class)); - cards.add(new SetCardInfo("Jolrael, Empress of Beasts", 115, Rarity.RARE, mage.cards.j.JolraelEmpressOfBeasts.class)); - cards.add(new SetCardInfo("Jolrael's Favor", 116, Rarity.COMMON, mage.cards.j.JolraelsFavor.class)); - cards.add(new SetCardInfo("Keldon Arsonist", 92, Rarity.UNCOMMON, mage.cards.k.KeldonArsonist.class)); - cards.add(new SetCardInfo("Keldon Battlewagon", 139, Rarity.RARE, mage.cards.k.KeldonBattlewagon.class)); - cards.add(new SetCardInfo("Keldon Berserker", 93, Rarity.COMMON, mage.cards.k.KeldonBerserker.class)); - cards.add(new SetCardInfo("Keldon Firebombers", 94, Rarity.RARE, mage.cards.k.KeldonFirebombers.class)); - cards.add(new SetCardInfo("Latulla, Keldon Overseer", 95, Rarity.RARE, mage.cards.l.LatullaKeldonOverseer.class)); - cards.add(new SetCardInfo("Latulla's Orders", 96, Rarity.COMMON, mage.cards.l.LatullasOrders.class)); - cards.add(new SetCardInfo("Lesser Gargadon", 97, Rarity.UNCOMMON, mage.cards.l.LesserGargadon.class)); - cards.add(new SetCardInfo("Living Terrain", 117, Rarity.UNCOMMON, mage.cards.l.LivingTerrain.class)); - cards.add(new SetCardInfo("Mageta's Boon", 14, Rarity.COMMON, mage.cards.m.MagetasBoon.class)); - cards.add(new SetCardInfo("Mageta the Lion", 13, Rarity.RARE, mage.cards.m.MagetaTheLion.class)); - cards.add(new SetCardInfo("Mana Vapors", 38, Rarity.UNCOMMON, mage.cards.m.ManaVapors.class)); - cards.add(new SetCardInfo("Marsh Boa", 118, Rarity.COMMON, mage.cards.m.MarshBoa.class)); - cards.add(new SetCardInfo("Mercenary Informer", 15, Rarity.RARE, mage.cards.m.MercenaryInformer.class)); - cards.add(new SetCardInfo("Mine Bearer", 16, Rarity.COMMON, mage.cards.m.MineBearer.class)); - cards.add(new SetCardInfo("Mirror Strike", 17, Rarity.UNCOMMON, mage.cards.m.MirrorStrike.class)); - cards.add(new SetCardInfo("Mungha Wurm", 119, Rarity.RARE, mage.cards.m.MunghaWurm.class)); - cards.add(new SetCardInfo("Nakaya Shade", 69, Rarity.UNCOMMON, mage.cards.n.NakayaShade.class)); - cards.add(new SetCardInfo("Noxious Field", 70, Rarity.UNCOMMON, mage.cards.n.NoxiousField.class)); - cards.add(new SetCardInfo("Outbreak", 71, Rarity.UNCOMMON, mage.cards.o.Outbreak.class)); - cards.add(new SetCardInfo("Overburden", 39, Rarity.RARE, mage.cards.o.Overburden.class)); - cards.add(new SetCardInfo("Panic Attack", 98, Rarity.COMMON, mage.cards.p.PanicAttack.class)); - cards.add(new SetCardInfo("Pit Raptor", 72, Rarity.UNCOMMON, mage.cards.p.PitRaptor.class)); - cards.add(new SetCardInfo("Plague Fiend", 73, Rarity.COMMON, mage.cards.p.PlagueFiend.class)); - cards.add(new SetCardInfo("Plague Wind", 74, Rarity.RARE, mage.cards.p.PlagueWind.class)); - cards.add(new SetCardInfo("Psychic Theft", 40, Rarity.RARE, mage.cards.p.PsychicTheft.class)); - cards.add(new SetCardInfo("Pygmy Razorback", 120, Rarity.COMMON, mage.cards.p.PygmyRazorback.class)); - cards.add(new SetCardInfo("Quicksilver Wall", 41, Rarity.UNCOMMON, mage.cards.q.QuicksilverWall.class)); - cards.add(new SetCardInfo("Rebel Informer", 75, Rarity.RARE, mage.cards.r.RebelInformer.class)); - cards.add(new SetCardInfo("Rethink", 42, Rarity.COMMON, mage.cards.r.Rethink.class)); - cards.add(new SetCardInfo("Reveille Squad", 18, Rarity.UNCOMMON, mage.cards.r.ReveilleSquad.class)); - cards.add(new SetCardInfo("Rhystic Cave", 142, Rarity.UNCOMMON, mage.cards.r.RhysticCave.class)); - cards.add(new SetCardInfo("Rhystic Circle", 19, Rarity.COMMON, mage.cards.r.RhysticCircle.class)); - cards.add(new SetCardInfo("Rhystic Deluge", 43, Rarity.COMMON, mage.cards.r.RhysticDeluge.class)); - cards.add(new SetCardInfo("Rhystic Lightning", 99, Rarity.COMMON, mage.cards.r.RhysticLightning.class)); - cards.add(new SetCardInfo("Rhystic Scrying", 44, Rarity.UNCOMMON, mage.cards.r.RhysticScrying.class)); - cards.add(new SetCardInfo("Rhystic Shield", 20, Rarity.COMMON, mage.cards.r.RhysticShield.class)); - cards.add(new SetCardInfo("Rhystic Study", 45, Rarity.COMMON, mage.cards.r.RhysticStudy.class)); - cards.add(new SetCardInfo("Rhystic Syphon", 76, Rarity.UNCOMMON, mage.cards.r.RhysticSyphon.class)); - cards.add(new SetCardInfo("Rhystic Tutor", 77, Rarity.RARE, mage.cards.r.RhysticTutor.class)); - cards.add(new SetCardInfo("Ribbon Snake", 46, Rarity.COMMON, mage.cards.r.RibbonSnake.class)); - cards.add(new SetCardInfo("Rib Cage Spider", 121, Rarity.COMMON, mage.cards.r.RibCageSpider.class)); - cards.add(new SetCardInfo("Ridgeline Rager", 100, Rarity.COMMON, mage.cards.r.RidgelineRager.class)); - cards.add(new SetCardInfo("Root Cage", 122, Rarity.UNCOMMON, mage.cards.r.RootCage.class)); - cards.add(new SetCardInfo("Samite Sanctuary", 21, Rarity.RARE, mage.cards.s.SamiteSanctuary.class)); - cards.add(new SetCardInfo("Scoria Cat", 101, Rarity.UNCOMMON, mage.cards.s.ScoriaCat.class)); - cards.add(new SetCardInfo("Searing Wind", 103, Rarity.RARE, mage.cards.s.SearingWind.class)); - cards.add(new SetCardInfo("Shield Dancer", 23, Rarity.UNCOMMON, mage.cards.s.ShieldDancer.class)); - cards.add(new SetCardInfo("Shrouded Serpent", 47, Rarity.RARE, mage.cards.s.ShroudedSerpent.class)); - cards.add(new SetCardInfo("Silt Crawler", 123, Rarity.COMMON, mage.cards.s.SiltCrawler.class)); - cards.add(new SetCardInfo("Snag", 124, Rarity.UNCOMMON, mage.cards.s.Snag.class)); - cards.add(new SetCardInfo("Soul Charmer", 24, Rarity.COMMON, mage.cards.s.SoulCharmer.class)); - cards.add(new SetCardInfo("Soul Strings", 78, Rarity.COMMON, mage.cards.s.SoulStrings.class)); - cards.add(new SetCardInfo("Spiketail Drake", 48, Rarity.UNCOMMON, mage.cards.s.SpiketailDrake.class)); - cards.add(new SetCardInfo("Spiketail Hatchling", 49, Rarity.COMMON, mage.cards.s.SpiketailHatchling.class)); - cards.add(new SetCardInfo("Spitting Spider", 125, Rarity.UNCOMMON, mage.cards.s.SpittingSpider.class)); - cards.add(new SetCardInfo("Spore Frog", 126, Rarity.COMMON, mage.cards.s.SporeFrog.class)); - cards.add(new SetCardInfo("Spur Grappler", 104, Rarity.COMMON, mage.cards.s.SpurGrappler.class)); - cards.add(new SetCardInfo("Squirrel Wrangler", 127, Rarity.RARE, mage.cards.s.SquirrelWrangler.class)); - cards.add(new SetCardInfo("Steal Strength", 79, Rarity.COMMON, mage.cards.s.StealStrength.class)); - cards.add(new SetCardInfo("Stormwatch Eagle", 50, Rarity.COMMON, mage.cards.s.StormwatchEagle.class)); - cards.add(new SetCardInfo("Sunken Field", 51, Rarity.UNCOMMON, mage.cards.s.SunkenField.class)); - cards.add(new SetCardInfo("Sword Dancer", 25, Rarity.UNCOMMON, mage.cards.s.SwordDancer.class)); - cards.add(new SetCardInfo("Task Mage Assembly", 105, Rarity.RARE, mage.cards.t.TaskMageAssembly.class)); - cards.add(new SetCardInfo("Thresher Beast", 128, Rarity.COMMON, mage.cards.t.ThresherBeast.class)); - cards.add(new SetCardInfo("Thrive", 129, Rarity.COMMON, mage.cards.t.Thrive.class)); - cards.add(new SetCardInfo("Trenching Steed", 26, Rarity.COMMON, mage.cards.t.TrenchingSteed.class)); - cards.add(new SetCardInfo("Troubled Healer", 27, Rarity.COMMON, mage.cards.t.TroubledHealer.class)); - cards.add(new SetCardInfo("Troublesome Spirit", 52, Rarity.RARE, mage.cards.t.TroublesomeSpirit.class)); - cards.add(new SetCardInfo("Verdant Field", 130, Rarity.UNCOMMON, mage.cards.v.VerdantField.class)); - cards.add(new SetCardInfo("Veteran Brawlers", 106, Rarity.RARE, mage.cards.v.VeteranBrawlers.class)); - cards.add(new SetCardInfo("Vintara Elephant", 131, Rarity.COMMON, mage.cards.v.VintaraElephant.class)); - cards.add(new SetCardInfo("Vintara Snapper", 132, Rarity.UNCOMMON, mage.cards.v.VintaraSnapper.class)); - cards.add(new SetCardInfo("Vitalizing Wind", 133, Rarity.RARE, mage.cards.v.VitalizingWind.class)); - cards.add(new SetCardInfo("Wall of Vipers", 80, Rarity.UNCOMMON, mage.cards.w.WallOfVipers.class)); - cards.add(new SetCardInfo("Well of Discovery", 140, Rarity.RARE, mage.cards.w.WellOfDiscovery.class)); - cards.add(new SetCardInfo("Well of Life", 141, Rarity.UNCOMMON, mage.cards.w.WellOfLife.class)); - cards.add(new SetCardInfo("Whip Sergeant", 107, Rarity.UNCOMMON, mage.cards.w.WhipSergeant.class)); - cards.add(new SetCardInfo("Whipstitched Zombie", 81, Rarity.COMMON, mage.cards.w.WhipstitchedZombie.class)); - cards.add(new SetCardInfo("Wild Might", 134, Rarity.COMMON, mage.cards.w.WildMight.class)); - cards.add(new SetCardInfo("Windscouter", 53, Rarity.UNCOMMON, mage.cards.w.Windscouter.class)); - cards.add(new SetCardInfo("Wing Storm", 135, Rarity.UNCOMMON, mage.cards.w.WingStorm.class)); - cards.add(new SetCardInfo("Wintermoon Mesa", 143, Rarity.RARE, mage.cards.w.WintermoonMesa.class)); - cards.add(new SetCardInfo("Withdraw", 54, Rarity.COMMON, mage.cards.w.Withdraw.class)); - cards.add(new SetCardInfo("Zerapa Minotaur", 108, Rarity.COMMON, mage.cards.z.ZerapaMinotaur.class)); - } -} + +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * + * @author North + */ +public final class Prophecy extends ExpansionSet { + + private static final Prophecy instance = new Prophecy(); + + public static Prophecy getInstance() { + return instance; + } + + private Prophecy() { + super("Prophecy", "PCY", ExpansionSet.buildDate(2000, 4, 27), SetType.EXPANSION); + this.blockName = "Masques"; + this.parentSet = MercadianMasques.getInstance(); + this.hasBasicLands = false; + this.hasBoosters = true; + this.numBoosterLands = 0; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + cards.add(new SetCardInfo("Abolish", 1, Rarity.UNCOMMON, mage.cards.a.Abolish.class)); + cards.add(new SetCardInfo("Agent of Shauku", 55, Rarity.COMMON, mage.cards.a.AgentOfShauku.class)); + cards.add(new SetCardInfo("Alexi's Cloak", 29, Rarity.COMMON, mage.cards.a.AlexisCloak.class)); + cards.add(new SetCardInfo("Alexi, Zephyr Mage", 28, Rarity.RARE, mage.cards.a.AlexiZephyrMage.class)); + cards.add(new SetCardInfo("Aura Fracture", 2, Rarity.COMMON, mage.cards.a.AuraFracture.class)); + cards.add(new SetCardInfo("Avatar of Fury", 82, Rarity.RARE, mage.cards.a.AvatarOfFury.class)); + cards.add(new SetCardInfo("Avatar of Hope", 3, Rarity.RARE, mage.cards.a.AvatarOfHope.class)); + cards.add(new SetCardInfo("Avatar of Might", 109, Rarity.RARE, mage.cards.a.AvatarOfMight.class)); + cards.add(new SetCardInfo("Avatar of Will", 30, Rarity.RARE, mage.cards.a.AvatarOfWill.class)); + cards.add(new SetCardInfo("Avatar of Woe", 56, Rarity.RARE, mage.cards.a.AvatarOfWoe.class)); + cards.add(new SetCardInfo("Barbed Field", 83, Rarity.UNCOMMON, mage.cards.b.BarbedField.class)); + cards.add(new SetCardInfo("Blessed Wind", 4, Rarity.RARE, mage.cards.b.BlessedWind.class)); + cards.add(new SetCardInfo("Bog Elemental", 57, Rarity.RARE, mage.cards.b.BogElemental.class)); + cards.add(new SetCardInfo("Bog Glider", 58, Rarity.COMMON, mage.cards.b.BogGlider.class)); + cards.add(new SetCardInfo("Branded Brawlers", 84, Rarity.COMMON, mage.cards.b.BrandedBrawlers.class)); + cards.add(new SetCardInfo("Brutal Suppression", 85, Rarity.UNCOMMON, mage.cards.b.BrutalSuppression.class)); + cards.add(new SetCardInfo("Calming Verse", 110, Rarity.COMMON, mage.cards.c.CalmingVerse.class)); + cards.add(new SetCardInfo("Celestial Convergence", 5, Rarity.RARE, mage.cards.c.CelestialConvergence.class)); + cards.add(new SetCardInfo("Chilling Apparition", 59, Rarity.UNCOMMON, mage.cards.c.ChillingApparition.class)); + cards.add(new SetCardInfo("Chimeric Idol", 136, Rarity.UNCOMMON, mage.cards.c.ChimericIdol.class)); + cards.add(new SetCardInfo("Citadel of Pain", 86, Rarity.UNCOMMON, mage.cards.c.CitadelOfPain.class)); + cards.add(new SetCardInfo("Coastal Hornclaw", 31, Rarity.COMMON, mage.cards.c.CoastalHornclaw.class)); + cards.add(new SetCardInfo("Coffin Puppets", 60, Rarity.RARE, mage.cards.c.CoffinPuppets.class)); + cards.add(new SetCardInfo("Copper-Leaf Angel", 137, Rarity.RARE, mage.cards.c.CopperLeafAngel.class)); + cards.add(new SetCardInfo("Darba", 111, Rarity.UNCOMMON, mage.cards.d.Darba.class)); + cards.add(new SetCardInfo("Death Charmer", 61, Rarity.COMMON, mage.cards.d.DeathCharmer.class)); + cards.add(new SetCardInfo("Denying Wind", 32, Rarity.RARE, mage.cards.d.DenyingWind.class)); + cards.add(new SetCardInfo("Despoil", 62, Rarity.COMMON, mage.cards.d.Despoil.class)); + cards.add(new SetCardInfo("Devastate", 87, Rarity.COMMON, mage.cards.d.Devastate.class)); + cards.add(new SetCardInfo("Diving Griffin", 6, Rarity.COMMON, mage.cards.d.DivingGriffin.class)); + cards.add(new SetCardInfo("Dual Nature", 112, Rarity.RARE, mage.cards.d.DualNature.class)); + cards.add(new SetCardInfo("Elephant Resurgence", 113, Rarity.RARE, mage.cards.e.ElephantResurgence.class)); + cards.add(new SetCardInfo("Endbringer's Revel", 63, Rarity.UNCOMMON, mage.cards.e.EndbringersRevel.class)); + cards.add(new SetCardInfo("Entangler", 7, Rarity.UNCOMMON, mage.cards.e.Entangler.class)); + cards.add(new SetCardInfo("Excavation", 33, Rarity.UNCOMMON, mage.cards.e.Excavation.class)); + cards.add(new SetCardInfo("Excise", 8, Rarity.COMMON, mage.cards.e.Excise.class)); + cards.add(new SetCardInfo("Fault Riders", 88, Rarity.COMMON, mage.cards.f.FaultRiders.class)); + cards.add(new SetCardInfo("Fen Stalker", 64, Rarity.COMMON, mage.cards.f.FenStalker.class)); + cards.add(new SetCardInfo("Fickle Efreet", 89, Rarity.RARE, mage.cards.f.FickleEfreet.class)); + cards.add(new SetCardInfo("Flameshot", 90, Rarity.UNCOMMON, mage.cards.f.Flameshot.class)); + cards.add(new SetCardInfo("Flay", 65, Rarity.COMMON, mage.cards.f.Flay.class)); + cards.add(new SetCardInfo("Flowering Field", 9, Rarity.UNCOMMON, mage.cards.f.FloweringField.class)); + cards.add(new SetCardInfo("Foil", 34, Rarity.UNCOMMON, mage.cards.f.Foil.class)); + cards.add(new SetCardInfo("Forgotten Harvest", 114, Rarity.RARE, mage.cards.f.ForgottenHarvest.class)); + cards.add(new SetCardInfo("Glittering Lion", 10, Rarity.UNCOMMON, mage.cards.g.GlitteringLion.class)); + cards.add(new SetCardInfo("Glittering Lynx", 11, Rarity.COMMON, mage.cards.g.GlitteringLynx.class)); + cards.add(new SetCardInfo("Greel's Caress", 67, Rarity.COMMON, mage.cards.g.GreelsCaress.class)); + cards.add(new SetCardInfo("Greel, Mind Raker", 66, Rarity.RARE, mage.cards.g.GreelMindRaker.class)); + cards.add(new SetCardInfo("Gulf Squid", 35, Rarity.COMMON, mage.cards.g.GulfSquid.class)); + cards.add(new SetCardInfo("Hazy Homunculus", 36, Rarity.COMMON, mage.cards.h.HazyHomunculus.class)); + cards.add(new SetCardInfo("Heightened Awareness", 37, Rarity.RARE, mage.cards.h.HeightenedAwareness.class)); + cards.add(new SetCardInfo("Hollow Warrior", 138, Rarity.UNCOMMON, mage.cards.h.HollowWarrior.class)); + cards.add(new SetCardInfo("Infernal Genesis", 68, Rarity.RARE, mage.cards.i.InfernalGenesis.class)); + cards.add(new SetCardInfo("Inflame", 91, Rarity.COMMON, mage.cards.i.Inflame.class)); + cards.add(new SetCardInfo("Jeweled Spirit", 12, Rarity.RARE, mage.cards.j.JeweledSpirit.class)); + cards.add(new SetCardInfo("Jolrael, Empress of Beasts", 115, Rarity.RARE, mage.cards.j.JolraelEmpressOfBeasts.class)); + cards.add(new SetCardInfo("Jolrael's Favor", 116, Rarity.COMMON, mage.cards.j.JolraelsFavor.class)); + cards.add(new SetCardInfo("Keldon Arsonist", 92, Rarity.UNCOMMON, mage.cards.k.KeldonArsonist.class)); + cards.add(new SetCardInfo("Keldon Battlewagon", 139, Rarity.RARE, mage.cards.k.KeldonBattlewagon.class)); + cards.add(new SetCardInfo("Keldon Berserker", 93, Rarity.COMMON, mage.cards.k.KeldonBerserker.class)); + cards.add(new SetCardInfo("Keldon Firebombers", 94, Rarity.RARE, mage.cards.k.KeldonFirebombers.class)); + cards.add(new SetCardInfo("Latulla, Keldon Overseer", 95, Rarity.RARE, mage.cards.l.LatullaKeldonOverseer.class)); + cards.add(new SetCardInfo("Latulla's Orders", 96, Rarity.COMMON, mage.cards.l.LatullasOrders.class)); + cards.add(new SetCardInfo("Lesser Gargadon", 97, Rarity.UNCOMMON, mage.cards.l.LesserGargadon.class)); + cards.add(new SetCardInfo("Living Terrain", 117, Rarity.UNCOMMON, mage.cards.l.LivingTerrain.class)); + cards.add(new SetCardInfo("Mageta's Boon", 14, Rarity.COMMON, mage.cards.m.MagetasBoon.class)); + cards.add(new SetCardInfo("Mageta the Lion", 13, Rarity.RARE, mage.cards.m.MagetaTheLion.class)); + cards.add(new SetCardInfo("Mana Vapors", 38, Rarity.UNCOMMON, mage.cards.m.ManaVapors.class)); + cards.add(new SetCardInfo("Marsh Boa", 118, Rarity.COMMON, mage.cards.m.MarshBoa.class)); + cards.add(new SetCardInfo("Mercenary Informer", 15, Rarity.RARE, mage.cards.m.MercenaryInformer.class)); + cards.add(new SetCardInfo("Mine Bearer", 16, Rarity.COMMON, mage.cards.m.MineBearer.class)); + cards.add(new SetCardInfo("Mirror Strike", 17, Rarity.UNCOMMON, mage.cards.m.MirrorStrike.class)); + cards.add(new SetCardInfo("Mungha Wurm", 119, Rarity.RARE, mage.cards.m.MunghaWurm.class)); + cards.add(new SetCardInfo("Nakaya Shade", 69, Rarity.UNCOMMON, mage.cards.n.NakayaShade.class)); + cards.add(new SetCardInfo("Noxious Field", 70, Rarity.UNCOMMON, mage.cards.n.NoxiousField.class)); + cards.add(new SetCardInfo("Outbreak", 71, Rarity.UNCOMMON, mage.cards.o.Outbreak.class)); + cards.add(new SetCardInfo("Overburden", 39, Rarity.RARE, mage.cards.o.Overburden.class)); + cards.add(new SetCardInfo("Panic Attack", 98, Rarity.COMMON, mage.cards.p.PanicAttack.class)); + cards.add(new SetCardInfo("Pit Raptor", 72, Rarity.UNCOMMON, mage.cards.p.PitRaptor.class)); + cards.add(new SetCardInfo("Plague Fiend", 73, Rarity.COMMON, mage.cards.p.PlagueFiend.class)); + cards.add(new SetCardInfo("Plague Wind", 74, Rarity.RARE, mage.cards.p.PlagueWind.class)); + cards.add(new SetCardInfo("Psychic Theft", 40, Rarity.RARE, mage.cards.p.PsychicTheft.class)); + cards.add(new SetCardInfo("Pygmy Razorback", 120, Rarity.COMMON, mage.cards.p.PygmyRazorback.class)); + cards.add(new SetCardInfo("Quicksilver Wall", 41, Rarity.UNCOMMON, mage.cards.q.QuicksilverWall.class)); + cards.add(new SetCardInfo("Rebel Informer", 75, Rarity.RARE, mage.cards.r.RebelInformer.class)); + cards.add(new SetCardInfo("Rethink", 42, Rarity.COMMON, mage.cards.r.Rethink.class)); + cards.add(new SetCardInfo("Reveille Squad", 18, Rarity.UNCOMMON, mage.cards.r.ReveilleSquad.class)); + cards.add(new SetCardInfo("Rhystic Cave", 142, Rarity.UNCOMMON, mage.cards.r.RhysticCave.class)); + cards.add(new SetCardInfo("Rhystic Circle", 19, Rarity.COMMON, mage.cards.r.RhysticCircle.class)); + cards.add(new SetCardInfo("Rhystic Deluge", 43, Rarity.COMMON, mage.cards.r.RhysticDeluge.class)); + cards.add(new SetCardInfo("Rhystic Lightning", 99, Rarity.COMMON, mage.cards.r.RhysticLightning.class)); + cards.add(new SetCardInfo("Rhystic Scrying", 44, Rarity.UNCOMMON, mage.cards.r.RhysticScrying.class)); + cards.add(new SetCardInfo("Rhystic Shield", 20, Rarity.COMMON, mage.cards.r.RhysticShield.class)); + cards.add(new SetCardInfo("Rhystic Study", 45, Rarity.COMMON, mage.cards.r.RhysticStudy.class)); + cards.add(new SetCardInfo("Rhystic Syphon", 76, Rarity.UNCOMMON, mage.cards.r.RhysticSyphon.class)); + cards.add(new SetCardInfo("Rhystic Tutor", 77, Rarity.RARE, mage.cards.r.RhysticTutor.class)); + cards.add(new SetCardInfo("Ribbon Snake", 46, Rarity.COMMON, mage.cards.r.RibbonSnake.class)); + cards.add(new SetCardInfo("Rib Cage Spider", 121, Rarity.COMMON, mage.cards.r.RibCageSpider.class)); + cards.add(new SetCardInfo("Ridgeline Rager", 100, Rarity.COMMON, mage.cards.r.RidgelineRager.class)); + cards.add(new SetCardInfo("Root Cage", 122, Rarity.UNCOMMON, mage.cards.r.RootCage.class)); + cards.add(new SetCardInfo("Samite Sanctuary", 21, Rarity.RARE, mage.cards.s.SamiteSanctuary.class)); + cards.add(new SetCardInfo("Scoria Cat", 101, Rarity.UNCOMMON, mage.cards.s.ScoriaCat.class)); + cards.add(new SetCardInfo("Search for Survivors", 102, Rarity.RARE, mage.cards.s.SearchForSurvivors.class)); + cards.add(new SetCardInfo("Searing Wind", 103, Rarity.RARE, mage.cards.s.SearingWind.class)); + cards.add(new SetCardInfo("Sheltering Prayers", 22, Rarity.RARE, mage.cards.s.ShelteringPrayers.class)); + cards.add(new SetCardInfo("Shield Dancer", 23, Rarity.UNCOMMON, mage.cards.s.ShieldDancer.class)); + cards.add(new SetCardInfo("Shrouded Serpent", 47, Rarity.RARE, mage.cards.s.ShroudedSerpent.class)); + cards.add(new SetCardInfo("Silt Crawler", 123, Rarity.COMMON, mage.cards.s.SiltCrawler.class)); + cards.add(new SetCardInfo("Snag", 124, Rarity.UNCOMMON, mage.cards.s.Snag.class)); + cards.add(new SetCardInfo("Soul Charmer", 24, Rarity.COMMON, mage.cards.s.SoulCharmer.class)); + cards.add(new SetCardInfo("Soul Strings", 78, Rarity.COMMON, mage.cards.s.SoulStrings.class)); + cards.add(new SetCardInfo("Spiketail Drake", 48, Rarity.UNCOMMON, mage.cards.s.SpiketailDrake.class)); + cards.add(new SetCardInfo("Spiketail Hatchling", 49, Rarity.COMMON, mage.cards.s.SpiketailHatchling.class)); + cards.add(new SetCardInfo("Spitting Spider", 125, Rarity.UNCOMMON, mage.cards.s.SpittingSpider.class)); + cards.add(new SetCardInfo("Spore Frog", 126, Rarity.COMMON, mage.cards.s.SporeFrog.class)); + cards.add(new SetCardInfo("Spur Grappler", 104, Rarity.COMMON, mage.cards.s.SpurGrappler.class)); + cards.add(new SetCardInfo("Squirrel Wrangler", 127, Rarity.RARE, mage.cards.s.SquirrelWrangler.class)); + cards.add(new SetCardInfo("Steal Strength", 79, Rarity.COMMON, mage.cards.s.StealStrength.class)); + cards.add(new SetCardInfo("Stormwatch Eagle", 50, Rarity.COMMON, mage.cards.s.StormwatchEagle.class)); + cards.add(new SetCardInfo("Sunken Field", 51, Rarity.UNCOMMON, mage.cards.s.SunkenField.class)); + cards.add(new SetCardInfo("Sword Dancer", 25, Rarity.UNCOMMON, mage.cards.s.SwordDancer.class)); + cards.add(new SetCardInfo("Task Mage Assembly", 105, Rarity.RARE, mage.cards.t.TaskMageAssembly.class)); + cards.add(new SetCardInfo("Thresher Beast", 128, Rarity.COMMON, mage.cards.t.ThresherBeast.class)); + cards.add(new SetCardInfo("Thrive", 129, Rarity.COMMON, mage.cards.t.Thrive.class)); + cards.add(new SetCardInfo("Trenching Steed", 26, Rarity.COMMON, mage.cards.t.TrenchingSteed.class)); + cards.add(new SetCardInfo("Troubled Healer", 27, Rarity.COMMON, mage.cards.t.TroubledHealer.class)); + cards.add(new SetCardInfo("Troublesome Spirit", 52, Rarity.RARE, mage.cards.t.TroublesomeSpirit.class)); + cards.add(new SetCardInfo("Verdant Field", 130, Rarity.UNCOMMON, mage.cards.v.VerdantField.class)); + cards.add(new SetCardInfo("Veteran Brawlers", 106, Rarity.RARE, mage.cards.v.VeteranBrawlers.class)); + cards.add(new SetCardInfo("Vintara Elephant", 131, Rarity.COMMON, mage.cards.v.VintaraElephant.class)); + cards.add(new SetCardInfo("Vintara Snapper", 132, Rarity.UNCOMMON, mage.cards.v.VintaraSnapper.class)); + cards.add(new SetCardInfo("Vitalizing Wind", 133, Rarity.RARE, mage.cards.v.VitalizingWind.class)); + cards.add(new SetCardInfo("Wall of Vipers", 80, Rarity.UNCOMMON, mage.cards.w.WallOfVipers.class)); + cards.add(new SetCardInfo("Well of Discovery", 140, Rarity.RARE, mage.cards.w.WellOfDiscovery.class)); + cards.add(new SetCardInfo("Well of Life", 141, Rarity.UNCOMMON, mage.cards.w.WellOfLife.class)); + cards.add(new SetCardInfo("Whip Sergeant", 107, Rarity.UNCOMMON, mage.cards.w.WhipSergeant.class)); + cards.add(new SetCardInfo("Whipstitched Zombie", 81, Rarity.COMMON, mage.cards.w.WhipstitchedZombie.class)); + cards.add(new SetCardInfo("Wild Might", 134, Rarity.COMMON, mage.cards.w.WildMight.class)); + cards.add(new SetCardInfo("Windscouter", 53, Rarity.UNCOMMON, mage.cards.w.Windscouter.class)); + cards.add(new SetCardInfo("Wing Storm", 135, Rarity.UNCOMMON, mage.cards.w.WingStorm.class)); + cards.add(new SetCardInfo("Wintermoon Mesa", 143, Rarity.RARE, mage.cards.w.WintermoonMesa.class)); + cards.add(new SetCardInfo("Withdraw", 54, Rarity.COMMON, mage.cards.w.Withdraw.class)); + cards.add(new SetCardInfo("Zerapa Minotaur", 108, Rarity.COMMON, mage.cards.z.ZerapaMinotaur.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java new file mode 100644 index 00000000000..b8c3a9a7634 --- /dev/null +++ b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java @@ -0,0 +1,88 @@ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.cards.repository.CardCriteria; +import mage.cards.repository.CardInfo; +import mage.cards.repository.CardRepository; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.SetType; + +import java.util.ArrayList; +import java.util.List; + +public final class RavnicaAllegiance extends ExpansionSet { + + private static final RavnicaAllegiance instance = new RavnicaAllegiance(); + + public static RavnicaAllegiance getInstance() { + return instance; + } + + private RavnicaAllegiance() { + super("Ravnica Allegiance", "RNA", ExpansionSet.buildDate(2019, 1, 25), SetType.EXPANSION); + this.blockName = "Guilds of Ravnica"; + this.hasBoosters = true; + this.hasBasicLands = false; // this is temporary until the actual basics have been spoiled to prevent a test fail + this.numBoosterSpecial = 1; + this.numBoosterLands = 0; + this.numBoosterCommon = 10; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 8; + this.maxCardNumberInBooster = 259; + + cards.add(new SetCardInfo("Aeromunculus", 152, Rarity.COMMON, mage.cards.a.Aeromunculus.class)); + cards.add(new SetCardInfo("Bedevil", 157, Rarity.RARE, mage.cards.b.Bedevil.class)); + cards.add(new SetCardInfo("Emergency Powers", 169, Rarity.MYTHIC, mage.cards.e.EmergencyPowers.class)); + cards.add(new SetCardInfo("Frenzied Arynx", 173, Rarity.COMMON, mage.cards.f.FrenziedArynx.class)); + cards.add(new SetCardInfo("Gate Colossus", 232, Rarity.UNCOMMON, mage.cards.g.GateColossus.class)); + cards.add(new SetCardInfo("Growth Spiral", 178, Rarity.COMMON, mage.cards.g.GrowthSpiral.class)); + cards.add(new SetCardInfo("Gruul Spellbreaker", 179, Rarity.RARE, mage.cards.g.GruulSpellbreaker.class)); + cards.add(new SetCardInfo("Imperious Oligarch", 184, Rarity.COMMON, mage.cards.i.ImperiousOligarch.class)); + cards.add(new SetCardInfo("Incubation // Incongruity", 226, Rarity.UNCOMMON, mage.cards.i.IncubationIncongruity.class)); + cards.add(new SetCardInfo("Light Up the Stage", 107, Rarity.UNCOMMON, mage.cards.l.LightUpTheStage.class)); + cards.add(new SetCardInfo("Mortify", 192, Rarity.UNCOMMON, mage.cards.m.Mortify.class)); + cards.add(new SetCardInfo("Rafter Demon", 196, Rarity.COMMON, mage.cards.r.RafterDemon.class)); + cards.add(new SetCardInfo("Rakdos Firewheeler", 197, Rarity.UNCOMMON, mage.cards.r.RakdosFirewheeler.class)); + cards.add(new SetCardInfo("Rix Maadi Reveler", 109, Rarity.RARE, mage.cards.r.RixMaadiReveler.class)); + cards.add(new SetCardInfo("Sphinx's Insight", 209, Rarity.COMMON, mage.cards.s.SphinxsInsight.class)); + cards.add(new SetCardInfo("The Haunt of Hightower", 273, Rarity.MYTHIC, mage.cards.t.TheHauntOfHightower.class)); + cards.add(new SetCardInfo("Tithe Taker", 27, Rarity.RARE, mage.cards.t.TitheTaker.class)); + cards.add(new SetCardInfo("Zegana, Utopian Speaker", 214, Rarity.RARE, mage.cards.z.ZeganaUtopianSpeaker.class)); + } + + @Override + public List getCardsByRarity(Rarity rarity) { + if (rarity == Rarity.COMMON) { + List savedCardsInfos = savedCards.get(rarity); + if (savedCardsInfos == null) { + CardCriteria criteria = new CardCriteria(); + criteria.setCodes(this.code).notTypes(CardType.LAND); + criteria.rarities(rarity).doubleFaced(false); + savedCardsInfos = CardRepository.instance.findCards(criteria); + if (maxCardNumberInBooster != Integer.MAX_VALUE) { + savedCardsInfos.removeIf(next -> next.getCardNumberAsInt() > maxCardNumberInBooster); + } + savedCards.put(rarity, savedCardsInfos); + } + // Return a copy of the saved cards information, as not to modify the original. + return new ArrayList<>(savedCardsInfos); + } else { + return super.getCardsByRarity(rarity); + } + } + + @Override + public List getSpecialCommon() { + List specialCards = getCardsByRarity(Rarity.SPECIAL); + if (specialCards.isEmpty()) { + CardCriteria criteria = new CardCriteria(); + criteria.rarities(Rarity.COMMON).setCodes(this.code).name("Guildgate"); + List specialCardsSave = CardRepository.instance.findCards(criteria); + savedCards.put(Rarity.SPECIAL, specialCardsSave); + specialCards.addAll(specialCardsSave); + } + return specialCards; + } +} diff --git a/Mage.Sets/src/mage/sets/Starter1999.java b/Mage.Sets/src/mage/sets/Starter1999.java index e7e5d8050ca..d41c6b095fd 100644 --- a/Mage.Sets/src/mage/sets/Starter1999.java +++ b/Mage.Sets/src/mage/sets/Starter1999.java @@ -1,200 +1,201 @@ -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -/** - * - * @author LevelX2 - */ -public final class Starter1999 extends ExpansionSet { - - private static final Starter1999 instance = new Starter1999(); - - public static Starter1999 getInstance() { - return instance; - } - - private Starter1999() { - super("Starter 1999", "S99", ExpansionSet.buildDate(1999, 7, 1), SetType.SUPPLEMENTAL); - this.blockName = "Beginner"; - this.hasBasicLands = true; - this.hasBoosters = true; - this.numBoosterLands = 2; - this.numBoosterCommon = 9; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - cards.add(new SetCardInfo("Abyssal Horror", 63, Rarity.RARE, mage.cards.a.AbyssalHorror.class)); - cards.add(new SetCardInfo("Air Elemental", 32, Rarity.UNCOMMON, mage.cards.a.AirElemental.class)); - cards.add(new SetCardInfo("Alluring Scent", 124, Rarity.RARE, mage.cards.a.AlluringScent.class)); - cards.add(new SetCardInfo("Ancient Craving", 64, Rarity.RARE, mage.cards.a.AncientCraving.class)); - cards.add(new SetCardInfo("Angelic Blessing", 3, Rarity.COMMON, mage.cards.a.AngelicBlessing.class)); - cards.add(new SetCardInfo("Angel of Light", 1, Rarity.UNCOMMON, mage.cards.a.AngelOfLight.class)); - cards.add(new SetCardInfo("Angel of Mercy", 2, Rarity.UNCOMMON, mage.cards.a.AngelOfMercy.class)); - cards.add(new SetCardInfo("Archangel", 4, Rarity.RARE, mage.cards.a.Archangel.class)); - cards.add(new SetCardInfo("Ardent Militia", 5, Rarity.UNCOMMON, mage.cards.a.ArdentMilitia.class)); - cards.add(new SetCardInfo("Armageddon", 6, Rarity.RARE, mage.cards.a.Armageddon.class)); - cards.add(new SetCardInfo("Barbtooth Wurm", 125, Rarity.COMMON, mage.cards.b.BarbtoothWurm.class)); - cards.add(new SetCardInfo("Bargain", 7, Rarity.UNCOMMON, mage.cards.b.Bargain.class)); - cards.add(new SetCardInfo("Blinding Light", 8, Rarity.RARE, mage.cards.b.BlindingLight.class)); - cards.add(new SetCardInfo("Bog Imp", 65, Rarity.COMMON, mage.cards.b.BogImp.class)); - cards.add(new SetCardInfo("Bog Raiders", 66, Rarity.COMMON, mage.cards.b.BogRaiders.class)); - cards.add(new SetCardInfo("Bog Wraith", 67, Rarity.UNCOMMON, mage.cards.b.BogWraith.class)); - cards.add(new SetCardInfo("Border Guard", 9, Rarity.COMMON, mage.cards.b.BorderGuard.class)); - cards.add(new SetCardInfo("Breath of Life", 10, Rarity.UNCOMMON, mage.cards.b.BreathOfLife.class)); - cards.add(new SetCardInfo("Bull Hippo", 126, Rarity.UNCOMMON, mage.cards.b.BullHippo.class)); - cards.add(new SetCardInfo("Champion Lancer", 11, Rarity.RARE, mage.cards.c.ChampionLancer.class)); - cards.add(new SetCardInfo("Charging Paladin", 12, Rarity.UNCOMMON, mage.cards.c.ChargingPaladin.class)); - cards.add(new SetCardInfo("Chorus of Woe", 68, Rarity.COMMON, mage.cards.c.ChorusOfWoe.class)); - cards.add(new SetCardInfo("Cinder Storm", 93, Rarity.UNCOMMON, mage.cards.c.CinderStorm.class)); - cards.add(new SetCardInfo("Coercion", 69, Rarity.UNCOMMON, mage.cards.c.Coercion.class)); - cards.add(new SetCardInfo("Coral Eel", 33, Rarity.COMMON, mage.cards.c.CoralEel.class)); - cards.add(new SetCardInfo("Counterspell", 34, Rarity.UNCOMMON, mage.cards.c.Counterspell.class)); - cards.add(new SetCardInfo("Dakmor Ghoul", 70, Rarity.UNCOMMON, mage.cards.d.DakmorGhoul.class)); - cards.add(new SetCardInfo("Dakmor Lancer", 71, Rarity.RARE, mage.cards.d.DakmorLancer.class)); - cards.add(new SetCardInfo("Dakmor Plague", 72, Rarity.UNCOMMON, mage.cards.d.DakmorPlague.class)); - cards.add(new SetCardInfo("Dakmor Scorpion", 73, Rarity.COMMON, mage.cards.d.DakmorScorpion.class)); - cards.add(new SetCardInfo("Dakmor Sorceress", 74, Rarity.RARE, mage.cards.d.DakmorSorceress.class)); - cards.add(new SetCardInfo("Dark Offering", 75, Rarity.UNCOMMON, mage.cards.d.DarkOffering.class)); - cards.add(new SetCardInfo("Denizen of the Deep", 35, Rarity.RARE, mage.cards.d.DenizenOfTheDeep.class)); - cards.add(new SetCardInfo("Devastation", 94, Rarity.RARE, mage.cards.d.Devastation.class)); - cards.add(new SetCardInfo("Devoted Hero", 13, Rarity.COMMON, mage.cards.d.DevotedHero.class)); - cards.add(new SetCardInfo("Devout Monk", 14, Rarity.COMMON, mage.cards.d.DevoutMonk.class)); - cards.add(new SetCardInfo("Dread Reaper", 76, Rarity.RARE, mage.cards.d.DreadReaper.class)); - cards.add(new SetCardInfo("Durkwood Boars", 127, Rarity.COMMON, mage.cards.d.DurkwoodBoars.class)); - cards.add(new SetCardInfo("Eager Cadet", 15, Rarity.COMMON, mage.cards.e.EagerCadet.class)); - cards.add(new SetCardInfo("Earth Elemental", 95, Rarity.UNCOMMON, mage.cards.e.EarthElemental.class)); - cards.add(new SetCardInfo("Exhaustion", 36, Rarity.UNCOMMON, mage.cards.e.Exhaustion.class)); - cards.add(new SetCardInfo("Extinguish", 37, Rarity.COMMON, mage.cards.e.Extinguish.class)); - cards.add(new SetCardInfo("Eye Spy", 38, Rarity.UNCOMMON, mage.cards.e.EyeSpy.class)); - cards.add(new SetCardInfo("False Peace", 16, Rarity.UNCOMMON, mage.cards.f.FalsePeace.class)); - cards.add(new SetCardInfo("Feral Shadow", 77, Rarity.COMMON, mage.cards.f.FeralShadow.class)); - cards.add(new SetCardInfo("Fire Elemental", 96, Rarity.UNCOMMON, mage.cards.f.FireElemental.class)); - cards.add(new SetCardInfo("Fire Tempest", 97, Rarity.RARE, mage.cards.f.FireTempest.class)); - cards.add(new SetCardInfo("Foot Soldiers", 17, Rarity.COMMON, mage.cards.f.FootSoldiers.class)); - cards.add(new SetCardInfo("Forest", 170, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 171, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 172, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 173, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Gerrard's Wisdom", 18, Rarity.RARE, mage.cards.g.GerrardsWisdom.class)); - cards.add(new SetCardInfo("Giant Octopus", 39, Rarity.COMMON, mage.cards.g.GiantOctopus.class)); - cards.add(new SetCardInfo("Goblin Cavaliers", 98, Rarity.COMMON, mage.cards.g.GoblinCavaliers.class)); - cards.add(new SetCardInfo("Goblin Chariot", 99, Rarity.COMMON, mage.cards.g.GoblinChariot.class)); - cards.add(new SetCardInfo("Goblin Commando", 100, Rarity.UNCOMMON, mage.cards.g.GoblinCommando.class)); - cards.add(new SetCardInfo("Goblin General", 101, Rarity.UNCOMMON, mage.cards.g.GoblinGeneral.class)); - cards.add(new SetCardInfo("Goblin Glider", 102, Rarity.UNCOMMON, mage.cards.g.GoblinGlider.class)); - cards.add(new SetCardInfo("Goblin Hero", 103, Rarity.COMMON, mage.cards.g.GoblinHero.class)); - cards.add(new SetCardInfo("Goblin Lore", 104, Rarity.UNCOMMON, mage.cards.g.GoblinLore.class)); - cards.add(new SetCardInfo("Goblin Mountaineer", 105, Rarity.COMMON, mage.cards.g.GoblinMountaineer.class)); - cards.add(new SetCardInfo("Goblin Settler", 106, Rarity.UNCOMMON, mage.cards.g.GoblinSettler.class)); - cards.add(new SetCardInfo("Gorilla Warrior", 128, Rarity.COMMON, mage.cards.g.GorillaWarrior.class)); - cards.add(new SetCardInfo("Gravedigger", 78, Rarity.UNCOMMON, mage.cards.g.Gravedigger.class)); - cards.add(new SetCardInfo("Grim Tutor", 79, Rarity.RARE, mage.cards.g.GrimTutor.class)); - cards.add(new SetCardInfo("Grizzly Bears", 129, Rarity.COMMON, mage.cards.g.GrizzlyBears.class)); - cards.add(new SetCardInfo("Hand of Death", 80, Rarity.COMMON, mage.cards.h.HandOfDeath.class)); - cards.add(new SetCardInfo("Hollow Dogs", 81, Rarity.COMMON, mage.cards.h.HollowDogs.class)); - cards.add(new SetCardInfo("Howling Fury", 82, Rarity.UNCOMMON, mage.cards.h.HowlingFury.class)); - cards.add(new SetCardInfo("Hulking Goblin", 107, Rarity.COMMON, mage.cards.h.HulkingGoblin.class)); - cards.add(new SetCardInfo("Hulking Ogre", 108, Rarity.UNCOMMON, mage.cards.h.HulkingOgre.class)); - cards.add(new SetCardInfo("Ingenious Thief", 40, Rarity.COMMON, mage.cards.i.IngeniousThief.class)); - cards.add(new SetCardInfo("Island", 158, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 159, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 160, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 161, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Jagged Lightning", 109, Rarity.UNCOMMON, mage.cards.j.JaggedLightning.class)); - cards.add(new SetCardInfo("Knight Errant", 19, Rarity.COMMON, mage.cards.k.KnightErrant.class)); - cards.add(new SetCardInfo("Last Chance", 110, Rarity.RARE, mage.cards.l.LastChance.class)); - cards.add(new SetCardInfo("Lava Axe", 111, Rarity.COMMON, mage.cards.l.LavaAxe.class)); - cards.add(new SetCardInfo("Lone Wolf", 130, Rarity.COMMON, mage.cards.l.LoneWolf.class)); - cards.add(new SetCardInfo("Loyal Sentry", 20, Rarity.RARE, mage.cards.l.LoyalSentry.class)); - cards.add(new SetCardInfo("Lynx", 131, Rarity.UNCOMMON, mage.cards.l.Lynx.class)); - cards.add(new SetCardInfo("Man-o'-War", 41, Rarity.UNCOMMON, mage.cards.m.ManOWar.class)); - cards.add(new SetCardInfo("Merfolk of the Pearl Trident", 42, Rarity.COMMON, mage.cards.m.MerfolkOfThePearlTrident.class)); - cards.add(new SetCardInfo("Mind Rot", 83, Rarity.COMMON, mage.cards.m.MindRot.class)); - cards.add(new SetCardInfo("Mons's Goblin Raiders", 112, Rarity.COMMON, mage.cards.m.MonssGoblinRaiders.class)); - cards.add(new SetCardInfo("Monstrous Growth", 132, Rarity.COMMON, mage.cards.m.MonstrousGrowth.class)); - cards.add(new SetCardInfo("Moon Sprite", 133, Rarity.UNCOMMON, mage.cards.m.MoonSprite.class)); - cards.add(new SetCardInfo("Mountain", 166, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 167, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 168, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 169, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Muck Rats", 84, Rarity.COMMON, mage.cards.m.MuckRats.class)); - cards.add(new SetCardInfo("Natural Spring", 134, Rarity.UNCOMMON, mage.cards.n.NaturalSpring.class)); - cards.add(new SetCardInfo("Nature's Cloak", 135, Rarity.RARE, mage.cards.n.NaturesCloak.class)); - cards.add(new SetCardInfo("Nature's Lore", 136, Rarity.COMMON, mage.cards.n.NaturesLore.class)); - cards.add(new SetCardInfo("Norwood Archers", 137, Rarity.COMMON, mage.cards.n.NorwoodArchers.class)); - cards.add(new SetCardInfo("Norwood Ranger", 138, Rarity.COMMON, mage.cards.n.NorwoodRanger.class)); - cards.add(new SetCardInfo("Ogre Warrior", 113, Rarity.COMMON, mage.cards.o.OgreWarrior.class)); - cards.add(new SetCardInfo("Path of Peace", 21, Rarity.COMMON, mage.cards.p.PathOfPeace.class)); - cards.add(new SetCardInfo("Phantom Warrior", 44, Rarity.RARE, mage.cards.p.PhantomWarrior.class)); - cards.add(new SetCardInfo("Plains", 154, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 155, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 156, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 157, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Pride of Lions", 139, Rarity.UNCOMMON, mage.cards.p.PrideOfLions.class)); - cards.add(new SetCardInfo("Psychic Transfer", 46, Rarity.RARE, mage.cards.p.PsychicTransfer.class)); - cards.add(new SetCardInfo("Raging Goblin", 114, Rarity.COMMON, mage.cards.r.RagingGoblin.class)); - cards.add(new SetCardInfo("Raise Dead", 85, Rarity.COMMON, mage.cards.r.RaiseDead.class)); - cards.add(new SetCardInfo("Ravenous Rats", 86, Rarity.UNCOMMON, mage.cards.r.RavenousRats.class)); - cards.add(new SetCardInfo("Relearn", 48, Rarity.UNCOMMON, mage.cards.r.Relearn.class)); - cards.add(new SetCardInfo("Relentless Assault", 115, Rarity.RARE, mage.cards.r.RelentlessAssault.class)); - cards.add(new SetCardInfo("Remove Soul", 49, Rarity.COMMON, mage.cards.r.RemoveSoul.class)); - cards.add(new SetCardInfo("Renewing Touch", 140, Rarity.UNCOMMON, mage.cards.r.RenewingTouch.class)); - cards.add(new SetCardInfo("Righteous Charge", 22, Rarity.UNCOMMON, mage.cards.r.RighteousCharge.class)); - cards.add(new SetCardInfo("Righteous Fury", 23, Rarity.RARE, mage.cards.r.RighteousFury.class)); - cards.add(new SetCardInfo("Royal Falcon", 24, Rarity.COMMON, mage.cards.r.RoyalFalcon.class)); - cards.add(new SetCardInfo("Royal Trooper", 25, Rarity.UNCOMMON, mage.cards.r.RoyalTrooper.class)); - cards.add(new SetCardInfo("Sacred Nectar", 26, Rarity.COMMON, mage.cards.s.SacredNectar.class)); - cards.add(new SetCardInfo("Scathe Zombies", 87, Rarity.COMMON, mage.cards.s.ScatheZombies.class)); - cards.add(new SetCardInfo("Scorching Spear", 116, Rarity.COMMON, mage.cards.s.ScorchingSpear.class)); - cards.add(new SetCardInfo("Sea Eagle", 50, Rarity.COMMON, mage.cards.s.SeaEagle.class)); - cards.add(new SetCardInfo("Serpent Warrior", 88, Rarity.COMMON, mage.cards.s.SerpentWarrior.class)); - cards.add(new SetCardInfo("Shrieking Specter", 89, Rarity.UNCOMMON, mage.cards.s.ShriekingSpecter.class)); - cards.add(new SetCardInfo("Silverback Ape", 141, Rarity.UNCOMMON, mage.cards.s.SilverbackApe.class)); - cards.add(new SetCardInfo("Sleight of Hand", 51, Rarity.COMMON, mage.cards.s.SleightOfHand.class)); - cards.add(new SetCardInfo("Snapping Drake", 52, Rarity.COMMON, mage.cards.s.SnappingDrake.class)); - cards.add(new SetCardInfo("Soul Feast", 90, Rarity.UNCOMMON, mage.cards.s.SoulFeast.class)); - cards.add(new SetCardInfo("Southern Elephant", 142, Rarity.COMMON, mage.cards.s.SouthernElephant.class)); - cards.add(new SetCardInfo("Spitting Earth", 117, Rarity.UNCOMMON, mage.cards.s.SpittingEarth.class)); - cards.add(new SetCardInfo("Squall", 143, Rarity.COMMON, mage.cards.s.Squall.class)); - cards.add(new SetCardInfo("Steadfastness", 27, Rarity.COMMON, mage.cards.s.Steadfastness.class)); - cards.add(new SetCardInfo("Stone Rain", 118, Rarity.COMMON, mage.cards.s.StoneRain.class)); - cards.add(new SetCardInfo("Storm Crow", 53, Rarity.COMMON, mage.cards.s.StormCrow.class)); - cards.add(new SetCardInfo("Stream of Acid", 91, Rarity.UNCOMMON, mage.cards.s.StreamOfAcid.class)); - cards.add(new SetCardInfo("Summer Bloom", 144, Rarity.RARE, mage.cards.s.SummerBloom.class)); - cards.add(new SetCardInfo("Swamp", 162, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 163, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 164, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 165, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Sylvan Basilisk", 145, Rarity.RARE, mage.cards.s.SylvanBasilisk.class)); - cards.add(new SetCardInfo("Sylvan Yeti", 146, Rarity.RARE, mage.cards.s.SylvanYeti.class)); - cards.add(new SetCardInfo("Thorn Elemental", 147, Rarity.RARE, mage.cards.t.ThornElemental.class)); - cards.add(new SetCardInfo("Thunder Dragon", 119, Rarity.RARE, mage.cards.t.ThunderDragon.class)); - cards.add(new SetCardInfo("Tidings", 54, Rarity.UNCOMMON, mage.cards.t.Tidings.class)); - cards.add(new SetCardInfo("Time Ebb", 55, Rarity.COMMON, mage.cards.t.TimeEbb.class)); - cards.add(new SetCardInfo("Time Warp", 56, Rarity.RARE, mage.cards.t.TimeWarp.class)); - cards.add(new SetCardInfo("Touch of Brilliance", 57, Rarity.COMMON, mage.cards.t.TouchOfBrilliance.class)); - cards.add(new SetCardInfo("Trained Orgg", 120, Rarity.RARE, mage.cards.t.TrainedOrgg.class)); - cards.add(new SetCardInfo("Tremor", 121, Rarity.COMMON, mage.cards.t.Tremor.class)); - cards.add(new SetCardInfo("Undo", 58, Rarity.UNCOMMON, mage.cards.u.Undo.class)); - cards.add(new SetCardInfo("Untamed Wilds", 148, Rarity.UNCOMMON, mage.cards.u.UntamedWilds.class)); - cards.add(new SetCardInfo("Venerable Monk", 28, Rarity.COMMON, mage.cards.v.VenerableMonk.class)); - cards.add(new SetCardInfo("Vengeance", 29, Rarity.UNCOMMON, mage.cards.v.Vengeance.class)); - cards.add(new SetCardInfo("Veteran Cavalier", 30, Rarity.UNCOMMON, mage.cards.v.VeteranCavalier.class)); - cards.add(new SetCardInfo("Vizzerdrix", 59, Rarity.RARE, mage.cards.v.Vizzerdrix.class)); - cards.add(new SetCardInfo("Volcanic Dragon", 122, Rarity.RARE, mage.cards.v.VolcanicDragon.class)); - cards.add(new SetCardInfo("Volcanic Hammer", 123, Rarity.COMMON, mage.cards.v.VolcanicHammer.class)); - cards.add(new SetCardInfo("Water Elemental", 60, Rarity.UNCOMMON, mage.cards.w.WaterElemental.class)); - cards.add(new SetCardInfo("Whiptail Wurm", 149, Rarity.UNCOMMON, mage.cards.w.WhiptailWurm.class)); - cards.add(new SetCardInfo("Whirlwind", 150, Rarity.RARE, mage.cards.w.Whirlwind.class)); - cards.add(new SetCardInfo("Wicked Pact", 92, Rarity.RARE, mage.cards.w.WickedPact.class)); - cards.add(new SetCardInfo("Wild Griffin", 31, Rarity.COMMON, mage.cards.w.WildGriffin.class)); - cards.add(new SetCardInfo("Wild Ox", 151, Rarity.UNCOMMON, mage.cards.w.WildOx.class)); - cards.add(new SetCardInfo("Willow Elf", 152, Rarity.COMMON, mage.cards.w.WillowElf.class)); - cards.add(new SetCardInfo("Wind Drake", 61, Rarity.COMMON, mage.cards.w.WindDrake.class)); - cards.add(new SetCardInfo("Wind Sail", 62, Rarity.UNCOMMON, mage.cards.w.WindSail.class)); - cards.add(new SetCardInfo("Wood Elves", 153, Rarity.UNCOMMON, mage.cards.w.WoodElves.class)); - } -} +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * + * @author LevelX2 + */ +public final class Starter1999 extends ExpansionSet { + + private static final Starter1999 instance = new Starter1999(); + + public static Starter1999 getInstance() { + return instance; + } + + private Starter1999() { + super("Starter 1999", "S99", ExpansionSet.buildDate(1999, 7, 1), SetType.SUPPLEMENTAL); + this.blockName = "Beginner"; + this.hasBasicLands = true; + this.hasBoosters = true; + this.numBoosterLands = 2; + this.numBoosterCommon = 9; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + cards.add(new SetCardInfo("Abyssal Horror", 63, Rarity.RARE, mage.cards.a.AbyssalHorror.class)); + cards.add(new SetCardInfo("Air Elemental", 32, Rarity.UNCOMMON, mage.cards.a.AirElemental.class)); + cards.add(new SetCardInfo("Alluring Scent", 124, Rarity.RARE, mage.cards.a.AlluringScent.class)); + cards.add(new SetCardInfo("Ancient Craving", 64, Rarity.RARE, mage.cards.a.AncientCraving.class)); + cards.add(new SetCardInfo("Angelic Blessing", 3, Rarity.COMMON, mage.cards.a.AngelicBlessing.class)); + cards.add(new SetCardInfo("Angel of Light", 1, Rarity.UNCOMMON, mage.cards.a.AngelOfLight.class)); + cards.add(new SetCardInfo("Angel of Mercy", 2, Rarity.UNCOMMON, mage.cards.a.AngelOfMercy.class)); + cards.add(new SetCardInfo("Archangel", 4, Rarity.RARE, mage.cards.a.Archangel.class)); + cards.add(new SetCardInfo("Ardent Militia", 5, Rarity.UNCOMMON, mage.cards.a.ArdentMilitia.class)); + cards.add(new SetCardInfo("Armageddon", 6, Rarity.RARE, mage.cards.a.Armageddon.class)); + cards.add(new SetCardInfo("Barbtooth Wurm", 125, Rarity.COMMON, mage.cards.b.BarbtoothWurm.class)); + cards.add(new SetCardInfo("Bargain", 7, Rarity.UNCOMMON, mage.cards.b.Bargain.class)); + cards.add(new SetCardInfo("Blinding Light", 8, Rarity.RARE, mage.cards.b.BlindingLight.class)); + cards.add(new SetCardInfo("Bog Imp", 65, Rarity.COMMON, mage.cards.b.BogImp.class)); + cards.add(new SetCardInfo("Bog Raiders", 66, Rarity.COMMON, mage.cards.b.BogRaiders.class)); + cards.add(new SetCardInfo("Bog Wraith", 67, Rarity.UNCOMMON, mage.cards.b.BogWraith.class)); + cards.add(new SetCardInfo("Border Guard", 9, Rarity.COMMON, mage.cards.b.BorderGuard.class)); + cards.add(new SetCardInfo("Breath of Life", 10, Rarity.UNCOMMON, mage.cards.b.BreathOfLife.class)); + cards.add(new SetCardInfo("Bull Hippo", 126, Rarity.UNCOMMON, mage.cards.b.BullHippo.class)); + cards.add(new SetCardInfo("Champion Lancer", 11, Rarity.RARE, mage.cards.c.ChampionLancer.class)); + cards.add(new SetCardInfo("Charging Paladin", 12, Rarity.UNCOMMON, mage.cards.c.ChargingPaladin.class)); + cards.add(new SetCardInfo("Chorus of Woe", 68, Rarity.COMMON, mage.cards.c.ChorusOfWoe.class)); + cards.add(new SetCardInfo("Cinder Storm", 93, Rarity.UNCOMMON, mage.cards.c.CinderStorm.class)); + cards.add(new SetCardInfo("Coercion", 69, Rarity.UNCOMMON, mage.cards.c.Coercion.class)); + cards.add(new SetCardInfo("Coral Eel", 33, Rarity.COMMON, mage.cards.c.CoralEel.class)); + cards.add(new SetCardInfo("Counterspell", 34, Rarity.UNCOMMON, mage.cards.c.Counterspell.class)); + cards.add(new SetCardInfo("Dakmor Ghoul", 70, Rarity.UNCOMMON, mage.cards.d.DakmorGhoul.class)); + cards.add(new SetCardInfo("Dakmor Lancer", 71, Rarity.RARE, mage.cards.d.DakmorLancer.class)); + cards.add(new SetCardInfo("Dakmor Plague", 72, Rarity.UNCOMMON, mage.cards.d.DakmorPlague.class)); + cards.add(new SetCardInfo("Dakmor Scorpion", 73, Rarity.COMMON, mage.cards.d.DakmorScorpion.class)); + cards.add(new SetCardInfo("Dakmor Sorceress", 74, Rarity.RARE, mage.cards.d.DakmorSorceress.class)); + cards.add(new SetCardInfo("Dark Offering", 75, Rarity.UNCOMMON, mage.cards.d.DarkOffering.class)); + cards.add(new SetCardInfo("Denizen of the Deep", 35, Rarity.RARE, mage.cards.d.DenizenOfTheDeep.class)); + cards.add(new SetCardInfo("Devastation", 94, Rarity.RARE, mage.cards.d.Devastation.class)); + cards.add(new SetCardInfo("Devoted Hero", 13, Rarity.COMMON, mage.cards.d.DevotedHero.class)); + cards.add(new SetCardInfo("Devout Monk", 14, Rarity.COMMON, mage.cards.d.DevoutMonk.class)); + cards.add(new SetCardInfo("Dread Reaper", 76, Rarity.RARE, mage.cards.d.DreadReaper.class)); + cards.add(new SetCardInfo("Durkwood Boars", 127, Rarity.COMMON, mage.cards.d.DurkwoodBoars.class)); + cards.add(new SetCardInfo("Eager Cadet", 15, Rarity.COMMON, mage.cards.e.EagerCadet.class)); + cards.add(new SetCardInfo("Earth Elemental", 95, Rarity.UNCOMMON, mage.cards.e.EarthElemental.class)); + cards.add(new SetCardInfo("Exhaustion", 36, Rarity.UNCOMMON, mage.cards.e.Exhaustion.class)); + cards.add(new SetCardInfo("Extinguish", 37, Rarity.COMMON, mage.cards.e.Extinguish.class)); + cards.add(new SetCardInfo("Eye Spy", 38, Rarity.UNCOMMON, mage.cards.e.EyeSpy.class)); + cards.add(new SetCardInfo("False Peace", 16, Rarity.UNCOMMON, mage.cards.f.FalsePeace.class)); + cards.add(new SetCardInfo("Feral Shadow", 77, Rarity.COMMON, mage.cards.f.FeralShadow.class)); + cards.add(new SetCardInfo("Fire Elemental", 96, Rarity.UNCOMMON, mage.cards.f.FireElemental.class)); + cards.add(new SetCardInfo("Fire Tempest", 97, Rarity.RARE, mage.cards.f.FireTempest.class)); + cards.add(new SetCardInfo("Foot Soldiers", 17, Rarity.COMMON, mage.cards.f.FootSoldiers.class)); + cards.add(new SetCardInfo("Forest", 170, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 171, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 172, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 173, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gerrard's Wisdom", 18, Rarity.RARE, mage.cards.g.GerrardsWisdom.class)); + cards.add(new SetCardInfo("Giant Octopus", 39, Rarity.COMMON, mage.cards.g.GiantOctopus.class)); + cards.add(new SetCardInfo("Goblin Cavaliers", 98, Rarity.COMMON, mage.cards.g.GoblinCavaliers.class)); + cards.add(new SetCardInfo("Goblin Chariot", 99, Rarity.COMMON, mage.cards.g.GoblinChariot.class)); + cards.add(new SetCardInfo("Goblin Commando", 100, Rarity.UNCOMMON, mage.cards.g.GoblinCommando.class)); + cards.add(new SetCardInfo("Goblin General", 101, Rarity.UNCOMMON, mage.cards.g.GoblinGeneral.class)); + cards.add(new SetCardInfo("Goblin Glider", 102, Rarity.UNCOMMON, mage.cards.g.GoblinGlider.class)); + cards.add(new SetCardInfo("Goblin Hero", 103, Rarity.COMMON, mage.cards.g.GoblinHero.class)); + cards.add(new SetCardInfo("Goblin Lore", 104, Rarity.UNCOMMON, mage.cards.g.GoblinLore.class)); + cards.add(new SetCardInfo("Goblin Mountaineer", 105, Rarity.COMMON, mage.cards.g.GoblinMountaineer.class)); + cards.add(new SetCardInfo("Goblin Settler", 106, Rarity.UNCOMMON, mage.cards.g.GoblinSettler.class)); + cards.add(new SetCardInfo("Gorilla Warrior", 128, Rarity.COMMON, mage.cards.g.GorillaWarrior.class)); + cards.add(new SetCardInfo("Gravedigger", 78, Rarity.UNCOMMON, mage.cards.g.Gravedigger.class)); + cards.add(new SetCardInfo("Grim Tutor", 79, Rarity.RARE, mage.cards.g.GrimTutor.class)); + cards.add(new SetCardInfo("Grizzly Bears", 129, Rarity.COMMON, mage.cards.g.GrizzlyBears.class)); + cards.add(new SetCardInfo("Hand of Death", 80, Rarity.COMMON, mage.cards.h.HandOfDeath.class)); + cards.add(new SetCardInfo("Hollow Dogs", 81, Rarity.COMMON, mage.cards.h.HollowDogs.class)); + cards.add(new SetCardInfo("Howling Fury", 82, Rarity.UNCOMMON, mage.cards.h.HowlingFury.class)); + cards.add(new SetCardInfo("Hulking Goblin", 107, Rarity.COMMON, mage.cards.h.HulkingGoblin.class)); + cards.add(new SetCardInfo("Hulking Ogre", 108, Rarity.UNCOMMON, mage.cards.h.HulkingOgre.class)); + cards.add(new SetCardInfo("Ingenious Thief", 40, Rarity.COMMON, mage.cards.i.IngeniousThief.class)); + cards.add(new SetCardInfo("Island", 158, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 159, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 160, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 161, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jagged Lightning", 109, Rarity.UNCOMMON, mage.cards.j.JaggedLightning.class)); + cards.add(new SetCardInfo("Knight Errant", 19, Rarity.COMMON, mage.cards.k.KnightErrant.class)); + cards.add(new SetCardInfo("Last Chance", 110, Rarity.RARE, mage.cards.l.LastChance.class)); + cards.add(new SetCardInfo("Lava Axe", 111, Rarity.COMMON, mage.cards.l.LavaAxe.class)); + cards.add(new SetCardInfo("Lone Wolf", 130, Rarity.COMMON, mage.cards.l.LoneWolf.class)); + cards.add(new SetCardInfo("Loyal Sentry", 20, Rarity.RARE, mage.cards.l.LoyalSentry.class)); + cards.add(new SetCardInfo("Lynx", 131, Rarity.UNCOMMON, mage.cards.l.Lynx.class)); + cards.add(new SetCardInfo("Man-o'-War", 41, Rarity.UNCOMMON, mage.cards.m.ManOWar.class)); + cards.add(new SetCardInfo("Merfolk of the Pearl Trident", 42, Rarity.COMMON, mage.cards.m.MerfolkOfThePearlTrident.class)); + cards.add(new SetCardInfo("Mind Rot", 83, Rarity.COMMON, mage.cards.m.MindRot.class)); + cards.add(new SetCardInfo("Mons's Goblin Raiders", 112, Rarity.COMMON, mage.cards.m.MonssGoblinRaiders.class)); + cards.add(new SetCardInfo("Monstrous Growth", 132, Rarity.COMMON, mage.cards.m.MonstrousGrowth.class)); + cards.add(new SetCardInfo("Moon Sprite", 133, Rarity.UNCOMMON, mage.cards.m.MoonSprite.class)); + cards.add(new SetCardInfo("Mountain", 166, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 167, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 168, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 169, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Muck Rats", 84, Rarity.COMMON, mage.cards.m.MuckRats.class)); + cards.add(new SetCardInfo("Natural Spring", 134, Rarity.UNCOMMON, mage.cards.n.NaturalSpring.class)); + cards.add(new SetCardInfo("Nature's Cloak", 135, Rarity.RARE, mage.cards.n.NaturesCloak.class)); + cards.add(new SetCardInfo("Nature's Lore", 136, Rarity.COMMON, mage.cards.n.NaturesLore.class)); + cards.add(new SetCardInfo("Norwood Archers", 137, Rarity.COMMON, mage.cards.n.NorwoodArchers.class)); + cards.add(new SetCardInfo("Norwood Ranger", 138, Rarity.COMMON, mage.cards.n.NorwoodRanger.class)); + cards.add(new SetCardInfo("Ogre Warrior", 113, Rarity.COMMON, mage.cards.o.OgreWarrior.class)); + cards.add(new SetCardInfo("Path of Peace", 21, Rarity.COMMON, mage.cards.p.PathOfPeace.class)); + cards.add(new SetCardInfo("Phantom Warrior", 44, Rarity.RARE, mage.cards.p.PhantomWarrior.class)); + cards.add(new SetCardInfo("Plains", 154, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 155, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 156, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 157, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Pride of Lions", 139, Rarity.UNCOMMON, mage.cards.p.PrideOfLions.class)); + cards.add(new SetCardInfo("Psychic Transfer", 46, Rarity.RARE, mage.cards.p.PsychicTransfer.class)); + cards.add(new SetCardInfo("Raging Goblin", 114, Rarity.COMMON, mage.cards.r.RagingGoblin.class)); + cards.add(new SetCardInfo("Raise Dead", 85, Rarity.COMMON, mage.cards.r.RaiseDead.class)); + cards.add(new SetCardInfo("Ransack", 47, Rarity.RARE, mage.cards.r.Ransack.class)); + cards.add(new SetCardInfo("Ravenous Rats", 86, Rarity.UNCOMMON, mage.cards.r.RavenousRats.class)); + cards.add(new SetCardInfo("Relearn", 48, Rarity.UNCOMMON, mage.cards.r.Relearn.class)); + cards.add(new SetCardInfo("Relentless Assault", 115, Rarity.RARE, mage.cards.r.RelentlessAssault.class)); + cards.add(new SetCardInfo("Remove Soul", 49, Rarity.COMMON, mage.cards.r.RemoveSoul.class)); + cards.add(new SetCardInfo("Renewing Touch", 140, Rarity.UNCOMMON, mage.cards.r.RenewingTouch.class)); + cards.add(new SetCardInfo("Righteous Charge", 22, Rarity.UNCOMMON, mage.cards.r.RighteousCharge.class)); + cards.add(new SetCardInfo("Righteous Fury", 23, Rarity.RARE, mage.cards.r.RighteousFury.class)); + cards.add(new SetCardInfo("Royal Falcon", 24, Rarity.COMMON, mage.cards.r.RoyalFalcon.class)); + cards.add(new SetCardInfo("Royal Trooper", 25, Rarity.UNCOMMON, mage.cards.r.RoyalTrooper.class)); + cards.add(new SetCardInfo("Sacred Nectar", 26, Rarity.COMMON, mage.cards.s.SacredNectar.class)); + cards.add(new SetCardInfo("Scathe Zombies", 87, Rarity.COMMON, mage.cards.s.ScatheZombies.class)); + cards.add(new SetCardInfo("Scorching Spear", 116, Rarity.COMMON, mage.cards.s.ScorchingSpear.class)); + cards.add(new SetCardInfo("Sea Eagle", 50, Rarity.COMMON, mage.cards.s.SeaEagle.class)); + cards.add(new SetCardInfo("Serpent Warrior", 88, Rarity.COMMON, mage.cards.s.SerpentWarrior.class)); + cards.add(new SetCardInfo("Shrieking Specter", 89, Rarity.UNCOMMON, mage.cards.s.ShriekingSpecter.class)); + cards.add(new SetCardInfo("Silverback Ape", 141, Rarity.UNCOMMON, mage.cards.s.SilverbackApe.class)); + cards.add(new SetCardInfo("Sleight of Hand", 51, Rarity.COMMON, mage.cards.s.SleightOfHand.class)); + cards.add(new SetCardInfo("Snapping Drake", 52, Rarity.COMMON, mage.cards.s.SnappingDrake.class)); + cards.add(new SetCardInfo("Soul Feast", 90, Rarity.UNCOMMON, mage.cards.s.SoulFeast.class)); + cards.add(new SetCardInfo("Southern Elephant", 142, Rarity.COMMON, mage.cards.s.SouthernElephant.class)); + cards.add(new SetCardInfo("Spitting Earth", 117, Rarity.UNCOMMON, mage.cards.s.SpittingEarth.class)); + cards.add(new SetCardInfo("Squall", 143, Rarity.COMMON, mage.cards.s.Squall.class)); + cards.add(new SetCardInfo("Steadfastness", 27, Rarity.COMMON, mage.cards.s.Steadfastness.class)); + cards.add(new SetCardInfo("Stone Rain", 118, Rarity.COMMON, mage.cards.s.StoneRain.class)); + cards.add(new SetCardInfo("Storm Crow", 53, Rarity.COMMON, mage.cards.s.StormCrow.class)); + cards.add(new SetCardInfo("Stream of Acid", 91, Rarity.UNCOMMON, mage.cards.s.StreamOfAcid.class)); + cards.add(new SetCardInfo("Summer Bloom", 144, Rarity.RARE, mage.cards.s.SummerBloom.class)); + cards.add(new SetCardInfo("Swamp", 162, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 163, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 164, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 165, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sylvan Basilisk", 145, Rarity.RARE, mage.cards.s.SylvanBasilisk.class)); + cards.add(new SetCardInfo("Sylvan Yeti", 146, Rarity.RARE, mage.cards.s.SylvanYeti.class)); + cards.add(new SetCardInfo("Thorn Elemental", 147, Rarity.RARE, mage.cards.t.ThornElemental.class)); + cards.add(new SetCardInfo("Thunder Dragon", 119, Rarity.RARE, mage.cards.t.ThunderDragon.class)); + cards.add(new SetCardInfo("Tidings", 54, Rarity.UNCOMMON, mage.cards.t.Tidings.class)); + cards.add(new SetCardInfo("Time Ebb", 55, Rarity.COMMON, mage.cards.t.TimeEbb.class)); + cards.add(new SetCardInfo("Time Warp", 56, Rarity.RARE, mage.cards.t.TimeWarp.class)); + cards.add(new SetCardInfo("Touch of Brilliance", 57, Rarity.COMMON, mage.cards.t.TouchOfBrilliance.class)); + cards.add(new SetCardInfo("Trained Orgg", 120, Rarity.RARE, mage.cards.t.TrainedOrgg.class)); + cards.add(new SetCardInfo("Tremor", 121, Rarity.COMMON, mage.cards.t.Tremor.class)); + cards.add(new SetCardInfo("Undo", 58, Rarity.UNCOMMON, mage.cards.u.Undo.class)); + cards.add(new SetCardInfo("Untamed Wilds", 148, Rarity.UNCOMMON, mage.cards.u.UntamedWilds.class)); + cards.add(new SetCardInfo("Venerable Monk", 28, Rarity.COMMON, mage.cards.v.VenerableMonk.class)); + cards.add(new SetCardInfo("Vengeance", 29, Rarity.UNCOMMON, mage.cards.v.Vengeance.class)); + cards.add(new SetCardInfo("Veteran Cavalier", 30, Rarity.UNCOMMON, mage.cards.v.VeteranCavalier.class)); + cards.add(new SetCardInfo("Vizzerdrix", 59, Rarity.RARE, mage.cards.v.Vizzerdrix.class)); + cards.add(new SetCardInfo("Volcanic Dragon", 122, Rarity.RARE, mage.cards.v.VolcanicDragon.class)); + cards.add(new SetCardInfo("Volcanic Hammer", 123, Rarity.COMMON, mage.cards.v.VolcanicHammer.class)); + cards.add(new SetCardInfo("Water Elemental", 60, Rarity.UNCOMMON, mage.cards.w.WaterElemental.class)); + cards.add(new SetCardInfo("Whiptail Wurm", 149, Rarity.UNCOMMON, mage.cards.w.WhiptailWurm.class)); + cards.add(new SetCardInfo("Whirlwind", 150, Rarity.RARE, mage.cards.w.Whirlwind.class)); + cards.add(new SetCardInfo("Wicked Pact", 92, Rarity.RARE, mage.cards.w.WickedPact.class)); + cards.add(new SetCardInfo("Wild Griffin", 31, Rarity.COMMON, mage.cards.w.WildGriffin.class)); + cards.add(new SetCardInfo("Wild Ox", 151, Rarity.UNCOMMON, mage.cards.w.WildOx.class)); + cards.add(new SetCardInfo("Willow Elf", 152, Rarity.COMMON, mage.cards.w.WillowElf.class)); + cards.add(new SetCardInfo("Wind Drake", 61, Rarity.COMMON, mage.cards.w.WindDrake.class)); + cards.add(new SetCardInfo("Wind Sail", 62, Rarity.UNCOMMON, mage.cards.w.WindSail.class)); + cards.add(new SetCardInfo("Wood Elves", 153, Rarity.UNCOMMON, mage.cards.w.WoodElves.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/Stronghold.java b/Mage.Sets/src/mage/sets/Stronghold.java index 03ae248545b..173d3fcf778 100644 --- a/Mage.Sets/src/mage/sets/Stronghold.java +++ b/Mage.Sets/src/mage/sets/Stronghold.java @@ -1,166 +1,174 @@ - -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -/** - * @author North - */ -public final class Stronghold extends ExpansionSet { - - private static final Stronghold instance = new Stronghold(); - - public static Stronghold getInstance() { - return instance; - } - - private Stronghold() { - super("Stronghold", "STH", ExpansionSet.buildDate(1998, 3, 2), SetType.EXPANSION); - this.blockName = "Tempest"; - this.parentSet = Tempest.getInstance(); - this.hasBasicLands = false; - this.hasBoosters = true; - this.numBoosterLands = 0; - this.numBoosterCommon = 11; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - cards.add(new SetCardInfo("Acidic Sliver", 126, Rarity.UNCOMMON, mage.cards.a.AcidicSliver.class)); - cards.add(new SetCardInfo("Amok", 76, Rarity.RARE, mage.cards.a.Amok.class)); - cards.add(new SetCardInfo("Awakening", 101, Rarity.RARE, mage.cards.a.Awakening.class)); - cards.add(new SetCardInfo("Bandage", 1, Rarity.COMMON, mage.cards.b.Bandage.class)); - cards.add(new SetCardInfo("Bottomless Pit", 51, Rarity.UNCOMMON, mage.cards.b.BottomlessPit.class)); - cards.add(new SetCardInfo("Brush with Death", 52, Rarity.COMMON, mage.cards.b.BrushWithDeath.class)); - cards.add(new SetCardInfo("Bullwhip", 132, Rarity.UNCOMMON, mage.cards.b.Bullwhip.class)); - cards.add(new SetCardInfo("Burgeoning", 102, Rarity.RARE, mage.cards.b.Burgeoning.class)); - cards.add(new SetCardInfo("Calming Licid", 2, Rarity.UNCOMMON, mage.cards.c.CalmingLicid.class)); - cards.add(new SetCardInfo("Cannibalize", 53, Rarity.COMMON, mage.cards.c.Cannibalize.class)); - cards.add(new SetCardInfo("Carnassid", 103, Rarity.RARE, mage.cards.c.Carnassid.class)); - cards.add(new SetCardInfo("Change of Heart", 3, Rarity.COMMON, mage.cards.c.ChangeOfHeart.class)); - cards.add(new SetCardInfo("Cloud Spirit", 26, Rarity.COMMON, mage.cards.c.CloudSpirit.class)); - cards.add(new SetCardInfo("Constant Mists", 104, Rarity.UNCOMMON, mage.cards.c.ConstantMists.class)); - cards.add(new SetCardInfo("Contemplation", 4, Rarity.UNCOMMON, mage.cards.c.Contemplation.class)); - cards.add(new SetCardInfo("Conviction", 5, Rarity.COMMON, mage.cards.c.Conviction.class)); - cards.add(new SetCardInfo("Convulsing Licid", 77, Rarity.UNCOMMON, mage.cards.c.ConvulsingLicid.class)); - cards.add(new SetCardInfo("Corrupting Licid", 54, Rarity.UNCOMMON, mage.cards.c.CorruptingLicid.class)); - cards.add(new SetCardInfo("Craven Giant", 78, Rarity.COMMON, mage.cards.c.CravenGiant.class)); - cards.add(new SetCardInfo("Crossbow Ambush", 105, Rarity.COMMON, mage.cards.c.CrossbowAmbush.class)); - cards.add(new SetCardInfo("Crovax the Cursed", 55, Rarity.RARE, mage.cards.c.CrovaxTheCursed.class)); - cards.add(new SetCardInfo("Crystalline Sliver", 127, Rarity.UNCOMMON, mage.cards.c.CrystallineSliver.class)); - cards.add(new SetCardInfo("Dauthi Trapper", 56, Rarity.UNCOMMON, mage.cards.d.DauthiTrapper.class)); - cards.add(new SetCardInfo("Death Stroke", 57, Rarity.COMMON, mage.cards.d.DeathStroke.class)); - cards.add(new SetCardInfo("Dream Halls", 28, Rarity.RARE, mage.cards.d.DreamHalls.class)); - cards.add(new SetCardInfo("Dream Prowler", 29, Rarity.COMMON, mage.cards.d.DreamProwler.class)); - cards.add(new SetCardInfo("Duct Crawler", 79, Rarity.COMMON, mage.cards.d.DuctCrawler.class)); - cards.add(new SetCardInfo("Dungeon Shade", 58, Rarity.COMMON, mage.cards.d.DungeonShade.class)); - cards.add(new SetCardInfo("Elven Rite", 106, Rarity.UNCOMMON, mage.cards.e.ElvenRite.class)); - cards.add(new SetCardInfo("Endangered Armodon", 107, Rarity.COMMON, mage.cards.e.EndangeredArmodon.class)); - cards.add(new SetCardInfo("Ensnaring Bridge", 133, Rarity.RARE, mage.cards.e.EnsnaringBridge.class)); - cards.add(new SetCardInfo("Evacuation", 30, Rarity.RARE, mage.cards.e.Evacuation.class)); - cards.add(new SetCardInfo("Fanning the Flames", 80, Rarity.UNCOMMON, mage.cards.f.FanningTheFlames.class)); - cards.add(new SetCardInfo("Flame Wave", 81, Rarity.UNCOMMON, mage.cards.f.FlameWave.class)); - cards.add(new SetCardInfo("Fling", 82, Rarity.COMMON, mage.cards.f.Fling.class)); - cards.add(new SetCardInfo("Flowstone Blade", 83, Rarity.COMMON, mage.cards.f.FlowstoneBlade.class)); - cards.add(new SetCardInfo("Flowstone Hellion", 84, Rarity.UNCOMMON, mage.cards.f.FlowstoneHellion.class)); - cards.add(new SetCardInfo("Flowstone Mauler", 85, Rarity.RARE, mage.cards.f.FlowstoneMauler.class)); - cards.add(new SetCardInfo("Flowstone Shambler", 86, Rarity.COMMON, mage.cards.f.FlowstoneShambler.class)); - cards.add(new SetCardInfo("Foul Imp", 59, Rarity.COMMON, mage.cards.f.FoulImp.class)); - cards.add(new SetCardInfo("Furnace Spirit", 87, Rarity.COMMON, mage.cards.f.FurnaceSpirit.class)); - cards.add(new SetCardInfo("Gliding Licid", 31, Rarity.UNCOMMON, mage.cards.g.GlidingLicid.class)); - cards.add(new SetCardInfo("Grave Pact", 60, Rarity.RARE, mage.cards.g.GravePact.class)); - cards.add(new SetCardInfo("Hammerhead Shark", 32, Rarity.COMMON, mage.cards.h.HammerheadShark.class)); - cards.add(new SetCardInfo("Heartstone", 134, Rarity.UNCOMMON, mage.cards.h.Heartstone.class)); - cards.add(new SetCardInfo("Heat of Battle", 88, Rarity.UNCOMMON, mage.cards.h.HeatOfBattle.class)); - cards.add(new SetCardInfo("Hermit Druid", 108, Rarity.RARE, mage.cards.h.HermitDruid.class)); - cards.add(new SetCardInfo("Hesitation", 33, Rarity.UNCOMMON, mage.cards.h.Hesitation.class)); - cards.add(new SetCardInfo("Hibernation Sliver", 128, Rarity.UNCOMMON, mage.cards.h.HibernationSliver.class)); - cards.add(new SetCardInfo("Honor Guard", 7, Rarity.COMMON, mage.cards.h.HonorGuard.class)); - cards.add(new SetCardInfo("Horn of Greed", 135, Rarity.RARE, mage.cards.h.HornOfGreed.class)); - cards.add(new SetCardInfo("Hornet Cannon", 136, Rarity.UNCOMMON, mage.cards.h.HornetCannon.class)); - cards.add(new SetCardInfo("Intruder Alarm", 34, Rarity.RARE, mage.cards.i.IntruderAlarm.class)); - cards.add(new SetCardInfo("Invasion Plans", 89, Rarity.RARE, mage.cards.i.InvasionPlans.class)); - cards.add(new SetCardInfo("Jinxed Ring", 137, Rarity.RARE, mage.cards.j.JinxedRing.class)); - cards.add(new SetCardInfo("Lab Rats", 61, Rarity.COMMON, mage.cards.l.LabRats.class)); - cards.add(new SetCardInfo("Lancers en-Kor", 8, Rarity.UNCOMMON, mage.cards.l.LancersEnKor.class)); - cards.add(new SetCardInfo("Leap", 35, Rarity.COMMON, mage.cards.l.Leap.class)); - cards.add(new SetCardInfo("Lowland Basilisk", 109, Rarity.COMMON, mage.cards.l.LowlandBasilisk.class)); - cards.add(new SetCardInfo("Mana Leak", 36, Rarity.COMMON, mage.cards.m.ManaLeak.class)); - cards.add(new SetCardInfo("Mask of the Mimic", 37, Rarity.UNCOMMON, mage.cards.m.MaskOfTheMimic.class)); - cards.add(new SetCardInfo("Megrim", 62, Rarity.UNCOMMON, mage.cards.m.Megrim.class)); - cards.add(new SetCardInfo("Mind Games", 38, Rarity.COMMON, mage.cards.m.MindGames.class)); - cards.add(new SetCardInfo("Mind Peel", 63, Rarity.UNCOMMON, mage.cards.m.MindPeel.class)); - cards.add(new SetCardInfo("Mindwarper", 64, Rarity.RARE, mage.cards.m.Mindwarper.class)); - cards.add(new SetCardInfo("Mob Justice", 90, Rarity.COMMON, mage.cards.m.MobJustice.class)); - cards.add(new SetCardInfo("Mogg Flunkies", 92, Rarity.COMMON, mage.cards.m.MoggFlunkies.class)); - cards.add(new SetCardInfo("Mogg Infestation", 93, Rarity.RARE, mage.cards.m.MoggInfestation.class)); - cards.add(new SetCardInfo("Mogg Maniac", 94, Rarity.UNCOMMON, mage.cards.m.MoggManiac.class)); - cards.add(new SetCardInfo("Morgue Thrull", 65, Rarity.COMMON, mage.cards.m.MorgueThrull.class)); - cards.add(new SetCardInfo("Mortuary", 66, Rarity.RARE, mage.cards.m.Mortuary.class)); - cards.add(new SetCardInfo("Mox Diamond", 138, Rarity.RARE, mage.cards.m.MoxDiamond.class)); - cards.add(new SetCardInfo("Mulch", 110, Rarity.COMMON, mage.cards.m.Mulch.class)); - cards.add(new SetCardInfo("Nomads en-Kor", 9, Rarity.COMMON, mage.cards.n.NomadsEnKor.class)); - cards.add(new SetCardInfo("Overgrowth", 111, Rarity.COMMON, mage.cards.o.Overgrowth.class)); - cards.add(new SetCardInfo("Portcullis", 139, Rarity.RARE, mage.cards.p.Portcullis.class)); - cards.add(new SetCardInfo("Primal Rage", 112, Rarity.UNCOMMON, mage.cards.p.PrimalRage.class)); - cards.add(new SetCardInfo("Provoke", 113, Rarity.COMMON, mage.cards.p.Provoke.class)); - cards.add(new SetCardInfo("Pursuit of Knowledge", 10, Rarity.RARE, mage.cards.p.PursuitOfKnowledge.class)); - cards.add(new SetCardInfo("Rabid Rats", 67, Rarity.COMMON, mage.cards.r.RabidRats.class)); - cards.add(new SetCardInfo("Reins of Power", 41, Rarity.RARE, mage.cards.r.ReinsOfPower.class)); - cards.add(new SetCardInfo("Revenant", 68, Rarity.RARE, mage.cards.r.Revenant.class)); - cards.add(new SetCardInfo("Rolling Stones", 11, Rarity.RARE, mage.cards.r.RollingStones.class)); - cards.add(new SetCardInfo("Ruination", 95, Rarity.RARE, mage.cards.r.Ruination.class)); - cards.add(new SetCardInfo("Sacred Ground", 12, Rarity.RARE, mage.cards.s.SacredGround.class)); - cards.add(new SetCardInfo("Scapegoat", 14, Rarity.UNCOMMON, mage.cards.s.Scapegoat.class)); - cards.add(new SetCardInfo("Seething Anger", 96, Rarity.COMMON, mage.cards.s.SeethingAnger.class)); - cards.add(new SetCardInfo("Serpent Warrior", 69, Rarity.COMMON, mage.cards.s.SerpentWarrior.class)); - cards.add(new SetCardInfo("Shaman en-Kor", 15, Rarity.RARE, mage.cards.s.ShamanEnKor.class)); - cards.add(new SetCardInfo("Shard Phoenix", 97, Rarity.RARE, mage.cards.s.ShardPhoenix.class)); - cards.add(new SetCardInfo("Shifting Wall", 140, Rarity.UNCOMMON, mage.cards.s.ShiftingWall.class)); - cards.add(new SetCardInfo("Shock", 98, Rarity.COMMON, mage.cards.s.Shock.class)); - cards.add(new SetCardInfo("Sift", 42, Rarity.COMMON, mage.cards.s.Sift.class)); - cards.add(new SetCardInfo("Silver Wyvern", 43, Rarity.RARE, mage.cards.s.SilverWyvern.class)); - cards.add(new SetCardInfo("Skyshroud Archer", 114, Rarity.COMMON, mage.cards.s.SkyshroudArcher.class)); - cards.add(new SetCardInfo("Skyshroud Falcon", 16, Rarity.COMMON, mage.cards.s.SkyshroudFalcon.class)); - cards.add(new SetCardInfo("Skyshroud Troopers", 115, Rarity.COMMON, mage.cards.s.SkyshroudTroopers.class)); - cards.add(new SetCardInfo("Sliver Queen", 129, Rarity.RARE, mage.cards.s.SliverQueen.class)); - cards.add(new SetCardInfo("Smite", 17, Rarity.COMMON, mage.cards.s.Smite.class)); - cards.add(new SetCardInfo("Soltari Champion", 18, Rarity.RARE, mage.cards.s.SoltariChampion.class)); - cards.add(new SetCardInfo("Spike Breeder", 116, Rarity.RARE, mage.cards.s.SpikeBreeder.class)); - cards.add(new SetCardInfo("Spike Colony", 117, Rarity.COMMON, mage.cards.s.SpikeColony.class)); - cards.add(new SetCardInfo("Spike Feeder", 118, Rarity.UNCOMMON, mage.cards.s.SpikeFeeder.class)); - cards.add(new SetCardInfo("Spike Soldier", 119, Rarity.UNCOMMON, mage.cards.s.SpikeSoldier.class)); - cards.add(new SetCardInfo("Spike Worker", 120, Rarity.COMMON, mage.cards.s.SpikeWorker.class)); - cards.add(new SetCardInfo("Spindrift Drake", 44, Rarity.COMMON, mage.cards.s.SpindriftDrake.class)); - cards.add(new SetCardInfo("Spined Sliver", 130, Rarity.UNCOMMON, mage.cards.s.SpinedSliver.class)); - cards.add(new SetCardInfo("Spined Wurm", 121, Rarity.COMMON, mage.cards.s.SpinedWurm.class)); - cards.add(new SetCardInfo("Spirit en-Kor", 19, Rarity.COMMON, mage.cards.s.SpiritEnKor.class)); - cards.add(new SetCardInfo("Spitting Hydra", 99, Rarity.RARE, mage.cards.s.SpittingHydra.class)); - cards.add(new SetCardInfo("Stronghold Assassin", 71, Rarity.RARE, mage.cards.s.StrongholdAssassin.class)); - cards.add(new SetCardInfo("Stronghold Taskmaster", 72, Rarity.UNCOMMON, mage.cards.s.StrongholdTaskmaster.class)); - cards.add(new SetCardInfo("Sword of the Chosen", 141, Rarity.RARE, mage.cards.s.SwordOfTheChosen.class)); - cards.add(new SetCardInfo("Temper", 20, Rarity.UNCOMMON, mage.cards.t.Temper.class)); - cards.add(new SetCardInfo("Tempting Licid", 122, Rarity.UNCOMMON, mage.cards.t.TemptingLicid.class)); - cards.add(new SetCardInfo("Thalakos Deceiver", 45, Rarity.RARE, mage.cards.t.ThalakosDeceiver.class)); - cards.add(new SetCardInfo("Tidal Surge", 46, Rarity.COMMON, mage.cards.t.TidalSurge.class)); - cards.add(new SetCardInfo("Tidal Warrior", 47, Rarity.COMMON, mage.cards.t.TidalWarrior.class)); - cards.add(new SetCardInfo("Torment", 73, Rarity.COMMON, mage.cards.t.Torment.class)); - cards.add(new SetCardInfo("Tortured Existence", 74, Rarity.COMMON, mage.cards.t.TorturedExistence.class)); - cards.add(new SetCardInfo("Venerable Monk", 21, Rarity.COMMON, mage.cards.v.VenerableMonk.class)); - cards.add(new SetCardInfo("Verdant Touch", 123, Rarity.RARE, mage.cards.v.VerdantTouch.class)); - cards.add(new SetCardInfo("Victual Sliver", 131, Rarity.UNCOMMON, mage.cards.v.VictualSliver.class)); - cards.add(new SetCardInfo("Volrath's Gardens", 124, Rarity.RARE, mage.cards.v.VolrathsGardens.class)); - cards.add(new SetCardInfo("Volrath's Laboratory", 142, Rarity.RARE, mage.cards.v.VolrathsLaboratory.class)); - cards.add(new SetCardInfo("Volrath's Shapeshifter", 48, Rarity.RARE, mage.cards.v.VolrathsShapeshifter.class)); - cards.add(new SetCardInfo("Volrath's Stronghold", 143, Rarity.RARE, mage.cards.v.VolrathsStronghold.class)); - cards.add(new SetCardInfo("Wall of Blossoms", 125, Rarity.UNCOMMON, mage.cards.w.WallOfBlossoms.class)); - cards.add(new SetCardInfo("Wall of Essence", 22, Rarity.UNCOMMON, mage.cards.w.WallOfEssence.class)); - cards.add(new SetCardInfo("Wall of Razors", 100, Rarity.UNCOMMON, mage.cards.w.WallOfRazors.class)); - cards.add(new SetCardInfo("Wall of Souls", 75, Rarity.UNCOMMON, mage.cards.w.WallOfSouls.class)); - cards.add(new SetCardInfo("Wall of Tears", 50, Rarity.UNCOMMON, mage.cards.w.WallOfTears.class)); - cards.add(new SetCardInfo("Warrior Angel", 24, Rarity.RARE, mage.cards.w.WarriorAngel.class)); - cards.add(new SetCardInfo("Warrior en-Kor", 23, Rarity.UNCOMMON, mage.cards.w.WarriorEnKor.class)); - cards.add(new SetCardInfo("Youthful Knight", 25, Rarity.COMMON, mage.cards.y.YouthfulKnight.class)); - } -} +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author North + */ +public final class Stronghold extends ExpansionSet { + + private static final Stronghold instance = new Stronghold(); + + public static Stronghold getInstance() { + return instance; + } + + private Stronghold() { + super("Stronghold", "STH", ExpansionSet.buildDate(1998, 3, 2), SetType.EXPANSION); + this.blockName = "Tempest"; + this.parentSet = Tempest.getInstance(); + this.hasBasicLands = false; + this.hasBoosters = true; + this.numBoosterLands = 0; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + + cards.add(new SetCardInfo("Acidic Sliver", 126, Rarity.UNCOMMON, mage.cards.a.AcidicSliver.class)); + cards.add(new SetCardInfo("Amok", 76, Rarity.RARE, mage.cards.a.Amok.class)); + cards.add(new SetCardInfo("Awakening", 101, Rarity.RARE, mage.cards.a.Awakening.class)); + cards.add(new SetCardInfo("Bandage", 1, Rarity.COMMON, mage.cards.b.Bandage.class)); + cards.add(new SetCardInfo("Bottomless Pit", 51, Rarity.UNCOMMON, mage.cards.b.BottomlessPit.class)); + cards.add(new SetCardInfo("Brush with Death", 52, Rarity.COMMON, mage.cards.b.BrushWithDeath.class)); + cards.add(new SetCardInfo("Bullwhip", 132, Rarity.UNCOMMON, mage.cards.b.Bullwhip.class)); + cards.add(new SetCardInfo("Burgeoning", 102, Rarity.RARE, mage.cards.b.Burgeoning.class)); + cards.add(new SetCardInfo("Calming Licid", 2, Rarity.UNCOMMON, mage.cards.c.CalmingLicid.class)); + cards.add(new SetCardInfo("Cannibalize", 53, Rarity.COMMON, mage.cards.c.Cannibalize.class)); + cards.add(new SetCardInfo("Carnassid", 103, Rarity.RARE, mage.cards.c.Carnassid.class)); + cards.add(new SetCardInfo("Change of Heart", 3, Rarity.COMMON, mage.cards.c.ChangeOfHeart.class)); + cards.add(new SetCardInfo("Cloud Spirit", 26, Rarity.COMMON, mage.cards.c.CloudSpirit.class)); + cards.add(new SetCardInfo("Constant Mists", 104, Rarity.UNCOMMON, mage.cards.c.ConstantMists.class)); + cards.add(new SetCardInfo("Contemplation", 4, Rarity.UNCOMMON, mage.cards.c.Contemplation.class)); + cards.add(new SetCardInfo("Contempt", 27, Rarity.COMMON, mage.cards.c.Contempt.class)); + cards.add(new SetCardInfo("Conviction", 5, Rarity.COMMON, mage.cards.c.Conviction.class)); + cards.add(new SetCardInfo("Convulsing Licid", 77, Rarity.UNCOMMON, mage.cards.c.ConvulsingLicid.class)); + cards.add(new SetCardInfo("Corrupting Licid", 54, Rarity.UNCOMMON, mage.cards.c.CorruptingLicid.class)); + cards.add(new SetCardInfo("Craven Giant", 78, Rarity.COMMON, mage.cards.c.CravenGiant.class)); + cards.add(new SetCardInfo("Crossbow Ambush", 105, Rarity.COMMON, mage.cards.c.CrossbowAmbush.class)); + cards.add(new SetCardInfo("Crovax the Cursed", 55, Rarity.RARE, mage.cards.c.CrovaxTheCursed.class)); + cards.add(new SetCardInfo("Crystalline Sliver", 127, Rarity.UNCOMMON, mage.cards.c.CrystallineSliver.class)); + cards.add(new SetCardInfo("Dauthi Trapper", 56, Rarity.UNCOMMON, mage.cards.d.DauthiTrapper.class)); + cards.add(new SetCardInfo("Death Stroke", 57, Rarity.COMMON, mage.cards.d.DeathStroke.class)); + cards.add(new SetCardInfo("Dream Halls", 28, Rarity.RARE, mage.cards.d.DreamHalls.class)); + cards.add(new SetCardInfo("Dream Prowler", 29, Rarity.COMMON, mage.cards.d.DreamProwler.class)); + cards.add(new SetCardInfo("Duct Crawler", 79, Rarity.COMMON, mage.cards.d.DuctCrawler.class)); + cards.add(new SetCardInfo("Dungeon Shade", 58, Rarity.COMMON, mage.cards.d.DungeonShade.class)); + cards.add(new SetCardInfo("Elven Rite", 106, Rarity.UNCOMMON, mage.cards.e.ElvenRite.class)); + cards.add(new SetCardInfo("Endangered Armodon", 107, Rarity.COMMON, mage.cards.e.EndangeredArmodon.class)); + cards.add(new SetCardInfo("Ensnaring Bridge", 133, Rarity.RARE, mage.cards.e.EnsnaringBridge.class)); + cards.add(new SetCardInfo("Evacuation", 30, Rarity.RARE, mage.cards.e.Evacuation.class)); + cards.add(new SetCardInfo("Fanning the Flames", 80, Rarity.UNCOMMON, mage.cards.f.FanningTheFlames.class)); + cards.add(new SetCardInfo("Flame Wave", 81, Rarity.UNCOMMON, mage.cards.f.FlameWave.class)); + cards.add(new SetCardInfo("Fling", 82, Rarity.COMMON, mage.cards.f.Fling.class)); + cards.add(new SetCardInfo("Flowstone Blade", 83, Rarity.COMMON, mage.cards.f.FlowstoneBlade.class)); + cards.add(new SetCardInfo("Flowstone Hellion", 84, Rarity.UNCOMMON, mage.cards.f.FlowstoneHellion.class)); + cards.add(new SetCardInfo("Flowstone Mauler", 85, Rarity.RARE, mage.cards.f.FlowstoneMauler.class)); + cards.add(new SetCardInfo("Flowstone Shambler", 86, Rarity.COMMON, mage.cards.f.FlowstoneShambler.class)); + cards.add(new SetCardInfo("Foul Imp", 59, Rarity.COMMON, mage.cards.f.FoulImp.class)); + cards.add(new SetCardInfo("Furnace Spirit", 87, Rarity.COMMON, mage.cards.f.FurnaceSpirit.class)); + cards.add(new SetCardInfo("Gliding Licid", 31, Rarity.UNCOMMON, mage.cards.g.GlidingLicid.class)); + cards.add(new SetCardInfo("Grave Pact", 60, Rarity.RARE, mage.cards.g.GravePact.class)); + cards.add(new SetCardInfo("Hammerhead Shark", 32, Rarity.COMMON, mage.cards.h.HammerheadShark.class)); + cards.add(new SetCardInfo("Heartstone", 134, Rarity.UNCOMMON, mage.cards.h.Heartstone.class)); + cards.add(new SetCardInfo("Heat of Battle", 88, Rarity.UNCOMMON, mage.cards.h.HeatOfBattle.class)); + cards.add(new SetCardInfo("Hermit Druid", 108, Rarity.RARE, mage.cards.h.HermitDruid.class)); + cards.add(new SetCardInfo("Hesitation", 33, Rarity.UNCOMMON, mage.cards.h.Hesitation.class)); + cards.add(new SetCardInfo("Hibernation Sliver", 128, Rarity.UNCOMMON, mage.cards.h.HibernationSliver.class)); + cards.add(new SetCardInfo("Hidden Retreat", 6, Rarity.RARE, mage.cards.h.HiddenRetreat.class)); + cards.add(new SetCardInfo("Honor Guard", 7, Rarity.COMMON, mage.cards.h.HonorGuard.class)); + cards.add(new SetCardInfo("Horn of Greed", 135, Rarity.RARE, mage.cards.h.HornOfGreed.class)); + cards.add(new SetCardInfo("Hornet Cannon", 136, Rarity.UNCOMMON, mage.cards.h.HornetCannon.class)); + cards.add(new SetCardInfo("Intruder Alarm", 34, Rarity.RARE, mage.cards.i.IntruderAlarm.class)); + cards.add(new SetCardInfo("Invasion Plans", 89, Rarity.RARE, mage.cards.i.InvasionPlans.class)); + cards.add(new SetCardInfo("Jinxed Ring", 137, Rarity.RARE, mage.cards.j.JinxedRing.class)); + cards.add(new SetCardInfo("Lab Rats", 61, Rarity.COMMON, mage.cards.l.LabRats.class)); + cards.add(new SetCardInfo("Lancers en-Kor", 8, Rarity.UNCOMMON, mage.cards.l.LancersEnKor.class)); + cards.add(new SetCardInfo("Leap", 35, Rarity.COMMON, mage.cards.l.Leap.class)); + cards.add(new SetCardInfo("Lowland Basilisk", 109, Rarity.COMMON, mage.cards.l.LowlandBasilisk.class)); + cards.add(new SetCardInfo("Mana Leak", 36, Rarity.COMMON, mage.cards.m.ManaLeak.class)); + cards.add(new SetCardInfo("Mask of the Mimic", 37, Rarity.UNCOMMON, mage.cards.m.MaskOfTheMimic.class)); + cards.add(new SetCardInfo("Megrim", 62, Rarity.UNCOMMON, mage.cards.m.Megrim.class)); + cards.add(new SetCardInfo("Mind Games", 38, Rarity.COMMON, mage.cards.m.MindGames.class)); + cards.add(new SetCardInfo("Mind Peel", 63, Rarity.UNCOMMON, mage.cards.m.MindPeel.class)); + cards.add(new SetCardInfo("Mindwarper", 64, Rarity.RARE, mage.cards.m.Mindwarper.class)); + cards.add(new SetCardInfo("Mob Justice", 90, Rarity.COMMON, mage.cards.m.MobJustice.class)); + cards.add(new SetCardInfo("Mogg Bombers", 91, Rarity.COMMON, mage.cards.m.MoggBombers.class)); + cards.add(new SetCardInfo("Mogg Flunkies", 92, Rarity.COMMON, mage.cards.m.MoggFlunkies.class)); + cards.add(new SetCardInfo("Mogg Infestation", 93, Rarity.RARE, mage.cards.m.MoggInfestation.class)); + cards.add(new SetCardInfo("Mogg Maniac", 94, Rarity.UNCOMMON, mage.cards.m.MoggManiac.class)); + cards.add(new SetCardInfo("Morgue Thrull", 65, Rarity.COMMON, mage.cards.m.MorgueThrull.class)); + cards.add(new SetCardInfo("Mortuary", 66, Rarity.RARE, mage.cards.m.Mortuary.class)); + cards.add(new SetCardInfo("Mox Diamond", 138, Rarity.RARE, mage.cards.m.MoxDiamond.class)); + cards.add(new SetCardInfo("Mulch", 110, Rarity.COMMON, mage.cards.m.Mulch.class)); + cards.add(new SetCardInfo("Nomads en-Kor", 9, Rarity.COMMON, mage.cards.n.NomadsEnKor.class)); + cards.add(new SetCardInfo("Overgrowth", 111, Rarity.COMMON, mage.cards.o.Overgrowth.class)); + cards.add(new SetCardInfo("Portcullis", 139, Rarity.RARE, mage.cards.p.Portcullis.class)); + cards.add(new SetCardInfo("Primal Rage", 112, Rarity.UNCOMMON, mage.cards.p.PrimalRage.class)); + cards.add(new SetCardInfo("Provoke", 113, Rarity.COMMON, mage.cards.p.Provoke.class)); + cards.add(new SetCardInfo("Pursuit of Knowledge", 10, Rarity.RARE, mage.cards.p.PursuitOfKnowledge.class)); + cards.add(new SetCardInfo("Rabid Rats", 67, Rarity.COMMON, mage.cards.r.RabidRats.class)); + cards.add(new SetCardInfo("Ransack", 39, Rarity.UNCOMMON, mage.cards.r.Ransack.class)); + cards.add(new SetCardInfo("Rebound", 40, Rarity.UNCOMMON, mage.cards.r.Rebound.class)); + cards.add(new SetCardInfo("Reins of Power", 41, Rarity.RARE, mage.cards.r.ReinsOfPower.class)); + cards.add(new SetCardInfo("Revenant", 68, Rarity.RARE, mage.cards.r.Revenant.class)); + cards.add(new SetCardInfo("Rolling Stones", 11, Rarity.RARE, mage.cards.r.RollingStones.class)); + cards.add(new SetCardInfo("Ruination", 95, Rarity.RARE, mage.cards.r.Ruination.class)); + cards.add(new SetCardInfo("Sacred Ground", 12, Rarity.RARE, mage.cards.s.SacredGround.class)); + cards.add(new SetCardInfo("Samite Blessing", 13, Rarity.COMMON, mage.cards.s.SamiteBlessing.class)); + cards.add(new SetCardInfo("Scapegoat", 14, Rarity.UNCOMMON, mage.cards.s.Scapegoat.class)); + cards.add(new SetCardInfo("Seething Anger", 96, Rarity.COMMON, mage.cards.s.SeethingAnger.class)); + cards.add(new SetCardInfo("Serpent Warrior", 69, Rarity.COMMON, mage.cards.s.SerpentWarrior.class)); + cards.add(new SetCardInfo("Shaman en-Kor", 15, Rarity.RARE, mage.cards.s.ShamanEnKor.class)); + cards.add(new SetCardInfo("Shard Phoenix", 97, Rarity.RARE, mage.cards.s.ShardPhoenix.class)); + cards.add(new SetCardInfo("Shifting Wall", 140, Rarity.UNCOMMON, mage.cards.s.ShiftingWall.class)); + cards.add(new SetCardInfo("Shock", 98, Rarity.COMMON, mage.cards.s.Shock.class)); + cards.add(new SetCardInfo("Sift", 42, Rarity.COMMON, mage.cards.s.Sift.class)); + cards.add(new SetCardInfo("Silver Wyvern", 43, Rarity.RARE, mage.cards.s.SilverWyvern.class)); + cards.add(new SetCardInfo("Skeleton Scavengers", 70, Rarity.RARE, mage.cards.s.SkeletonScavengers.class)); + cards.add(new SetCardInfo("Skyshroud Archer", 114, Rarity.COMMON, mage.cards.s.SkyshroudArcher.class)); + cards.add(new SetCardInfo("Skyshroud Falcon", 16, Rarity.COMMON, mage.cards.s.SkyshroudFalcon.class)); + cards.add(new SetCardInfo("Skyshroud Troopers", 115, Rarity.COMMON, mage.cards.s.SkyshroudTroopers.class)); + cards.add(new SetCardInfo("Sliver Queen", 129, Rarity.RARE, mage.cards.s.SliverQueen.class)); + cards.add(new SetCardInfo("Smite", 17, Rarity.COMMON, mage.cards.s.Smite.class)); + cards.add(new SetCardInfo("Soltari Champion", 18, Rarity.RARE, mage.cards.s.SoltariChampion.class)); + cards.add(new SetCardInfo("Spike Breeder", 116, Rarity.RARE, mage.cards.s.SpikeBreeder.class)); + cards.add(new SetCardInfo("Spike Colony", 117, Rarity.COMMON, mage.cards.s.SpikeColony.class)); + cards.add(new SetCardInfo("Spike Feeder", 118, Rarity.UNCOMMON, mage.cards.s.SpikeFeeder.class)); + cards.add(new SetCardInfo("Spike Soldier", 119, Rarity.UNCOMMON, mage.cards.s.SpikeSoldier.class)); + cards.add(new SetCardInfo("Spike Worker", 120, Rarity.COMMON, mage.cards.s.SpikeWorker.class)); + cards.add(new SetCardInfo("Spindrift Drake", 44, Rarity.COMMON, mage.cards.s.SpindriftDrake.class)); + cards.add(new SetCardInfo("Spined Sliver", 130, Rarity.UNCOMMON, mage.cards.s.SpinedSliver.class)); + cards.add(new SetCardInfo("Spined Wurm", 121, Rarity.COMMON, mage.cards.s.SpinedWurm.class)); + cards.add(new SetCardInfo("Spirit en-Kor", 19, Rarity.COMMON, mage.cards.s.SpiritEnKor.class)); + cards.add(new SetCardInfo("Spitting Hydra", 99, Rarity.RARE, mage.cards.s.SpittingHydra.class)); + cards.add(new SetCardInfo("Stronghold Assassin", 71, Rarity.RARE, mage.cards.s.StrongholdAssassin.class)); + cards.add(new SetCardInfo("Stronghold Taskmaster", 72, Rarity.UNCOMMON, mage.cards.s.StrongholdTaskmaster.class)); + cards.add(new SetCardInfo("Sword of the Chosen", 141, Rarity.RARE, mage.cards.s.SwordOfTheChosen.class)); + cards.add(new SetCardInfo("Temper", 20, Rarity.UNCOMMON, mage.cards.t.Temper.class)); + cards.add(new SetCardInfo("Tempting Licid", 122, Rarity.UNCOMMON, mage.cards.t.TemptingLicid.class)); + cards.add(new SetCardInfo("Thalakos Deceiver", 45, Rarity.RARE, mage.cards.t.ThalakosDeceiver.class)); + cards.add(new SetCardInfo("Tidal Surge", 46, Rarity.COMMON, mage.cards.t.TidalSurge.class)); + cards.add(new SetCardInfo("Tidal Warrior", 47, Rarity.COMMON, mage.cards.t.TidalWarrior.class)); + cards.add(new SetCardInfo("Torment", 73, Rarity.COMMON, mage.cards.t.Torment.class)); + cards.add(new SetCardInfo("Tortured Existence", 74, Rarity.COMMON, mage.cards.t.TorturedExistence.class)); + cards.add(new SetCardInfo("Venerable Monk", 21, Rarity.COMMON, mage.cards.v.VenerableMonk.class)); + cards.add(new SetCardInfo("Verdant Touch", 123, Rarity.RARE, mage.cards.v.VerdantTouch.class)); + cards.add(new SetCardInfo("Victual Sliver", 131, Rarity.UNCOMMON, mage.cards.v.VictualSliver.class)); + cards.add(new SetCardInfo("Volrath's Gardens", 124, Rarity.RARE, mage.cards.v.VolrathsGardens.class)); + cards.add(new SetCardInfo("Volrath's Laboratory", 142, Rarity.RARE, mage.cards.v.VolrathsLaboratory.class)); + cards.add(new SetCardInfo("Volrath's Shapeshifter", 48, Rarity.RARE, mage.cards.v.VolrathsShapeshifter.class)); + cards.add(new SetCardInfo("Volrath's Stronghold", 143, Rarity.RARE, mage.cards.v.VolrathsStronghold.class)); + cards.add(new SetCardInfo("Walking Dream", 49, Rarity.UNCOMMON, mage.cards.w.WalkingDream.class)); + cards.add(new SetCardInfo("Wall of Blossoms", 125, Rarity.UNCOMMON, mage.cards.w.WallOfBlossoms.class)); + cards.add(new SetCardInfo("Wall of Essence", 22, Rarity.UNCOMMON, mage.cards.w.WallOfEssence.class)); + cards.add(new SetCardInfo("Wall of Razors", 100, Rarity.UNCOMMON, mage.cards.w.WallOfRazors.class)); + cards.add(new SetCardInfo("Wall of Souls", 75, Rarity.UNCOMMON, mage.cards.w.WallOfSouls.class)); + cards.add(new SetCardInfo("Wall of Tears", 50, Rarity.UNCOMMON, mage.cards.w.WallOfTears.class)); + cards.add(new SetCardInfo("Warrior Angel", 24, Rarity.RARE, mage.cards.w.WarriorAngel.class)); + cards.add(new SetCardInfo("Warrior en-Kor", 23, Rarity.UNCOMMON, mage.cards.w.WarriorEnKor.class)); + cards.add(new SetCardInfo("Youthful Knight", 25, Rarity.COMMON, mage.cards.y.YouthfulKnight.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/Tempest.java b/Mage.Sets/src/mage/sets/Tempest.java index 5269f4c17c7..e1ec411d32e 100644 --- a/Mage.Sets/src/mage/sets/Tempest.java +++ b/Mage.Sets/src/mage/sets/Tempest.java @@ -1,368 +1,369 @@ -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -public final class Tempest extends ExpansionSet { - - private static final Tempest instance = new Tempest(); - - public static Tempest getInstance() { - return instance; - } - - private Tempest() { - super("Tempest", "TMP", ExpansionSet.buildDate(1997, 10, 1), SetType.EXPANSION); - this.blockName = "Tempest"; - this.hasBoosters = true; - this.numBoosterLands = 0; - this.numBoosterCommon = 11; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - cards.add(new SetCardInfo("Abandon Hope", 107, Rarity.UNCOMMON, mage.cards.a.AbandonHope.class)); - cards.add(new SetCardInfo("Advance Scout", 1, Rarity.COMMON, mage.cards.a.AdvanceScout.class)); - cards.add(new SetCardInfo("Aftershock", 160, Rarity.COMMON, mage.cards.a.Aftershock.class)); - cards.add(new SetCardInfo("Altar of Dementia", 276, Rarity.RARE, mage.cards.a.AltarOfDementia.class)); - cards.add(new SetCardInfo("Aluren", 213, Rarity.RARE, mage.cards.a.Aluren.class)); - cards.add(new SetCardInfo("Ancient Runes", 161, Rarity.UNCOMMON, mage.cards.a.AncientRunes.class)); - cards.add(new SetCardInfo("Ancient Tomb", 315, Rarity.UNCOMMON, mage.cards.a.AncientTomb.class)); - cards.add(new SetCardInfo("Angelic Protector", 2, Rarity.UNCOMMON, mage.cards.a.AngelicProtector.class)); - cards.add(new SetCardInfo("Anoint", 3, Rarity.COMMON, mage.cards.a.Anoint.class)); - cards.add(new SetCardInfo("Apes of Rath", 214, Rarity.UNCOMMON, mage.cards.a.ApesOfRath.class)); - cards.add(new SetCardInfo("Apocalypse", 162, Rarity.RARE, mage.cards.a.Apocalypse.class)); - cards.add(new SetCardInfo("Armor Sliver", 4, Rarity.UNCOMMON, mage.cards.a.ArmorSliver.class)); - cards.add(new SetCardInfo("Armored Pegasus", 5, Rarity.COMMON, mage.cards.a.ArmoredPegasus.class)); - cards.add(new SetCardInfo("Auratog", 6, Rarity.RARE, mage.cards.a.Auratog.class)); - cards.add(new SetCardInfo("Avenging Angel", 7, Rarity.RARE, mage.cards.a.AvengingAngel.class)); - cards.add(new SetCardInfo("Barbed Sliver", 163, Rarity.UNCOMMON, mage.cards.b.BarbedSliver.class)); - cards.add(new SetCardInfo("Bayou Dragonfly", 215, Rarity.COMMON, mage.cards.b.BayouDragonfly.class)); - cards.add(new SetCardInfo("Bellowing Fiend", 108, Rarity.RARE, mage.cards.b.BellowingFiend.class)); - cards.add(new SetCardInfo("Benthic Behemoth", 54, Rarity.RARE, mage.cards.b.BenthicBehemoth.class)); - cards.add(new SetCardInfo("Blood Frenzy", 164, Rarity.COMMON, mage.cards.b.BloodFrenzy.class)); - cards.add(new SetCardInfo("Blood Pet", 109, Rarity.COMMON, mage.cards.b.BloodPet.class)); - cards.add(new SetCardInfo("Boil", 165, Rarity.UNCOMMON, mage.cards.b.Boil.class)); - cards.add(new SetCardInfo("Booby Trap", 277, Rarity.RARE, mage.cards.b.BoobyTrap.class)); - cards.add(new SetCardInfo("Bottle Gnomes", 278, Rarity.UNCOMMON, mage.cards.b.BottleGnomes.class)); - cards.add(new SetCardInfo("Bounty Hunter", 110, Rarity.RARE, mage.cards.b.BountyHunter.class)); - cards.add(new SetCardInfo("Broken Fall", 216, Rarity.COMMON, mage.cards.b.BrokenFall.class)); - cards.add(new SetCardInfo("Caldera Lake", 316, Rarity.RARE, mage.cards.c.CalderaLake.class)); - cards.add(new SetCardInfo("Canopy Spider", 217, Rarity.COMMON, mage.cards.c.CanopySpider.class)); - cards.add(new SetCardInfo("Canyon Drake", 166, Rarity.RARE, mage.cards.c.CanyonDrake.class)); - cards.add(new SetCardInfo("Canyon Wildcat", 167, Rarity.COMMON, mage.cards.c.CanyonWildcat.class)); - cards.add(new SetCardInfo("Capsize", 55, Rarity.COMMON, mage.cards.c.Capsize.class)); - cards.add(new SetCardInfo("Carrionette", 111, Rarity.RARE, mage.cards.c.Carrionette.class)); - cards.add(new SetCardInfo("Chaotic Goo", 168, Rarity.RARE, mage.cards.c.ChaoticGoo.class)); - cards.add(new SetCardInfo("Charging Rhino", 218, Rarity.UNCOMMON, mage.cards.c.ChargingRhino.class)); - cards.add(new SetCardInfo("Chill", 56, Rarity.UNCOMMON, mage.cards.c.Chill.class)); - cards.add(new SetCardInfo("Choke", 219, Rarity.UNCOMMON, mage.cards.c.Choke.class)); - cards.add(new SetCardInfo("Cinder Marsh", 317, Rarity.UNCOMMON, mage.cards.c.CinderMarsh.class)); - cards.add(new SetCardInfo("Circle of Protection: Black", 8, Rarity.COMMON, mage.cards.c.CircleOfProtectionBlack.class)); - cards.add(new SetCardInfo("Circle of Protection: Blue", 9, Rarity.COMMON, mage.cards.c.CircleOfProtectionBlue.class)); - cards.add(new SetCardInfo("Circle of Protection: Green", 10, Rarity.COMMON, mage.cards.c.CircleOfProtectionGreen.class)); - cards.add(new SetCardInfo("Circle of Protection: Red", 11, Rarity.COMMON, mage.cards.c.CircleOfProtectionRed.class)); - cards.add(new SetCardInfo("Circle of Protection: Shadow", 12, Rarity.COMMON, mage.cards.c.CircleOfProtectionShadow.class)); - cards.add(new SetCardInfo("Circle of Protection: White", 13, Rarity.COMMON, mage.cards.c.CircleOfProtectionWhite.class)); - cards.add(new SetCardInfo("Clergy en-Vec", 14, Rarity.COMMON, mage.cards.c.ClergyEnVec.class)); - cards.add(new SetCardInfo("Clot Sliver", 112, Rarity.COMMON, mage.cards.c.ClotSliver.class)); - cards.add(new SetCardInfo("Cloudchaser Eagle", 15, Rarity.COMMON, mage.cards.c.CloudchaserEagle.class)); - cards.add(new SetCardInfo("Coercion", 113, Rarity.COMMON, mage.cards.c.Coercion.class)); - cards.add(new SetCardInfo("Coffin Queen", 114, Rarity.RARE, mage.cards.c.CoffinQueen.class)); - cards.add(new SetCardInfo("Coiled Tinviper", 279, Rarity.COMMON, mage.cards.c.CoiledTinviper.class)); - cards.add(new SetCardInfo("Cold Storage", 280, Rarity.RARE, mage.cards.c.ColdStorage.class)); - cards.add(new SetCardInfo("Commander Greven il-Vec", 115, Rarity.RARE, mage.cards.c.CommanderGrevenIlVec.class)); - cards.add(new SetCardInfo("Corpse Dance", 116, Rarity.RARE, mage.cards.c.CorpseDance.class)); - cards.add(new SetCardInfo("Counterspell", 57, Rarity.COMMON, mage.cards.c.Counterspell.class)); - cards.add(new SetCardInfo("Crazed Armodon", 220, Rarity.RARE, mage.cards.c.CrazedArmodon.class)); - cards.add(new SetCardInfo("Crown of Flames", 169, Rarity.COMMON, mage.cards.c.CrownOfFlames.class)); - cards.add(new SetCardInfo("Cursed Scroll", 281, Rarity.RARE, mage.cards.c.CursedScroll.class)); - cards.add(new SetCardInfo("Dark Banishing", 117, Rarity.COMMON, mage.cards.d.DarkBanishing.class)); - cards.add(new SetCardInfo("Dark Ritual", 118, Rarity.COMMON, mage.cards.d.DarkRitual.class)); - cards.add(new SetCardInfo("Darkling Stalker", 119, Rarity.COMMON, mage.cards.d.DarklingStalker.class)); - cards.add(new SetCardInfo("Dauthi Embrace", 120, Rarity.UNCOMMON, mage.cards.d.DauthiEmbrace.class)); - cards.add(new SetCardInfo("Dauthi Ghoul", 121, Rarity.UNCOMMON, mage.cards.d.DauthiGhoul.class)); - cards.add(new SetCardInfo("Dauthi Horror", 122, Rarity.COMMON, mage.cards.d.DauthiHorror.class)); - cards.add(new SetCardInfo("Dauthi Marauder", 123, Rarity.COMMON, mage.cards.d.DauthiMarauder.class)); - cards.add(new SetCardInfo("Dauthi Mercenary", 124, Rarity.UNCOMMON, mage.cards.d.DauthiMercenary.class)); - cards.add(new SetCardInfo("Dauthi Mindripper", 125, Rarity.UNCOMMON, mage.cards.d.DauthiMindripper.class)); - cards.add(new SetCardInfo("Dauthi Slayer", 126, Rarity.COMMON, mage.cards.d.DauthiSlayer.class)); - cards.add(new SetCardInfo("Deadshot", 170, Rarity.RARE, mage.cards.d.Deadshot.class)); - cards.add(new SetCardInfo("Death Pits of Rath", 127, Rarity.RARE, mage.cards.d.DeathPitsOfRath.class)); - cards.add(new SetCardInfo("Diabolic Edict", 128, Rarity.COMMON, mage.cards.d.DiabolicEdict.class)); - cards.add(new SetCardInfo("Dirtcowl Wurm", 221, Rarity.RARE, mage.cards.d.DirtcowlWurm.class)); - cards.add(new SetCardInfo("Disenchant", 16, Rarity.COMMON, mage.cards.d.Disenchant.class)); - cards.add(new SetCardInfo("Dismiss", 58, Rarity.UNCOMMON, mage.cards.d.Dismiss.class)); - cards.add(new SetCardInfo("Disturbed Burial", 129, Rarity.COMMON, mage.cards.d.DisturbedBurial.class)); - cards.add(new SetCardInfo("Dracoplasm", 266, Rarity.RARE, mage.cards.d.Dracoplasm.class)); - cards.add(new SetCardInfo("Dread of Night", 130, Rarity.UNCOMMON, mage.cards.d.DreadOfNight.class)); - cards.add(new SetCardInfo("Dream Cache", 59, Rarity.COMMON, mage.cards.d.DreamCache.class)); - cards.add(new SetCardInfo("Dregs of Sorrow", 131, Rarity.RARE, mage.cards.d.DregsOfSorrow.class)); - cards.add(new SetCardInfo("Earthcraft", 222, Rarity.RARE, mage.cards.e.Earthcraft.class)); - cards.add(new SetCardInfo("Echo Chamber", 282, Rarity.RARE, mage.cards.e.EchoChamber.class)); - cards.add(new SetCardInfo("Eladamri's Vineyard", 223, Rarity.RARE, mage.cards.e.EladamrisVineyard.class)); - cards.add(new SetCardInfo("Eladamri, Lord of Leaves", 224, Rarity.RARE, mage.cards.e.EladamriLordOfLeaves.class)); - cards.add(new SetCardInfo("Elite Javelineer", 17, Rarity.COMMON, mage.cards.e.EliteJavelineer.class)); - cards.add(new SetCardInfo("Elven Warhounds", 225, Rarity.RARE, mage.cards.e.ElvenWarhounds.class)); - cards.add(new SetCardInfo("Elvish Fury", 226, Rarity.COMMON, mage.cards.e.ElvishFury.class)); - cards.add(new SetCardInfo("Emerald Medallion", 283, Rarity.RARE, mage.cards.e.EmeraldMedallion.class)); - cards.add(new SetCardInfo("Emmessi Tome", 284, Rarity.RARE, mage.cards.e.EmmessiTome.class)); - cards.add(new SetCardInfo("Endless Scream", 132, Rarity.COMMON, mage.cards.e.EndlessScream.class)); - cards.add(new SetCardInfo("Energizer", 285, Rarity.RARE, mage.cards.e.Energizer.class)); - cards.add(new SetCardInfo("Enfeeblement", 133, Rarity.COMMON, mage.cards.e.Enfeeblement.class)); - cards.add(new SetCardInfo("Enraging Licid", 171, Rarity.UNCOMMON, mage.cards.e.EnragingLicid.class)); - cards.add(new SetCardInfo("Essence Bottle", 286, Rarity.UNCOMMON, mage.cards.e.EssenceBottle.class)); - cards.add(new SetCardInfo("Evincar's Justice", 134, Rarity.COMMON, mage.cards.e.EvincarsJustice.class)); - cards.add(new SetCardInfo("Excavator", 287, Rarity.UNCOMMON, mage.cards.e.Excavator.class)); - cards.add(new SetCardInfo("Extinction", 135, Rarity.RARE, mage.cards.e.Extinction.class)); - cards.add(new SetCardInfo("Fevered Convulsions", 136, Rarity.RARE, mage.cards.f.FeveredConvulsions.class)); - cards.add(new SetCardInfo("Field of Souls", 18, Rarity.RARE, mage.cards.f.FieldOfSouls.class)); - cards.add(new SetCardInfo("Fighting Drake", 63, Rarity.UNCOMMON, mage.cards.f.FightingDrake.class)); - cards.add(new SetCardInfo("Firefly", 172, Rarity.UNCOMMON, mage.cards.f.Firefly.class)); - cards.add(new SetCardInfo("Fireslinger", 173, Rarity.COMMON, mage.cards.f.Fireslinger.class)); - cards.add(new SetCardInfo("Flailing Drake", 227, Rarity.UNCOMMON, mage.cards.f.FlailingDrake.class)); - cards.add(new SetCardInfo("Flickering Ward", 19, Rarity.UNCOMMON, mage.cards.f.FlickeringWard.class)); - cards.add(new SetCardInfo("Flowstone Giant", 174, Rarity.COMMON, mage.cards.f.FlowstoneGiant.class)); - cards.add(new SetCardInfo("Flowstone Salamander", 175, Rarity.UNCOMMON, mage.cards.f.FlowstoneSalamander.class)); - cards.add(new SetCardInfo("Flowstone Sculpture", 288, Rarity.RARE, mage.cards.f.FlowstoneSculpture.class)); - cards.add(new SetCardInfo("Flowstone Wyvern", 176, Rarity.RARE, mage.cards.f.FlowstoneWyvern.class)); - cards.add(new SetCardInfo("Fool's Tome", 289, Rarity.RARE, mage.cards.f.FoolsTome.class)); - cards.add(new SetCardInfo("Forest", 347, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 348, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 349, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 350, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Frog Tongue", 228, Rarity.COMMON, mage.cards.f.FrogTongue.class)); - cards.add(new SetCardInfo("Fugitive Druid", 229, Rarity.RARE, mage.cards.f.FugitiveDruid.class)); - cards.add(new SetCardInfo("Furnace of Rath", 177, Rarity.RARE, mage.cards.f.FurnaceOfRath.class)); - cards.add(new SetCardInfo("Fylamarid", 64, Rarity.UNCOMMON, mage.cards.f.Fylamarid.class)); - cards.add(new SetCardInfo("Gallantry", 20, Rarity.UNCOMMON, mage.cards.g.Gallantry.class)); - cards.add(new SetCardInfo("Gaseous Form", 65, Rarity.COMMON, mage.cards.g.GaseousForm.class)); - cards.add(new SetCardInfo("Gerrard's Battle Cry", 21, Rarity.RARE, mage.cards.g.GerrardsBattleCry.class)); - cards.add(new SetCardInfo("Ghost Town", 318, Rarity.UNCOMMON, mage.cards.g.GhostTown.class)); - cards.add(new SetCardInfo("Giant Crab", 66, Rarity.COMMON, mage.cards.g.GiantCrab.class)); - cards.add(new SetCardInfo("Giant Strength", 178, Rarity.COMMON, mage.cards.g.GiantStrength.class)); - cards.add(new SetCardInfo("Goblin Bombardment", 179, Rarity.UNCOMMON, mage.cards.g.GoblinBombardment.class)); - cards.add(new SetCardInfo("Gravedigger", 137, Rarity.COMMON, mage.cards.g.Gravedigger.class)); - cards.add(new SetCardInfo("Grindstone", 290, Rarity.RARE, mage.cards.g.Grindstone.class)); - cards.add(new SetCardInfo("Hand to Hand", 180, Rarity.RARE, mage.cards.h.HandToHand.class)); - cards.add(new SetCardInfo("Hanna's Custody", 22, Rarity.RARE, mage.cards.h.HannasCustody.class)); - cards.add(new SetCardInfo("Harrow", 230, Rarity.UNCOMMON, mage.cards.h.Harrow.class)); - cards.add(new SetCardInfo("Havoc", 181, Rarity.UNCOMMON, mage.cards.h.Havoc.class)); - cards.add(new SetCardInfo("Heart Sliver", 182, Rarity.COMMON, mage.cards.h.HeartSliver.class)); - cards.add(new SetCardInfo("Heartwood Dryad", 231, Rarity.COMMON, mage.cards.h.HeartwoodDryad.class)); - cards.add(new SetCardInfo("Heartwood Giant", 232, Rarity.RARE, mage.cards.h.HeartwoodGiant.class)); - cards.add(new SetCardInfo("Heartwood Treefolk", 233, Rarity.UNCOMMON, mage.cards.h.HeartwoodTreefolk.class)); - cards.add(new SetCardInfo("Helm of Possession", 291, Rarity.RARE, mage.cards.h.HelmOfPossession.class)); - cards.add(new SetCardInfo("Hero's Resolve", 23, Rarity.COMMON, mage.cards.h.HerosResolve.class)); - cards.add(new SetCardInfo("Horned Sliver", 234, Rarity.UNCOMMON, mage.cards.h.HornedSliver.class)); - cards.add(new SetCardInfo("Horned Turtle", 67, Rarity.COMMON, mage.cards.h.HornedTurtle.class)); - cards.add(new SetCardInfo("Humility", 24, Rarity.RARE, mage.cards.h.Humility.class)); - cards.add(new SetCardInfo("Imps' Taunt", 138, Rarity.UNCOMMON, mage.cards.i.ImpsTaunt.class)); - cards.add(new SetCardInfo("Insight", 68, Rarity.UNCOMMON, mage.cards.i.Insight.class)); - cards.add(new SetCardInfo("Interdict", 69, Rarity.UNCOMMON, mage.cards.i.Interdict.class)); - cards.add(new SetCardInfo("Intuition", 70, Rarity.RARE, mage.cards.i.Intuition.class)); - cards.add(new SetCardInfo("Invulnerability", 25, Rarity.UNCOMMON, mage.cards.i.Invulnerability.class)); - cards.add(new SetCardInfo("Island", 335, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 336, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 337, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 338, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Jackal Pup", 183, Rarity.UNCOMMON, mage.cards.j.JackalPup.class)); - cards.add(new SetCardInfo("Jet Medallion", 292, Rarity.RARE, mage.cards.j.JetMedallion.class)); - cards.add(new SetCardInfo("Jinxed Idol", 293, Rarity.RARE, mage.cards.j.JinxedIdol.class)); - cards.add(new SetCardInfo("Kezzerdrix", 139, Rarity.RARE, mage.cards.k.Kezzerdrix.class)); - cards.add(new SetCardInfo("Kindle", 184, Rarity.COMMON, mage.cards.k.Kindle.class)); - cards.add(new SetCardInfo("Knight of Dawn", 26, Rarity.UNCOMMON, mage.cards.k.KnightOfDawn.class)); - cards.add(new SetCardInfo("Knight of Dusk", 140, Rarity.UNCOMMON, mage.cards.k.KnightOfDusk.class)); - cards.add(new SetCardInfo("Krakilin", 235, Rarity.UNCOMMON, mage.cards.k.Krakilin.class)); - cards.add(new SetCardInfo("Leeching Licid", 141, Rarity.UNCOMMON, mage.cards.l.LeechingLicid.class)); - cards.add(new SetCardInfo("Legacy's Allure", 71, Rarity.UNCOMMON, mage.cards.l.LegacysAllure.class)); - cards.add(new SetCardInfo("Legerdemain", 72, Rarity.UNCOMMON, mage.cards.l.Legerdemain.class)); - cards.add(new SetCardInfo("Light of Day", 27, Rarity.UNCOMMON, mage.cards.l.LightOfDay.class)); - cards.add(new SetCardInfo("Lightning Blast", 185, Rarity.COMMON, mage.cards.l.LightningBlast.class)); - cards.add(new SetCardInfo("Lightning Elemental", 186, Rarity.COMMON, mage.cards.l.LightningElemental.class)); - cards.add(new SetCardInfo("Living Death", 142, Rarity.RARE, mage.cards.l.LivingDeath.class)); - cards.add(new SetCardInfo("Lobotomy", 267, Rarity.UNCOMMON, mage.cards.l.Lobotomy.class)); - cards.add(new SetCardInfo("Lotus Petal", 294, Rarity.COMMON, mage.cards.l.LotusPetal.class)); - cards.add(new SetCardInfo("Lowland Giant", 187, Rarity.COMMON, mage.cards.l.LowlandGiant.class)); - cards.add(new SetCardInfo("Maddening Imp", 143, Rarity.RARE, mage.cards.m.MaddeningImp.class)); - cards.add(new SetCardInfo("Magmasaur", 188, Rarity.RARE, mage.cards.m.Magmasaur.class)); - cards.add(new SetCardInfo("Mana Severance", 73, Rarity.RARE, mage.cards.m.ManaSeverance.class)); - cards.add(new SetCardInfo("Manakin", 296, Rarity.COMMON, mage.cards.m.Manakin.class)); - cards.add(new SetCardInfo("Manta Riders", 74, Rarity.COMMON, mage.cards.m.MantaRiders.class)); - cards.add(new SetCardInfo("Marble Titan", 28, Rarity.RARE, mage.cards.m.MarbleTitan.class)); - cards.add(new SetCardInfo("Marsh Lurker", 144, Rarity.COMMON, mage.cards.m.MarshLurker.class)); - cards.add(new SetCardInfo("Master Decoy", 29, Rarity.COMMON, mage.cards.m.MasterDecoy.class)); - cards.add(new SetCardInfo("Mawcor", 75, Rarity.RARE, mage.cards.m.Mawcor.class)); - cards.add(new SetCardInfo("Maze of Shadows", 319, Rarity.UNCOMMON, mage.cards.m.MazeOfShadows.class)); - cards.add(new SetCardInfo("Meditate", 76, Rarity.RARE, mage.cards.m.Meditate.class)); - cards.add(new SetCardInfo("Metallic Sliver", 297, Rarity.COMMON, mage.cards.m.MetallicSliver.class)); - cards.add(new SetCardInfo("Mindwhip Sliver", 145, Rarity.UNCOMMON, mage.cards.m.MindwhipSliver.class)); - cards.add(new SetCardInfo("Minion of the Wastes", 146, Rarity.RARE, mage.cards.m.MinionOfTheWastes.class)); - cards.add(new SetCardInfo("Mirri's Guile", 236, Rarity.RARE, mage.cards.m.MirrisGuile.class)); - cards.add(new SetCardInfo("Mnemonic Sliver", 77, Rarity.UNCOMMON, mage.cards.m.MnemonicSliver.class)); - cards.add(new SetCardInfo("Mogg Cannon", 298, Rarity.UNCOMMON, mage.cards.m.MoggCannon.class)); - cards.add(new SetCardInfo("Mogg Conscripts", 189, Rarity.COMMON, mage.cards.m.MoggConscripts.class)); - cards.add(new SetCardInfo("Mogg Fanatic", 190, Rarity.COMMON, mage.cards.m.MoggFanatic.class)); - cards.add(new SetCardInfo("Mogg Hollows", 320, Rarity.UNCOMMON, mage.cards.m.MoggHollows.class)); - cards.add(new SetCardInfo("Mogg Raider", 191, Rarity.COMMON, mage.cards.m.MoggRaider.class)); - cards.add(new SetCardInfo("Mogg Squad", 192, Rarity.UNCOMMON, mage.cards.m.MoggSquad.class)); - cards.add(new SetCardInfo("Mongrel Pack", 237, Rarity.RARE, mage.cards.m.MongrelPack.class)); - cards.add(new SetCardInfo("Mountain", 343, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 344, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 345, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 346, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mounted Archers", 30, Rarity.COMMON, mage.cards.m.MountedArchers.class)); - cards.add(new SetCardInfo("Muscle Sliver", 238, Rarity.COMMON, mage.cards.m.MuscleSliver.class)); - cards.add(new SetCardInfo("Natural Spring", 239, Rarity.COMMON, mage.cards.n.NaturalSpring.class)); - cards.add(new SetCardInfo("Nature's Revolt", 240, Rarity.RARE, mage.cards.n.NaturesRevolt.class)); - cards.add(new SetCardInfo("Needle Storm", 241, Rarity.UNCOMMON, mage.cards.n.NeedleStorm.class)); - cards.add(new SetCardInfo("Nurturing Licid", 242, Rarity.UNCOMMON, mage.cards.n.NurturingLicid.class)); - cards.add(new SetCardInfo("Opportunist", 194, Rarity.UNCOMMON, mage.cards.o.Opportunist.class)); - cards.add(new SetCardInfo("Oracle en-Vec", 31, Rarity.RARE, mage.cards.o.OracleEnVec.class)); - cards.add(new SetCardInfo("Orim's Prayer", 32, Rarity.UNCOMMON, mage.cards.o.OrimsPrayer.class)); - cards.add(new SetCardInfo("Orim, Samite Healer", 33, Rarity.RARE, mage.cards.o.OrimSamiteHealer.class)); - cards.add(new SetCardInfo("Overrun", 243, Rarity.UNCOMMON, mage.cards.o.Overrun.class)); - cards.add(new SetCardInfo("Pacifism", 34, Rarity.COMMON, mage.cards.p.Pacifism.class)); - cards.add(new SetCardInfo("Pallimud", 195, Rarity.RARE, mage.cards.p.Pallimud.class)); - cards.add(new SetCardInfo("Patchwork Gnomes", 299, Rarity.UNCOMMON, mage.cards.p.PatchworkGnomes.class)); - cards.add(new SetCardInfo("Pearl Medallion", 300, Rarity.RARE, mage.cards.p.PearlMedallion.class)); - cards.add(new SetCardInfo("Pegasus Refuge", 35, Rarity.RARE, mage.cards.p.PegasusRefuge.class)); - cards.add(new SetCardInfo("Perish", 147, Rarity.UNCOMMON, mage.cards.p.Perish.class)); - cards.add(new SetCardInfo("Phyrexian Grimoire", 301, Rarity.RARE, mage.cards.p.PhyrexianGrimoire.class)); - cards.add(new SetCardInfo("Phyrexian Hulk", 302, Rarity.UNCOMMON, mage.cards.p.PhyrexianHulk.class)); - cards.add(new SetCardInfo("Pincher Beetles", 244, Rarity.COMMON, mage.cards.p.PincherBeetles.class)); - cards.add(new SetCardInfo("Pine Barrens", 321, Rarity.RARE, mage.cards.p.PineBarrens.class)); - cards.add(new SetCardInfo("Pit Imp", 148, Rarity.COMMON, mage.cards.p.PitImp.class)); - cards.add(new SetCardInfo("Plains", 331, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 332, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 333, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 334, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Power Sink", 78, Rarity.COMMON, mage.cards.p.PowerSink.class)); - cards.add(new SetCardInfo("Precognition", 79, Rarity.RARE, mage.cards.p.Precognition.class)); - cards.add(new SetCardInfo("Propaganda", 80, Rarity.UNCOMMON, mage.cards.p.Propaganda.class)); - cards.add(new SetCardInfo("Puppet Strings", 304, Rarity.UNCOMMON, mage.cards.p.PuppetStrings.class)); - cards.add(new SetCardInfo("Quickening Licid", 36, Rarity.UNCOMMON, mage.cards.q.QuickeningLicid.class)); - cards.add(new SetCardInfo("Rain of Tears", 149, Rarity.UNCOMMON, mage.cards.r.RainOfTears.class)); - cards.add(new SetCardInfo("Rampant Growth", 245, Rarity.COMMON, mage.cards.r.RampantGrowth.class)); - cards.add(new SetCardInfo("Ranger en-Vec", 268, Rarity.UNCOMMON, mage.cards.r.RangerEnVec.class)); - cards.add(new SetCardInfo("Rathi Dragon", 196, Rarity.RARE, mage.cards.r.RathiDragon.class)); - cards.add(new SetCardInfo("Rats of Rath", 150, Rarity.COMMON, mage.cards.r.RatsOfRath.class)); - cards.add(new SetCardInfo("Reality Anchor", 246, Rarity.COMMON, mage.cards.r.RealityAnchor.class)); - cards.add(new SetCardInfo("Reanimate", 151, Rarity.UNCOMMON, mage.cards.r.Reanimate.class)); - cards.add(new SetCardInfo("Reap", 247, Rarity.UNCOMMON, mage.cards.r.Reap.class)); - cards.add(new SetCardInfo("Reckless Spite", 152, Rarity.UNCOMMON, mage.cards.r.RecklessSpite.class)); - cards.add(new SetCardInfo("Recycle", 248, Rarity.RARE, mage.cards.r.Recycle.class)); - cards.add(new SetCardInfo("Reflecting Pool", 322, Rarity.RARE, mage.cards.r.ReflectingPool.class)); - cards.add(new SetCardInfo("Renegade Warlord", 197, Rarity.UNCOMMON, mage.cards.r.RenegadeWarlord.class)); - cards.add(new SetCardInfo("Repentance", 37, Rarity.UNCOMMON, mage.cards.r.Repentance.class)); - cards.add(new SetCardInfo("Respite", 249, Rarity.COMMON, mage.cards.r.Respite.class)); - cards.add(new SetCardInfo("Rolling Thunder", 198, Rarity.COMMON, mage.cards.r.RollingThunder.class)); - cards.add(new SetCardInfo("Root Maze", 250, Rarity.RARE, mage.cards.r.RootMaze.class)); - cards.add(new SetCardInfo("Rootbreaker Wurm", 251, Rarity.COMMON, mage.cards.r.RootbreakerWurm.class)); - cards.add(new SetCardInfo("Rootwalla", 252, Rarity.COMMON, mage.cards.r.Rootwalla.class)); - cards.add(new SetCardInfo("Rootwater Depths", 323, Rarity.UNCOMMON, mage.cards.r.RootwaterDepths.class)); - cards.add(new SetCardInfo("Rootwater Diver", 81, Rarity.UNCOMMON, mage.cards.r.RootwaterDiver.class)); - cards.add(new SetCardInfo("Rootwater Hunter", 82, Rarity.COMMON, mage.cards.r.RootwaterHunter.class)); - cards.add(new SetCardInfo("Rootwater Matriarch", 83, Rarity.RARE, mage.cards.r.RootwaterMatriarch.class)); - cards.add(new SetCardInfo("Rootwater Shaman", 84, Rarity.RARE, mage.cards.r.RootwaterShaman.class)); - cards.add(new SetCardInfo("Ruby Medallion", 305, Rarity.RARE, mage.cards.r.RubyMedallion.class)); - cards.add(new SetCardInfo("Sacred Guide", 38, Rarity.RARE, mage.cards.s.SacredGuide.class)); - cards.add(new SetCardInfo("Sadistic Glee", 153, Rarity.COMMON, mage.cards.s.SadisticGlee.class)); - cards.add(new SetCardInfo("Safeguard", 39, Rarity.RARE, mage.cards.s.Safeguard.class)); - cards.add(new SetCardInfo("Salt Flats", 324, Rarity.RARE, mage.cards.s.SaltFlats.class)); - cards.add(new SetCardInfo("Sandstone Warrior", 199, Rarity.COMMON, mage.cards.s.SandstoneWarrior.class)); - cards.add(new SetCardInfo("Sapphire Medallion", 306, Rarity.RARE, mage.cards.s.SapphireMedallion.class)); - cards.add(new SetCardInfo("Sarcomancy", 154, Rarity.RARE, mage.cards.s.Sarcomancy.class)); - cards.add(new SetCardInfo("Scabland", 325, Rarity.RARE, mage.cards.s.Scabland.class)); - cards.add(new SetCardInfo("Scalding Tongs", 307, Rarity.RARE, mage.cards.s.ScaldingTongs.class)); - cards.add(new SetCardInfo("Scorched Earth", 200, Rarity.RARE, mage.cards.s.ScorchedEarth.class)); - cards.add(new SetCardInfo("Scragnoth", 253, Rarity.UNCOMMON, mage.cards.s.Scragnoth.class)); - cards.add(new SetCardInfo("Screeching Harpy", 155, Rarity.UNCOMMON, mage.cards.s.ScreechingHarpy.class)); - cards.add(new SetCardInfo("Scroll Rack", 308, Rarity.RARE, mage.cards.s.ScrollRack.class)); - cards.add(new SetCardInfo("Sea Monster", 85, Rarity.COMMON, mage.cards.s.SeaMonster.class)); - cards.add(new SetCardInfo("Searing Touch", 201, Rarity.UNCOMMON, mage.cards.s.SearingTouch.class)); - cards.add(new SetCardInfo("Seeker of Skybreak", 254, Rarity.COMMON, mage.cards.s.SeekerOfSkybreak.class)); - cards.add(new SetCardInfo("Segmented Wurm", 269, Rarity.UNCOMMON, mage.cards.s.SegmentedWurm.class)); - cards.add(new SetCardInfo("Selenia, Dark Angel", 270, Rarity.RARE, mage.cards.s.SeleniaDarkAngel.class)); - cards.add(new SetCardInfo("Serene Offering", 40, Rarity.UNCOMMON, mage.cards.s.SereneOffering.class)); - cards.add(new SetCardInfo("Servant of Volrath", 156, Rarity.COMMON, mage.cards.s.ServantOfVolrath.class)); - cards.add(new SetCardInfo("Shadow Rift", 86, Rarity.COMMON, mage.cards.s.ShadowRift.class)); - cards.add(new SetCardInfo("Shadowstorm", 202, Rarity.UNCOMMON, mage.cards.s.Shadowstorm.class)); - cards.add(new SetCardInfo("Shatter", 203, Rarity.COMMON, mage.cards.s.Shatter.class)); - cards.add(new SetCardInfo("Shimmering Wings", 87, Rarity.COMMON, mage.cards.s.ShimmeringWings.class)); - cards.add(new SetCardInfo("Shocker", 204, Rarity.RARE, mage.cards.s.Shocker.class)); - cards.add(new SetCardInfo("Sky Spirit", 271, Rarity.UNCOMMON, mage.cards.s.SkySpirit.class)); - cards.add(new SetCardInfo("Skyshroud Condor", 88, Rarity.UNCOMMON, mage.cards.s.SkyshroudCondor.class)); - cards.add(new SetCardInfo("Skyshroud Elf", 255, Rarity.COMMON, mage.cards.s.SkyshroudElf.class)); - cards.add(new SetCardInfo("Skyshroud Forest", 326, Rarity.RARE, mage.cards.s.SkyshroudForest.class)); - cards.add(new SetCardInfo("Skyshroud Ranger", 256, Rarity.COMMON, mage.cards.s.SkyshroudRanger.class)); - cards.add(new SetCardInfo("Skyshroud Troll", 257, Rarity.COMMON, mage.cards.s.SkyshroudTroll.class)); - cards.add(new SetCardInfo("Skyshroud Vampire", 157, Rarity.UNCOMMON, mage.cards.s.SkyshroudVampire.class)); - cards.add(new SetCardInfo("Soltari Crusader", 41, Rarity.UNCOMMON, mage.cards.s.SoltariCrusader.class)); - cards.add(new SetCardInfo("Soltari Emissary", 42, Rarity.RARE, mage.cards.s.SoltariEmissary.class)); - cards.add(new SetCardInfo("Soltari Foot Soldier", 43, Rarity.COMMON, mage.cards.s.SoltariFootSoldier.class)); - cards.add(new SetCardInfo("Soltari Guerrillas", 272, Rarity.RARE, mage.cards.s.SoltariGuerrillas.class)); - cards.add(new SetCardInfo("Soltari Lancer", 44, Rarity.COMMON, mage.cards.s.SoltariLancer.class)); - cards.add(new SetCardInfo("Soltari Monk", 45, Rarity.UNCOMMON, mage.cards.s.SoltariMonk.class)); - cards.add(new SetCardInfo("Soltari Priest", 46, Rarity.UNCOMMON, mage.cards.s.SoltariPriest.class)); - cards.add(new SetCardInfo("Soltari Trooper", 47, Rarity.COMMON, mage.cards.s.SoltariTrooper.class)); - cards.add(new SetCardInfo("Souldrinker", 158, Rarity.UNCOMMON, mage.cards.s.Souldrinker.class)); - cards.add(new SetCardInfo("Spell Blast", 89, Rarity.COMMON, mage.cards.s.SpellBlast.class)); - cards.add(new SetCardInfo("Spike Drone", 258, Rarity.COMMON, mage.cards.s.SpikeDrone.class)); - cards.add(new SetCardInfo("Spinal Graft", 159, Rarity.COMMON, mage.cards.s.SpinalGraft.class)); - cards.add(new SetCardInfo("Spirit Mirror", 48, Rarity.RARE, mage.cards.s.SpiritMirror.class)); - cards.add(new SetCardInfo("Spontaneous Combustion", 273, Rarity.UNCOMMON, mage.cards.s.SpontaneousCombustion.class)); - cards.add(new SetCardInfo("Squee's Toy", 309, Rarity.COMMON, mage.cards.s.SqueesToy.class)); - cards.add(new SetCardInfo("Stalking Stones", 327, Rarity.UNCOMMON, mage.cards.s.StalkingStones.class)); - cards.add(new SetCardInfo("Starke of Rath", 205, Rarity.RARE, mage.cards.s.StarkeOfRath.class)); - cards.add(new SetCardInfo("Static Orb", 310, Rarity.RARE, mage.cards.s.StaticOrb.class)); - cards.add(new SetCardInfo("Staunch Defenders", 49, Rarity.UNCOMMON, mage.cards.s.StaunchDefenders.class)); - cards.add(new SetCardInfo("Steal Enchantment", 90, Rarity.UNCOMMON, mage.cards.s.StealEnchantment.class)); - cards.add(new SetCardInfo("Stinging Licid", 91, Rarity.UNCOMMON, mage.cards.s.StingingLicid.class)); - cards.add(new SetCardInfo("Stone Rain", 206, Rarity.COMMON, mage.cards.s.StoneRain.class)); - cards.add(new SetCardInfo("Storm Front", 259, Rarity.UNCOMMON, mage.cards.s.StormFront.class)); - cards.add(new SetCardInfo("Stun", 207, Rarity.COMMON, mage.cards.s.Stun.class)); - cards.add(new SetCardInfo("Sudden Impact", 208, Rarity.UNCOMMON, mage.cards.s.SuddenImpact.class)); - cards.add(new SetCardInfo("Swamp", 339, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 340, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 341, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 342, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Tahngarth's Rage", 209, Rarity.UNCOMMON, mage.cards.t.TahngarthsRage.class)); - cards.add(new SetCardInfo("Talon Sliver", 50, Rarity.COMMON, mage.cards.t.TalonSliver.class)); - cards.add(new SetCardInfo("Telethopter", 311, Rarity.UNCOMMON, mage.cards.t.Telethopter.class)); - cards.add(new SetCardInfo("Thalakos Dreamsower", 92, Rarity.UNCOMMON, mage.cards.t.ThalakosDreamsower.class)); - cards.add(new SetCardInfo("Thalakos Lowlands", 328, Rarity.UNCOMMON, mage.cards.t.ThalakosLowlands.class)); - cards.add(new SetCardInfo("Thalakos Mistfolk", 93, Rarity.COMMON, mage.cards.t.ThalakosMistfolk.class)); - cards.add(new SetCardInfo("Thalakos Seer", 94, Rarity.COMMON, mage.cards.t.ThalakosSeer.class)); - cards.add(new SetCardInfo("Thalakos Sentry", 95, Rarity.COMMON, mage.cards.t.ThalakosSentry.class)); - cards.add(new SetCardInfo("Thumbscrews", 312, Rarity.RARE, mage.cards.t.Thumbscrews.class)); - cards.add(new SetCardInfo("Time Ebb", 96, Rarity.COMMON, mage.cards.t.TimeEbb.class)); - cards.add(new SetCardInfo("Time Warp", 97, Rarity.RARE, mage.cards.t.TimeWarp.class)); - cards.add(new SetCardInfo("Tooth and Claw", 210, Rarity.RARE, mage.cards.t.ToothAndClaw.class)); - cards.add(new SetCardInfo("Torture Chamber", 313, Rarity.RARE, mage.cards.t.TortureChamber.class)); - cards.add(new SetCardInfo("Tradewind Rider", 98, Rarity.RARE, mage.cards.t.TradewindRider.class)); - cards.add(new SetCardInfo("Trained Armodon", 260, Rarity.COMMON, mage.cards.t.TrainedArmodon.class)); - cards.add(new SetCardInfo("Tranquility", 261, Rarity.COMMON, mage.cards.t.Tranquility.class)); - cards.add(new SetCardInfo("Trumpeting Armodon", 262, Rarity.UNCOMMON, mage.cards.t.TrumpetingArmodon.class)); - cards.add(new SetCardInfo("Twitch", 99, Rarity.COMMON, mage.cards.t.Twitch.class)); - cards.add(new SetCardInfo("Unstable Shapeshifter", 100, Rarity.RARE, mage.cards.u.UnstableShapeshifter.class)); - cards.add(new SetCardInfo("Vec Townships", 329, Rarity.UNCOMMON, mage.cards.v.VecTownships.class)); - cards.add(new SetCardInfo("Verdant Force", 263, Rarity.RARE, mage.cards.v.VerdantForce.class)); - cards.add(new SetCardInfo("Verdigris", 264, Rarity.UNCOMMON, mage.cards.v.Verdigris.class)); - cards.add(new SetCardInfo("Vhati il-Dal", 274, Rarity.RARE, mage.cards.v.VhatiIlDal.class)); - cards.add(new SetCardInfo("Volrath's Curse", 101, Rarity.COMMON, mage.cards.v.VolrathsCurse.class)); - cards.add(new SetCardInfo("Wall of Diffusion", 211, Rarity.COMMON, mage.cards.w.WallOfDiffusion.class)); - cards.add(new SetCardInfo("Warmth", 51, Rarity.UNCOMMON, mage.cards.w.Warmth.class)); - cards.add(new SetCardInfo("Wasteland", 330, Rarity.UNCOMMON, mage.cards.w.Wasteland.class)); - cards.add(new SetCardInfo("Watchdog", 314, Rarity.UNCOMMON, mage.cards.w.Watchdog.class)); - cards.add(new SetCardInfo("Whispers of the Muse", 103, Rarity.UNCOMMON, mage.cards.w.WhispersOfTheMuse.class)); - cards.add(new SetCardInfo("Wild Wurm", 212, Rarity.UNCOMMON, mage.cards.w.WildWurm.class)); - cards.add(new SetCardInfo("Wind Dancer", 104, Rarity.UNCOMMON, mage.cards.w.WindDancer.class)); - cards.add(new SetCardInfo("Wind Drake", 105, Rarity.COMMON, mage.cards.w.WindDrake.class)); - cards.add(new SetCardInfo("Winds of Rath", 52, Rarity.RARE, mage.cards.w.WindsOfRath.class)); - cards.add(new SetCardInfo("Winged Sliver", 106, Rarity.COMMON, mage.cards.w.WingedSliver.class)); - cards.add(new SetCardInfo("Winter's Grasp", 265, Rarity.UNCOMMON, mage.cards.w.WintersGrasp.class)); - cards.add(new SetCardInfo("Wood Sage", 275, Rarity.RARE, mage.cards.w.WoodSage.class)); - cards.add(new SetCardInfo("Worthy Cause", 53, Rarity.UNCOMMON, mage.cards.w.WorthyCause.class)); - } -} +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +public final class Tempest extends ExpansionSet { + + private static final Tempest instance = new Tempest(); + + public static Tempest getInstance() { + return instance; + } + + private Tempest() { + super("Tempest", "TMP", ExpansionSet.buildDate(1997, 10, 1), SetType.EXPANSION); + this.blockName = "Tempest"; + this.hasBoosters = true; + this.numBoosterLands = 0; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + cards.add(new SetCardInfo("Abandon Hope", 107, Rarity.UNCOMMON, mage.cards.a.AbandonHope.class)); + cards.add(new SetCardInfo("Advance Scout", 1, Rarity.COMMON, mage.cards.a.AdvanceScout.class)); + cards.add(new SetCardInfo("Aftershock", 160, Rarity.COMMON, mage.cards.a.Aftershock.class)); + cards.add(new SetCardInfo("Altar of Dementia", 276, Rarity.RARE, mage.cards.a.AltarOfDementia.class)); + cards.add(new SetCardInfo("Aluren", 213, Rarity.RARE, mage.cards.a.Aluren.class)); + cards.add(new SetCardInfo("Ancient Runes", 161, Rarity.UNCOMMON, mage.cards.a.AncientRunes.class)); + cards.add(new SetCardInfo("Ancient Tomb", 315, Rarity.UNCOMMON, mage.cards.a.AncientTomb.class)); + cards.add(new SetCardInfo("Angelic Protector", 2, Rarity.UNCOMMON, mage.cards.a.AngelicProtector.class)); + cards.add(new SetCardInfo("Anoint", 3, Rarity.COMMON, mage.cards.a.Anoint.class)); + cards.add(new SetCardInfo("Apes of Rath", 214, Rarity.UNCOMMON, mage.cards.a.ApesOfRath.class)); + cards.add(new SetCardInfo("Apocalypse", 162, Rarity.RARE, mage.cards.a.Apocalypse.class)); + cards.add(new SetCardInfo("Armor Sliver", 4, Rarity.UNCOMMON, mage.cards.a.ArmorSliver.class)); + cards.add(new SetCardInfo("Armored Pegasus", 5, Rarity.COMMON, mage.cards.a.ArmoredPegasus.class)); + cards.add(new SetCardInfo("Auratog", 6, Rarity.RARE, mage.cards.a.Auratog.class)); + cards.add(new SetCardInfo("Avenging Angel", 7, Rarity.RARE, mage.cards.a.AvengingAngel.class)); + cards.add(new SetCardInfo("Barbed Sliver", 163, Rarity.UNCOMMON, mage.cards.b.BarbedSliver.class)); + cards.add(new SetCardInfo("Bayou Dragonfly", 215, Rarity.COMMON, mage.cards.b.BayouDragonfly.class)); + cards.add(new SetCardInfo("Bellowing Fiend", 108, Rarity.RARE, mage.cards.b.BellowingFiend.class)); + cards.add(new SetCardInfo("Benthic Behemoth", 54, Rarity.RARE, mage.cards.b.BenthicBehemoth.class)); + cards.add(new SetCardInfo("Blood Frenzy", 164, Rarity.COMMON, mage.cards.b.BloodFrenzy.class)); + cards.add(new SetCardInfo("Blood Pet", 109, Rarity.COMMON, mage.cards.b.BloodPet.class)); + cards.add(new SetCardInfo("Boil", 165, Rarity.UNCOMMON, mage.cards.b.Boil.class)); + cards.add(new SetCardInfo("Booby Trap", 277, Rarity.RARE, mage.cards.b.BoobyTrap.class)); + cards.add(new SetCardInfo("Bottle Gnomes", 278, Rarity.UNCOMMON, mage.cards.b.BottleGnomes.class)); + cards.add(new SetCardInfo("Bounty Hunter", 110, Rarity.RARE, mage.cards.b.BountyHunter.class)); + cards.add(new SetCardInfo("Broken Fall", 216, Rarity.COMMON, mage.cards.b.BrokenFall.class)); + cards.add(new SetCardInfo("Caldera Lake", 316, Rarity.RARE, mage.cards.c.CalderaLake.class)); + cards.add(new SetCardInfo("Canopy Spider", 217, Rarity.COMMON, mage.cards.c.CanopySpider.class)); + cards.add(new SetCardInfo("Canyon Drake", 166, Rarity.RARE, mage.cards.c.CanyonDrake.class)); + cards.add(new SetCardInfo("Canyon Wildcat", 167, Rarity.COMMON, mage.cards.c.CanyonWildcat.class)); + cards.add(new SetCardInfo("Capsize", 55, Rarity.COMMON, mage.cards.c.Capsize.class)); + cards.add(new SetCardInfo("Carrionette", 111, Rarity.RARE, mage.cards.c.Carrionette.class)); + cards.add(new SetCardInfo("Chaotic Goo", 168, Rarity.RARE, mage.cards.c.ChaoticGoo.class)); + cards.add(new SetCardInfo("Charging Rhino", 218, Rarity.UNCOMMON, mage.cards.c.ChargingRhino.class)); + cards.add(new SetCardInfo("Chill", 56, Rarity.UNCOMMON, mage.cards.c.Chill.class)); + cards.add(new SetCardInfo("Choke", 219, Rarity.UNCOMMON, mage.cards.c.Choke.class)); + cards.add(new SetCardInfo("Cinder Marsh", 317, Rarity.UNCOMMON, mage.cards.c.CinderMarsh.class)); + cards.add(new SetCardInfo("Circle of Protection: Black", 8, Rarity.COMMON, mage.cards.c.CircleOfProtectionBlack.class)); + cards.add(new SetCardInfo("Circle of Protection: Blue", 9, Rarity.COMMON, mage.cards.c.CircleOfProtectionBlue.class)); + cards.add(new SetCardInfo("Circle of Protection: Green", 10, Rarity.COMMON, mage.cards.c.CircleOfProtectionGreen.class)); + cards.add(new SetCardInfo("Circle of Protection: Red", 11, Rarity.COMMON, mage.cards.c.CircleOfProtectionRed.class)); + cards.add(new SetCardInfo("Circle of Protection: Shadow", 12, Rarity.COMMON, mage.cards.c.CircleOfProtectionShadow.class)); + cards.add(new SetCardInfo("Circle of Protection: White", 13, Rarity.COMMON, mage.cards.c.CircleOfProtectionWhite.class)); + cards.add(new SetCardInfo("Clergy en-Vec", 14, Rarity.COMMON, mage.cards.c.ClergyEnVec.class)); + cards.add(new SetCardInfo("Clot Sliver", 112, Rarity.COMMON, mage.cards.c.ClotSliver.class)); + cards.add(new SetCardInfo("Cloudchaser Eagle", 15, Rarity.COMMON, mage.cards.c.CloudchaserEagle.class)); + cards.add(new SetCardInfo("Coercion", 113, Rarity.COMMON, mage.cards.c.Coercion.class)); + cards.add(new SetCardInfo("Coffin Queen", 114, Rarity.RARE, mage.cards.c.CoffinQueen.class)); + cards.add(new SetCardInfo("Coiled Tinviper", 279, Rarity.COMMON, mage.cards.c.CoiledTinviper.class)); + cards.add(new SetCardInfo("Cold Storage", 280, Rarity.RARE, mage.cards.c.ColdStorage.class)); + cards.add(new SetCardInfo("Commander Greven il-Vec", 115, Rarity.RARE, mage.cards.c.CommanderGrevenIlVec.class)); + cards.add(new SetCardInfo("Corpse Dance", 116, Rarity.RARE, mage.cards.c.CorpseDance.class)); + cards.add(new SetCardInfo("Counterspell", 57, Rarity.COMMON, mage.cards.c.Counterspell.class)); + cards.add(new SetCardInfo("Crazed Armodon", 220, Rarity.RARE, mage.cards.c.CrazedArmodon.class)); + cards.add(new SetCardInfo("Crown of Flames", 169, Rarity.COMMON, mage.cards.c.CrownOfFlames.class)); + cards.add(new SetCardInfo("Cursed Scroll", 281, Rarity.RARE, mage.cards.c.CursedScroll.class)); + cards.add(new SetCardInfo("Dark Banishing", 117, Rarity.COMMON, mage.cards.d.DarkBanishing.class)); + cards.add(new SetCardInfo("Dark Ritual", 118, Rarity.COMMON, mage.cards.d.DarkRitual.class)); + cards.add(new SetCardInfo("Darkling Stalker", 119, Rarity.COMMON, mage.cards.d.DarklingStalker.class)); + cards.add(new SetCardInfo("Dauthi Embrace", 120, Rarity.UNCOMMON, mage.cards.d.DauthiEmbrace.class)); + cards.add(new SetCardInfo("Dauthi Ghoul", 121, Rarity.UNCOMMON, mage.cards.d.DauthiGhoul.class)); + cards.add(new SetCardInfo("Dauthi Horror", 122, Rarity.COMMON, mage.cards.d.DauthiHorror.class)); + cards.add(new SetCardInfo("Dauthi Marauder", 123, Rarity.COMMON, mage.cards.d.DauthiMarauder.class)); + cards.add(new SetCardInfo("Dauthi Mercenary", 124, Rarity.UNCOMMON, mage.cards.d.DauthiMercenary.class)); + cards.add(new SetCardInfo("Dauthi Mindripper", 125, Rarity.UNCOMMON, mage.cards.d.DauthiMindripper.class)); + cards.add(new SetCardInfo("Dauthi Slayer", 126, Rarity.COMMON, mage.cards.d.DauthiSlayer.class)); + cards.add(new SetCardInfo("Deadshot", 170, Rarity.RARE, mage.cards.d.Deadshot.class)); + cards.add(new SetCardInfo("Death Pits of Rath", 127, Rarity.RARE, mage.cards.d.DeathPitsOfRath.class)); + cards.add(new SetCardInfo("Diabolic Edict", 128, Rarity.COMMON, mage.cards.d.DiabolicEdict.class)); + cards.add(new SetCardInfo("Dirtcowl Wurm", 221, Rarity.RARE, mage.cards.d.DirtcowlWurm.class)); + cards.add(new SetCardInfo("Disenchant", 16, Rarity.COMMON, mage.cards.d.Disenchant.class)); + cards.add(new SetCardInfo("Dismiss", 58, Rarity.UNCOMMON, mage.cards.d.Dismiss.class)); + cards.add(new SetCardInfo("Disturbed Burial", 129, Rarity.COMMON, mage.cards.d.DisturbedBurial.class)); + cards.add(new SetCardInfo("Dracoplasm", 266, Rarity.RARE, mage.cards.d.Dracoplasm.class)); + cards.add(new SetCardInfo("Dread of Night", 130, Rarity.UNCOMMON, mage.cards.d.DreadOfNight.class)); + cards.add(new SetCardInfo("Dream Cache", 59, Rarity.COMMON, mage.cards.d.DreamCache.class)); + cards.add(new SetCardInfo("Dregs of Sorrow", 131, Rarity.RARE, mage.cards.d.DregsOfSorrow.class)); + cards.add(new SetCardInfo("Duplicity", 60, Rarity.RARE, mage.cards.d.Duplicity.class)); + cards.add(new SetCardInfo("Earthcraft", 222, Rarity.RARE, mage.cards.e.Earthcraft.class)); + cards.add(new SetCardInfo("Echo Chamber", 282, Rarity.RARE, mage.cards.e.EchoChamber.class)); + cards.add(new SetCardInfo("Eladamri's Vineyard", 223, Rarity.RARE, mage.cards.e.EladamrisVineyard.class)); + cards.add(new SetCardInfo("Eladamri, Lord of Leaves", 224, Rarity.RARE, mage.cards.e.EladamriLordOfLeaves.class)); + cards.add(new SetCardInfo("Elite Javelineer", 17, Rarity.COMMON, mage.cards.e.EliteJavelineer.class)); + cards.add(new SetCardInfo("Elven Warhounds", 225, Rarity.RARE, mage.cards.e.ElvenWarhounds.class)); + cards.add(new SetCardInfo("Elvish Fury", 226, Rarity.COMMON, mage.cards.e.ElvishFury.class)); + cards.add(new SetCardInfo("Emerald Medallion", 283, Rarity.RARE, mage.cards.e.EmeraldMedallion.class)); + cards.add(new SetCardInfo("Emmessi Tome", 284, Rarity.RARE, mage.cards.e.EmmessiTome.class)); + cards.add(new SetCardInfo("Endless Scream", 132, Rarity.COMMON, mage.cards.e.EndlessScream.class)); + cards.add(new SetCardInfo("Energizer", 285, Rarity.RARE, mage.cards.e.Energizer.class)); + cards.add(new SetCardInfo("Enfeeblement", 133, Rarity.COMMON, mage.cards.e.Enfeeblement.class)); + cards.add(new SetCardInfo("Enraging Licid", 171, Rarity.UNCOMMON, mage.cards.e.EnragingLicid.class)); + cards.add(new SetCardInfo("Essence Bottle", 286, Rarity.UNCOMMON, mage.cards.e.EssenceBottle.class)); + cards.add(new SetCardInfo("Evincar's Justice", 134, Rarity.COMMON, mage.cards.e.EvincarsJustice.class)); + cards.add(new SetCardInfo("Excavator", 287, Rarity.UNCOMMON, mage.cards.e.Excavator.class)); + cards.add(new SetCardInfo("Extinction", 135, Rarity.RARE, mage.cards.e.Extinction.class)); + cards.add(new SetCardInfo("Fevered Convulsions", 136, Rarity.RARE, mage.cards.f.FeveredConvulsions.class)); + cards.add(new SetCardInfo("Field of Souls", 18, Rarity.RARE, mage.cards.f.FieldOfSouls.class)); + cards.add(new SetCardInfo("Fighting Drake", 63, Rarity.UNCOMMON, mage.cards.f.FightingDrake.class)); + cards.add(new SetCardInfo("Firefly", 172, Rarity.UNCOMMON, mage.cards.f.Firefly.class)); + cards.add(new SetCardInfo("Fireslinger", 173, Rarity.COMMON, mage.cards.f.Fireslinger.class)); + cards.add(new SetCardInfo("Flailing Drake", 227, Rarity.UNCOMMON, mage.cards.f.FlailingDrake.class)); + cards.add(new SetCardInfo("Flickering Ward", 19, Rarity.UNCOMMON, mage.cards.f.FlickeringWard.class)); + cards.add(new SetCardInfo("Flowstone Giant", 174, Rarity.COMMON, mage.cards.f.FlowstoneGiant.class)); + cards.add(new SetCardInfo("Flowstone Salamander", 175, Rarity.UNCOMMON, mage.cards.f.FlowstoneSalamander.class)); + cards.add(new SetCardInfo("Flowstone Sculpture", 288, Rarity.RARE, mage.cards.f.FlowstoneSculpture.class)); + cards.add(new SetCardInfo("Flowstone Wyvern", 176, Rarity.RARE, mage.cards.f.FlowstoneWyvern.class)); + cards.add(new SetCardInfo("Fool's Tome", 289, Rarity.RARE, mage.cards.f.FoolsTome.class)); + cards.add(new SetCardInfo("Forest", 347, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 348, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 349, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 350, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Frog Tongue", 228, Rarity.COMMON, mage.cards.f.FrogTongue.class)); + cards.add(new SetCardInfo("Fugitive Druid", 229, Rarity.RARE, mage.cards.f.FugitiveDruid.class)); + cards.add(new SetCardInfo("Furnace of Rath", 177, Rarity.RARE, mage.cards.f.FurnaceOfRath.class)); + cards.add(new SetCardInfo("Fylamarid", 64, Rarity.UNCOMMON, mage.cards.f.Fylamarid.class)); + cards.add(new SetCardInfo("Gallantry", 20, Rarity.UNCOMMON, mage.cards.g.Gallantry.class)); + cards.add(new SetCardInfo("Gaseous Form", 65, Rarity.COMMON, mage.cards.g.GaseousForm.class)); + cards.add(new SetCardInfo("Gerrard's Battle Cry", 21, Rarity.RARE, mage.cards.g.GerrardsBattleCry.class)); + cards.add(new SetCardInfo("Ghost Town", 318, Rarity.UNCOMMON, mage.cards.g.GhostTown.class)); + cards.add(new SetCardInfo("Giant Crab", 66, Rarity.COMMON, mage.cards.g.GiantCrab.class)); + cards.add(new SetCardInfo("Giant Strength", 178, Rarity.COMMON, mage.cards.g.GiantStrength.class)); + cards.add(new SetCardInfo("Goblin Bombardment", 179, Rarity.UNCOMMON, mage.cards.g.GoblinBombardment.class)); + cards.add(new SetCardInfo("Gravedigger", 137, Rarity.COMMON, mage.cards.g.Gravedigger.class)); + cards.add(new SetCardInfo("Grindstone", 290, Rarity.RARE, mage.cards.g.Grindstone.class)); + cards.add(new SetCardInfo("Hand to Hand", 180, Rarity.RARE, mage.cards.h.HandToHand.class)); + cards.add(new SetCardInfo("Hanna's Custody", 22, Rarity.RARE, mage.cards.h.HannasCustody.class)); + cards.add(new SetCardInfo("Harrow", 230, Rarity.UNCOMMON, mage.cards.h.Harrow.class)); + cards.add(new SetCardInfo("Havoc", 181, Rarity.UNCOMMON, mage.cards.h.Havoc.class)); + cards.add(new SetCardInfo("Heart Sliver", 182, Rarity.COMMON, mage.cards.h.HeartSliver.class)); + cards.add(new SetCardInfo("Heartwood Dryad", 231, Rarity.COMMON, mage.cards.h.HeartwoodDryad.class)); + cards.add(new SetCardInfo("Heartwood Giant", 232, Rarity.RARE, mage.cards.h.HeartwoodGiant.class)); + cards.add(new SetCardInfo("Heartwood Treefolk", 233, Rarity.UNCOMMON, mage.cards.h.HeartwoodTreefolk.class)); + cards.add(new SetCardInfo("Helm of Possession", 291, Rarity.RARE, mage.cards.h.HelmOfPossession.class)); + cards.add(new SetCardInfo("Hero's Resolve", 23, Rarity.COMMON, mage.cards.h.HerosResolve.class)); + cards.add(new SetCardInfo("Horned Sliver", 234, Rarity.UNCOMMON, mage.cards.h.HornedSliver.class)); + cards.add(new SetCardInfo("Horned Turtle", 67, Rarity.COMMON, mage.cards.h.HornedTurtle.class)); + cards.add(new SetCardInfo("Humility", 24, Rarity.RARE, mage.cards.h.Humility.class)); + cards.add(new SetCardInfo("Imps' Taunt", 138, Rarity.UNCOMMON, mage.cards.i.ImpsTaunt.class)); + cards.add(new SetCardInfo("Insight", 68, Rarity.UNCOMMON, mage.cards.i.Insight.class)); + cards.add(new SetCardInfo("Interdict", 69, Rarity.UNCOMMON, mage.cards.i.Interdict.class)); + cards.add(new SetCardInfo("Intuition", 70, Rarity.RARE, mage.cards.i.Intuition.class)); + cards.add(new SetCardInfo("Invulnerability", 25, Rarity.UNCOMMON, mage.cards.i.Invulnerability.class)); + cards.add(new SetCardInfo("Island", 335, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 336, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 337, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 338, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jackal Pup", 183, Rarity.UNCOMMON, mage.cards.j.JackalPup.class)); + cards.add(new SetCardInfo("Jet Medallion", 292, Rarity.RARE, mage.cards.j.JetMedallion.class)); + cards.add(new SetCardInfo("Jinxed Idol", 293, Rarity.RARE, mage.cards.j.JinxedIdol.class)); + cards.add(new SetCardInfo("Kezzerdrix", 139, Rarity.RARE, mage.cards.k.Kezzerdrix.class)); + cards.add(new SetCardInfo("Kindle", 184, Rarity.COMMON, mage.cards.k.Kindle.class)); + cards.add(new SetCardInfo("Knight of Dawn", 26, Rarity.UNCOMMON, mage.cards.k.KnightOfDawn.class)); + cards.add(new SetCardInfo("Knight of Dusk", 140, Rarity.UNCOMMON, mage.cards.k.KnightOfDusk.class)); + cards.add(new SetCardInfo("Krakilin", 235, Rarity.UNCOMMON, mage.cards.k.Krakilin.class)); + cards.add(new SetCardInfo("Leeching Licid", 141, Rarity.UNCOMMON, mage.cards.l.LeechingLicid.class)); + cards.add(new SetCardInfo("Legacy's Allure", 71, Rarity.UNCOMMON, mage.cards.l.LegacysAllure.class)); + cards.add(new SetCardInfo("Legerdemain", 72, Rarity.UNCOMMON, mage.cards.l.Legerdemain.class)); + cards.add(new SetCardInfo("Light of Day", 27, Rarity.UNCOMMON, mage.cards.l.LightOfDay.class)); + cards.add(new SetCardInfo("Lightning Blast", 185, Rarity.COMMON, mage.cards.l.LightningBlast.class)); + cards.add(new SetCardInfo("Lightning Elemental", 186, Rarity.COMMON, mage.cards.l.LightningElemental.class)); + cards.add(new SetCardInfo("Living Death", 142, Rarity.RARE, mage.cards.l.LivingDeath.class)); + cards.add(new SetCardInfo("Lobotomy", 267, Rarity.UNCOMMON, mage.cards.l.Lobotomy.class)); + cards.add(new SetCardInfo("Lotus Petal", 294, Rarity.COMMON, mage.cards.l.LotusPetal.class)); + cards.add(new SetCardInfo("Lowland Giant", 187, Rarity.COMMON, mage.cards.l.LowlandGiant.class)); + cards.add(new SetCardInfo("Maddening Imp", 143, Rarity.RARE, mage.cards.m.MaddeningImp.class)); + cards.add(new SetCardInfo("Magmasaur", 188, Rarity.RARE, mage.cards.m.Magmasaur.class)); + cards.add(new SetCardInfo("Mana Severance", 73, Rarity.RARE, mage.cards.m.ManaSeverance.class)); + cards.add(new SetCardInfo("Manakin", 296, Rarity.COMMON, mage.cards.m.Manakin.class)); + cards.add(new SetCardInfo("Manta Riders", 74, Rarity.COMMON, mage.cards.m.MantaRiders.class)); + cards.add(new SetCardInfo("Marble Titan", 28, Rarity.RARE, mage.cards.m.MarbleTitan.class)); + cards.add(new SetCardInfo("Marsh Lurker", 144, Rarity.COMMON, mage.cards.m.MarshLurker.class)); + cards.add(new SetCardInfo("Master Decoy", 29, Rarity.COMMON, mage.cards.m.MasterDecoy.class)); + cards.add(new SetCardInfo("Mawcor", 75, Rarity.RARE, mage.cards.m.Mawcor.class)); + cards.add(new SetCardInfo("Maze of Shadows", 319, Rarity.UNCOMMON, mage.cards.m.MazeOfShadows.class)); + cards.add(new SetCardInfo("Meditate", 76, Rarity.RARE, mage.cards.m.Meditate.class)); + cards.add(new SetCardInfo("Metallic Sliver", 297, Rarity.COMMON, mage.cards.m.MetallicSliver.class)); + cards.add(new SetCardInfo("Mindwhip Sliver", 145, Rarity.UNCOMMON, mage.cards.m.MindwhipSliver.class)); + cards.add(new SetCardInfo("Minion of the Wastes", 146, Rarity.RARE, mage.cards.m.MinionOfTheWastes.class)); + cards.add(new SetCardInfo("Mirri's Guile", 236, Rarity.RARE, mage.cards.m.MirrisGuile.class)); + cards.add(new SetCardInfo("Mnemonic Sliver", 77, Rarity.UNCOMMON, mage.cards.m.MnemonicSliver.class)); + cards.add(new SetCardInfo("Mogg Cannon", 298, Rarity.UNCOMMON, mage.cards.m.MoggCannon.class)); + cards.add(new SetCardInfo("Mogg Conscripts", 189, Rarity.COMMON, mage.cards.m.MoggConscripts.class)); + cards.add(new SetCardInfo("Mogg Fanatic", 190, Rarity.COMMON, mage.cards.m.MoggFanatic.class)); + cards.add(new SetCardInfo("Mogg Hollows", 320, Rarity.UNCOMMON, mage.cards.m.MoggHollows.class)); + cards.add(new SetCardInfo("Mogg Raider", 191, Rarity.COMMON, mage.cards.m.MoggRaider.class)); + cards.add(new SetCardInfo("Mogg Squad", 192, Rarity.UNCOMMON, mage.cards.m.MoggSquad.class)); + cards.add(new SetCardInfo("Mongrel Pack", 237, Rarity.RARE, mage.cards.m.MongrelPack.class)); + cards.add(new SetCardInfo("Mountain", 343, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 344, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 345, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 346, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mounted Archers", 30, Rarity.COMMON, mage.cards.m.MountedArchers.class)); + cards.add(new SetCardInfo("Muscle Sliver", 238, Rarity.COMMON, mage.cards.m.MuscleSliver.class)); + cards.add(new SetCardInfo("Natural Spring", 239, Rarity.COMMON, mage.cards.n.NaturalSpring.class)); + cards.add(new SetCardInfo("Nature's Revolt", 240, Rarity.RARE, mage.cards.n.NaturesRevolt.class)); + cards.add(new SetCardInfo("Needle Storm", 241, Rarity.UNCOMMON, mage.cards.n.NeedleStorm.class)); + cards.add(new SetCardInfo("Nurturing Licid", 242, Rarity.UNCOMMON, mage.cards.n.NurturingLicid.class)); + cards.add(new SetCardInfo("Opportunist", 194, Rarity.UNCOMMON, mage.cards.o.Opportunist.class)); + cards.add(new SetCardInfo("Oracle en-Vec", 31, Rarity.RARE, mage.cards.o.OracleEnVec.class)); + cards.add(new SetCardInfo("Orim's Prayer", 32, Rarity.UNCOMMON, mage.cards.o.OrimsPrayer.class)); + cards.add(new SetCardInfo("Orim, Samite Healer", 33, Rarity.RARE, mage.cards.o.OrimSamiteHealer.class)); + cards.add(new SetCardInfo("Overrun", 243, Rarity.UNCOMMON, mage.cards.o.Overrun.class)); + cards.add(new SetCardInfo("Pacifism", 34, Rarity.COMMON, mage.cards.p.Pacifism.class)); + cards.add(new SetCardInfo("Pallimud", 195, Rarity.RARE, mage.cards.p.Pallimud.class)); + cards.add(new SetCardInfo("Patchwork Gnomes", 299, Rarity.UNCOMMON, mage.cards.p.PatchworkGnomes.class)); + cards.add(new SetCardInfo("Pearl Medallion", 300, Rarity.RARE, mage.cards.p.PearlMedallion.class)); + cards.add(new SetCardInfo("Pegasus Refuge", 35, Rarity.RARE, mage.cards.p.PegasusRefuge.class)); + cards.add(new SetCardInfo("Perish", 147, Rarity.UNCOMMON, mage.cards.p.Perish.class)); + cards.add(new SetCardInfo("Phyrexian Grimoire", 301, Rarity.RARE, mage.cards.p.PhyrexianGrimoire.class)); + cards.add(new SetCardInfo("Phyrexian Hulk", 302, Rarity.UNCOMMON, mage.cards.p.PhyrexianHulk.class)); + cards.add(new SetCardInfo("Pincher Beetles", 244, Rarity.COMMON, mage.cards.p.PincherBeetles.class)); + cards.add(new SetCardInfo("Pine Barrens", 321, Rarity.RARE, mage.cards.p.PineBarrens.class)); + cards.add(new SetCardInfo("Pit Imp", 148, Rarity.COMMON, mage.cards.p.PitImp.class)); + cards.add(new SetCardInfo("Plains", 331, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 332, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 333, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 334, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Power Sink", 78, Rarity.COMMON, mage.cards.p.PowerSink.class)); + cards.add(new SetCardInfo("Precognition", 79, Rarity.RARE, mage.cards.p.Precognition.class)); + cards.add(new SetCardInfo("Propaganda", 80, Rarity.UNCOMMON, mage.cards.p.Propaganda.class)); + cards.add(new SetCardInfo("Puppet Strings", 304, Rarity.UNCOMMON, mage.cards.p.PuppetStrings.class)); + cards.add(new SetCardInfo("Quickening Licid", 36, Rarity.UNCOMMON, mage.cards.q.QuickeningLicid.class)); + cards.add(new SetCardInfo("Rain of Tears", 149, Rarity.UNCOMMON, mage.cards.r.RainOfTears.class)); + cards.add(new SetCardInfo("Rampant Growth", 245, Rarity.COMMON, mage.cards.r.RampantGrowth.class)); + cards.add(new SetCardInfo("Ranger en-Vec", 268, Rarity.UNCOMMON, mage.cards.r.RangerEnVec.class)); + cards.add(new SetCardInfo("Rathi Dragon", 196, Rarity.RARE, mage.cards.r.RathiDragon.class)); + cards.add(new SetCardInfo("Rats of Rath", 150, Rarity.COMMON, mage.cards.r.RatsOfRath.class)); + cards.add(new SetCardInfo("Reality Anchor", 246, Rarity.COMMON, mage.cards.r.RealityAnchor.class)); + cards.add(new SetCardInfo("Reanimate", 151, Rarity.UNCOMMON, mage.cards.r.Reanimate.class)); + cards.add(new SetCardInfo("Reap", 247, Rarity.UNCOMMON, mage.cards.r.Reap.class)); + cards.add(new SetCardInfo("Reckless Spite", 152, Rarity.UNCOMMON, mage.cards.r.RecklessSpite.class)); + cards.add(new SetCardInfo("Recycle", 248, Rarity.RARE, mage.cards.r.Recycle.class)); + cards.add(new SetCardInfo("Reflecting Pool", 322, Rarity.RARE, mage.cards.r.ReflectingPool.class)); + cards.add(new SetCardInfo("Renegade Warlord", 197, Rarity.UNCOMMON, mage.cards.r.RenegadeWarlord.class)); + cards.add(new SetCardInfo("Repentance", 37, Rarity.UNCOMMON, mage.cards.r.Repentance.class)); + cards.add(new SetCardInfo("Respite", 249, Rarity.COMMON, mage.cards.r.Respite.class)); + cards.add(new SetCardInfo("Rolling Thunder", 198, Rarity.COMMON, mage.cards.r.RollingThunder.class)); + cards.add(new SetCardInfo("Root Maze", 250, Rarity.RARE, mage.cards.r.RootMaze.class)); + cards.add(new SetCardInfo("Rootbreaker Wurm", 251, Rarity.COMMON, mage.cards.r.RootbreakerWurm.class)); + cards.add(new SetCardInfo("Rootwalla", 252, Rarity.COMMON, mage.cards.r.Rootwalla.class)); + cards.add(new SetCardInfo("Rootwater Depths", 323, Rarity.UNCOMMON, mage.cards.r.RootwaterDepths.class)); + cards.add(new SetCardInfo("Rootwater Diver", 81, Rarity.UNCOMMON, mage.cards.r.RootwaterDiver.class)); + cards.add(new SetCardInfo("Rootwater Hunter", 82, Rarity.COMMON, mage.cards.r.RootwaterHunter.class)); + cards.add(new SetCardInfo("Rootwater Matriarch", 83, Rarity.RARE, mage.cards.r.RootwaterMatriarch.class)); + cards.add(new SetCardInfo("Rootwater Shaman", 84, Rarity.RARE, mage.cards.r.RootwaterShaman.class)); + cards.add(new SetCardInfo("Ruby Medallion", 305, Rarity.RARE, mage.cards.r.RubyMedallion.class)); + cards.add(new SetCardInfo("Sacred Guide", 38, Rarity.RARE, mage.cards.s.SacredGuide.class)); + cards.add(new SetCardInfo("Sadistic Glee", 153, Rarity.COMMON, mage.cards.s.SadisticGlee.class)); + cards.add(new SetCardInfo("Safeguard", 39, Rarity.RARE, mage.cards.s.Safeguard.class)); + cards.add(new SetCardInfo("Salt Flats", 324, Rarity.RARE, mage.cards.s.SaltFlats.class)); + cards.add(new SetCardInfo("Sandstone Warrior", 199, Rarity.COMMON, mage.cards.s.SandstoneWarrior.class)); + cards.add(new SetCardInfo("Sapphire Medallion", 306, Rarity.RARE, mage.cards.s.SapphireMedallion.class)); + cards.add(new SetCardInfo("Sarcomancy", 154, Rarity.RARE, mage.cards.s.Sarcomancy.class)); + cards.add(new SetCardInfo("Scabland", 325, Rarity.RARE, mage.cards.s.Scabland.class)); + cards.add(new SetCardInfo("Scalding Tongs", 307, Rarity.RARE, mage.cards.s.ScaldingTongs.class)); + cards.add(new SetCardInfo("Scorched Earth", 200, Rarity.RARE, mage.cards.s.ScorchedEarth.class)); + cards.add(new SetCardInfo("Scragnoth", 253, Rarity.UNCOMMON, mage.cards.s.Scragnoth.class)); + cards.add(new SetCardInfo("Screeching Harpy", 155, Rarity.UNCOMMON, mage.cards.s.ScreechingHarpy.class)); + cards.add(new SetCardInfo("Scroll Rack", 308, Rarity.RARE, mage.cards.s.ScrollRack.class)); + cards.add(new SetCardInfo("Sea Monster", 85, Rarity.COMMON, mage.cards.s.SeaMonster.class)); + cards.add(new SetCardInfo("Searing Touch", 201, Rarity.UNCOMMON, mage.cards.s.SearingTouch.class)); + cards.add(new SetCardInfo("Seeker of Skybreak", 254, Rarity.COMMON, mage.cards.s.SeekerOfSkybreak.class)); + cards.add(new SetCardInfo("Segmented Wurm", 269, Rarity.UNCOMMON, mage.cards.s.SegmentedWurm.class)); + cards.add(new SetCardInfo("Selenia, Dark Angel", 270, Rarity.RARE, mage.cards.s.SeleniaDarkAngel.class)); + cards.add(new SetCardInfo("Serene Offering", 40, Rarity.UNCOMMON, mage.cards.s.SereneOffering.class)); + cards.add(new SetCardInfo("Servant of Volrath", 156, Rarity.COMMON, mage.cards.s.ServantOfVolrath.class)); + cards.add(new SetCardInfo("Shadow Rift", 86, Rarity.COMMON, mage.cards.s.ShadowRift.class)); + cards.add(new SetCardInfo("Shadowstorm", 202, Rarity.UNCOMMON, mage.cards.s.Shadowstorm.class)); + cards.add(new SetCardInfo("Shatter", 203, Rarity.COMMON, mage.cards.s.Shatter.class)); + cards.add(new SetCardInfo("Shimmering Wings", 87, Rarity.COMMON, mage.cards.s.ShimmeringWings.class)); + cards.add(new SetCardInfo("Shocker", 204, Rarity.RARE, mage.cards.s.Shocker.class)); + cards.add(new SetCardInfo("Sky Spirit", 271, Rarity.UNCOMMON, mage.cards.s.SkySpirit.class)); + cards.add(new SetCardInfo("Skyshroud Condor", 88, Rarity.UNCOMMON, mage.cards.s.SkyshroudCondor.class)); + cards.add(new SetCardInfo("Skyshroud Elf", 255, Rarity.COMMON, mage.cards.s.SkyshroudElf.class)); + cards.add(new SetCardInfo("Skyshroud Forest", 326, Rarity.RARE, mage.cards.s.SkyshroudForest.class)); + cards.add(new SetCardInfo("Skyshroud Ranger", 256, Rarity.COMMON, mage.cards.s.SkyshroudRanger.class)); + cards.add(new SetCardInfo("Skyshroud Troll", 257, Rarity.COMMON, mage.cards.s.SkyshroudTroll.class)); + cards.add(new SetCardInfo("Skyshroud Vampire", 157, Rarity.UNCOMMON, mage.cards.s.SkyshroudVampire.class)); + cards.add(new SetCardInfo("Soltari Crusader", 41, Rarity.UNCOMMON, mage.cards.s.SoltariCrusader.class)); + cards.add(new SetCardInfo("Soltari Emissary", 42, Rarity.RARE, mage.cards.s.SoltariEmissary.class)); + cards.add(new SetCardInfo("Soltari Foot Soldier", 43, Rarity.COMMON, mage.cards.s.SoltariFootSoldier.class)); + cards.add(new SetCardInfo("Soltari Guerrillas", 272, Rarity.RARE, mage.cards.s.SoltariGuerrillas.class)); + cards.add(new SetCardInfo("Soltari Lancer", 44, Rarity.COMMON, mage.cards.s.SoltariLancer.class)); + cards.add(new SetCardInfo("Soltari Monk", 45, Rarity.UNCOMMON, mage.cards.s.SoltariMonk.class)); + cards.add(new SetCardInfo("Soltari Priest", 46, Rarity.UNCOMMON, mage.cards.s.SoltariPriest.class)); + cards.add(new SetCardInfo("Soltari Trooper", 47, Rarity.COMMON, mage.cards.s.SoltariTrooper.class)); + cards.add(new SetCardInfo("Souldrinker", 158, Rarity.UNCOMMON, mage.cards.s.Souldrinker.class)); + cards.add(new SetCardInfo("Spell Blast", 89, Rarity.COMMON, mage.cards.s.SpellBlast.class)); + cards.add(new SetCardInfo("Spike Drone", 258, Rarity.COMMON, mage.cards.s.SpikeDrone.class)); + cards.add(new SetCardInfo("Spinal Graft", 159, Rarity.COMMON, mage.cards.s.SpinalGraft.class)); + cards.add(new SetCardInfo("Spirit Mirror", 48, Rarity.RARE, mage.cards.s.SpiritMirror.class)); + cards.add(new SetCardInfo("Spontaneous Combustion", 273, Rarity.UNCOMMON, mage.cards.s.SpontaneousCombustion.class)); + cards.add(new SetCardInfo("Squee's Toy", 309, Rarity.COMMON, mage.cards.s.SqueesToy.class)); + cards.add(new SetCardInfo("Stalking Stones", 327, Rarity.UNCOMMON, mage.cards.s.StalkingStones.class)); + cards.add(new SetCardInfo("Starke of Rath", 205, Rarity.RARE, mage.cards.s.StarkeOfRath.class)); + cards.add(new SetCardInfo("Static Orb", 310, Rarity.RARE, mage.cards.s.StaticOrb.class)); + cards.add(new SetCardInfo("Staunch Defenders", 49, Rarity.UNCOMMON, mage.cards.s.StaunchDefenders.class)); + cards.add(new SetCardInfo("Steal Enchantment", 90, Rarity.UNCOMMON, mage.cards.s.StealEnchantment.class)); + cards.add(new SetCardInfo("Stinging Licid", 91, Rarity.UNCOMMON, mage.cards.s.StingingLicid.class)); + cards.add(new SetCardInfo("Stone Rain", 206, Rarity.COMMON, mage.cards.s.StoneRain.class)); + cards.add(new SetCardInfo("Storm Front", 259, Rarity.UNCOMMON, mage.cards.s.StormFront.class)); + cards.add(new SetCardInfo("Stun", 207, Rarity.COMMON, mage.cards.s.Stun.class)); + cards.add(new SetCardInfo("Sudden Impact", 208, Rarity.UNCOMMON, mage.cards.s.SuddenImpact.class)); + cards.add(new SetCardInfo("Swamp", 339, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 340, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 341, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 342, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tahngarth's Rage", 209, Rarity.UNCOMMON, mage.cards.t.TahngarthsRage.class)); + cards.add(new SetCardInfo("Talon Sliver", 50, Rarity.COMMON, mage.cards.t.TalonSliver.class)); + cards.add(new SetCardInfo("Telethopter", 311, Rarity.UNCOMMON, mage.cards.t.Telethopter.class)); + cards.add(new SetCardInfo("Thalakos Dreamsower", 92, Rarity.UNCOMMON, mage.cards.t.ThalakosDreamsower.class)); + cards.add(new SetCardInfo("Thalakos Lowlands", 328, Rarity.UNCOMMON, mage.cards.t.ThalakosLowlands.class)); + cards.add(new SetCardInfo("Thalakos Mistfolk", 93, Rarity.COMMON, mage.cards.t.ThalakosMistfolk.class)); + cards.add(new SetCardInfo("Thalakos Seer", 94, Rarity.COMMON, mage.cards.t.ThalakosSeer.class)); + cards.add(new SetCardInfo("Thalakos Sentry", 95, Rarity.COMMON, mage.cards.t.ThalakosSentry.class)); + cards.add(new SetCardInfo("Thumbscrews", 312, Rarity.RARE, mage.cards.t.Thumbscrews.class)); + cards.add(new SetCardInfo("Time Ebb", 96, Rarity.COMMON, mage.cards.t.TimeEbb.class)); + cards.add(new SetCardInfo("Time Warp", 97, Rarity.RARE, mage.cards.t.TimeWarp.class)); + cards.add(new SetCardInfo("Tooth and Claw", 210, Rarity.RARE, mage.cards.t.ToothAndClaw.class)); + cards.add(new SetCardInfo("Torture Chamber", 313, Rarity.RARE, mage.cards.t.TortureChamber.class)); + cards.add(new SetCardInfo("Tradewind Rider", 98, Rarity.RARE, mage.cards.t.TradewindRider.class)); + cards.add(new SetCardInfo("Trained Armodon", 260, Rarity.COMMON, mage.cards.t.TrainedArmodon.class)); + cards.add(new SetCardInfo("Tranquility", 261, Rarity.COMMON, mage.cards.t.Tranquility.class)); + cards.add(new SetCardInfo("Trumpeting Armodon", 262, Rarity.UNCOMMON, mage.cards.t.TrumpetingArmodon.class)); + cards.add(new SetCardInfo("Twitch", 99, Rarity.COMMON, mage.cards.t.Twitch.class)); + cards.add(new SetCardInfo("Unstable Shapeshifter", 100, Rarity.RARE, mage.cards.u.UnstableShapeshifter.class)); + cards.add(new SetCardInfo("Vec Townships", 329, Rarity.UNCOMMON, mage.cards.v.VecTownships.class)); + cards.add(new SetCardInfo("Verdant Force", 263, Rarity.RARE, mage.cards.v.VerdantForce.class)); + cards.add(new SetCardInfo("Verdigris", 264, Rarity.UNCOMMON, mage.cards.v.Verdigris.class)); + cards.add(new SetCardInfo("Vhati il-Dal", 274, Rarity.RARE, mage.cards.v.VhatiIlDal.class)); + cards.add(new SetCardInfo("Volrath's Curse", 101, Rarity.COMMON, mage.cards.v.VolrathsCurse.class)); + cards.add(new SetCardInfo("Wall of Diffusion", 211, Rarity.COMMON, mage.cards.w.WallOfDiffusion.class)); + cards.add(new SetCardInfo("Warmth", 51, Rarity.UNCOMMON, mage.cards.w.Warmth.class)); + cards.add(new SetCardInfo("Wasteland", 330, Rarity.UNCOMMON, mage.cards.w.Wasteland.class)); + cards.add(new SetCardInfo("Watchdog", 314, Rarity.UNCOMMON, mage.cards.w.Watchdog.class)); + cards.add(new SetCardInfo("Whispers of the Muse", 103, Rarity.UNCOMMON, mage.cards.w.WhispersOfTheMuse.class)); + cards.add(new SetCardInfo("Wild Wurm", 212, Rarity.UNCOMMON, mage.cards.w.WildWurm.class)); + cards.add(new SetCardInfo("Wind Dancer", 104, Rarity.UNCOMMON, mage.cards.w.WindDancer.class)); + cards.add(new SetCardInfo("Wind Drake", 105, Rarity.COMMON, mage.cards.w.WindDrake.class)); + cards.add(new SetCardInfo("Winds of Rath", 52, Rarity.RARE, mage.cards.w.WindsOfRath.class)); + cards.add(new SetCardInfo("Winged Sliver", 106, Rarity.COMMON, mage.cards.w.WingedSliver.class)); + cards.add(new SetCardInfo("Winter's Grasp", 265, Rarity.UNCOMMON, mage.cards.w.WintersGrasp.class)); + cards.add(new SetCardInfo("Wood Sage", 275, Rarity.RARE, mage.cards.w.WoodSage.class)); + cards.add(new SetCardInfo("Worthy Cause", 53, Rarity.UNCOMMON, mage.cards.w.WorthyCause.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/UltimateBoxTopperPromos.java b/Mage.Sets/src/mage/sets/UltimateBoxTopperPromos.java index 26eb20d5717..545985a829e 100644 --- a/Mage.Sets/src/mage/sets/UltimateBoxTopperPromos.java +++ b/Mage.Sets/src/mage/sets/UltimateBoxTopperPromos.java @@ -36,9 +36,9 @@ public final class UltimateBoxTopperPromos extends ExpansionSet { cards.add(new SetCardInfo("Gaddock Teeg", "U21", Rarity.MYTHIC, mage.cards.g.GaddockTeeg.class)); cards.add(new SetCardInfo("Goryo's Vengeance", "U9", Rarity.MYTHIC, mage.cards.g.GoryosVengeance.class)); cards.add(new SetCardInfo("Karakas", "U36", Rarity.MYTHIC, mage.cards.k.Karakas.class)); - cards.add(new SetCardInfo("Karn Liberated", "U02", Rarity.MYTHIC, mage.cards.k.KarnLiberated.class)); + cards.add(new SetCardInfo("Karn Liberated", "U2", Rarity.MYTHIC, mage.cards.k.KarnLiberated.class)); cards.add(new SetCardInfo("Kitchen Finks", "U27", Rarity.MYTHIC, mage.cards.k.KitchenFinks.class)); - cards.add(new SetCardInfo("Kozilek, Butcher of Truth", "U03", Rarity.MYTHIC, mage.cards.k.KozilekButcherOfTruth.class)); + cards.add(new SetCardInfo("Kozilek, Butcher of Truth", "U3", Rarity.MYTHIC, mage.cards.k.KozilekButcherOfTruth.class)); cards.add(new SetCardInfo("Lavaclaw Reaches", "U37", Rarity.MYTHIC, mage.cards.l.LavaclawReaches.class)); cards.add(new SetCardInfo("Leovold, Emissary of Trest", "U22", Rarity.MYTHIC, mage.cards.l.LeovoldEmissaryOfTrest.class)); cards.add(new SetCardInfo("Life from the Loam", "U17", Rarity.MYTHIC, mage.cards.l.LifeFromTheLoam.class)); diff --git a/Mage.Stats/pom.xml b/Mage.Stats/pom.xml index 394db54aa1a..04ae3d81691 100644 --- a/Mage.Stats/pom.xml +++ b/Mage.Stats/pom.xml @@ -6,10 +6,9 @@ org.mage mage-root - 1.4.31 + 1.4.32 - org.mage mage-stats war XMage Stats Web Service diff --git a/Mage.Tests/pom.xml b/Mage.Tests/pom.xml index 1f5e3496407..210ea3d16e4 100644 --- a/Mage.Tests/pom.xml +++ b/Mage.Tests/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.31 + 1.4.32 mage-tests diff --git a/Mage.Tests/src/frozen/org/mage/test/clientside/base/MageBase.java b/Mage.Tests/src/frozen/org/mage/test/clientside/base/MageBase.java index ff7a6990ad9..057c83b1f30 100644 --- a/Mage.Tests/src/frozen/org/mage/test/clientside/base/MageBase.java +++ b/Mage.Tests/src/frozen/org/mage/test/clientside/base/MageBase.java @@ -1,13 +1,5 @@ package org.mage.test.clientside.base; -import java.rmi.NotBoundException; -import java.rmi.RemoteException; -import java.rmi.registry.LocateRegistry; -import java.rmi.registry.Registry; -import java.util.Date; -import java.util.UUID; -import java.util.logging.Level; -import java.util.logging.Logger; import mage.constants.MultiplayerAttackOption; import mage.constants.RangeOfInfluence; import mage.game.match.MatchOptions; @@ -20,7 +12,15 @@ import mage.interfaces.callback.ClientCallback; import mage.server.Main; import mage.sets.Sets; import mage.util.Logging; -import mage.view.*; + +import java.rmi.NotBoundException; +import java.rmi.RemoteException; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.util.Date; +import java.util.UUID; +import java.util.logging.Level; +import java.util.logging.Logger; /** * Base for starting Mage server. Controls interactions between MageAPI and Mage @@ -189,9 +189,9 @@ public class MageBase { } catch (MageException ex) { logger.log(Level.SEVERE, null, ex); } catch (RemoteException ex) { - logger.log(Level.SEVERE, "Unable to connect to server - ", ex); + logger.log(Level.SEVERE, "Unable connect to server - ", ex); } catch (NotBoundException ex) { - logger.log(Level.SEVERE, "Unable to connect to server - ", ex); + logger.log(Level.SEVERE, "Unable connect to server - ", ex); } } @@ -205,7 +205,7 @@ public class MageBase { } gameView = server.getGameView(gameId, sessionId, playerId); for (CardView card : gameView.getHand().values()) { - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { return true; } } @@ -224,7 +224,7 @@ public class MageBase { CardsView cards = gameView.getHand(); CardView cardToPlay = null; for (CardView card : cards.values()) { - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { cardToPlay = card; } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/LicidAbilityTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/LicidAbilityTest.java index 5d4eca287e1..62f5cef1457 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/LicidAbilityTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/LicidAbilityTest.java @@ -59,7 +59,7 @@ public class LicidAbilityTest extends CardTestPlayerBase { execute(); - assertActionCount(playerA, 0); + assertActionsCount(playerA, 0); assertAbility(playerA, "Pillarfield Ox", HasteAbility.getInstance(), false); assertAbility(playerA, "Enraging Licid", new LicidAbility(new ColoredManaCost(ColoredManaSymbol.R), new ColoredManaCost(ColoredManaSymbol.R)), true); assertType("Enraging Licid", CardType.ENCHANTMENT, false); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/equipped/EquipRestrictedTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/equipped/EquipRestrictedTest.java index e6013f7d61f..0f2193091e3 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/equipped/EquipRestrictedTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/equipped/EquipRestrictedTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.abilities.equipped; import mage.constants.PhaseStep; @@ -9,7 +8,6 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class EquipRestrictedTest extends CardTestPlayerBase { @@ -21,7 +19,7 @@ public class EquipRestrictedTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Leonin Scimitar"); activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerB, "{T}: Attach target Equipment you control to target creature you control.", "Leonin Scimitar"); - addTarget(playerB, "Silvercout Lion"); + addTarget(playerB, "Silvercoat Lion"); setStopAt(2, PhaseStep.BEGIN_COMBAT); execute(); @@ -43,7 +41,7 @@ public class EquipRestrictedTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Konda's Banner"); activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerB, "{T}: Attach target Equipment you control to target creature you control.", "Konda's Banner"); - addTarget(playerB, "Silvercout Lion"); + addTarget(playerB, "Silvercoat Lion"); setStopAt(2, PhaseStep.BEGIN_COMBAT); execute(); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CipherTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CipherTest.java index a1e43021628..2f109ed839b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CipherTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CipherTest.java @@ -1,68 +1,66 @@ - -package org.mage.test.cards.abilities.keywords; - -import mage.constants.PhaseStep; -import mage.constants.Zone; -import org.junit.Test; -import org.mage.test.serverside.base.CardTestPlayerBase; - -/** - * - * @author LevelX2 - */ -public class CipherTest extends CardTestPlayerBase { - - /** - * Produced a copy of the opponents Roil Elemental with Stolen Identity and - * used Cipher on that same token. The token's landfall ability then did - * trigger normally up to the point where a target creature could be - * selected. The selection was logged by XMage, but the effect simply did - * not work. The original Roil Elemental controlled by the other player - * worked as intended, though. - * - * Edit: Opponent was AI, if that helps. - */ - @Test - public void testStolenIdentity() { - addCard(Zone.BATTLEFIELD, playerA, "Island", 6); - addCard(Zone.HAND, playerA, "Mountain", 1); - - // Create a token that's a copy of target artifact or creature. - // Cipher (Then you may exile this spell card encoded on a creature you control. Whenever that creature deals combat damage to a player, its controller may cast a copy of the encoded card without paying its mana cost.) - addCard(Zone.HAND, playerA, "Stolen Identity"); // Sorcery {4}{U}{U} - - // Flying - // Landfall - Whenever a land enters the battlefield under your control, you may gain control of target creature for as long as you control Roil Elemental. - addCard(Zone.BATTLEFIELD, playerB, "Roil Elemental"); - addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox"); - addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); - - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Stolen Identity", "Roil Elemental"); - setChoice(playerA, "Yes"); - - playLand(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Mountain"); - addTarget(playerA, "Silvercoat Lion"); // Triggered ability of copied Roil Elemental to gain control - - attack(3, playerA, "Roil Elemental"); // Creature 3/2 - addTarget(playerA, "Pillarfield Ox"); - - setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); - execute(); - - assertLife(playerB, 17); - - assertExileCount(playerA, "Stolen Identity", 1); - - assertPermanentCount(playerA, "Mountain", 1); - - assertPermanentCount(playerB, "Pillarfield Ox", 1); - assertPermanentCount(playerA, "Pillarfield Ox", 1); // a copy from the cipered Stolen Identity caused by the Roil Elelemtal Attack - - assertPermanentCount(playerB, "Silvercoat Lion", 0); - assertPermanentCount(playerA, "Silvercoat Lion", 1); // Gain control from triggered ability of the copied Roil Elemental ????? TARGET ??? - - assertPermanentCount(playerB, "Roil Elemental", 1); - assertPermanentCount(playerA, "Roil Elemental", 1); - - } -} + +package org.mage.test.cards.abilities.keywords; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class CipherTest extends CardTestPlayerBase { + + /** + * Produced a copy of the opponents Roil Elemental with Stolen Identity and + * used Cipher on that same token. The token's landfall ability then did + * trigger normally up to the point where a target creature could be + * selected. The selection was logged by XMage, but the effect simply did + * not work. The original Roil Elemental controlled by the other player + * worked as intended, though. + * + * Edit: Opponent was AI, if that helps. + */ + @Test + public void testStolenIdentity() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 6); + addCard(Zone.HAND, playerA, "Mountain", 1); + + // Create a token that's a copy of target artifact or creature. + // Cipher (Then you may exile this spell card encoded on a creature you control. Whenever that creature deals combat damage to a player, its controller may cast a copy of the encoded card without paying its mana cost.) + addCard(Zone.HAND, playerA, "Stolen Identity"); // Sorcery {4}{U}{U} + + // Flying + // Landfall - Whenever a land enters the battlefield under your control, you may gain control of target creature for as long as you control Roil Elemental. + addCard(Zone.BATTLEFIELD, playerB, "Roil Elemental"); + addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox"); + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); + + // cast spell, create copy token, exile spell card and encode it to that token of Roil Elemental + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Stolen Identity", "Roil Elemental"); + setChoice(playerA, "Yes"); // Cipher activate + addTarget(playerA, "Roil Elemental"); // Cipher target for encode + checkPermanentCount("playerA must have Roil Elemental", 2, PhaseStep.PRECOMBAT_MAIN, playerA, "Roil Elemental", 1); + checkPermanentCount("playerB must have Roil Elemental", 2, PhaseStep.PRECOMBAT_MAIN, playerB, "Roil Elemental", 1); + checkExileCount("Stolen Identity must be in exile zone", 2, PhaseStep.PRECOMBAT_MAIN, playerA, "Stolen Identity", 1); + + // Roil Elemental must activated on new land + playLand(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Mountain"); + setChoice(playerA, "Yes"); // activate landfall to control opponent creature + addTarget(playerA, "Silvercoat Lion"); // Triggered ability of copied Roil Elemental to gain control + checkPermanentCount("must gain control of Lion", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Silvercoat Lion", 1); + checkPermanentCount("must lose control of Lion", 3, PhaseStep.POSTCOMBAT_MAIN, playerB, "Silvercoat Lion", 0); + + // on attack must activated ability to free cast + attack(5, playerA, "Roil Elemental"); + setChoice(playerA, "Yes"); // activate free cast of encoded card + checkPermanentCount("playerA must have 2 Roil Elemental", 5, PhaseStep.POSTCOMBAT_MAIN, playerA, "Roil Elemental", 2); + checkPermanentCount("playerB must have Roil Elemental", 5, PhaseStep.POSTCOMBAT_MAIN, playerB, "Roil Elemental", 1); + + setStopAt(5, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertLife(playerB, 17); // -3 by Roil + } +} \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/EchoTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/EchoTest.java index c75ebd9b231..07cf2e1902d 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/EchoTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/EchoTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.abilities.keywords; import mage.constants.PhaseStep; @@ -7,29 +6,27 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class EchoTest extends CardTestPlayerBase { - /* - * I flickered an Avalanche Riders with its Echo trigger on the stack with Restoration Angel. - * When the trigger resolved, my Riders was sacrificed, even though it should have been - * considered a new permanent. - */ + /* + * I flickered an Avalanche Riders with its Echo trigger on the stack with Restoration Angel. + * When the trigger resolved, my Riders was sacrificed, even though it should have been + * considered a new permanent. + */ @Test public void testEchoTriggerChecksIdentity() { - - addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); - addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); - // Avalanche Riders Creature - Human Nomad 2/2 + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4); + // Avalanche Riders Creature - Human Nomad 2/2 {3}{R} // Haste // Echo (At the beginning of your upkeep, if this came under your control since the beginning of your last upkeep, sacrifice it unless you pay its echo cost.) // When Avalanche Riders enters the battlefield, destroy target land. addCard(Zone.HAND, playerA, "Avalanche Riders"); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); // Restoration Angel {3}{W} // Flash // Flying @@ -37,12 +34,19 @@ public class EchoTest extends CardTestPlayerBase { // then return that card to the battlefield under your control. addCard(Zone.HAND, playerA, "Restoration Angel"); - addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1); + // cast Avalanche Riders and destroy forest + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Avalanche Riders"); + addTarget(playerA, "Forest"); + // Avalanche Riders go to echo, cast Restoration Angel to restore rider (do not apply echo with 4 mana) + activateManaAbility(3, PhaseStep.UPKEEP, playerA, "{T}: Add {W}"); + activateManaAbility(3, PhaseStep.UPKEEP, playerA, "{T}: Add {W}"); + activateManaAbility(3, PhaseStep.UPKEEP, playerA, "{T}: Add {W}"); + activateManaAbility(3, PhaseStep.UPKEEP, playerA, "{T}: Add {W}"); castSpell(3, PhaseStep.UPKEEP, playerA, "Restoration Angel", null, "Echo {3}{R} (At the beginning of your upkeep, if this came under your control since the beginning of your last upkeep, sacrifice it unless you pay its echo cost.)"); - addTarget(playerA, "Avalanche Riders"); + setChoice(playerA, "Yes"); // raider do restore setStopAt(3, PhaseStep.PRECOMBAT_MAIN); execute(); @@ -52,7 +56,9 @@ public class EchoTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Avalanche Riders", 1); assertPermanentCount(playerA, "Restoration Angel", 1); - assertPermanentCount(playerB, "Mountain", 0); + assertPermanentCount(playerB, "Forest", 0); + assertTappedCount("Plains", true, 4); + assertTappedCount("Mountain", true, 0); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/FlashbackTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/FlashbackTest.java index a1a900ba11e..23abdec9c32 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/FlashbackTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/FlashbackTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.abilities.keywords; import mage.abilities.keyword.TrampleAbility; @@ -9,7 +8,6 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class FlashbackTest extends CardTestPlayerBase { @@ -71,10 +69,9 @@ public class FlashbackTest extends CardTestPlayerBase { } /** - * * Test Granting Flashback to spells with X in manacost which have targeting * requirements depending on the choice of X - * + *

    * Specific instance: Snapcaster Mage granting Flashback to Repeal */ @Test @@ -84,7 +81,7 @@ public class FlashbackTest extends CardTestPlayerBase { addCard(Zone.GRAVEYARD, playerA, "Repeal", 1); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Snapcaster Mage"); - setChoice(playerA, "Repeal"); + addTarget(playerA, "Repeal"); activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Flashback"); setChoice(playerA, "X=2"); @@ -100,10 +97,9 @@ public class FlashbackTest extends CardTestPlayerBase { } /** - * * Test Granting Flashback to spells with X in mana cost, where X has no * influence on targeting requirements - * + *

    * Specific instance: Snapcaster Mage granting Flashback to Blaze */ @Test @@ -115,7 +111,7 @@ public class FlashbackTest extends CardTestPlayerBase { addCard(Zone.GRAVEYARD, playerA, "Blaze", 1); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Snapcaster Mage"); - setChoice(playerA, "Blaze"); + addTarget(playerA, "Blaze"); activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Flashback"); setChoice(playerA, "X=1"); @@ -133,7 +129,6 @@ public class FlashbackTest extends CardTestPlayerBase { /** * My opponent put Iona on the battlefield using Unburial Rites, but my game * log didn't show me the color he has chosen. - * */ @Test public void testUnburialRites() { @@ -238,7 +233,7 @@ public class FlashbackTest extends CardTestPlayerBase { * Ancestral Vision has no casting cost (this is different to a casting cost * of {0}). Snapcaster Mage, for example, is able to give it flashback * whilst it is in the graveyard. - * + *

    * However the controller should not be able to cast Ancestral Visions from * the graveyard for {0} mana. */ @@ -348,7 +343,7 @@ public class FlashbackTest extends CardTestPlayerBase { // When Snapcaster Mage enters the battlefield, target instant or sorcery card in your graveyard gains flashback until end of turn. The flashback cost is equal to its mana cost. castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Snapcaster Mage"); - setChoice(playerA, "Terminate"); + addTarget(playerA, "Terminate"); activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Flashback"); // Flashback Terminate addTarget(playerA, "Icefall Regent"); @@ -537,7 +532,7 @@ public class FlashbackTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Snapcaster Mage"); - setChoice(playerA, "Force of Will"); + addTarget(playerA, "Force of Will"); castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Lightning Bolt", "Snapcaster Mage"); activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Flashback", null, "Lightning Bolt"); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ManifestTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ManifestTest.java index 75bbdb228d9..55b83475619 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ManifestTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ManifestTest.java @@ -1,7 +1,7 @@ - package org.mage.test.cards.abilities.keywords; import mage.cards.Card; +import mage.constants.EmptyNames; import mage.constants.PhaseStep; import mage.constants.Zone; import mage.game.permanent.Permanent; @@ -10,7 +10,6 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class ManifestTest extends CardTestPlayerBase { @@ -34,15 +33,16 @@ public class ManifestTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); // no life gain assertLife(playerA, 20); assertLife(playerB, 20); // a facedown creature is on the battlefield - assertPermanentCount(playerA, "", 1); - assertPowerToughness(playerA, "", 2, 2); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); + assertPowerToughness(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2, 2); // not tapped - assertTapped("", false); + assertTapped(EmptyNames.FACE_DOWN_CREATURE.toString(), false); } /** @@ -66,13 +66,14 @@ public class ManifestTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); // no life gain assertLife(playerA, 20); assertLife(playerB, 20); // a facedown creature is on the battlefield - assertPermanentCount(playerA, "", 1); - assertPowerToughness(playerA, "", 2, 2); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); + assertPowerToughness(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2, 2); // PlayerB's Silvercoat Lion should not have get -1/-1/ assertPermanentCount(playerB, "Silvercoat Lion", 1); assertPowerToughness(playerB, "Silvercoat Lion", 2, 2); @@ -101,6 +102,7 @@ public class ManifestTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); // no life gain assertLife(playerA, 20); @@ -108,8 +110,8 @@ public class ManifestTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Reality Shift", 1); assertExileCount("Silvercoat Lion", 1); // a facedown creature is on the battlefield - assertPermanentCount(playerA, "", 1); - assertPowerToughness(playerA, "", 2, 2); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); + assertPowerToughness(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2, 2); // PlayerA's Pillarfield Ox should not have get -1/-1/ assertPermanentCount(playerB, "Pillarfield Ox", 1); assertPowerToughness(playerB, "Pillarfield Ox", 2, 4); @@ -137,6 +139,7 @@ public class ManifestTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); // no life gain assertLife(playerA, 20); @@ -144,8 +147,8 @@ public class ManifestTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Reality Shift", 1); assertExileCount("Silvercoat Lion", 1); // a facedown creature is on the battlefield - assertPermanentCount(playerA, "", 1); - assertPowerToughness(playerA, "", 2, 2); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); + assertPowerToughness(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2, 2); } @@ -173,6 +176,7 @@ public class ManifestTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); // no life gain assertLife(playerA, 20); @@ -180,8 +184,8 @@ public class ManifestTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Reality Shift", 1); assertExileCount("Silvercoat Lion", 1); // a facedown creature is on the battlefield - assertPermanentCount(playerA, "", 1); - assertPowerToughness(playerA, "", 2, 2); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); + assertPowerToughness(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2, 2); assertPowerToughness(playerA, "Foundry Street Denizen", 1, 1); } @@ -199,7 +203,6 @@ public class ManifestTest extends CardTestPlayerBase { // Strive — Silence the Believers costs more to cast for each target beyond the first. // Exile any number of target creatures and all Auras attached to them. addCard(Zone.HAND, playerB, "Silence the Believers"); - addTarget(playerB, ""); // Gore Swine {2}{R} // 4/1 addCard(Zone.LIBRARY, playerA, "Gore Swine"); @@ -210,10 +213,13 @@ public class ManifestTest extends CardTestPlayerBase { skipInitShuffling(); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Reality Shift", "Silvercoat Lion"); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Silence the Believers", ""); + showBattlefield("A battle", 1, PhaseStep.POSTCOMBAT_MAIN, playerA); + showBattlefield("B battle", 1, PhaseStep.POSTCOMBAT_MAIN, playerB); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Silence the Believers", EmptyNames.FACE_DOWN_CREATURE.toString()); - setStopAt(1, PhaseStep.BEGIN_COMBAT); + setStopAt(1, PhaseStep.END_TURN); execute(); + assertAllCommandsUsed(); // no life gain assertLife(playerA, 20); @@ -222,7 +228,7 @@ public class ManifestTest extends CardTestPlayerBase { assertExileCount("Silvercoat Lion", 1); assertExileCount("Gore Swine", 1); // no facedown creature is on the battlefield - assertPermanentCount(playerA, "", 0); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 0); for (Card card : currentGame.getExile().getAllCards(currentGame)) { if (card.getName().equals("Gore Swine")) { @@ -248,10 +254,11 @@ public class ManifestTest extends CardTestPlayerBase { skipInitShuffling(); activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerB, "{1}{B}, {T}, Sacrifice another creature"); - addTarget(playerB, "Silvercoat Lion"); + setChoice(playerB, "Silvercoat Lion"); setStopAt(2, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); // no life gain assertLife(playerA, 20); @@ -261,7 +268,7 @@ public class ManifestTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Silvercoat Lion", 1); // a facedown creature is on the battlefield - assertPermanentCount(playerB, "", 1); + assertPermanentCount(playerB, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); } @@ -284,12 +291,13 @@ public class ManifestTest extends CardTestPlayerBase { skipInitShuffling(); activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerB, "{1}{B}, {T}, Sacrifice another creature"); - addTarget(playerB, "Silvercoat Lion"); + setChoice(playerB, "Silvercoat Lion"); activateAbility(2, PhaseStep.POSTCOMBAT_MAIN, playerB, "{5}{G}: Turn"); setStopAt(2, PhaseStep.END_TURN); execute(); + assertAllCommandsUsed(); // no life gain assertLife(playerA, 20); @@ -297,7 +305,7 @@ public class ManifestTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Silvercoat Lion", 1); - assertPermanentCount(playerB, "", 0); + assertPermanentCount(playerB, EmptyNames.FACE_DOWN_CREATURE.toString(), 0); assertPermanentCount(playerB, "Aerie Bowmasters", 1); assertPowerToughness(playerB, "Aerie Bowmasters", 4, 5); // 3/4 and the +1/+1 counter from Megamorph Permanent aerie = getPermanent("Aerie Bowmasters", playerB); @@ -308,7 +316,6 @@ public class ManifestTest extends CardTestPlayerBase { /** * When a Forest came manifested into play my Courser of Kruphix gained me a * life. - * */ @Test public void testManifestForest() { @@ -328,10 +335,11 @@ public class ManifestTest extends CardTestPlayerBase { skipInitShuffling(); activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerB, "{1}{B}, {T}, Sacrifice another creature"); - addTarget(playerB, "Silvercoat Lion"); + setChoice(playerB, "Silvercoat Lion"); setStopAt(2, PhaseStep.END_TURN); execute(); + assertAllCommandsUsed(); // no life gain assertLife(playerA, 20); @@ -339,13 +347,12 @@ public class ManifestTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Silvercoat Lion", 1); - assertPermanentCount(playerB, "", 1); + assertPermanentCount(playerB, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); } /** * Whisperwood Elemental - Its sacrifice ability doesn't work.. - * */ @Test public void testWhisperwoodElemental() { @@ -365,6 +372,7 @@ public class ManifestTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.END_TURN); execute(); + assertAllCommandsUsed(); // no life gain assertLife(playerA, 20); @@ -374,14 +382,13 @@ public class ManifestTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Whisperwood Elemental", 1); assertGraveyardCount(playerB, "Silvercoat Lion", 2); - assertPermanentCount(playerB, "", 2); + assertPermanentCount(playerB, EmptyNames.FACE_DOWN_CREATURE.toString(), 2); } /** * I sacrificed a manifested face-down Smothering Abomination to Nantuko * Husk and it made me draw a card. - * */ @Test public void testDiesTriggeredAbilitiesOfManifestedCreatures() { @@ -409,10 +416,11 @@ public class ManifestTest extends CardTestPlayerBase { setChoice(playerB, "Silvercoat Lion"); activateAbility(2, PhaseStep.POSTCOMBAT_MAIN, playerB, "Sacrifice a creature"); - setChoice(playerB, ""); + setChoice(playerB, EmptyNames.FACE_DOWN_CREATURE.toString()); setStopAt(2, PhaseStep.END_TURN); execute(); + assertAllCommandsUsed(); // no life gain assertLife(playerA, 20); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MorphTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MorphTest.java index c3b430166c8..50bf73e391a 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MorphTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MorphTest.java @@ -1,11 +1,7 @@ - package org.mage.test.cards.abilities.keywords; import mage.cards.Card; -import mage.constants.CardType; -import mage.constants.PhaseStep; -import mage.constants.SubType; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.Filter; import mage.game.permanent.Permanent; import org.junit.Assert; @@ -13,7 +9,6 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author levelX2 */ public class MorphTest extends CardTestPlayerBase { @@ -21,7 +16,6 @@ public class MorphTest extends CardTestPlayerBase { /** * Tests if a creature with Morph is cast normal, it behaves as normal * creature - * */ @Test public void testCastMorphCreatureWithoutMorph() { @@ -60,8 +54,8 @@ public class MorphTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - assertPermanentCount(playerA, "", 1); - assertPowerToughness(playerA, "", 2, 2); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); + assertPowerToughness(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2, 2); } @@ -76,7 +70,7 @@ public class MorphTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pine Walker"); setChoice(playerA, "Yes"); // cast it face down as 2/2 creature - attack(3, playerA, ""); + attack(3, playerA, EmptyNames.FACE_DOWN_CREATURE.toString()); activateAbility(3, PhaseStep.POSTCOMBAT_MAIN, playerA, "{4}{G}: Turn this face-down permanent face up."); setStopAt(3, PhaseStep.END_TURN); @@ -84,7 +78,7 @@ public class MorphTest extends CardTestPlayerBase { assertLife(playerB, 18); - assertPermanentCount(playerA, "", 0); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 0); assertPermanentCount(playerA, "Pine Walker", 1); assertPowerToughness(playerA, "Pine Walker", 5, 5); assertTapped("Pine Walker", false); @@ -94,7 +88,6 @@ public class MorphTest extends CardTestPlayerBase { /** * Test that the triggered "turned face up" ability of Pine Walker does not * trigger as long as Pine Walker is not turned face up. - * */ @Test public void testDoesNotTriggerFaceDown() { @@ -110,8 +103,8 @@ public class MorphTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Icefeather Aven", NO_TARGET, "Pine Walker", StackClause.WHILE_NOT_ON_STACK); setChoice(playerA, "Yes"); // cast it face down as 2/2 creature - attack(3, playerA, ""); - attack(3, playerA, ""); + attack(3, playerA, EmptyNames.FACE_DOWN_CREATURE.toString()); + attack(3, playerA, EmptyNames.FACE_DOWN_CREATURE.toString()); activateAbility(3, PhaseStep.DECLARE_BLOCKERS, playerA, "{1}{G}{U}: Turn this face-down permanent face up."); setChoice(playerA, "No"); // Don't use return permanent to hand effect @@ -123,7 +116,7 @@ public class MorphTest extends CardTestPlayerBase { assertHandCount(playerA, "Pine Walker", 0); assertHandCount(playerA, "Icefeather Aven", 0); - assertPermanentCount(playerA, "", 1); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); assertPermanentCount(playerA, "Icefeather Aven", 1); assertTapped("Icefeather Aven", true); @@ -132,7 +125,6 @@ public class MorphTest extends CardTestPlayerBase { /** * Test that Morph creature do not trigger abilities with their face up * attributes - * */ @Test public void testMorphedRemovesAttributesCreature() { @@ -156,14 +148,13 @@ public class MorphTest extends CardTestPlayerBase { assertLife(playerB, 20); // and not 21 - assertPermanentCount(playerA, "", 1); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); assertPermanentCount(playerB, "Soldier of the Pantheon", 1); } /** * Test to copy a morphed 2/2 creature - * */ @Test public void testCopyAMorphedCreature() { @@ -182,22 +173,21 @@ public class MorphTest extends CardTestPlayerBase { castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Clever Impersonator"); setChoice(playerB, "Yes"); // use to copy a nonland permanent - addTarget(playerB, ""); // Morphed creature + addTarget(playerB, EmptyNames.FACE_DOWN_CREATURE.toString()); // Morphed creature setStopAt(2, PhaseStep.BEGIN_COMBAT); execute(); assertLife(playerB, 20); - assertPermanentCount(playerA, "", 1); - assertPowerToughness(playerA, "", 2, 2); - assertPermanentCount(playerB, "", 1); - assertPowerToughness(playerB, "", 2, 2); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); + assertPowerToughness(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2, 2); + assertPermanentCount(playerB, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); + assertPowerToughness(playerB, EmptyNames.FACE_DOWN_CREATURE.toString(), 2, 2); } /** - * * */ @Test @@ -229,7 +219,7 @@ public class MorphTest extends CardTestPlayerBase { assertHandCount(playerA, "Pine Walker", 0); assertHandCount(playerB, "Doomwake Giant", 0); - assertPermanentCount(playerA, "", 0); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 0); assertPermanentCount(playerB, "Doomwake Giant", 1); assertPermanentCount(playerA, "Pine Walker", 1); assertPowerToughness(playerA, "Pine Walker", 4, 4); @@ -241,7 +231,6 @@ public class MorphTest extends CardTestPlayerBase { * morph goes down to 1/1 correctly. If you unmorph the 2/2 and is also a * 2/2 after umorphing, the morph will be erroneously reduced to 0/0 and * die. - * */ @Test public void testDoomwakeGiantEffect() { @@ -271,7 +260,7 @@ public class MorphTest extends CardTestPlayerBase { assertHandCount(playerA, "Ponyback Brigade", 0); assertHandCount(playerB, "Doomwake Giant", 0); - assertPermanentCount(playerA, "", 0); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 0); assertPermanentCount(playerA, "Goblin", 3); assertPowerToughness(playerA, "Goblin", 1, 1, Filter.ComparisonScope.Any); assertPermanentCount(playerB, "Doomwake Giant", 1); @@ -283,7 +272,6 @@ public class MorphTest extends CardTestPlayerBase { /** * Clone a Morph creature that was cast face down and meanwhile was turned * face up - * */ @Test public void testCloneFaceUpMorphEffect() { @@ -317,7 +305,6 @@ public class MorphTest extends CardTestPlayerBase { /** * Check that you can't counter a creature cast for it morph costs with * Disdainful Stroke if it's normal cmc > 3 - * */ @Test public void testCounterCastWithMorphEffect() { @@ -346,7 +333,7 @@ public class MorphTest extends CardTestPlayerBase { assertHandCount(playerA, "Sagu Mauler", 0); assertHandCount(playerB, "Disdainful Stroke", 1); // can't be cast - assertPermanentCount(playerA, "", 1); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); } @@ -355,7 +342,6 @@ public class MorphTest extends CardTestPlayerBase { * the same name" does only effect one face down creature, also if multiple * on the battlefield. Because they have no name, they don't have the same * name. - * */ @Test public void testEchoingDecaySameNameEffect() { @@ -376,18 +362,23 @@ public class MorphTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sagu Mauler", NO_TARGET, "Sagu Mauler", StackClause.WHILE_NOT_ON_STACK); setChoice(playerA, "Yes"); // cast it face down as 2/2 creature - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Echoing Decay", ""); + showBattlefield("A battle", 1, PhaseStep.POSTCOMBAT_MAIN, playerA); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Echoing Decay", EmptyNames.FACE_DOWN_CREATURE.toString()); - setStopAt(1, PhaseStep.BEGIN_COMBAT); + showBattlefield("A battle after", 1, PhaseStep.END_TURN, playerA); + setStopAt(1, PhaseStep.END_TURN); execute(); + assertAllCommandsUsed(); assertLife(playerB, 20); + assertHandCount(playerB, "Echoing Decay", 0); + assertGraveyardCount(playerB, "Echoing Decay", 1); + assertHandCount(playerA, "Sagu Mauler", 0); assertHandCount(playerB, "Echoing Decay", 0); - - assertPermanentCount(playerA, "", 1); - + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); + assertGraveyardCount(playerA, "Sagu Mauler", 1); } /** @@ -472,7 +463,7 @@ public class MorphTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ashcloud Phoenix"); setChoice(playerA, "Yes"); // cast it face down as 2/2 creature - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", ""); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", EmptyNames.FACE_DOWN_CREATURE.toString()); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); @@ -513,7 +504,7 @@ public class MorphTest extends CardTestPlayerBase { setChoice(playerA, "Yes"); // cast it face down as 2/2 creature attack(2, playerB, "Mirri, Cat Warrior"); - block(2, playerA, "", "Mirri, Cat Warrior"); + block(2, playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), "Mirri, Cat Warrior"); setStopAt(2, PhaseStep.POSTCOMBAT_MAIN); execute(); @@ -549,20 +540,27 @@ public class MorphTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akroma, Angel of Fury"); setChoice(playerA, "Yes"); // cast it face down as 2/2 creature - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Supplant Form", ""); + showBattlefield("A battle", 1, PhaseStep.POSTCOMBAT_MAIN, playerA); + showBattlefield("B battle", 1, PhaseStep.POSTCOMBAT_MAIN, playerB); - setStopAt(1, PhaseStep.BEGIN_COMBAT); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Supplant Form"); + addTarget(playerB, EmptyNames.FACE_DOWN_CREATURE.toString()); + + showBattlefield("A battle end", 1, PhaseStep.END_TURN, playerA); + showBattlefield("B battle end", 1, PhaseStep.END_TURN, playerB); + setStopAt(1, PhaseStep.END_TURN); execute(); assertLife(playerB, 20); - assertGraveyardCount(playerB, "Supplant Form", 1); assertHandCount(playerA, "Akroma, Angel of Fury", 1); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 0); + assertPermanentCount(playerA, "Akroma, Angel of Fury", 0); + assertGraveyardCount(playerB, "Supplant Form", 1); assertPermanentCount(playerB, "Akroma, Angel of Fury", 0); - assertPermanentCount(playerB, "", 1); - assertPowerToughness(playerB, "", 2, 2); - + assertPermanentCount(playerB, EmptyNames.FACE_DOWN_TOKEN.toString(), 1); + assertPowerToughness(playerB, EmptyNames.FACE_DOWN_TOKEN.toString(), 2, 2); } /** @@ -588,7 +586,7 @@ public class MorphTest extends CardTestPlayerBase { assertLife(playerA, 20); - assertPermanentCount(playerA, "", 1); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); } @@ -613,7 +611,7 @@ public class MorphTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pine Walker"); setChoice(playerA, "Yes"); // cast it face down as 2/2 creature - attack(3, playerA, ""); + attack(3, playerA, EmptyNames.FACE_DOWN_CREATURE.toString()); activateAbility(3, PhaseStep.POSTCOMBAT_MAIN, playerA, "{4}{G}: Turn this face-down permanent face up."); setStopAt(3, PhaseStep.END_TURN); @@ -621,7 +619,7 @@ public class MorphTest extends CardTestPlayerBase { assertLife(playerB, 18); - assertPermanentCount(playerA, "", 0); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 0); assertPermanentCount(playerA, "Pine Walker", 1); assertPowerToughness(playerA, "Pine Walker", 5, 5); assertTapped("Pine Walker", false); @@ -631,7 +629,7 @@ public class MorphTest extends CardTestPlayerBase { * Reflector Mage bouncing a creature that can be played as a morph should * not prevent the card from being replayed as a morph. Morph creatures are * nameless. - * + *

    * Reported bug: Face-up morph creatures that are bounced by Reflector Mage * should be able to be replayed as morphs without the "until the next turn" * restriction." @@ -666,18 +664,18 @@ public class MorphTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Reflector Mage", 1); assertPermanentCount(playerB, "Rattleclaw Mystic", 0); assertHandCount(playerB, "Rattleclaw Mystic", 0); // should have been replayed - assertPermanentCount(playerB, "", 1); // Rattleclaw played as a morph + assertPermanentCount(playerB, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); // Rattleclaw played as a morph } /** * Reflector Mage bouncing a creature that can be played as a morph should * not prevent the card from being replayed as a morph. Morph creatures are * nameless. - * + *

    * Reported bug: Face-up morph creatures that are bounced by Reflector Mage * should be able to be replayed as morphs without the "until the next turn" * restriction." - * + *

    * Testing bouncing a face-down creature played next turn face-up. */ @Test @@ -701,7 +699,6 @@ public class MorphTest extends CardTestPlayerBase { setChoice(playerA, "Yes"); // cast it face down as 2/2 creature castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Reflector Mage"); - addTarget(playerB, ""); castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Rattleclaw Mystic"); setChoice(playerA, "No"); // cast it face down as 2/2 creature @@ -790,7 +787,7 @@ public class MorphTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Fatal Push", 1); assertGraveyardCount(playerA, "Pine Walker", 1); - assertPermanentCount(playerA, "", 0); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 0); } @@ -824,7 +821,7 @@ public class MorphTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - assertPermanentCount(playerA, "", 1); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); assertHandCount(playerA, 0); assertTappedCount("Island", true, 3); @@ -859,7 +856,7 @@ public class MorphTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Quicksilver Dragon"); setChoice(playerA, "Yes"); // cast it face down as 2/2 creature - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", ""); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", EmptyNames.FACE_DOWN_CREATURE.toString()); setStopAt(2, PhaseStep.UPKEEP); execute(); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SpliceOnArcaneTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SpliceOnArcaneTest.java index a5abc4c3f3a..48f77593810 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SpliceOnArcaneTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SpliceOnArcaneTest.java @@ -1,15 +1,14 @@ - package org.mage.test.cards.abilities.keywords; import mage.abilities.keyword.HasteAbility; import mage.constants.PhaseStep; import mage.constants.Zone; import org.junit.Assert; +import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class SpliceOnArcaneTest extends CardTestPlayerBase { @@ -17,7 +16,6 @@ public class SpliceOnArcaneTest extends CardTestPlayerBase { /** * Test that it works to cast Through the Breach by slicing it on an arcane * spell - * */ @Test public void testSpliceThroughTheBreach() { @@ -32,7 +30,10 @@ public class SpliceOnArcaneTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Silvercoat Lion", 1); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lava Spike", playerB); - setChoice(playerA, "Silvercoat Lion"); + // activate splice: yes -> card with splice ability -> new target for spliced ability + setChoice(playerA, "Yes"); + addTarget(playerA, "Through the Breach"); + addTarget(playerA, "Silvercoat Lion"); // target for spliced ability: put from hand to battlefield setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); @@ -60,8 +61,12 @@ public class SpliceOnArcaneTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1); + // cast arcane Lava Spike castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lava Spike", playerB); - addTarget(playerA, "Silvercoat Lion"); + // activate splice: yes -> card with splice ability -> new target for spliced ability + setChoice(playerA, "Yes"); + addTarget(playerA, "Torrent of Stone"); + addTarget(playerA, "Silvercoat Lion"); // target for spliced ability: 4 damage setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); @@ -97,8 +102,10 @@ public class SpliceOnArcaneTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Silvercoat Lion", 1); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Nourishing Shoal"); + // activate splice: yes -> card with splice ability -> new target for spliced ability setChoice(playerA, "Yes"); - setChoice(playerA, "Silvercoat Lion"); + addTarget(playerA, "Through the Breach"); + addTarget(playerA, "Silvercoat Lion"); // target for spliced ability: put from hand to battlefield setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); @@ -117,12 +124,12 @@ public class SpliceOnArcaneTest extends CardTestPlayerBase { /** * Cards involved: Nourishing Shoal, Goryo's Vengeance, Griselbrand, * Terminate - * + *

    * I actually noticed this bug on the 1.4.3 client, but I didn't see it in * the change log for 1.4.4, so I assume it is still unknown. Also, it is a * bit of a rules corner case and I haven't seen anyone else report it, so * the players of this deck may actually not realize it's incorrect. - * + *

    * The scenario was that I cast a Nourishing Shoal with a Goryo's Vengeance * spliced to it targeting Griselbrand in my graveyard and exiling * Worldspine Wurm. My opponent responded with a Snapcaster Mage, so to @@ -132,7 +139,7 @@ public class SpliceOnArcaneTest extends CardTestPlayerBase { * resolve, it should have been countered due to no legal target. However, * it caused me to gain 11 life. It did not resurrect Griselbrand * (correctly), but it should have done nothing at all. - * + *

    * I include the info about the Terminate because thinking through, it could * be pertinent. I would guess what is going on here is one of two things. * Either the client doesn't recognize the Shoal with a spliced Vengeance as @@ -145,7 +152,10 @@ public class SpliceOnArcaneTest extends CardTestPlayerBase { * the error against a bot and update this report. */ @Test + @Ignore public void testCounteredBecauseOfNoLegalTarget() { + // TODO: rewrite test, it's wrong and misleading-- user report about Griselbrand was destroyed by Terminate after splice anounce, but tests don't use it at all (Griselbrand legal target all the time) + addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); addCard(Zone.BATTLEFIELD, playerA, "Swamp", 8); // You may exile a green card with converted mana cost X from your hand rather than pay Nourishing Shoal's mana cost. @@ -174,5 +184,4 @@ public class SpliceOnArcaneTest extends CardTestPlayerBase { assertLife(playerB, 20); } - } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/OblivionSowerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/OblivionSowerTest.java index 3dcb48df920..19680d13807 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/OblivionSowerTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/OblivionSowerTest.java @@ -30,6 +30,7 @@ public class OblivionSowerTest extends CardTestPlayerBase { skipInitShuffling(); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Oblivion Sower"); + addTarget(playerA, playerB); addTarget(playerA, "Canopy Vista^Canopy Vista^Canopy Vista"); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/conditional/TragicSlipTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/conditional/TragicSlipTest.java index 0bbcfee3ab3..8d272382fbb 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/conditional/TragicSlipTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/conditional/TragicSlipTest.java @@ -1,4 +1,4 @@ - package org.mage.test.cards.conditional; +package org.mage.test.cards.conditional; import mage.constants.PhaseStep; import mage.constants.Zone; @@ -6,12 +6,8 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ - - - public class TragicSlipTest extends CardTestPlayerBase { @Test @@ -108,7 +104,7 @@ public class TragicSlipTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Tragic Slip", "Silvercoat Lion"); castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Snapcaster Mage"); - setChoice(playerA, "Tragic Slip"); + addTarget(playerA, "Tragic Slip"); castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", "Snapcaster Mage"); @@ -122,7 +118,7 @@ public class TragicSlipTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Snapcaster Mage", 0); assertExileCount("Tragic Slip", 1); assertPermanentCount(playerB, "Silvercoat Lion", 1); - assertPowerToughness(playerB, "Silvercoat Lion", 1,1); + assertPowerToughness(playerB, "Silvercoat Lion", 1, 1); assertGraveyardCount(playerB, "Tarmogoyf", 1); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/MasterThiefTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/MasterThiefTest.java index ba821b9a540..8bfe2420bd4 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/MasterThiefTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/MasterThiefTest.java @@ -1,13 +1,12 @@ - package org.mage.test.cards.continuous; +import mage.abilities.keyword.VigilanceAbility; import mage.constants.PhaseStep; import mage.constants.Zone; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author JayDi85 */ public class MasterThiefTest extends CardTestPlayerBase { @@ -42,7 +41,7 @@ public class MasterThiefTest extends CardTestPlayerBase { // cast and get control of shield castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Master Thief"); - addTarget(playerB, "Accorder's Shield"); + addTarget(playerA, "Accorder's Shield"); // sacrifice Master Thief -- must lost control activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Sacrifice a creature"); @@ -72,11 +71,13 @@ public class MasterThiefTest extends CardTestPlayerBase { // cast and get control of shield castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Master Thief"); - addTarget(playerB, "Accorder's Shield"); + addTarget(playerA, "Accorder's Shield"); + checkPermanentCount("must control shield", 1, PhaseStep.BEGIN_COMBAT, playerA, "Accorder's Shield", 1); // attach and boost activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Equip {3}"); addTarget(playerA, "Bearer of the Heavens"); + checkAbility("bear must have boost", 1, PhaseStep.END_TURN, playerA, "Bearer of the Heavens", VigilanceAbility.class, true); // sacrifice Master Thief -- must lost control, but attached and boosted activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Sacrifice a creature"); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/control/ExileAndReturnUnderYourControl.java b/Mage.Tests/src/test/java/org/mage/test/cards/control/ExileAndReturnUnderYourControl.java index 59009ff581a..8d5cbf28f57 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/control/ExileAndReturnUnderYourControl.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/control/ExileAndReturnUnderYourControl.java @@ -1,5 +1,6 @@ package org.mage.test.cards.control; +import mage.constants.EmptyNames; import mage.constants.PhaseStep; import mage.constants.Zone; import org.junit.Assert; @@ -9,7 +10,7 @@ import org.mage.test.serverside.base.CardTestPlayerBase; /** * Tests the effect: - Exile target creature you control, then return that card * to the battlefield under your control - * + *

    * This effect grants you permanent control over the returned creature. So you * mail steal opponent's creature with "Act of Treason" and then use this effect * for permanent control effect. @@ -103,8 +104,8 @@ public class ExileAndReturnUnderYourControl extends CardTestPlayerBase { assertExileCount("Secret Plans", 0); assertPermanentCount(playerA, "Secret Plans", 1); - assertPermanentCount(playerA, "", 1); - assertPowerToughness(playerA, "", 2, 3); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); + assertPowerToughness(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2, 3); } /** diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopySpellTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopySpellTest.java index 2ec1c261ed3..9c39f31353c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopySpellTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopySpellTest.java @@ -1,14 +1,13 @@ - package org.mage.test.cards.copy; import mage.abilities.keyword.FlyingAbility; import mage.constants.PhaseStep; import mage.constants.Zone; import org.junit.Test; +import org.mage.test.player.TestPlayer; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class CopySpellTest extends CardTestPlayerBase { @@ -17,23 +16,38 @@ public class CopySpellTest extends CardTestPlayerBase { public void copyChainOfVapor() { // Return target nonland permanent to its owner's hand. Then that permanent's controller may sacrifice a land. If the player does, he or she may copy this spell and may choose a new target for that copy. addCard(Zone.HAND, playerA, "Chain of Vapor", 1); - addCard(Zone.BATTLEFIELD, playerA, "Island", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 10); - addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1); + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 10); - addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox", 1); - addCard(Zone.BATTLEFIELD, playerB, "Island", 1); + addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox", 10); + addCard(Zone.BATTLEFIELD, playerB, "Island", 10); + // start chain from A - return pillar to hand castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Chain of Vapor", "Pillarfield Ox"); - setChoice(playerB, "Yes"); - addTarget(playerB, "Silvercoat Lion"); + // chain 1 - B can return + addTarget(playerB, "Island"); // select a land to sacrifice + setChoice(playerB, "Yes"); // want to copy spell + setChoice(playerB, "Yes"); // want to change target + addTarget(playerB, "Silvercoat Lion"); // new target after copy + // chain 2 - A can return + addTarget(playerA, "Island"); // select a land to sacrifice + setChoice(playerA, "Yes"); // want to copy spell + setChoice(playerA, "Yes"); // want to change target + addTarget(playerA, "Pillarfield Ox"); // new target after copy + // stop the chain by B + addTarget(playerB, TestPlayer.TARGET_SKIP); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); - assertGraveyardCount(playerB, "Island", 1); - assertHandCount(playerB, "Pillarfield Ox", 1); assertHandCount(playerA, "Silvercoat Lion", 1); + assertHandCount(playerB, "Pillarfield Ox", 2); + assertPermanentCount(playerA, "Silvercoat Lion", 10 - 1); + assertPermanentCount(playerB, "Pillarfield Ox", 10 - 2); + assertGraveyardCount(playerA, "Island", 1); + assertGraveyardCount(playerB, "Island", 1); } @Test @@ -135,7 +149,7 @@ public class CopySpellTest extends CardTestPlayerBase { * before it is cast and therefore before Zada's ability triggers, e.g. * Desperate Ritual spliced onto Into the Fray should generate 3 red mana * for every creature i control. - * + *

    * 702.46a Splice is a static ability that functions while a card is in your * hand. “Splice onto [subtype] [cost]” means “You may reveal this card from * your hand as you cast a [subtype] spell. If you do, copy this card's text @@ -184,7 +198,7 @@ public class CopySpellTest extends CardTestPlayerBase { * {4}{U} Enchantment (Enchant Player) Whenever enchanted player casts an * instant or sorcery spell, each other player may copy that spell and may * choose new targets for the copy he or she controls. - * + *

    * Reported bug: "A player with Curse of Echoes attached to them played * Bribery and the player who controlled the curse had control of all 3 * copies. This seems to be the case for all spells." diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CryptoplasmTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CryptoplasmTest.java index ec85a76adaa..34c014aed2b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CryptoplasmTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CryptoplasmTest.java @@ -52,15 +52,24 @@ public class CryptoplasmTest extends CardTestPlayerBase { // At the beginning of your upkeep, you may have Cryptoplasm become a copy of another target creature. If you do, Cryptoplasm gains this ability. addCard(Zone.BATTLEFIELD, playerB, "Cryptoplasm", 1); // {1}{U}{U} + // turn 2 - prepare (crypto to paladin, footsteps to crypto) + // crypto: copy as paladin on upkeep + setChoice(playerB, "Yes"); + addTarget(playerB, "Sigiled Paladin"); + // footsteps: enchant copy of paladin (crypto) castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Followed Footsteps"); addTarget(playerB, "Sigiled Paladin[only copy]"); + // turn 4 - ignore crypto ask for new copy + setChoice(playerB, "No"); + setStopAt(4, PhaseStep.END_TURN); execute(); assertPermanentCount(playerB, "Followed Footsteps", 1); - assertPermanentCount(playerB, "Cryptoplasm", 0); - assertPermanentCount(playerB, "Sigiled Paladin", 2); + assertPermanentCount(playerB, "Cryptoplasm", 0); // it's a copy + assertPermanentCount(playerB, "Sigiled Paladin", 2); // crypto as copy + footstep token as copy + assertPermanentCount(playerA, "Sigiled Paladin", 1); // original } /** diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/IsochronScepterTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/IsochronScepterTest.java index c49391815cb..810e5ea6280 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/IsochronScepterTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/IsochronScepterTest.java @@ -44,10 +44,12 @@ public class IsochronScepterTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Lightning Bolt"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Isochron Scepter"); - addTarget(playerA, "Lightning Bolt"); + setChoice(playerA, "Yes"); // use imprint + setChoice(playerA, "Lightning Bolt"); // target for imprint (excile from hand) + + // copy and cast imprinted card activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{2}, {T}:"); setChoice(playerA, "Yes"); - setChoice(playerA, "Yes"); setStopAt(1, PhaseStep.END_TURN); execute(); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/ReversalOfFortuneTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/ReversalOfFortuneTest.java index ad5641993a0..a47e832365a 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/ReversalOfFortuneTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/ReversalOfFortuneTest.java @@ -28,8 +28,8 @@ public class ReversalOfFortuneTest extends CardTestPlayerBase { addCard(Zone.HAND, playerB, "Lightning Bolt"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reversal of Fortune", playerB); - addTarget(playerA, "Lightning Bolt"); - setChoice(playerA, "Yes"); + setChoice(playerA, "Lightning Bolt"); // select to copy + setChoice(playerA, "Yes"); // cast copy setStopAt(1, PhaseStep.END_TURN); execute(); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/SharuumTheHegemonTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/SharuumTheHegemonTest.java index 5421dfca18f..0ac2a0db441 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/SharuumTheHegemonTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/SharuumTheHegemonTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.copy; import mage.constants.PhaseStep; @@ -7,7 +6,6 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ @@ -15,34 +13,33 @@ public class SharuumTheHegemonTest extends CardTestPlayerBase { /** * http://www.slightlymagic.net/forum/viewtopic.php?f=70&t=16732&p=172937&hilit=Sharuum+the+Hegemon#p172920 - * - * My Sharuum EDH deck uses the standard Sharuum + Clone Effect + Blood Artist as one of the win - * conditions, but when I have Sharuum in plan and play a Clever Impersonator, targetting Sharuum - * and choose to keep the Clever Impersonator and send the original Sharuum to the graveyard Xmage - * never gives me the option to use the Sharuum Ability that the Clever Impersonator should get, + *

    + * My Sharuum EDH deck uses the standard Sharuum + Clone Effect + Blood Artist as one of the win + * conditions, but when I have Sharuum in plan and play a Clever Impersonator, targetting Sharuum + * and choose to keep the Clever Impersonator and send the original Sharuum to the graveyard Xmage + * never gives me the option to use the Sharuum Ability that the Clever Impersonator should get, * making the combo not work. - * - * I run a Sharuum EDH deck that wins by cloning Sharuum for infinite death triggers. I know the rules + *

    + * I run a Sharuum EDH deck that wins by cloning Sharuum for infinite death triggers. I know the rules * check out on this combo irl, but no matter how I stack the triggers for cloning Sharuum and her enter * the battlefield effect it does not work. It either ends with Sharuum in my graveyard or the reanimate * effect hits the stack before the legend rule applies - * - [1] Sharuum the Hegemon is on the battlefield. - [2] You cast Clone (or any other Clone-like card). - [3] When Clone resolves, you choose Sharuum for the replacement effect. - [4] Since fake-Sharuum entered the battlefield, its EtB ability triggers. - [5] State-based actions are checked and you are prompted to keep one Sharuum. You sacrifice real-Sharuum. - * 116.2a Triggered abilities can trigger at any time, including while a spell is being cast, an ability is being activated, or a spell or - * ability is resolving. (See rule 603, "Handling Triggered Abilities.") However, nothing actually happens at the time an ability triggers. - * Each time a player would receive priority, each ability that has triggered but hasn't yet been put on the stack is put on the stack. See rule 116.5 - * 116.5. Each time a player would get priority, the game first performs all applicable state-based actions as a single event (see rule 704, - * "State-Based Actions"), then repeats this process until no state-based actions are performed. Then triggered abilities are put on the stack - * (see rule 603, "Handling Triggered Abilities"). These steps repeat in order until no further state-based actions are performed and no abilities - * trigger. Then the player who would have received priority does so. - [6] Once State-based actions are finished, triggered abilities go on the stack. You put the EtB from [4] choosing real-Sharuum. - [7] Real-Sharuum enters the battlefield. - [8] Rinse and repeat. - * + *

    + * [1] Sharuum the Hegemon is on the battlefield. + * [2] You cast Clone (or any other Clone-like card). + * [3] When Clone resolves, you choose Sharuum for the replacement effect. + * [4] Since fake-Sharuum entered the battlefield, its EtB ability triggers. + * [5] State-based actions are checked and you are prompted to keep one Sharuum. You sacrifice real-Sharuum. + * 116.2a Triggered abilities can trigger at any time, including while a spell is being cast, an ability is being activated, or a spell or + * ability is resolving. (See rule 603, "Handling Triggered Abilities.") However, nothing actually happens at the time an ability triggers. + * Each time a player would receive priority, each ability that has triggered but hasn't yet been put on the stack is put on the stack. See rule 116.5 + * 116.5. Each time a player would get priority, the game first performs all applicable state-based actions as a single event (see rule 704, + * "State-Based Actions"), then repeats this process until no state-based actions are performed. Then triggered abilities are put on the stack + * (see rule 603, "Handling Triggered Abilities"). These steps repeat in order until no further state-based actions are performed and no abilities + * trigger. Then the player who would have received priority does so. + * [6] Once State-based actions are finished, triggered abilities go on the stack. You put the EtB from [4] choosing real-Sharuum. + * [7] Real-Sharuum enters the battlefield. + * [8] Rinse and repeat. */ @Test public void testCloneTriggered() { @@ -59,17 +56,26 @@ public class SharuumTheHegemonTest extends CardTestPlayerBase { setChoice(playerA, "Sharuum the Hegemon"); // what creature to clone addTarget(playerA, "Sharuum the Hegemon[only copy]"); // which legend to keep - setChoice(playerA, "Yes"); - - addTarget(playerA, "Sharuum the Hegemon[only copy]"); // which legend to keep - setChoice(playerA, "Yes"); + setChoice(playerA, "Whenever {this} or another creature dies"); // blood first + addTarget(playerA, playerB); // damage by blood + setChoice(playerA, "Yes"); // return + addTarget(playerA, "Sharuum the Hegemon"); // return real sharuum addTarget(playerA, "Sharuum the Hegemon[only copy]"); // which legend to keep - setChoice(playerA, "Yes"); + setChoice(playerA, "Whenever {this} or another creature dies"); // blood first + addTarget(playerA, playerB); // damage by blood + setChoice(playerA, "Yes"); // return + addTarget(playerA, "Sharuum the Hegemon"); // return real sharuum + + addTarget(playerA, "Sharuum the Hegemon[only copy]"); // which legend to keep + setChoice(playerA, "Whenever {this} or another creature dies"); // blood first + addTarget(playerA, playerB); // damage by blood + setChoice(playerA, "Yes"); // return + addTarget(playerA, "Sharuum the Hegemon"); // return real sharuum addTarget(playerA, "Sharuum the Hegemon[only copy]"); // which legend to keep setChoice(playerA, "No"); // Don't use it anymore - + setStopAt(1, PhaseStep.END_TURN); execute(); @@ -77,7 +83,6 @@ public class SharuumTheHegemonTest extends CardTestPlayerBase { assertLife(playerB, 16); - } } \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/SpelltwineTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/SpelltwineTest.java index 548f7528522..f4859dc486e 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/SpelltwineTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/SpelltwineTest.java @@ -1,8 +1,8 @@ - package org.mage.test.cards.copy; import mage.constants.PhaseStep; import mage.constants.Zone; +import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -48,6 +48,7 @@ public class SpelltwineTest extends CardTestPlayerBase { * after this, failing to be in the stack box or resolve all. */ @Test + @Ignore // TODO: test is wrong -- mirari exile cards and must cast their copies, on copies cast mirari triggers again (two times). public void testCopyCardsMirari() { addCard(Zone.BATTLEFIELD, playerA, "Island", 9); // Exile target instant or sorcery card from your graveyard and target instant or sorcery card from an opponent's graveyard. @@ -66,9 +67,13 @@ public class SpelltwineTest extends CardTestPlayerBase { // Whenever you cast an instant or sorcery spell, you may pay {3}. If you do, copy that spell. You may choose new targets for the copy. addCard(Zone.BATTLEFIELD, playerA, "Mirari", 1); + // cast spellwin castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Spelltwine"); - addTarget(playerA, "Impulse"); - addTarget(playerA, "Blasphemous Act"); + addTarget(playerA, "Impulse"); // target 1 to excile + addTarget(playerA, "Blasphemous Act"); // target 2 to excile + + + setChoice(playerA, "Yes"); // pay {3} and copy spell setChoice(playerA, "Yes"); // Change targets addTarget(playerA, "Night's Whisper"); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/splitcards/CastSplitCardsFromOtherZonesTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/splitcards/CastSplitCardsFromOtherZonesTest.java index ae388836b4f..5d0b75df076 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/cost/splitcards/CastSplitCardsFromOtherZonesTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/splitcards/CastSplitCardsFromOtherZonesTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.cost.splitcards; import mage.constants.PhaseStep; @@ -7,7 +6,6 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class CastSplitCardsFromOtherZonesTest extends CardTestPlayerBase { @@ -27,31 +25,6 @@ public class CastSplitCardsFromOtherZonesTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Mindclaw Shaman"); // Creature {4}{R} addCard(Zone.BATTLEFIELD, playerB, "Sanguine Bond", 1); // Enchantment to destroy - // Wear - // Destroy target artifact. - // Tear - // Destroy target enchantment. - addCard(Zone.HAND, playerB, "Wear // Tear"); // Instant {1}{R} // {W} - - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mindclaw Shaman"); - addTarget(playerA, "Sanguine Bond"); - - setStopAt(1, PhaseStep.BEGIN_COMBAT); - execute(); - - assertPermanentCount(playerA, "Mindclaw Shaman", 1); - assertGraveyardCount(playerB, "Wear // Tear", 1); - assertGraveyardCount(playerB, "Sanguine Bond", 1); - - } - - @Test - public void testCastFearFromOpponentsHand() { - addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); - // When Mindclaw Shaman enters the battlefield, target opponent reveals their hand. - // You may cast an instant or sorcery card from it without paying its mana cost. - addCard(Zone.HAND, playerA, "Mindclaw Shaman"); // Creature {4}{R} - addCard(Zone.BATTLEFIELD, playerB, "Icy Manipulator", 1); // Artifact to destroy // Wear // Destroy target artifact. @@ -60,7 +33,42 @@ public class CastSplitCardsFromOtherZonesTest extends CardTestPlayerBase { addCard(Zone.HAND, playerB, "Wear // Tear"); // Instant {1}{R} // {W} castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mindclaw Shaman"); - addTarget(playerA, "Icy Manipulator"); + addTarget(playerA, playerB); + setChoice(playerA, "Wear // Tear"); // select card + setChoice(playerA, "Yes"); // confirm to cast + setChoice(playerA, "Tear"); // select tear side + addTarget(playerA, "Sanguine Bond"); // target for tear + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Mindclaw Shaman", 1); + assertGraveyardCount(playerB, "Wear // Tear", 1); + assertGraveyardCount(playerB, "Icy Manipulator", 0); + assertGraveyardCount(playerB, "Sanguine Bond", 1); + } + + @Test + public void testCastWearFromOpponentsHand() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); + // When Mindclaw Shaman enters the battlefield, target opponent reveals their hand. + // You may cast an instant or sorcery card from it without paying its mana cost. + addCard(Zone.HAND, playerA, "Mindclaw Shaman"); // Creature {4}{R} + + addCard(Zone.BATTLEFIELD, playerB, "Sanguine Bond", 1); // Enchantment to destroy + addCard(Zone.BATTLEFIELD, playerB, "Icy Manipulator", 1); // Artifact to destroy + // Wear + // Destroy target artifact. + // Tear + // Destroy target enchantment. + addCard(Zone.HAND, playerB, "Wear // Tear"); // Instant {1}{R} // {W} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mindclaw Shaman"); + addTarget(playerA, playerB); + setChoice(playerA, "Wear // Tear"); // select card + setChoice(playerA, "Yes"); // confirm to cast + setChoice(playerA, "Wear"); // select wear side + addTarget(playerA, "Icy Manipulator"); // target for wear setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); @@ -68,7 +76,7 @@ public class CastSplitCardsFromOtherZonesTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Mindclaw Shaman", 1); assertGraveyardCount(playerB, "Wear // Tear", 1); assertGraveyardCount(playerB, "Icy Manipulator", 1); - + assertGraveyardCount(playerB, "Sanguine Bond", 0); } @Test @@ -87,16 +95,20 @@ public class CastSplitCardsFromOtherZonesTest extends CardTestPlayerBase { addCard(Zone.HAND, playerB, "Wear // Tear"); // Instant {1}{R} // {W} castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mindclaw Shaman"); - addTarget(playerA, "Sanguine Bond"); + addTarget(playerA, playerB); + setChoice(playerA, "Wear // Tear"); // select card + setChoice(playerA, "Yes"); // confirm to cast + setChoice(playerA, "Wear // Tear"); // select fused + addTarget(playerA, "Icy Manipulator"); // target for wear + addTarget(playerA, "Sanguine Bond"); // target for tear setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); assertPermanentCount(playerA, "Mindclaw Shaman", 1); assertGraveyardCount(playerB, "Wear // Tear", 1); - assertGraveyardCount(playerB, "Sanguine Bond", 1); assertGraveyardCount(playerB, "Icy Manipulator", 1); - + assertGraveyardCount(playerB, "Sanguine Bond", 1); } /** @@ -119,7 +131,7 @@ public class CastSplitCardsFromOtherZonesTest extends CardTestPlayerBase { attack(2, playerB, "Etali, Primal Storm"); setChoice(playerB, "Yes"); - setChoice(playerB, "Cast Fire"); + setChoice(playerB, "Fire"); addTarget(playerB, "Silvercoat Lion"); setStopAt(2, PhaseStep.END_COMBAT); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/dynamicvalue/SweepTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/dynamicvalue/SweepTest.java index 68788a44295..61942c0313c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/dynamicvalue/SweepTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/dynamicvalue/SweepTest.java @@ -1,14 +1,12 @@ - - package org.mage.test.cards.dynamicvalue; import mage.constants.PhaseStep; import mage.constants.Zone; import org.junit.Test; +import org.mage.test.player.TestPlayer; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author BetaSteward */ public class SweepTest extends CardTestPlayerBase { @@ -18,10 +16,9 @@ public class SweepTest extends CardTestPlayerBase { * Plow Through Reito * 1W * Instant -- Arcane - * Sweep -- Return any number of Plains you control to their owner's hand. + * Sweep -- Return any number of Plains you control to their owner's hand. * Target creature gets +1/+1 until end of turn for each Plains returned this way. - * - */ + */ @Test public void testSweep1x() { addCard(Zone.BATTLEFIELD, playerA, "Plains", 5); @@ -29,17 +26,17 @@ public class SweepTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Plow Through Reito"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Plow Through Reito"); - addTarget(playerA, "Plains"); + addTarget(playerA, "Raging Goblin"); // target to boost + addTarget(playerA, "Plains"); // targets to sweep setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); assertPermanentCount(playerA, "Raging Goblin", 1); assertPermanentCount(playerA, "Plains", 4); - assertPowerToughness(playerA, "Raging Goblin", 2, 2); - + assertPowerToughness(playerA, "Raging Goblin", 2, 2); } - + @Test public void testSweep2x() { addCard(Zone.BATTLEFIELD, playerA, "Plains", 5); @@ -47,15 +44,15 @@ public class SweepTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Plow Through Reito"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Plow Through Reito"); - addTarget(playerA, "Plains^Plains"); + addTarget(playerA, "Raging Goblin"); // target to boost + addTarget(playerA, "Plains^Plains"); // targets to sweep setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); assertPermanentCount(playerA, "Raging Goblin", 1); assertPermanentCount(playerA, "Plains", 3); - assertPowerToughness(playerA, "Raging Goblin", 3, 3); - + assertPowerToughness(playerA, "Raging Goblin", 3, 3); } @Test @@ -65,15 +62,15 @@ public class SweepTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Plow Through Reito"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Plow Through Reito"); - addTarget(playerA, "Plains^Plains^Plains"); + addTarget(playerA, "Raging Goblin"); // target to boost + addTarget(playerA, "Plains^Plains^Plains"); // targets to sweep setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); assertPermanentCount(playerA, "Raging Goblin", 1); assertPermanentCount(playerA, "Plains", 2); - assertPowerToughness(playerA, "Raging Goblin", 4, 4); - + assertPowerToughness(playerA, "Raging Goblin", 4, 4); } @Test @@ -83,14 +80,16 @@ public class SweepTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Plow Through Reito"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Plow Through Reito"); + addTarget(playerA, "Raging Goblin"); // target to boost + addTarget(playerA, TestPlayer.TARGET_SKIP); // targets to sweep (zero) setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertPermanentCount(playerA, "Raging Goblin", 1); assertPermanentCount(playerA, "Plains", 5); - assertPowerToughness(playerA, "Raging Goblin", 1, 1); - + assertPowerToughness(playerA, "Raging Goblin", 1, 1); } - + } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/OathOfLiegesTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/OathOfLiegesTest.java index 2334af2b072..6db1d8e5728 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/OathOfLiegesTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/OathOfLiegesTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.enchantments; import mage.constants.PhaseStep; @@ -7,93 +6,229 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * - * @author LevelX2 + * @author LevelX2, JayDi85 */ public class OathOfLiegesTest extends CardTestPlayerBase { + //addCard(Zone.BATTLEFIELD, playerA, "Hypersonic Dragon", 1); // can cast spells at any time + //addCard(Zone.HAND, playerA, "Breath of Life", 1); // {3}{W} // return creatures + //addCard(Zone.HAND, playerA, "Replenish", 1); // {3}{W} // return all enchantments + @Test - public void testSearchLandOwner() { - addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); - // At the beginning of each player's upkeep, that player chooses target player who controls more lands than he or she does and is their opponent. - // The first player may search their library for a basic land card, put that card onto the battlefield, then shuffle their library. - addCard(Zone.HAND, playerA, "Oath of Lieges", 1); // {1}{W} - addCard(Zone.LIBRARY, playerA, "Plains", 1); + public void testOath_OwnCardTriggersOnOwnTurn() { + // A + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + addCard(Zone.LIBRARY, playerA, "Plains", 5); + addCard(Zone.BATTLEFIELD, playerA, "Oath of Lieges", 1); // {1}{W} + // B + addCard(Zone.BATTLEFIELD, playerB, "Island", 5); - addCard(Zone.BATTLEFIELD, playerB, "Plains", 3); + // turn 1 - A + // oath A triggers for A and activates + addTarget(playerA, playerB); // who control more lands + setChoice(playerA, "Yes"); // search library + addTarget(playerA, "Plains"); // card from library - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Oath of Lieges"); - addTarget(playerA, playerB); - addTarget(playerA, "Plains"); - - setStopAt(3, PhaseStep.PRECOMBAT_MAIN); + setStopAt(1, PhaseStep.END_TURN); execute(); + assertAllCommandsUsed(); - assertPermanentCount(playerA, "Oath of Lieges", 1); - assertPermanentCount(playerA, "Plains", 3); - + assertPermanentCount(playerA, "Plains", 4 + 1); + assertPermanentCount(playerB, "Island", 5); } @Test - public void testSearchLandOpponent() { - addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); - // At the beginning of each player's upkeep, that player chooses target player who controls more lands than he or she does and is their opponent. - // The first player may search their library for a basic land card, put that card onto the battlefield, then shuffle their library. - addCard(Zone.HAND, playerA, "Oath of Lieges", 1); // {1}{W} + public void testOath_OwnCardTriggersOnOpponentTurn() { + // A + addCard(Zone.BATTLEFIELD, playerA, "Plains", 5); + addCard(Zone.LIBRARY, playerA, "Plains", 5); + addCard(Zone.BATTLEFIELD, playerA, "Hypersonic Dragon", 1); // can cast spells at any time + addCard(Zone.GRAVEYARD, playerA, "Oath of Lieges", 1); // {1}{W} + addCard(Zone.HAND, playerA, "Replenish", 1); // {3}{W} // return all enchantments + // B + addCard(Zone.BATTLEFIELD, playerB, "Plains", 4); + addCard(Zone.LIBRARY, playerB, "Plains", 5); - addCard(Zone.BATTLEFIELD, playerB, "Plains", 1); - addCard(Zone.LIBRARY, playerB, "Plains", 1); + // turn 1 - A (play oath from grave) + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Replenish"); + checkPermanentCount("A have oath", 1, PhaseStep.END_TURN, playerA, "Oath of Lieges", 1); + checkPermanentCount("A have 5 plains", 1, PhaseStep.END_TURN, playerA, "Plains", 5); + checkPermanentCount("B have 4 plains", 1, PhaseStep.END_TURN, playerB, "Plains", 4); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Oath of Lieges"); - addTarget(playerB, playerA); - addTarget(playerB, "Plains"); + // turn 2 - B + // oath A triggers for B and activates + addTarget(playerB, playerA); // who control more lands + setChoice(playerB, "Yes"); // search library + addTarget(playerB, "Plains"); // card from library - setStopAt(2, PhaseStep.PRECOMBAT_MAIN); + setStopAt(2, PhaseStep.END_TURN); execute(); + assertAllCommandsUsed(); - assertPermanentCount(playerA, "Oath of Lieges", 1); - assertPermanentCount(playerA, "Plains", 2); - assertPermanentCount(playerB, "Plains", 2); + assertPermanentCount(playerA, "Plains", 5); + assertPermanentCount(playerB, "Plains", 4 + 1); } @Test - public void testSearchLandOwnerCopy() { - addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); - // At the beginning of each player's upkeep, that player chooses target player who controls more lands than he or she does and is their opponent. - // The first player may search their library for a basic land card, put that card onto the battlefield, then shuffle their library. - addCard(Zone.HAND, playerA, "Oath of Lieges", 1); // {1}{W} - addCard(Zone.LIBRARY, playerA, "Plains", 3); - addCard(Zone.HAND, playerA, "Plains", 1); + public void testOath_OpponentCardTriggersOnOwnTurn() { + // A + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + addCard(Zone.LIBRARY, playerA, "Plains", 5); + // B + addCard(Zone.LIBRARY, playerB, "Plains", 5); + addCard(Zone.BATTLEFIELD, playerB, "Plains", 5); + addCard(Zone.BATTLEFIELD, playerB, "Oath of Lieges", 1); // {1}{W} + // turn 1 - A + // oath B triggers for A and activates + addTarget(playerA, playerB); // who control more lands + setChoice(playerA, "Yes"); // search library + addTarget(playerA, "Plains"); // card from library + + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Plains", 4 + 1); + assertPermanentCount(playerB, "Plains", 5); + } + + @Test + public void testOath_DoubleOath() { + // A + addCard(Zone.BATTLEFIELD, playerA, "Plains", 3); + addCard(Zone.LIBRARY, playerA, "Plains", 5); + addCard(Zone.BATTLEFIELD, playerA, "Oath of Lieges", 2); // {1}{W} + // B + addCard(Zone.BATTLEFIELD, playerB, "Plains", 5); + + // turn 1 - A + // oath A triggers for A and activates + // oath B triggers for A and activates + // 1 + addTarget(playerA, playerB); // who control more lands + setChoice(playerA, "Yes"); // search library + addTarget(playerA, "Plains"); // card from library + // 2 + addTarget(playerA, playerB); // who control more lands + setChoice(playerA, "Yes"); // search library + addTarget(playerA, "Plains"); // card from library + + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Plains", 3 + 2); + assertPermanentCount(playerB, "Plains", 5); + } + + @Test + public void testOath_OwnNormalAndOwnCopy() { + // A + addCard(Zone.BATTLEFIELD, playerA, "Plains", 10); + addCard(Zone.BATTLEFIELD, playerA, "Island", 3); // for copy + addCard(Zone.LIBRARY, playerA, "Plains", 5); + addCard(Zone.BATTLEFIELD, playerA, "Hypersonic Dragon", 1); // can cast spells at any time + addCard(Zone.GRAVEYARD, playerA, "Oath of Lieges", 1); // {1}{W} + addCard(Zone.HAND, playerA, "Replenish", 1); // {3}{W} // return all enchantments + addCard(Zone.HAND, playerA, "Copy Enchantment", 1); // {2}{U} // copy target + // B + addCard(Zone.BATTLEFIELD, playerB, "Plains", 12); addCard(Zone.BATTLEFIELD, playerB, "Island", 3); - addCard(Zone.HAND, playerB, "Copy Enchantment", 1); // {2}{U} - addCard(Zone.LIBRARY, playerB, "Plains", 3); + addCard(Zone.LIBRARY, playerB, "Plains", 5); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Oath of Lieges"); + // turn 1 - A + // cast oath A + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Replenish"); + showBattlefield("A perms", 1, PhaseStep.POSTCOMBAT_MAIN, playerA); + // cast oath copy + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Copy Enchantment"); + setChoice(playerA, "Yes"); // use copy effect + setChoice(playerA, "Oath of Lieges"); // target for copy + checkPermanentCount("A have 2 oath", 1, PhaseStep.END_TURN, playerA, "Oath of Lieges", 2); + checkPermanentCount("A have 10 plains", 1, PhaseStep.END_TURN, playerA, "Plains", 10); + checkPermanentCount("B have 12 plains", 1, PhaseStep.END_TURN, playerB, "Plains", 12); - castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Copy Enchantment"); - setChoice(playerB, "Oath of Lieges"); + // turn 2 - B + // oath A triggers for B and do nothing + // copy oath A triggers for B and do nothing + checkPermanentCount("A have 10 plains", 1, PhaseStep.END_TURN, playerA, "Plains", 10); + checkPermanentCount("B have 12 plains", 1, PhaseStep.END_TURN, playerB, "Plains", 12); - // turn 3 - addTarget(playerA, playerB); - addTarget(playerA, "Plains"); // 3rd land - addTarget(playerA, "Plains"); // second trigger will fail because target player has no longer more lands than controller + // turn 3 - A + // oath A triggers for A and activates + // copy oath A triggers for A and activates + // 1 + addTarget(playerA, playerB); // who control more lands + setChoice(playerA, "Yes"); // search library + addTarget(playerA, "Plains"); // card from library + // 2 + addTarget(playerA, playerB); // who control more lands + setChoice(playerA, "Yes"); // search library + addTarget(playerA, "Plains"); // card from library - playLand(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Plains"); // 4th land - - // turn 4 - addTarget(playerB, playerA); - addTarget(playerB, "Plains"); - addTarget(playerB, "Plains"); // second trigger will fail because target player has no longer more lands than controller - - setStopAt(4, PhaseStep.PRECOMBAT_MAIN); + setStopAt(3, PhaseStep.END_TURN); execute(); + assertAllCommandsUsed(); - assertPermanentCount(playerB, "Oath of Lieges", 1); - assertPermanentCount(playerA, "Oath of Lieges", 1); + assertPermanentCount(playerA, "Plains", 10 + 2); + assertPermanentCount(playerB, "Plains", 12); + } - assertPermanentCount(playerB, "Plains", 1); - assertPermanentCount(playerA, "Plains", 4); + @Test + public void testOath_OwnNormalAndOpponentCopy() { + // special test to check targetadjusters (copy card must used target adjuster from original card, not from copied) + // A + addCard(Zone.BATTLEFIELD, playerA, "Plains", 10); + addCard(Zone.BATTLEFIELD, playerA, "Island", 3); + addCard(Zone.LIBRARY, playerA, "Plains", 5); + addCard(Zone.GRAVEYARD, playerA, "Oath of Lieges", 1); // {1}{W} + addCard(Zone.HAND, playerA, "Replenish", 1); // {3}{W} // return all enchantments + addCard(Zone.BATTLEFIELD, playerA, "Hypersonic Dragon", 1); // can cast spells at any time + // B + addCard(Zone.BATTLEFIELD, playerB, "Plains", 12); + addCard(Zone.BATTLEFIELD, playerB, "Island", 3); // for copy + addCard(Zone.LIBRARY, playerB, "Plains", 5); + addCard(Zone.HAND, playerB, "Copy Enchantment", 1); // {2}{U} // copy target + + // turn 1 - A + // nothing + + // turn 2 - B + // cast oath A + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Replenish"); + // cast oath copy by opponent + showBattlefield("A perms", 2, PhaseStep.POSTCOMBAT_MAIN, playerA); + showBattlefield("B perms", 2, PhaseStep.POSTCOMBAT_MAIN, playerB); + showAvaileableAbilities("B abils", 2, PhaseStep.POSTCOMBAT_MAIN, playerB); + showHand("B hand", 2, PhaseStep.POSTCOMBAT_MAIN, playerB); + castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerB, "Copy Enchantment"); + setChoice(playerB, "Yes"); // use copy effect + setChoice(playerB, "Oath of Lieges"); // target for copy + checkPermanentCount("A have 1 oath", 2, PhaseStep.END_TURN, playerA, "Oath of Lieges", 1); + checkPermanentCount("B have 1 oath", 2, PhaseStep.END_TURN, playerA, "Oath of Lieges", 1); + checkPermanentCount("A have 10 plains", 2, PhaseStep.END_TURN, playerA, "Plains", 10); + checkPermanentCount("B have 12 plains", 2, PhaseStep.END_TURN, playerB, "Plains", 12); + showLibrary("lib B", 2, PhaseStep.END_TURN, playerB); + + // turn 3 - A + // oath A triggers for A and activates + // copy oath B triggers for A and activates + // 1 + addTarget(playerA, playerB); // who control more lands + setChoice(playerA, "Yes"); // search library + addTarget(playerA, "Plains"); // card from library + // 2 + addTarget(playerA, playerB); // who control more lands + setChoice(playerA, "Yes"); // search library + addTarget(playerA, "Plains"); // card from library + + setStopAt(3, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Plains", 10 + 2); + assertPermanentCount(playerB, "Plains", 12); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/StarfieldOfNyxTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/StarfieldOfNyxTest.java index ec167a63152..882c8e1efb8 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/StarfieldOfNyxTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/StarfieldOfNyxTest.java @@ -1,7 +1,7 @@ - package org.mage.test.cards.enchantments; import mage.abilities.keyword.FlyingAbility; +import mage.constants.EmptyNames; import mage.constants.PhaseStep; import mage.constants.Zone; import mage.filter.Filter; @@ -11,7 +11,6 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class StarfieldOfNyxTest extends CardTestPlayerBase { @@ -22,7 +21,6 @@ public class StarfieldOfNyxTest extends CardTestPlayerBase { * Starfield of Nyx not only turned both of them into creatures (it * shouldn't, because they're auras), but it also destroyed them. The * manifests stayed on the battlefield without Flying or Hexproof. - * */ @Test public void testCloudform() { @@ -49,7 +47,7 @@ public class StarfieldOfNyxTest extends CardTestPlayerBase { execute(); assertGraveyardCount(playerA, "Thopter Spy Network", 0); - assertPowerToughness(playerA, "", 2, 2, Filter.ComparisonScope.All); // the manifested cards + assertPowerToughness(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2, 2, Filter.ComparisonScope.All); // the manifested cards assertPermanentCount(playerA, "Starfield of Nyx", 1); assertPowerToughness(playerA, "Thopter Spy Network", 4, 4, Filter.ComparisonScope.All); assertPermanentCount(playerA, "Cloudform", 2); @@ -97,19 +95,19 @@ public class StarfieldOfNyxTest extends CardTestPlayerBase { Assert.assertEquals("Singing Bell Strike not on the battlefield", false, true); } } - + @Test public void testStarfieldOfNyxLayers() { - + addCard(Zone.BATTLEFIELD, playerA, "Starfield of Nyx"); // enchantments you control become creatures addCard(Zone.BATTLEFIELD, playerA, "Humility"); // creatures lose all abilities and are 1/1 addCard(Zone.BATTLEFIELD, playerA, "Pharika, God of Affliction"); // enchantment addCard(Zone.BATTLEFIELD, playerA, "Emrakul, the Aeons Torn"); //15/15 creature addCard(Zone.BATTLEFIELD, playerA, "Crusade", 4); // enchantments to fulfill requirement of Starfield of Nyx - + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); execute(); - + assertPowerToughness(playerA, "Pharika, God of Affliction", 3, 3, Filter.ComparisonScope.All); assertPowerToughness(playerA, "Humility", 4, 4, Filter.ComparisonScope.All); // Humility loses its ability in layer 6. Layer 7 never gets Humility's effect @@ -117,6 +115,6 @@ public class StarfieldOfNyxTest extends CardTestPlayerBase { Permanent emrakul = getPermanent("Emrakul, the Aeons Torn", playerA.getId()); Assert.assertNotNull(emrakul); Assert.assertFalse(emrakul.getAbilities().contains(FlyingAbility.getInstance())); // loses flying though - + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/facedown/GhastlyConscriptionTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/facedown/GhastlyConscriptionTest.java index e4a92ee7267..b516159d9b8 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/facedown/GhastlyConscriptionTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/facedown/GhastlyConscriptionTest.java @@ -1,5 +1,6 @@ package org.mage.test.cards.facedown; +import mage.constants.EmptyNames; import mage.constants.PhaseStep; import mage.constants.Zone; import org.junit.Test; @@ -13,13 +14,12 @@ public class GhastlyConscriptionTest extends CardTestPlayerBase { /** * Ghastly Conscription * Sorcery, 5BB (7) - * Exile all creature cards from target player's graveyard in a face-down pile, - * shuffle that pile, then manifest those cards. (To manifest a card, put it - * onto the battlefield face down as a 2/2 creature. Turn it face up any time + * Exile all creature cards from target player's graveyard in a face-down pile, + * shuffle that pile, then manifest those cards. (To manifest a card, put it + * onto the battlefield face down as a 2/2 creature. Turn it face up any time * for its mana cost if it's a creature card.) - * */ - + // test that cards exiled using Ghastly Conscription return face down @Test public void testGhastlyConscription() { @@ -36,9 +36,9 @@ public class GhastlyConscriptionTest extends CardTestPlayerBase { assertLife(playerA, 20); assertLife(playerB, 20); - + assertGraveyardCount(playerA, 2); - assertPermanentCount(playerA, "", 2); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/facedown/ObscuringAetherTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/facedown/ObscuringAetherTest.java index b0755813afb..77ec01543d0 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/facedown/ObscuringAetherTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/facedown/ObscuringAetherTest.java @@ -1,13 +1,12 @@ - package org.mage.test.cards.facedown; +import mage.constants.EmptyNames; import mage.constants.PhaseStep; import mage.constants.Zone; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class ObscuringAetherTest extends CardTestPlayerBase { @@ -15,7 +14,6 @@ public class ObscuringAetherTest extends CardTestPlayerBase { /** * Obscuring Aether cannot turn into a face down 2/2 like it should. When * activating the ability to turn it over it, it dies immediately. - * */ // test that cards exiled using Ghastly Conscription return face down @Test @@ -35,8 +33,8 @@ public class ObscuringAetherTest extends CardTestPlayerBase { assertHandCount(playerA, "Obscuring Aether", 0); assertGraveyardCount(playerA, "Obscuring Aether", 0); - assertPermanentCount(playerA, "", 1); - assertPowerToughness(playerA, "", 2, 2); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); + assertPowerToughness(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2, 2); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/rules/CantCastTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/rules/CantCastTest.java index 7fb74ea1ada..4a8ac07bbe3 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/rules/CantCastTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/rules/CantCastTest.java @@ -1,6 +1,6 @@ - package org.mage.test.cards.rules; +import mage.constants.EmptyNames; import mage.constants.PhaseStep; import mage.constants.Zone; import mage.counters.CounterType; @@ -8,7 +8,6 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class CantCastTest extends CardTestPlayerBase { @@ -113,7 +112,7 @@ public class CantCastTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - assertPermanentCount(playerA, "", 0); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 0); assertHandCount(playerA, "Pine Walker", 1); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/MisdirectionTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/MisdirectionTest.java index a84870f89d8..efb30757b70 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/MisdirectionTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/MisdirectionTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.single; import mage.constants.PhaseStep; @@ -7,8 +6,7 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * - * @author LevelX2 + * @author LevelX2, JayDi85 */ public class MisdirectionTest extends CardTestPlayerBase { @@ -17,10 +15,58 @@ public class MisdirectionTest extends CardTestPlayerBase { * Tests if Misdirection for target opponent works correctly * https://github.com/magefree/mage/issues/574 */ + @Test - public void testChangeTargetOpponent() { + public void test_RakshaDiscardWorks() { // Target opponent discards two cards. Put the top two cards of your library into your graveyard. - addCard(Zone.HAND, playerA, "Rakshasa's Secret"); + addCard(Zone.HAND, playerA, "Rakshasa's Secret"); // {2}{B} + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3); + addCard(Zone.HAND, playerB, "Silvercoat Lion", 2); + addCard(Zone.HAND, playerB, "Ashcoat Bear", 5); + + // A cast discard + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Rakshasa's Secret", playerB); + setChoice(playerB, "Silvercoat Lion"); // select target 1 + setChoice(playerB, "Silvercoat Lion"); // select target 2 + checkHandCardCount("B haven't lions", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Silvercoat Lion", 0); + checkHandCardCount("B have 5 bears", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Ashcoat Bear", 5); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + } + + @Test + public void test_MisdirectionRetargetWorks() { + // Return target permanent to its owner’s hand. + addCard(Zone.HAND, playerA, "Boomerang", 1); // {U}{U} + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); + addCard(Zone.BATTLEFIELD, playerA, "Ashcoat Bear", 1); + // Change the target of target spell with a single target. + addCard(Zone.HAND, playerB, "Misdirection"); // {3}{U}{U} + addCard(Zone.BATTLEFIELD, playerB, "Island", 5); + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1); + + // A cast Boomerang to remove lion + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Boomerang", "Silvercoat Lion"); + // B counter it by Misdirection and remove bear + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Misdirection", "Boomerang", "Boomerang"); + addTarget(playerB, "Ashcoat Bear"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertGraveyardCount(playerA, "Boomerang", 1); + assertPermanentCount(playerA, "Ashcoat Bear", 0); + assertGraveyardCount(playerB, "Misdirection", 1); + assertPermanentCount(playerB, "Silvercoat Lion", 1); + } + + @Test + public void test_MisdirectionCantTargetToIllegal() { + // Target opponent discards two cards. Put the top two cards of your library into your graveyard. + addCard(Zone.HAND, playerA, "Rakshasa's Secret"); // {2}{B} addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3); /* Misdirection {3}{U}{U} @@ -30,23 +76,31 @@ public class MisdirectionTest extends CardTestPlayerBase { */ addCard(Zone.HAND, playerB, "Misdirection"); addCard(Zone.HAND, playerB, "Silvercoat Lion", 2); + addCard(Zone.HAND, playerB, "Ashcoat Bear", 5); addCard(Zone.BATTLEFIELD, playerB, "Island", 5); - + + // cast Raksha and select B castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Rakshasa's Secret", playerB); + // cast misdir, but it's not apply and taget will be same castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Misdirection", "Rakshasa's Secret", "Rakshasa's Secret"); - addTarget(playerB, playerA); // only legal target is player B as opponent - so player A should not be allowed - - setStopAt(1, PhaseStep.BEGIN_COMBAT); + // B must select cards to discard (2 lions, not bears) + setChoice(playerB, "Silvercoat Lion"); // select target 1 + setChoice(playerB, "Silvercoat Lion"); // select target 2 + checkHandCardCount("B haven't lions", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Silvercoat Lion", 0); + checkHandCardCount("B have 5 bears", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Ashcoat Bear", 5); + + setStopAt(1, PhaseStep.END_TURN); execute(); + assertAllCommandsUsed(); assertGraveyardCount(playerA, "Rakshasa's Secret", 1); assertGraveyardCount(playerB, "Misdirection", 1); assertHandCount(playerB, "Silvercoat Lion", 0); } - + // check to change target permanent creature legal to to a creature the opponent of the spell controller controls @Test - public void testChangePublicExecution() { + public void test_ChangePublicExecution() { // Destroy target creature an opponent controls. Each other creature that player controls gets -2/-0 until end of turn. addCard(Zone.HAND, playerA, "Public Execution"); addCard(Zone.BATTLEFIELD, playerA, "Swamp", 6); @@ -60,26 +114,27 @@ public class MisdirectionTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox", 1); addCard(Zone.BATTLEFIELD, playerB, "Custodian of the Trove", 1); // 4/3 addCard(Zone.BATTLEFIELD, playerB, "Island", 5); - + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Public Execution", "Pillarfield Ox"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Misdirection", "Public Execution", "Public Execution"); - addTarget(playerB, "Custodian of the Trove"); - + addTarget(playerB, "Custodian of the Trove"); + setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertGraveyardCount(playerA, "Public Execution", 1); assertGraveyardCount(playerB, "Misdirection", 1); - - assertGraveyardCount(playerB, "Custodian of the Trove",1); + + assertGraveyardCount(playerB, "Custodian of the Trove", 1); assertPermanentCount(playerB, "Pillarfield Ox", 1); assertPowerToughness(playerB, "Pillarfield Ox", 0, 4); - } - + } + // check to change target permanent creature not legal to to a creature the your opponent controls @Test - public void testChangePublicExecution2() { + public void test_ChangePublicExecution2() { // Destroy target creature an opponent controls. Each other creature that player controls gets -2/-0 until end of turn. addCard(Zone.HAND, playerA, "Public Execution"); addCard(Zone.BATTLEFIELD, playerA, "Swamp", 6); @@ -94,13 +149,13 @@ public class MisdirectionTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox", 1); addCard(Zone.BATTLEFIELD, playerB, "Custodian of the Trove", 1); // 4/3 addCard(Zone.BATTLEFIELD, playerB, "Island", 5); - + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Public Execution", "Custodian of the Trove"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Misdirection", "Public Execution", "Public Execution"); - addTarget(playerB, "Keeper of the Lens"); - + setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertGraveyardCount(playerA, "Public Execution", 1); assertGraveyardCount(playerB, "Misdirection", 1); @@ -108,8 +163,7 @@ public class MisdirectionTest extends CardTestPlayerBase { assertPermanentCount(playerB, "Pillarfield Ox", 1); assertPowerToughness(playerB, "Pillarfield Ox", 0, 4); - - assertGraveyardCount(playerB, "Custodian of the Trove",1); - } + assertGraveyardCount(playerB, "Custodian of the Trove", 1); + } } \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/fut/MuragandaPetroglyphsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/fut/MuragandaPetroglyphsTest.java index 713ea046c00..0b86e47c8b5 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/fut/MuragandaPetroglyphsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/fut/MuragandaPetroglyphsTest.java @@ -1,5 +1,6 @@ package org.mage.test.cards.single.fut; +import mage.constants.EmptyNames; import mage.constants.PhaseStep; import mage.constants.Zone; import mage.filter.Filter; @@ -50,8 +51,8 @@ public class MuragandaPetroglyphsTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - assertPermanentCount(playerA, "", 1); - assertPowerToughness(playerA, "", 4, 4); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); + assertPowerToughness(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 4, 4); } @Test @@ -69,8 +70,8 @@ public class MuragandaPetroglyphsTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - assertPermanentCount(playerA, "", 1); - assertPowerToughness(playerA, "", 2, 2); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); + assertPowerToughness(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2, 2); } @Test @@ -155,7 +156,7 @@ public class MuragandaPetroglyphsTest extends CardTestPlayerBase { // Enchanted creature doesn't untap during itscontroller's untap step. addCard(Zone.HAND, playerA, "Dehydration"); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA,"Rancor", "Grizzly Bears"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Rancor", "Grizzly Bears"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Dehydration", "Runeclaw Bear"); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/PrizedAmalgamTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/PrizedAmalgamTest.java index 807859f205b..6dc75feb43d 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/PrizedAmalgamTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/PrizedAmalgamTest.java @@ -66,23 +66,24 @@ public class PrizedAmalgamTest extends CardTestPlayerBase { public void testOpponentReturnsCreatureFromGrave() { addCard(Zone.HAND, playerA, "Reanimate", 1); - addCard(Zone.GRAVEYARD, playerA, "Hill Giant", 1); // {3}{R} 3/3 + addCard(Zone.GRAVEYARD, playerA, "Hill Giant", 1); // {3}{R} 3/3, 4 CMC addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); - addCard(Zone.GRAVEYARD, playerB, "Prized Amalgam", 1); + addCard(Zone.GRAVEYARD, playerB, "Prized Amalgam", 1); // {1}{U}{B}, 3 CMC - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reanimate", "Hill Giant"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reanimate"); + addTarget(playerA, "Hill Giant"); setStopAt(1, PhaseStep.END_TURN); execute(); - assertLife(playerA, 16); // lose 4 life from reanimate 4 CMC + assertLife(playerA, 16); // lose 4 life from reanimate 4 CMC by Hill Giant assertPermanentCount(playerA, "Hill Giant", 1); assertPermanentCount(playerB, "Prized Amalgam", 0); // should not recur assertGraveyardCount(playerB, "Prized Amalgam", 1); // stays in grave } /* - * Test opponent returning a card from your graveyard to battlefield. + * Test opponent returning a card from your graveyard to battlefield. */ @Test public void testOpponentReturnsCreatureFromYourGrave() { diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/ths/PurphorosGodOfTheForgeTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/ths/PurphorosGodOfTheForgeTest.java index 18e0ded9a02..d124f0882a6 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/ths/PurphorosGodOfTheForgeTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/ths/PurphorosGodOfTheForgeTest.java @@ -1,7 +1,7 @@ - package org.mage.test.cards.single.ths; import mage.constants.CardType; +import mage.constants.EmptyNames; import mage.constants.PhaseStep; import mage.constants.Zone; import mage.game.permanent.Permanent; @@ -10,26 +10,25 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class PurphorosGodOfTheForgeTest extends CardTestPlayerBase { /** * I had a situation come up today where I had a Purphoros on the field - * and 5 devotion with an Eidolon and Phoenix. My opponent killed the + * and 5 devotion with an Eidolon and Phoenix. My opponent killed the * Phoenix, but Purphoros still was "turned on". */ @Test public void testFacedownNotCountedForDevotion1() { addCard(Zone.BATTLEFIELD, playerB, "Swamp", 5); addCard(Zone.HAND, playerB, "Reach of Shadows"); - + // Indestructible // As long as your devotion to red is less than five, Purphoros isn't a creature. // Whenever another creature enters the battlefield under your control, Purphoros deals 2 damage to each opponent. // {2}{R}: Creatures you control get +1/+0 until end of turn. addCard(Zone.BATTLEFIELD, playerA, "Purphoros, God of the Forge"); - + // Whenever a player casts a spell with converted mana cost 3 or less, // Eidolon of the Great Revel deals 2 damage to that player. addCard(Zone.BATTLEFIELD, playerA, "Eidolon of the Great Revel"); @@ -46,24 +45,24 @@ public class PurphorosGodOfTheForgeTest extends CardTestPlayerBase { assertLife(playerA, 20); assertLife(playerB, 18); // 2 damage from the returning Phoenix - + assertGraveyardCount(playerB, "Reach of Shadows", 1); assertPermanentCount(playerA, "Ashcloud Phoenix", 0); - assertPermanentCount(playerA, "", 1); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); Permanent purphorosGodOfTheForge = getPermanent("Purphoros, God of the Forge", playerA); Assert.assertFalse("Purphoros may not be a creature but it is", purphorosGodOfTheForge.getCardType().contains(CardType.CREATURE)); } - + @Test - public void testFacedownNotCountedForDevotion2() { + public void testFacedownNotCountedForDevotion2() { addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); // Indestructible // As long as your devotion to red is less than five, Purphoros isn't a creature. // Whenever another creature enters the battlefield under your control, Purphoros deals 2 damage to each opponent. // {2}{R}: Creatures you control get +1/+0 until end of turn. addCard(Zone.BATTLEFIELD, playerA, "Purphoros, God of the Forge"); - + // Whenever a player casts a spell with converted mana cost 3 or less, // Eidolon of the Great Revel deals 2 damage to that player. addCard(Zone.BATTLEFIELD, playerA, "Eidolon of the Great Revel"); @@ -81,18 +80,18 @@ public class PurphorosGodOfTheForgeTest extends CardTestPlayerBase { execute(); assertPermanentCount(playerA, "Ashcloud Phoenix", 0); - assertPermanentCount(playerA, "", 1); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); assertLife(playerA, 18); // 2 damage from Eidolon of the Great Revel assertLife(playerB, 18); // 2 damage from Purphoros for the morphed Phoenix - + Permanent purphorosGodOfTheForge = getPermanent("Purphoros, God of the Forge", playerA); Assert.assertFalse("Purphoros may not be a creature but it is", purphorosGodOfTheForge.getCardType().contains(CardType.CREATURE)); - } - + } + @Test public void testHybridManaCostsForDevotion() { - + // Indestructible // As long as your devotion to red is less than five, Purphoros isn't a creature. // Whenever another creature enters the battlefield under your control, Purphoros deals 2 damage to each opponent. @@ -101,11 +100,11 @@ public class PurphorosGodOfTheForgeTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Goblin Guide", 1); // {R} addCard(Zone.HAND, playerA, "Boros Reckoner", 1); // {R/W}{R/W}{R/W} addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); - + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Boros Reckoner"); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - + assertLife(playerB, 18); Permanent purphorosGodOfTheForge = getPermanent("Purphoros, God of the Forge", playerA); Assert.assertTrue("Purphoros should be a creature now but is not", purphorosGodOfTheForge.getCardType().contains(CardType.CREATURE)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/SpellskiteTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/SpellskiteTest.java index 9c45cc42e7b..af57b93243b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/SpellskiteTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/SpellskiteTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.triggers; import mage.constants.PhaseStep; @@ -7,7 +6,6 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class SpellskiteTest extends CardTestPlayerBase { @@ -30,6 +28,7 @@ public class SpellskiteTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertGraveyardCount(playerA, "Lightning Bolt", 1); assertPermanentCount(playerA, "Spellskite", 1); @@ -80,6 +79,7 @@ public class SpellskiteTest extends CardTestPlayerBase { setStopAt(2, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertPermanentCount(playerA, "Spellskite", 1); assertPermanentCount(playerB, "Frost Titan", 1); @@ -119,6 +119,7 @@ public class SpellskiteTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertGraveyardCount(playerB, "Lightning Bolt", 1); @@ -160,6 +161,7 @@ public class SpellskiteTest extends CardTestPlayerBase { setStopAt(2, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertGraveyardCount(playerA, "Cryptic Command", 1); @@ -188,16 +190,16 @@ public class SpellskiteTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB); - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{U/P}: Change a target of target spell or ability to {this}.", "Lightning Bolt"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{U/P}: Change a target", "Lightning Bolt"); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertGraveyardCount(playerA, "Lightning Bolt", 1); assertLife(playerA, 20); assertLife(playerB, 18); - } /** @@ -219,6 +221,7 @@ public class SpellskiteTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertGraveyardCount(playerA, "Flame Slash", 1); assertPowerToughness(playerB, "Spellskite", 3, 7); @@ -238,24 +241,36 @@ public class SpellskiteTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Spellskite"); addCard(Zone.BATTLEFIELD, playerB, "Scute Mob"); addCard(Zone.BATTLEFIELD, playerB, "Island"); + // + addCard(Zone.BATTLEFIELD, playerB, "Memnite"); // 1/1 + addCard(Zone.BATTLEFIELD, playerB, "Royal Assassin"); // 1/1 + addCard(Zone.BATTLEFIELD, playerB, "Blinking Spirit"); // 2/2 + addCard(Zone.BATTLEFIELD, playerB, "Pearled Unicorn"); // 2/2 addCard(Zone.HAND, playerA, "Fiery Justice"); + // A cast Fiery Justice castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Fiery Justice"); - addTarget(playerA, "Scute Mob"); - setChoice(playerA, "X=1"); - addTarget(playerA, "Spellskite"); - setChoice(playerA, "X=4"); - - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{UP}: Change a target of target spell or ability to {this}.", "Fiery Justice", "Fiery Justice"); - setChoice(playerA, "Yes"); + addTarget(playerA, playerB); // 5 life to B + addTarget(playerA, "Scute Mob^X=1"); // target 1 + addTarget(playerA, "Spellskite^X=4"); // target 2 + // B activate Spellskite, but can't change any targets cause it's already targeted + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{U/P}: Change a target", "Fiery Justice", "Fiery Justice"); + setChoice(playerB, "Yes"); // pay 2 life + showBattlefield("B battle", 1, PhaseStep.BEGIN_COMBAT, playerB); + showGraveyard("B grave", 1, PhaseStep.BEGIN_COMBAT, playerB); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); + assertLife(playerB, 20 + 5 - 2); assertGraveyardCount(playerB, 2); + assertGraveyardCount(playerB, "Scute Mob", 1); + assertGraveyardCount(playerB, "Spellskite", 1); } + @Test public void testThatSplitDamageCanGetRedirected() { /* Standard redirect test The Spellskite should die from the 5 damage that was redirected to it @@ -267,59 +282,64 @@ public class SpellskiteTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Spellskite");// 0/4 creature addCard(Zone.BATTLEFIELD, playerB, "Scute Mob"); // 1/1 creauture addCard(Zone.BATTLEFIELD, playerB, "Island"); + addCard(Zone.BATTLEFIELD, playerB, "Memnite"); // 1/1 + addCard(Zone.BATTLEFIELD, playerB, "Royal Assassin"); // 1/1 + addCard(Zone.BATTLEFIELD, playerB, "Blinking Spirit"); // 2/2 + addCard(Zone.BATTLEFIELD, playerB, "Pearled Unicorn"); // 2/2 addCard(Zone.HAND, playerA, "Fiery Justice"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Fiery Justice"); // 5 damage distributed to any number of targets - addTarget(playerA, "Scute Mob"); - setChoice(playerA, "X=5"); + addTarget(playerA, "Scute Mob^X=5"); - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{UP}: Change a target of target spell or ability to {this}.", "Fiery Justice", "Fiery Justice"); - setChoice(playerA, "Yes"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{U/P}: Change a target", "Fiery Justice", "Fiery Justice"); + setChoice(playerB, "Yes"); // pay 2 life + setChoice(playerB, "Yes"); // retarget setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); + assertLife(playerB, 20 + 5 - 2); assertGraveyardCount(playerB, 1); assertPermanentCount(playerB, "Scute Mob", 1); } + @Test public void testThatSplitDamageGetsRedirectedFromTheCorrectChoice() { addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); addCard(Zone.BATTLEFIELD, playerB, "Spellskite");// 0/4 creature - addCard(Zone.BATTLEFIELD, playerB, "Memnite"); // 1/1 creauture - addCard(Zone.BATTLEFIELD, playerB, "Royal Assassin"); - addCard(Zone.BATTLEFIELD, playerB, "Blinking Spirit"); - addCard(Zone.BATTLEFIELD, playerB, "Pearled Unicorn"); + addCard(Zone.BATTLEFIELD, playerB, "Memnite"); // 1/1 + addCard(Zone.BATTLEFIELD, playerB, "Royal Assassin"); // 1/1 + addCard(Zone.BATTLEFIELD, playerB, "Blinking Spirit"); // 2/2 + addCard(Zone.BATTLEFIELD, playerB, "Pearled Unicorn"); // 2/2 addCard(Zone.BATTLEFIELD, playerB, "Island"); addCard(Zone.HAND, playerA, "Fiery Justice"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Fiery Justice"); // 5 damage distributed to any number of targets - addTarget(playerA, "Memnite"); - setChoice(playerA, "X=1"); - addTarget(playerA, "Royal Assassin"); - setChoice(playerA, "X=1"); - addTarget(playerA, "Blinking Spirit"); - setChoice(playerA, "X=1"); - addTarget(playerA, "Pearled Unicorn"); - setChoice(playerA, "X=2");//the unicorn deserves it + addTarget(playerA, "Royal Assassin^X=1"); + addTarget(playerA, "Blinking Spirit^X=2"); + addTarget(playerA, "Pearled Unicorn^X=2"); - - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{UP}: Change a target of target spell or ability to {this}.", "Fiery Justice", "Fiery Justice"); - setChoice(playerA, "No"); - setChoice(playerA, "No"); - setChoice(playerA, "No"); - setChoice(playerA, "Yes"); //of course + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{U/P}: Change a target", "Fiery Justice", "Fiery Justice"); + setChoice(playerB, "Yes"); // pay 2 life + setChoice(playerB, "No"); // skip royal + setChoice(playerB, "No"); // skip blink + setChoice(playerB, "Yes"); // change pearl setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); - assertGraveyardCount(playerB, 3); - assertPermanentCount(playerB, "Pearled Unicorn", 1);//it lives on - assertPowerToughness(playerB, "Spellskite", 0, 2); + assertLife(playerB, 20 + 5 - 2); + assertGraveyardCount(playerB, "Memnite", 0); + assertGraveyardCount(playerB, "Royal Assassin", 1); + assertGraveyardCount(playerB, "Blinking Spirit", 1); + assertGraveyardCount(playerB, "Pearled Unicorn", 0); + assertGraveyardCount(playerB, "Spellskite", 0); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/BrainMaggotTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/BrainMaggotTest.java index 16973a7acb7..f77652b4dd0 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/BrainMaggotTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/BrainMaggotTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.triggers.dies; import mage.constants.PhaseStep; @@ -7,7 +6,6 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class BrainMaggotTest extends CardTestPlayerBase { @@ -16,7 +14,6 @@ public class BrainMaggotTest extends CardTestPlayerBase { * When Brain Maggot enters the battlefield, target opponent reveals his or * her hand and you choose a nonland card from it. Exile that card until * Brain Maggot leaves the battlefield. - * */ @Test public void testCardFromHandWillBeExiled() { @@ -26,10 +23,12 @@ public class BrainMaggotTest extends CardTestPlayerBase { addCard(Zone.HAND, playerB, "Bloodflow Connoisseur", 1); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Brain Maggot"); - addTarget(playerA, "Bloodflow Connoisseur"); + addTarget(playerA, playerB); + setChoice(playerA, "Bloodflow Connoisseur"); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertPermanentCount(playerA, "Brain Maggot", 1); assertExileCount("Bloodflow Connoisseur", 1); @@ -45,12 +44,22 @@ public class BrainMaggotTest extends CardTestPlayerBase { addCard(Zone.HAND, playerB, "Lightning Bolt", 1); addCard(Zone.BATTLEFIELD, playerB, "Mountain", 2); + // exile castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Brain Maggot"); - addTarget(playerA, "Bloodflow Connoisseur"); - castSpell(1, PhaseStep.BEGIN_COMBAT, playerB, "Lightning Bolt", "Brain Maggot"); + addTarget(playerA, playerB); + setChoice(playerA, "Bloodflow Connoisseur"); + showExile("exile", 1, PhaseStep.BEGIN_COMBAT, playerB); + checkExileCount("blood must be in exile", 1, PhaseStep.BEGIN_COMBAT, playerB, "Bloodflow Connoisseur", 1); - setStopAt(1, PhaseStep.DECLARE_ATTACKERS); + // return + castSpell(1, PhaseStep.END_COMBAT, playerB, "Lightning Bolt", "Brain Maggot"); + checkPermanentCount("brain must die", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Brain Maggot", 0); + checkExileCount("blood must return from exile", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Bloodflow Connoisseur", 0); + checkHandCardCount("blood must be in hand", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Bloodflow Connoisseur", 1); + + setStopAt(1, PhaseStep.END_TURN); execute(); + assertAllCommandsUsed(); assertGraveyardCount(playerA, "Brain Maggot", 1); assertGraveyardCount(playerB, "Lightning Bolt", 1); @@ -68,11 +77,14 @@ public class BrainMaggotTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Mountain", 2); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mesmeric Fiend"); - addTarget(playerA, "Bloodflow Connoisseur"); + addTarget(playerA, playerB); + setChoice(playerA, "Bloodflow Connoisseur"); + // castSpell(1, PhaseStep.BEGIN_COMBAT, playerB, "Lightning Bolt", "Mesmeric Fiend"); setStopAt(1, PhaseStep.DECLARE_ATTACKERS); execute(); + assertAllCommandsUsed(); assertGraveyardCount(playerA, "Mesmeric Fiend", 1); assertGraveyardCount(playerB, "Lightning Bolt", 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/OmnathLocusOfRageTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/OmnathLocusOfRageTest.java index 0b7b8221ea9..63bfb1557fb 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/OmnathLocusOfRageTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/OmnathLocusOfRageTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.triggers.dies; import mage.constants.PhaseStep; @@ -7,7 +6,6 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class OmnathLocusOfRageTest extends CardTestPlayerBase { @@ -27,10 +25,10 @@ public class OmnathLocusOfRageTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Diabolic Edict", playerA); - addTarget(playerA, playerB); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertGraveyardCount(playerB, "Diabolic Edict", 1); assertGraveyardCount(playerA, "Omnath, Locus of Rage", 1); @@ -53,12 +51,11 @@ public class OmnathLocusOfRageTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Mountain", 7); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", "Lightning Elemental"); // Dying Lightning Elemental does no longer trigger ability of Omnath - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Blastfire Bolt", "Omnath, Locus of Rage", "Lightning Bolt"); - addTarget(playerA, playerB); - addTarget(playerA, playerB); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Blastfire Bolt", "Omnath, Locus of Rage"); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertGraveyardCount(playerB, "Lightning Bolt", 1); assertGraveyardCount(playerB, "Blastfire Bolt", 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/TidehollowScullerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/TidehollowScullerTest.java index 3551024a717..7661906c858 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/TidehollowScullerTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/TidehollowScullerTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.triggers.dies; import mage.constants.PhaseStep; @@ -7,8 +6,7 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * - * @author LevelX2 + * @author LevelX2, JayDi85 */ public class TidehollowScullerTest extends CardTestPlayerBase { @@ -17,43 +15,104 @@ public class TidehollowScullerTest extends CardTestPlayerBase { * Test if the same Tidehollow Sculler is cast multiple times, the correct * corresponding exiled cards are returned */ + @Test - public void testCardFromHandWillBeExiled() { + public void test_CastOneCardFromHandWillBeExiled() { addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); addCard(Zone.BATTLEFIELD, playerA, "Island", 2); addCard(Zone.BATTLEFIELD, playerA, "Plains", 3); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); // Tidehollow Sculler {W}{B} // When Tidehollow Sculler enters the battlefield, target opponent reveals their hand and you choose a nonland card from it. Exile that card. // When Tidehollow Sculler leaves the battlefield, return the exiled card to its owner's hand. - addCard(Zone.HAND, playerA, "Tidehollow Sculler", 1); - // Boomerang {U}{U} - // Return target creature card from your graveyard to your hand. - addCard(Zone.HAND, playerA, "Boomerang", 1); - // Scout's Warning {W} - // The next creature card you play this turn can be played as though it had flash. - // Draw a card. - addCard(Zone.HAND, playerA, "Scout's Warning", 1); + addCard(Zone.HAND, playerA, "Tidehollow Sculler", 1); // 2/2 + addCard(Zone.HAND, playerA, "Lightning Bolt", 1); // {R} + // + addCard(Zone.HAND, playerB, "Bloodflow Connoisseur", 1); + + // cast and exile from hand + checkHandCardCount("B hand must have blood", 1, PhaseStep.UPKEEP, playerB, "Bloodflow Connoisseur", 1); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Tidehollow Sculler"); + addTarget(playerA, playerB); // choose opponent + setChoice(playerA, "Bloodflow Connoisseur"); // card to exile + checkHandCardCount("B hand must lost blood", 1, PhaseStep.BEGIN_COMBAT, playerB, "Bloodflow Connoisseur", 0); + + // destroy and return card to hand + checkPermanentCount("A must have tide", 1, PhaseStep.END_COMBAT, playerA, "Tidehollow Sculler", 1); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", "Tidehollow Sculler"); + checkPermanentCount("A must lost tide", 1, PhaseStep.END_TURN, playerA, "Tidehollow Sculler", 0); + checkHandCardCount("B must return blood", 1, PhaseStep.END_TURN, playerB, "Bloodflow Connoisseur", 1); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertHandCount(playerB, "Bloodflow Connoisseur", 1); + assertPermanentCount(playerA, "Tidehollow Sculler", 0); + } + + @Test + public void test_CastTwoCardFromHandWillBeExiled() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 3); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); + // Tidehollow Sculler {W}{B} + // When Tidehollow Sculler enters the battlefield, target opponent reveals their hand and you choose a nonland card from it. Exile that card. + // When Tidehollow Sculler leaves the battlefield, return the exiled card to its owner's hand. + addCard(Zone.HAND, playerA, "Tidehollow Sculler@tide", 2); // 2/2 + addCard(Zone.HAND, playerA, "Lightning Bolt", 2); // {R} + // addCard(Zone.HAND, playerB, "Bloodflow Connoisseur", 1); addCard(Zone.HAND, playerB, "Silvercoat Lion", 1); + // turn 1 - A + // cast 1 and exile from hand + checkHandCardCount("B hand must have blood", 1, PhaseStep.UPKEEP, playerB, "Bloodflow Connoisseur", 1); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Tidehollow Sculler"); - addTarget(playerA, "Bloodflow Connoisseur"); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Boomerang", "Tidehollow Sculler"); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Scout's Warning", null, "Boomerang"); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Tidehollow Sculler", null, "", "When {this} leaves the battlefield, return the exiled card to its owner's hand."); - addTarget(playerA, "Silvercoat Lion"); + addTarget(playerA, playerB); // choose opponent + setChoice(playerA, "Bloodflow Connoisseur"); // card to exile + checkHandCardCount("B hand must lost blood", 1, PhaseStep.BEGIN_COMBAT, playerB, "Bloodflow Connoisseur", 0); + // cast 2 and exile from hand + checkHandCardCount("B hand must have lion", 1, PhaseStep.END_COMBAT, playerB, "Silvercoat Lion", 1); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Tidehollow Sculler"); + addTarget(playerA, playerB); // choose opponent + setChoice(playerA, "Silvercoat Lion"); // card to exile + checkHandCardCount("B hand must lost lion", 1, PhaseStep.END_TURN, playerB, "Silvercoat Lion", 0); - setStopAt(1, PhaseStep.BEGIN_COMBAT); + // turn 2 - B + // destroy 1 and return card to hand + checkPermanentCount("A must have 2 tide", 2, PhaseStep.UPKEEP, playerA, "Tidehollow Sculler", 2); + checkHandCardCount("B hand must have 0 blood", 2, PhaseStep.UPKEEP, playerB, "Bloodflow Connoisseur", 0); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "@tide.1"); + showHand("B hand", 2, PhaseStep.BEGIN_COMBAT, playerB); + checkPermanentCount("A must have 1 tide", 2, PhaseStep.BEGIN_COMBAT, playerA, "Tidehollow Sculler", 1); + checkHandCardCount("B hand must have 1 blood", 2, PhaseStep.BEGIN_COMBAT, playerB, "Bloodflow Connoisseur", 1); + // destroy 2 and return card to hand + checkPermanentCount("A must have 1 tide", 2, PhaseStep.END_COMBAT, playerA, "Tidehollow Sculler", 1); + checkHandCardCount("B hand must have 0 lion", 2, PhaseStep.END_COMBAT, playerB, "Silvercoat Lion", 0); + castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", "@tide.2"); + checkPermanentCount("A must have 0 tide", 2, PhaseStep.END_TURN, playerA, "Tidehollow Sculler", 0); + checkHandCardCount("B hand must have 1 lion", 2, PhaseStep.END_TURN, playerB, "Silvercoat Lion", 1); + + setStopAt(2, PhaseStep.END_TURN); execute(); - - assertGraveyardCount(playerA,"Boomerang", 1); - assertGraveyardCount(playerA,"Scout's Warning", 1); - assertHandCount(playerB, "Bloodflow Connoisseur", 0); // never comes back because first Tidehollow Sculler left battlefield before target was exiled - assertHandCount(playerB, "Silvercoat Lion", 0); - assertExileCount("Silvercoat Lion", 1); - - assertPermanentCount(playerA, "Tidehollow Sculler", 1); - + assertAllCommandsUsed(); } + + @Test + public void test_MultipleRuns() { + // test random selection by AI (must use direct select by alias, not AI) + for (int i = 1; i <= 10; i++) { + try { + this.reset(); + System.out.println("run " + i); + test_CastTwoCardFromHandWillBeExiled(); + } catch (Exception e) { + // + } + } + } + } \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/WhisperwoodElementalTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/WhisperwoodElementalTest.java index e2a1849c848..e6a48d117a6 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/WhisperwoodElementalTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/WhisperwoodElementalTest.java @@ -1,6 +1,6 @@ - package org.mage.test.cards.triggers.dies; +import mage.constants.EmptyNames; import mage.constants.PhaseStep; import mage.constants.Zone; import org.junit.Test; @@ -18,7 +18,6 @@ public class WhisperwoodElementalTest extends CardTestPlayerBase { /** * Tests that the dies triggered ability of silvercoat lion (gained by sacrificed Whisperwood Elemental) * triggers as he dies from Ligning Bolt - * */ @Test public void testDiesTriggeredAbility() { @@ -30,17 +29,20 @@ public class WhisperwoodElementalTest extends CardTestPlayerBase { activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sacrifice {this}: Until end of turn, face-up, nontoken creatures you control gain \"When this creature dies, manifest the top card of your library."); castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", "Silvercoat Lion"); + showBattlefield("A battle", 1, PhaseStep.END_TURN, playerA); + showGraveyard("A grave", 1, PhaseStep.END_TURN, playerA); setStopAt(1, PhaseStep.END_TURN); execute(); + assertAllCommandsUsed(); assertLife(playerA, 20); assertLife(playerB, 20); - + assertGraveyardCount(playerA, "Whisperwood Elemental", 1); assertGraveyardCount(playerA, "Silvercoat Lion", 1); // Manifested creature from dying Silvercoat Lion - assertPermanentCount(playerA, "", 1); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/lki/LastKnownInformationTest.java b/Mage.Tests/src/test/java/org/mage/test/lki/LastKnownInformationTest.java index ef914921778..352ec36de59 100644 --- a/Mage.Tests/src/test/java/org/mage/test/lki/LastKnownInformationTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/lki/LastKnownInformationTest.java @@ -58,7 +58,7 @@ public class LastKnownInformationTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Soldier", 2); assertGraveyardCount(playerB, "Lightning Bolt", 2); - assertActionCount(playerB, 0); + assertActionsCount(playerB, 0); } diff --git a/Mage.Tests/src/test/java/org/mage/test/load/SimpleMageClient.java b/Mage.Tests/src/test/java/org/mage/test/load/SimpleMageClient.java index 305b0411066..930f37f2a0d 100644 --- a/Mage.Tests/src/test/java/org/mage/test/load/SimpleMageClient.java +++ b/Mage.Tests/src/test/java/org/mage/test/load/SimpleMageClient.java @@ -16,7 +16,7 @@ import org.apache.log4j.Logger; public class SimpleMageClient implements MageClient { private final UUID clientId; - private static final MageVersion version = new MageVersion(MageVersion.MAGE_VERSION_MAJOR, MageVersion.MAGE_VERSION_MINOR, MageVersion.MAGE_VERSION_PATCH, MageVersion.MAGE_VERSION_MINOR_PATCH, MageVersion.MAGE_VERSION_INFO); + private static final MageVersion version = new MageVersion(MageClient.class); private static final Logger log = Logger.getLogger(SimpleMageClient.class); diff --git a/Mage.Tests/src/test/java/org/mage/test/multiplayer/MyriadTest.java b/Mage.Tests/src/test/java/org/mage/test/multiplayer/MyriadTest.java index 8f93c6ebee3..0538e0c3d67 100644 --- a/Mage.Tests/src/test/java/org/mage/test/multiplayer/MyriadTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/multiplayer/MyriadTest.java @@ -1,7 +1,5 @@ - package org.mage.test.multiplayer; -import java.io.FileNotFoundException; import mage.constants.MultiplayerAttackOption; import mage.constants.PhaseStep; import mage.constants.RangeOfInfluence; @@ -12,8 +10,9 @@ import mage.game.GameException; import org.junit.Test; import org.mage.test.serverside.base.CardTestMultiPlayerBase; +import java.io.FileNotFoundException; + /** - * * @author LevelX2 */ public class MyriadTest extends CardTestMultiPlayerBase { @@ -72,27 +71,32 @@ public class MyriadTest extends CardTestMultiPlayerBase { // Myriad (Whenever this creature attacks, for each opponent other than the defending player, put a token that's a copy of this creature onto the battlefield tapped and attacking that player or a planeswalker he or she controls. Exile those tokens at the end of combat.) addCard(Zone.BATTLEFIELD, playerD, "Caller of the Pack"); // 8/6 + // turns: A, D, C, B + // +1: You gain 2 life. // -1: Put a +1/+1 counter on each creature you control. Those creatures gain vigilance until end of turn. // -6: Create a white Avatar creature token. It has "This creature's power and toughness are each equal to your life total." addCard(Zone.BATTLEFIELD, playerA, "Ajani Goldmane"); + // +2 life activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1:"); + checkLife("must have +2 life", 2, PhaseStep.PRECOMBAT_MAIN, playerA, 40 + 2); + // D attack C, create 2 copy of caller (for each opponent exclude defender = 2) and attack to ajani attack(2, playerD, "Caller of the Pack", playerC); - addTarget(playerD, "Ajani Goldmane"); + addTarget(playerD, "Ajani Goldmane"); // select ajani instead playerA for pack attack + checkPermanentCount("must have 3 packs", 2, PhaseStep.END_COMBAT, playerD, "Caller of the Pack", 3); + checkPermanentCount("ajani must die", 2, PhaseStep.END_COMBAT, playerA, "Ajani Goldmane", 0); + checkLife("pack must not damage playerA", 2, PhaseStep.END_COMBAT, playerA, 40 + 2); + checkLife("pack must damage playerB by 8", 2, PhaseStep.END_COMBAT, playerB, 40 - 8); + checkLife("pack must damage playerC", 2, PhaseStep.END_COMBAT, playerC, 40 - 8); + checkLife("pack must not damage playerD", 2, PhaseStep.END_COMBAT, playerD, 40); setStopAt(2, PhaseStep.POSTCOMBAT_MAIN); execute(); assertPermanentCount(playerD, "Caller of the Pack", 1); assertGraveyardCount(playerA, "Ajani Goldmane", 1); - - assertLife(playerA, 42); - assertLife(playerB, 32); - assertLife(playerC, 32); - assertLife(playerD, 40); - } /** diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer.java new file mode 100644 index 00000000000..7e9d8b2cf14 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer.java @@ -0,0 +1,73 @@ +package org.mage.test.player; + +import mage.MageObject; +import mage.abilities.ActivatedAbility; +import mage.abilities.SpellAbility; +import mage.constants.Outcome; +import mage.constants.RangeOfInfluence; +import mage.game.Game; +import mage.player.ai.ComputerPlayer; +import mage.target.Target; + +import java.util.LinkedHashMap; +import java.util.UUID; + +/** + * @author JayDi85 + */ + +// mock class to override to override AI logic for test +public class TestComputerPlayer extends ComputerPlayer { + + private TestPlayer testPlayerLink; + + public TestComputerPlayer(String name, RangeOfInfluence range) { + super(name, range); + } + + public void setTestPlayerLink(TestPlayer testPlayerLink) { + this.testPlayerLink = testPlayerLink; + } + + @Override + public SpellAbility chooseSpellAbilityForCast(SpellAbility ability, Game game, boolean noMana) { + // copy-paste for TestComputerXXX + + // workaround to cast fused cards in tests by it's NAMES (Wear, Tear, Wear // Tear) + // reason: TestPlayer uses outer computerPlayer to cast, not TestPlayer + switch (ability.getSpellAbilityType()) { + case SPLIT: + case SPLIT_FUSED: + case SPLIT_AFTERMATH: + if (!this.testPlayerLink.getChoices().isEmpty()) { + MageObject object = game.getObject(ability.getSourceId()); + if (object != null) { + LinkedHashMap useableAbilities = this.getSpellAbilities(object, game.getState().getZone(object.getId()), game); + + // left, right or fused cast + for (String choose : this.testPlayerLink.getChoices()) { + for (ActivatedAbility activatedAbility : useableAbilities.values()) { + if (activatedAbility instanceof SpellAbility) { + if (((SpellAbility) activatedAbility).getCardName().equals(choose)) { + return (SpellAbility) activatedAbility; + } + } + } + } + } + } + } + + // default implementation by AI + return super.chooseSpellAbilityForCast(ability, game, noMana); + } + + @Override + public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game) { + // copy-paste for TestComputerXXX + + // workaround for discard spells + // reason: TestPlayer uses outer computerPlayer to discard but inner code uses choose + return testPlayerLink.choose(outcome, target, sourceId, game); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer7.java b/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer7.java new file mode 100644 index 00000000000..e647128bb6c --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer7.java @@ -0,0 +1,73 @@ +package org.mage.test.player; + +import mage.MageObject; +import mage.abilities.ActivatedAbility; +import mage.abilities.SpellAbility; +import mage.constants.Outcome; +import mage.constants.RangeOfInfluence; +import mage.game.Game; +import mage.player.ai.ComputerPlayer7; +import mage.target.Target; + +import java.util.LinkedHashMap; +import java.util.UUID; + +/** + * @author JayDi85 + */ + +// mock class to override AI logic in tests +public class TestComputerPlayer7 extends ComputerPlayer7 { + + private TestPlayer testPlayerLink; + + public TestComputerPlayer7(String name, RangeOfInfluence range, int skill) { + super(name, range, skill); + } + + public void setTestPlayerLink(TestPlayer testPlayerLink) { + this.testPlayerLink = testPlayerLink; + } + + @Override + public SpellAbility chooseSpellAbilityForCast(SpellAbility ability, Game game, boolean noMana) { + // copy-paste for TestComputerXXX + + // workaround to cast fused cards in tests by it's NAMES (Wear, Tear, Wear // Tear) + // reason: TestPlayer uses outer computerPlayer to cast, not TestPlayer + switch (ability.getSpellAbilityType()) { + case SPLIT: + case SPLIT_FUSED: + case SPLIT_AFTERMATH: + if (!this.testPlayerLink.getChoices().isEmpty()) { + MageObject object = game.getObject(ability.getSourceId()); + if (object != null) { + LinkedHashMap useableAbilities = this.getSpellAbilities(object, game.getState().getZone(object.getId()), game); + + // left, right or fused cast + for (String choose : this.testPlayerLink.getChoices()) { + for (ActivatedAbility activatedAbility : useableAbilities.values()) { + if (activatedAbility instanceof SpellAbility) { + if (((SpellAbility) activatedAbility).getCardName().equals(choose)) { + return (SpellAbility) activatedAbility; + } + } + } + } + } + } + } + + // default implementation by AI + return super.chooseSpellAbilityForCast(ability, game, noMana); + } + + @Override + public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game) { + // copy-paste for TestComputerXXX + + // workaround for discard spells + // reason: TestPlayer uses outer computerPlayer to discard but inner code uses choose + return testPlayerLink.choose(outcome, target, sourceId, game); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index ae5cdf3ca3f..afdbc2270e0 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -1,5 +1,6 @@ package org.mage.test.player; +import mage.MageItem; import mage.MageObject; import mage.MageObjectReference; import mage.ObjectColor; @@ -43,10 +44,10 @@ import mage.player.ai.ComputerPlayer; import mage.players.Library; import mage.players.ManaPool; import mage.players.Player; -import mage.players.PlayerList; import mage.players.net.UserData; import mage.target.*; import mage.target.common.*; +import mage.util.CardUtil; import org.apache.log4j.Logger; import org.junit.Assert; import org.junit.Ignore; @@ -55,6 +56,7 @@ import java.io.Serializable; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; import static org.mage.test.serverside.base.impl.CardTestPlayerAPIImpl.*; @@ -68,12 +70,15 @@ public class TestPlayer implements Player { private static final Logger logger = Logger.getLogger(TestPlayer.class); + public static final String TARGET_SKIP = "[skip]"; + private int maxCallsWithoutAction = 100; private int foundNoAction = 0; private boolean AIPlayer; private final List actions = new ArrayList<>(); - private final List choices = new ArrayList<>(); - private final List targets = new ArrayList<>(); + private final List choices = new ArrayList<>(); // choices stack for choice + private final List targets = new ArrayList<>(); // targets stack for choose (it's uses on empty direct target by cast command) + private final Map aliases = new HashMap<>(); // aliases for game objects/players (use it for cards with same name to save and use) private final List modesSet = new ArrayList<>(); private final ComputerPlayer computerPlayer; @@ -84,9 +89,16 @@ public class TestPlayer implements Player { // Before actual turns start. Needed for checking attacker/blocker legality in the tests private static int initialTurns = 0; - public TestPlayer(ComputerPlayer computerPlayer) { + public TestPlayer(TestComputerPlayer computerPlayer) { this.computerPlayer = computerPlayer; AIPlayer = false; + computerPlayer.setTestPlayerLink(this); + } + + public TestPlayer(TestComputerPlayer7 computerPlayer) { + this.computerPlayer = computerPlayer; + AIPlayer = false; + computerPlayer.setTestPlayerLink(this); } public TestPlayer(final TestPlayer testPlayer) { @@ -95,6 +107,7 @@ public class TestPlayer implements Player { this.actions.addAll(testPlayer.actions); this.choices.addAll(testPlayer.choices); this.targets.addAll(testPlayer.targets); + this.aliases.putAll(testPlayer.aliases); this.modesSet.addAll(testPlayer.modesSet); this.computerPlayer = testPlayer.computerPlayer.copy(); if (testPlayer.groupsForTargetHandling != null) { @@ -106,6 +119,26 @@ public class TestPlayer implements Player { choices.add(choice); } + public List getChoices() { + return this.choices; + } + + public List getTargets() { + return this.targets; + } + + public Map getAliases() { + return this.aliases; + } + + public UUID getAliasByName(String searchName) { + if (searchName.startsWith("@")) { + return this.aliases.getOrDefault(searchName.substring(1), null); + } else { + return this.aliases.getOrDefault(searchName, null); + } + } + public void addModeChoice(String mode) { modesSet.add(mode); } @@ -114,6 +147,10 @@ public class TestPlayer implements Player { targets.add(target); } + public void addAlias(String name, UUID Id) { + aliases.put(name, Id); + } + public ManaOptions getAvailableManaTest(Game game) { return computerPlayer.getManaAvailable(game); } @@ -184,7 +221,7 @@ public class TestPlayer implements Player { filteredName = indexedMatcher.group(1); index = Integer.valueOf(indexedMatcher.group(2)); } - filter.add(new NamePredicate(filteredName)); + filter.add(new NamePredicate(filteredName, true)); // must find any cards even without names List allPermanents = game.getBattlefield().getAllActivePermanents(filter, controllerID, game); if (allPermanents.isEmpty()) { if (failOnNotFound) { @@ -299,6 +336,31 @@ public class TestPlayer implements Player { return result; } + public String generateAliasName(String baseAlias, boolean useMiltiNames, int iteration) { + if (useMiltiNames) { + return baseAlias + "." + iteration; + } else { + return baseAlias; + } + } + + private boolean isObjectHaveTargetNameOrAliase(MageObject object, String nameOrAliase) { + if (object == null || nameOrAliase == null) { + return false; + } + + if (nameOrAliase.startsWith("@") && object.getId().equals(getAliasByName(nameOrAliase))) { + return true; + } + + // must search any names, even empty + if (CardUtil.haveSameNames(nameOrAliase, object.getName(), true)) { + return true; + } + + return object.getName().startsWith(nameOrAliase); + } + private boolean handleNonPlayerTargetTarget(String target, Ability ability, Game game) { boolean result = true; if (target == null) { @@ -360,28 +422,46 @@ public class TestPlayer implements Player { for (UUID id : currentTarget.possibleTargets(ability.getSourceId(), ability.getControllerId(), game)) { if (!currentTarget.getTargets().contains(id)) { MageObject object = game.getObject(id); - if (object != null - && ((object.isCopy() && !originOnly) || (!object.isCopy() && !copyOnly)) - && ((!targetName.isEmpty() && object.getName().startsWith(targetName)) || (targetName.isEmpty() && object.getName().isEmpty()))) { - if (currentTarget.getNumberOfTargets() == 1) { - currentTarget.clearChosen(); - } - if (currentTarget instanceof TargetCreaturePermanentAmount) { - // supports only to set the complete amount to one target - TargetCreaturePermanentAmount targetAmount = (TargetCreaturePermanentAmount) currentTarget; - targetAmount.setAmount(ability, game); - int amount = targetAmount.getAmountRemaining(); - targetAmount.addTarget(id, amount, ability, game); - targetsSet++; - } else { - currentTarget.addTarget(id, ability, game); - targetsSet++; - } - if (currentTarget.getTargets().size() == currentTarget.getMaxNumberOfTargets()) { - index++; - } - break; + + if (object == null) { + continue; } + + // only origin + if (originOnly && object.isCopy()) { + continue; + } + + // only copy + if (copyOnly && !object.isCopy()) { + continue; + } + + // need by alias or by name + if (!isObjectHaveTargetNameOrAliase(object, targetName)) { + continue; + } + + // founded, can use as target + + if (currentTarget.getNumberOfTargets() == 1) { + currentTarget.clearChosen(); + } + if (currentTarget instanceof TargetCreaturePermanentAmount) { + // supports only to set the complete amount to one target + TargetCreaturePermanentAmount targetAmount = (TargetCreaturePermanentAmount) currentTarget; + targetAmount.setAmount(ability, game); + int amount = targetAmount.getAmountRemaining(); + targetAmount.addTarget(id, amount, ability, game); + targetsSet++; + } else { + currentTarget.addTarget(id, ability, game); + targetsSet++; + } + if (currentTarget.getTargets().size() == currentTarget.getMaxNumberOfTargets()) { + index++; + } + break; } } } @@ -435,6 +515,8 @@ public class TestPlayer implements Player { groupsForTargetHandling = null; } } + // TODO: fix wrong commands (on non existing card), it's HUGE (350+ failed tests with wrong commands) + //Assert.fail("Can't find ability to activate command: " + command); } else if (action.getAction().startsWith("manaActivate:")) { String command = action.getAction(); command = command.substring(command.indexOf("manaActivate:") + 13); @@ -515,78 +597,168 @@ public class TestPlayer implements Player { } } else if (action.getAction().startsWith("check:")) { String command = action.getAction(); - command = command.substring(command.indexOf("check:") + 6); + command = command.substring(command.indexOf("check:") + "check:".length()); String[] params = command.split("@"); - boolean checkProccessed = false; + boolean wasProccessed = false; if (params.length > 0) { // check PT: card name, P, T if (params[0].equals(CHECK_COMMAND_PT) && params.length == 4) { assertPT(action, game, computerPlayer, params[1], Integer.parseInt(params[2]), Integer.parseInt(params[3])); actions.remove(action); - checkProccessed = true; + wasProccessed = true; } - // check PT: life + // check life: life if (params[0].equals(CHECK_COMMAND_LIFE) && params.length == 2) { assertLife(action, game, computerPlayer, Integer.parseInt(params[1])); actions.remove(action); - checkProccessed = true; + wasProccessed = true; } // check ability: card name, ability class, must have if (params[0].equals(CHECK_COMMAND_ABILITY) && params.length == 4) { assertAbility(action, game, computerPlayer, params[1], params[2], Boolean.parseBoolean(params[3])); actions.remove(action); - checkProccessed = true; + wasProccessed = true; } // check battlefield count: card name, count if (params[0].equals(CHECK_COMMAND_PERMANENT_COUNT) && params.length == 3) { assertPermanentCount(action, game, computerPlayer, params[1], Integer.parseInt(params[2])); actions.remove(action); - checkProccessed = true; + wasProccessed = true; } // check exile count: card name, count if (params[0].equals(CHECK_COMMAND_EXILE_COUNT) && params.length == 3) { assertExileCount(action, game, computerPlayer, params[1], Integer.parseInt(params[2])); actions.remove(action); - checkProccessed = true; + wasProccessed = true; } // check hand count: count if (params[0].equals(CHECK_COMMAND_HAND_COUNT) && params.length == 2) { assertHandCount(action, game, computerPlayer, Integer.parseInt(params[1])); actions.remove(action); - checkProccessed = true; + wasProccessed = true; + } + + // check hand card count: card name, count + if (params[0].equals(CHECK_COMMAND_HAND_CARD_COUNT) && params.length == 3) { + assertHandCardCount(action, game, computerPlayer, params[1], Integer.parseInt(params[2])); + actions.remove(action); + wasProccessed = true; } // check color: card name, colors, must have if (params[0].equals(CHECK_COMMAND_COLOR) && params.length == 4) { assertColor(action, game, computerPlayer, params[1], params[2], Boolean.parseBoolean(params[3])); actions.remove(action); - checkProccessed = true; + wasProccessed = true; } // check subtype: card name, subtype, must have if (params[0].equals(CHECK_COMMAND_SUBTYPE) && params.length == 4) { assertSubType(action, game, computerPlayer, params[1], SubType.fromString(params[2]), Boolean.parseBoolean(params[3])); actions.remove(action); - checkProccessed = true; + wasProccessed = true; } // check mana pool: colors, amount if (params[0].equals(CHECK_COMMAND_MANA_POOL) && params.length == 3) { assertManaPool(action, game, computerPlayer, params[1], Integer.parseInt(params[2])); actions.remove(action); - checkProccessed = true; + wasProccessed = true; + } + + // check aliase at zone: alias name, zone, must have (only for TestPlayer) + if (params[0].equals(CHECK_COMMAND_ALIAS_ZONE) && params.length == 4) { + assertAliasZone(action, game, this, params[1], Zone.valueOf(params[2]), Boolean.parseBoolean(params[3])); + actions.remove(action); + wasProccessed = true; + } + } + if (!wasProccessed) { + Assert.fail("Unknow check command or params: " + command); + } + } else if (action.getAction().startsWith("show:")) { + String command = action.getAction(); + command = command.substring(command.indexOf("show:") + "show:".length()); + + String[] params = command.split("@"); + boolean wasProccessed = false; + if (params.length > 0) { + + // show library + if (params[0].equals(SHOW_COMMAND_LIBRARY) && params.length == 1) { + printStart(action.getActionName()); + printCards(computerPlayer.getLibrary().getCards(game)); + printEnd(); + actions.remove(action); + wasProccessed = true; + } + + // show hand + if (params[0].equals(SHOW_COMMAND_HAND) && params.length == 1) { + printStart(action.getActionName()); + printCards(computerPlayer.getHand().getCards(game)); + printEnd(); + actions.remove(action); + wasProccessed = true; + } + + // show battlefield + if (params[0].equals(SHOW_COMMAND_BATTLEFIELD) && params.length == 1) { + printStart(action.getActionName()); + printPermanents(game.getBattlefield().getAllActivePermanents(computerPlayer.getId())); + printEnd(); + actions.remove(action); + wasProccessed = true; + } + + // show graveyard + if (params[0].equals(SHOW_COMMAND_GRAVEYEARD) && params.length == 1) { + printStart(action.getActionName()); + printCards(computerPlayer.getGraveyard().getCards(game)); + printEnd(); + actions.remove(action); + wasProccessed = true; + } + + // show exile + if (params[0].equals(SHOW_COMMAND_EXILE) && params.length == 1) { + printStart(action.getActionName()); + printCards(game.getExile().getAllCards(game).stream() + .filter(card -> card.isOwnedBy(computerPlayer.getId())) + .collect(Collectors.toList())); + printEnd(); + actions.remove(action); + wasProccessed = true; + } + + // show available abilities + if (params[0].equals(SHOW_COMMAND_AVAILABLE_ABILITIES) && params.length == 1) { + printStart(action.getActionName()); + printAbilities(game, computerPlayer.getPlayable(game, true)); + printEnd(); + actions.remove(action); + wasProccessed = true; + } + + // show aliases + if (params[0].equals(SHOW_COMMAND_ALIASES) && params.length == 1) { + printStart(action.getActionName()); + printAliases(game, this); + printEnd(); + actions.remove(action); + wasProccessed = true; } } - if (!checkProccessed) { - Assert.fail("Unknow check command or params: " + command); + if (!wasProccessed) { + Assert.fail("Unknow show command or params: " + command); } } } @@ -619,6 +791,105 @@ public class TestPlayer implements Player { return null; } + private void printStart(String name) { + System.out.println("\n" + name + ":"); + } + + private void printEnd() { + System.out.println(); + } + + private void printCards(Set cards) { + printCards(cards.stream().collect(Collectors.toList())); + } + + private void printCards(List cards) { + System.out.println("Total cards: " + cards.size()); + + List data = cards.stream() + .map(Card::getIdName) + .sorted() + .collect(Collectors.toList()); + + for (String s : data) { + System.out.println(s); + } + } + + private void printPermanents(List cards) { + System.out.println("Total permanents: " + cards.size()); + + List data = cards.stream() + .map(c -> (c.getIdName() + + " - " + c.getPower().getValue() + + "/" + c.getToughness().getValue() + + ", " + (c.isTapped() ? "Tapped" : "Untapped") + )) + .sorted() + .collect(Collectors.toList()); + + for (String s : data) { + System.out.println(s); + } + } + + private void printAbilities(Game game, List abilities) { + + + System.out.println("Total abilities: " + (abilities != null ? abilities.size() : 0)); + if (abilities == null) { + return; + } + + List data = abilities.stream() + .map(a -> ( + a.getZone() + " -> " + + a.getSourceObject(game).getIdName() + " -> " + + (a.getRule().length() > 0 + ? a.getRule().substring(0, Math.min(20, a.getRule().length()) - 1) + : a.getClass().getSimpleName()) + + "..." + )) + .sorted() + .collect(Collectors.toList()); + + for (String s : data) { + System.out.println(s); + } + } + + + private String getAliasInfo(Game game, TestPlayer player, String aliasName) { + MageItem item = findAliasObject(game, player, aliasName); + if (item == null) { + return aliasName + " [not exists]"; + } + + if (item instanceof MageObject) { + Zone zone = game.getState().getZone(item.getId()); + return aliasName + " - " + ((MageObject) item).getIdName() + " - " + (zone != null ? zone.toString() : "null"); + } + + if (item instanceof Player) { + return aliasName + " - " + ((Player) item).getName(); + } + + return aliasName + " [unknown object " + item.getId() + "]"; + } + + private void printAliases(Game game, TestPlayer player) { + System.out.println("Total aliases: " + player.getAliases().size()); + + List data = player.getAliases().entrySet().stream() + .map(entry -> (getAliasInfo(game, player, entry.getKey()))) + .sorted() + .collect(Collectors.toList()); + + for (String s : data) { + System.out.println(s); + } + } + private void assertPT(PlayerAction action, Game game, Player player, String permanentName, int Power, int Toughness) { Permanent perm = findPermanentWithAssert(action, game, player, permanentName); @@ -677,6 +948,18 @@ public class TestPlayer implements Player { Assert.assertEquals(action.getActionName() + " - hand must contain " + count, count, player.getHand().size()); } + private void assertHandCardCount(PlayerAction action, Game game, Player player, String cardName, int count) { + int realCount = 0; + for (UUID cardId : player.getHand()) { + Card card = game.getCard(cardId); + if (card != null && card.getName().equals(cardName)) { + realCount++; + } + } + + Assert.assertEquals(action.getActionName() + " - hand must contain " + count + " cards of " + cardName, count, realCount); + } + private void assertColor(PlayerAction action, Game game, Player player, String permanentName, String colors, boolean mustHave) { Assert.assertNotEquals(action.getActionName() + " - must setup colors", "", colors); @@ -721,6 +1004,36 @@ public class TestPlayer implements Player { } } + private MageItem findAliasObject(Game game, TestPlayer player, String aliasName) { + UUID objectId = player.getAliasByName(aliasName); + if (objectId == null) { + return null; + } + + MageObject itemObject = game.getObject(objectId); + if (itemObject != null) { + return itemObject; + } + + Player itemPlayer = game.getPlayer(objectId); + if (itemPlayer != null) { + return itemPlayer; + } + + return null; + } + + private void assertAliasZone(PlayerAction action, Game game, TestPlayer player, String aliasName, Zone needZone, boolean mustHave) { + MageItem item = findAliasObject(game, player, aliasName); + Zone currentZone = (item == null ? null : game.getState().getZone(item.getId())); + + if (mustHave) { + Assert.assertEquals(action.getActionName() + " - alias " + aliasName + " must have zone " + needZone.toString(), needZone, currentZone); + } else { + Assert.assertNotEquals(action.getActionName() + " - alias " + aliasName + " must have not zone " + needZone.toString(), needZone, currentZone); + } + } + private void assertManaPoolInner(PlayerAction action, Player player, ManaType manaType, Integer amount) { Integer current = player.getManaPool().get(manaType); Assert.assertEquals(action.getActionName() + " - mana pool must contain [" + amount.toString() + " " + manaType.toString() + "], but found [" + current.toString() + "]", amount, current); @@ -966,6 +1279,8 @@ public class TestPlayer implements Player { if (choice.setChoiceByAnswers(choices, true)) { return true; } + // TODO: enable fail checks and fix tests + //Assert.fail("Wrong choice"); } return computerPlayer.choose(outcome, choice, game); } @@ -981,6 +1296,8 @@ public class TestPlayer implements Player { } } } + // TODO: enable fail checks and fix tests + //Assert.fail("wrong choice"); } return computerPlayer.chooseReplacementEffect(rEffects, game); } @@ -988,11 +1305,16 @@ public class TestPlayer implements Player { @Override public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game, Map options) { if (!choices.isEmpty()) { + + List usedChoices = new ArrayList<>(); + List usedTargets = new ArrayList<>(); + Ability source = null; StackObject stackObject = game.getStack().getStackObject(sourceId); if (stackObject != null) { source = stackObject.getStackAbility(); } + if ((target instanceof TargetPermanent) || (target instanceof TargetPermanentOrPlayer)) { // player target not implemted yet FilterPermanent filterPermanent; if (target instanceof TargetPermanentOrPlayer) { @@ -1046,6 +1368,7 @@ public class TestPlayer implements Player { } } } + if (target instanceof TargetPlayer) { for (Player player : game.getPlayers().values()) { for (String choose2 : choices) { @@ -1059,42 +1382,74 @@ public class TestPlayer implements Player { } } } + + // TODO: add same choices fixes for other target types (one choice must uses only one time for one target) if (target instanceof TargetCard) { - TargetCard targetCard = ((TargetCard) target); - Set possibleTargets = targetCard.possibleTargets(sourceId, target.getTargetController() == null ? getId() : target.getTargetController(), game); - for (String choose2 : choices) { - String[] targetList = choose2.split("\\^"); + // one choice per target + // only unique targets + //TargetCard targetFull = ((TargetCard) target); + + usedChoices.clear(); + usedTargets.clear(); + boolean targetCompleted = false; + + CheckAllChoices: + for (String choiceRecord : choices) { + if (targetCompleted) { + break CheckAllChoices; + } + boolean targetFound = false; - Choice: - for (String targetName : targetList) { - for (UUID targetId : possibleTargets) { + String[] possibleChoices = choiceRecord.split("\\^"); + + CheckOneChoice: + for (String possibleChoice : possibleChoices) { + Set possibleCards = target.possibleTargets(sourceId, target.getTargetController() == null ? getId() : target.getTargetController(), game); + CheckTargetsList: + for (UUID targetId : possibleCards) { MageObject targetObject = game.getObject(targetId); - if (targetObject != null) { - if (targetObject.getName().equals(targetName)) { - if (targetCard.canTarget(targetObject.getId(), game)) { - if (targetCard.getTargets() != null && !targetCard.getTargets().contains(targetObject.getId())) { - targetCard.add(targetObject.getId(), game); - targetFound = true; - if (target.getTargets().size() >= target.getMaxNumberOfTargets()) { - break Choice; - } - } + if (targetObject != null && targetObject.getName().equals(possibleChoice)) { + if (target.canTarget(targetObject.getId(), game)) { + // only unique targets + if (usedTargets.contains(targetObject.getId())) { + continue; } + + // OK, can use it + target.add(targetObject.getId(), game); + targetFound = true; + usedTargets.add(targetObject.getId()); + + // break on full targets list + if (target.getTargets().size() >= target.getMaxNumberOfTargets()) { + targetCompleted = true; + break CheckOneChoice; + } + + // restart search + break CheckTargetsList; } } - } } + if (targetFound) { - if (targetCard.isChosen()) { - choices.remove(choose2); - return true; - } else { - target.clearChosen(); - } + usedChoices.add(choiceRecord); + } + } + + // apply only on ALL targets or revert + if (usedChoices.size() > 0) { + if (target.isChosen()) { + choices.removeAll(usedChoices); + return true; + } else { + Assert.fail("Not full targets list."); + target.clearChosen(); } } } + if (target instanceof TargetSource) { Set possibleTargets; TargetSource t = ((TargetSource) target); @@ -1125,11 +1480,40 @@ public class TestPlayer implements Player { } } } + + // TODO: enable fail checks and fix tests + /* + if (!target.getTargetName().equals("starting player")) { + Assert.fail("Wrong choice"); + } + */ } return computerPlayer.choose(outcome, target, sourceId, game, options); } + private void checkTargetDefinitionMarksSupport(Target needTarget, String targetDefinition, String canSupportChars) { + // fail on wrong chars in definition + // ^ - multiple targets + // [] - special option like [no copy] + // = - target type like targetPlayer=PlayerA + Boolean foundMulti = targetDefinition.contains("^"); + Boolean foundSpecialStart = targetDefinition.contains("["); + Boolean foundSpecialClose = targetDefinition.contains("]"); + Boolean foundEquals = targetDefinition.contains("="); + + Boolean canMulti = canSupportChars.contains("^"); + Boolean canSpecialStart = canSupportChars.contains("["); + Boolean canSpecialClose = canSupportChars.contains("]"); + Boolean canEquals = canSupportChars.contains("="); + + // how to fix: change target definition for addTarget in test's code or update choose from targets implementation in TestPlayer + if ((foundMulti && !canMulti) || (foundSpecialStart && !canSpecialStart) || (foundSpecialClose && !canSpecialClose) || (foundEquals && !canEquals)) { + Assert.fail("Targets list was setup by addTarget with " + targets + ", but target definition [" + targetDefinition + "]" + + " is not supported by [" + canSupportChars + "] for target class " + needTarget.getClass().getSimpleName()); + } + } + @Override public boolean chooseTarget(Outcome outcome, Target target, Ability source, Game game) { if (!targets.isEmpty()) { @@ -1137,11 +1521,22 @@ public class TestPlayer implements Player { if (target.getTargetController() != null && target.getAbilityController() != null) { abilityControllerId = target.getAbilityController(); } + + // do not select + if (targets.get(0).equals(TARGET_SKIP)) { + Assert.assertEquals("found empty choice, but target is not support 0 choice", 0, target.getMinNumberOfTargets()); + targets.remove(0); + return true; + } + + // player if (target instanceof TargetPlayer || target instanceof TargetAnyTarget || target instanceof TargetCreatureOrPlayer - || target instanceof TargetPermanentOrPlayer) { + || target instanceof TargetPermanentOrPlayer + || target instanceof TargetDefender) { for (String targetDefinition : targets) { + checkTargetDefinitionMarksSupport(target, targetDefinition, "="); if (targetDefinition.startsWith("targetPlayer=")) { String playerName = targetDefinition.substring(targetDefinition.indexOf("targetPlayer=") + 13); for (Player player : game.getPlayers().values()) { @@ -1156,11 +1551,15 @@ public class TestPlayer implements Player { } } + + // permanent in battlefield if ((target instanceof TargetPermanent) || (target instanceof TargetPermanentOrPlayer) || (target instanceof TargetAnyTarget) - || (target instanceof TargetCreatureOrPlayer)) { + || (target instanceof TargetCreatureOrPlayer) + || (target instanceof TargetDefender)) { for (String targetDefinition : targets) { + checkTargetDefinitionMarksSupport(target, targetDefinition, "^[]"); String[] targetList = targetDefinition.split("\\^"); boolean targetFound = false; for (String targetName : targetList) { @@ -1183,8 +1582,11 @@ public class TestPlayer implements Player { if (filter instanceof FilterCreaturePlayerOrPlaneswalker) { filter = ((FilterCreaturePlayerOrPlaneswalker) filter).getCreatureFilter(); } - if (filter instanceof TargetPermanentOrPlayer) { - filter = ((TargetPermanentOrPlayer) filter).getFilterPermanent(); + if (filter instanceof FilterPermanentOrPlayer) { + filter = ((FilterPermanentOrPlayer) filter).getPermanentFilter(); + } + if (filter instanceof FilterPlaneswalkerOrPlayer) { + filter = ((FilterPlaneswalkerOrPlayer) filter).getFilterPermanent(); } for (Permanent permanent : game.getBattlefield().getAllActivePermanents((FilterPermanent) filter, game)) { if (permanent.getName().equals(targetName) || (permanent.getName() + '-' + permanent.getExpansionSetCode()).equals(targetName)) { @@ -1206,8 +1608,10 @@ public class TestPlayer implements Player { } } + // card in hand if (target instanceof TargetCardInHand) { for (String targetDefinition : targets) { + checkTargetDefinitionMarksSupport(target, targetDefinition, "^"); String[] targetList = targetDefinition.split("\\^"); boolean targetFound = false; for (String targetName : targetList) { @@ -1226,17 +1630,20 @@ public class TestPlayer implements Player { return true; } } - } - if (target instanceof TargetCardInYourGraveyard) { + + // card in exile + if (target instanceof TargetCardInExile) { + TargetCardInExile targetFull = (TargetCardInExile) target; for (String targetDefinition : targets) { + checkTargetDefinitionMarksSupport(target, targetDefinition, "^"); String[] targetList = targetDefinition.split("\\^"); boolean targetFound = false; for (String targetName : targetList) { - for (Card card : computerPlayer.getGraveyard().getCards(((TargetCardInYourGraveyard) target).getFilter(), game)) { + for (Card card : game.getExile().getCards(targetFull.getFilter(), game)) { if (card.getName().equals(targetName) || (card.getName() + '-' + card.getExpansionSetCode()).equals(targetName)) { - if (((TargetCardInYourGraveyard) target).canTarget(abilityControllerId, card.getId(), source, game) && !target.getTargets().contains(card.getId())) { - target.add(card.getId(), game); + if (targetFull.canTarget(abilityControllerId, card.getId(), source, game) && !targetFull.getTargets().contains(card.getId())) { + targetFull.add(card.getId(), game); targetFound = true; break; } @@ -1248,26 +1655,22 @@ public class TestPlayer implements Player { return true; } } - } - if (target instanceof TargetCardInOpponentsGraveyard) { + + // card in battlefield + if (target instanceof TargetCardInGraveyardOrBattlefield) { + TargetCard targetFull = (TargetCard) target; for (String targetDefinition : targets) { + checkTargetDefinitionMarksSupport(target, targetDefinition, "^"); String[] targetList = targetDefinition.split("\\^"); boolean targetFound = false; - for (String targetName : targetList) { - IterateOpponentsGraveyards: - for (UUID opponentId : game.getState().getPlayersInRange(getId(), game)) { - if (computerPlayer.hasOpponent(opponentId, game)) { - Player opponent = game.getPlayer(opponentId); - for (Card card : opponent.getGraveyard().getCards(((TargetCardInOpponentsGraveyard) target).getFilter(), game)) { - if (card.getName().equals(targetName) || (card.getName() + '-' + card.getExpansionSetCode()).equals(targetName)) { - if (((TargetCardInOpponentsGraveyard) target).canTarget(abilityControllerId, card.getId(), source, game) && !target.getTargets().contains(card.getId())) { - target.add(card.getId(), game); - targetFound = true; - break IterateOpponentsGraveyards; - } - } + for (Card card : game.getBattlefield().getAllActivePermanents()) { + if (card.getName().equals(targetName) || (card.getName() + '-' + card.getExpansionSetCode()).equals(targetName)) { + if (targetFull.canTarget(abilityControllerId, card.getId(), source, game) && !targetFull.getTargets().contains(card.getId())) { + targetFull.add(card.getId(), game); + targetFound = true; + break; } } } @@ -1277,10 +1680,67 @@ public class TestPlayer implements Player { return true; } } + } + + + // card in graveyard + if (target instanceof TargetCardInOpponentsGraveyard + || target instanceof TargetCardInYourGraveyard + || target instanceof TargetCardInGraveyard + || target instanceof TargetCardInGraveyardOrBattlefield) { + TargetCard targetFull = (TargetCard) target; + + List needPlayers = game.getState().getPlayersInRange(getId(), game).toList(); + // fix for opponent graveyard + if (target instanceof TargetCardInOpponentsGraveyard) { + // current player remove + Assert.assertTrue(needPlayers.contains(getId())); + needPlayers.remove(getId()); + Assert.assertFalse(needPlayers.contains(getId())); + } + // fix for your graveyard + if (target instanceof TargetCardInYourGraveyard) { + // only current player + Assert.assertTrue(needPlayers.contains(getId())); + needPlayers.clear(); + needPlayers.add(getId()); + Assert.assertEquals(1, needPlayers.size()); + } + + for (String targetDefinition : targets) { + checkTargetDefinitionMarksSupport(target, targetDefinition, "^"); + + String[] targetList = targetDefinition.split("\\^"); + boolean targetFound = false; + for (String targetName : targetList) { + IterateGraveyards: + for (UUID playerId : needPlayers) { + Player player = game.getPlayer(playerId); + for (Card card : player.getGraveyard().getCards(targetFull.getFilter(), game)) { + if (card.getName().equals(targetName) || (card.getName() + '-' + card.getExpansionSetCode()).equals(targetName)) { + if (targetFull.canTarget(abilityControllerId, card.getId(), source, game) && !target.getTargets().contains(card.getId())) { + target.add(card.getId(), game); + targetFound = true; + break IterateGraveyards; + } + } + } + + } + } + + if (targetFound) { + targets.remove(targetDefinition); + return true; + } + } } + + // stack if (target instanceof TargetSpell) { for (String targetDefinition : targets) { + checkTargetDefinitionMarksSupport(target, targetDefinition, "^"); String[] targetList = targetDefinition.split("\\^"); boolean targetFound = false; for (String targetName : targetList) { @@ -1298,8 +1758,28 @@ public class TestPlayer implements Player { } } } - } + + // wrong target settings by addTarget + // how to fix: implement target class processing above + if (!targets.isEmpty()) { + String message; + + if (source != null) { + message = "Targets list was setup by addTarget with " + targets + ", but not used in [" + + "card " + source.getSourceObject(game) + + " -> ability " + source.getClass().getSimpleName() + " (" + source.getRule().substring(0, Math.min(20, source.getRule().length()) - 1) + "..." + ")" + + " -> target " + target.getClass().getSimpleName() + " (" + target.getMessage() + ")" + + "]"; + } else { + message = "Targets list was setup by addTarget with " + targets + ", but not used in [" + + "card XXX" + + " -> target " + target.getClass().getSimpleName() + " (" + target.getMessage() + ")" + + "]"; + } + Assert.fail(message); + } + return computerPlayer.chooseTarget(outcome, target, source, game); } @@ -1323,6 +1803,9 @@ public class TestPlayer implements Player { return true; } } + + // TODO: enable fail checks and fix tests + //Assert.fail("Wrong target"); } return computerPlayer.chooseTarget(outcome, cards, target, source, game); } @@ -1336,6 +1819,8 @@ public class TestPlayer implements Player { return ability; } } + // TODO: enable fail checks and fix tests + //Assert.fail("Wrong choice"); } return computerPlayer.chooseTriggeredAbility(abilities, game); } @@ -1359,6 +1844,8 @@ public class TestPlayer implements Player { choices.remove(0); return true; } + // TODO: enable fail checks and fix tests + //Assert.fail("Wrong choice"); } return computerPlayer.chooseUse(outcome, message, secondMessage, trueText, falseText, source, game); } @@ -1441,6 +1928,8 @@ public class TestPlayer implements Player { this.choices.addAll(((TestPlayer) player).choices); this.targets.clear(); this.targets.addAll(((TestPlayer) player).targets); + this.aliases.clear(); + this.aliases.putAll(((TestPlayer) player).aliases); computerPlayer.restore(player); } @@ -1674,6 +2163,8 @@ public class TestPlayer implements Player { @Override public boolean cast(SpellAbility ability, Game game, boolean noMana, MageObjectReference reference) { + // TestPlayer, ComputerPlayer always call inherited cast() from PlayerImpl + // that's why chooseSpellAbilityForCast will be ignored in TestPlayer, see workaround with TestComputerPlayerXXX return computerPlayer.cast(ability, game, noMana, reference); } @@ -2107,6 +2598,11 @@ public class TestPlayer implements Player { return computerPlayer.searchLibrary(target, game, targetPlayerId, triggerEvents); } + @Override + public void lookAtAllLibraries(Ability source, Game game) { + computerPlayer.lookAtAllLibraries(source, game); + } + @Override public boolean flipCoin(Game game) { return computerPlayer.flipCoin(game); @@ -2468,24 +2964,7 @@ public class TestPlayer implements Player { @Override public SpellAbility chooseSpellAbilityForCast(SpellAbility ability, Game game, boolean noMana) { - switch (ability.getSpellAbilityType()) { - case SPLIT: - case SPLIT_FUSED: - case SPLIT_AFTERMATH: - if (!choices.isEmpty()) { - MageObject object = game.getObject(ability.getSourceId()); - if (object != null) { - LinkedHashMap useableAbilities = computerPlayer.getSpellAbilities(object, game.getState().getZone(object.getId()), game); - for (String choose : choices) { - for (ActivatedAbility actiavtedAbility : useableAbilities.values()) { - if (actiavtedAbility.getRule().startsWith(choose)) { - return (SpellAbility) actiavtedAbility; - } - } - } - } - } - } + Assert.fail("That's method must calls only from computerPlayer->cast(), see TestComputerPlayerXXX"); return computerPlayer.chooseSpellAbilityForCast(ability, game, noMana); } @@ -2530,6 +3009,8 @@ public class TestPlayer implements Player { return true; } } + // TODO: enable fail checks and fix tests + //Assert.fail("Wrong choice"); } return computerPlayer.choose(outcome, cards, target, game); } @@ -2538,6 +3019,51 @@ public class TestPlayer implements Player { public boolean chooseTargetAmount(Outcome outcome, TargetAmount target, Ability source, Game game ) { + // command format: targetName^X=3 + + // chooseTargetAmount calls by TargetAmount for EACH target cycle + Assert.assertTrue("chooseTargetAmount supports only one target, but found " + target.getMaxNumberOfTargets(), target.getMaxNumberOfTargets() <= 1); + Assert.assertNotEquals("chooseTargetAmount need remaining > 0", 0, target.getAmountRemaining()); + + if (!targets.isEmpty()) { + + boolean founded = false; + String foundedRecord = ""; + CheckTargets: + for (String targetRecord : targets) { + String[] choiceSettings = targetRecord.split("\\^"); + if (choiceSettings.length == 2 && choiceSettings[1].startsWith("X=")) { + // can choice + String choiceName = choiceSettings[0]; + int choiceAmount = Integer.parseInt(choiceSettings[1].substring(2)); + + Assert.assertNotEquals("choice amount must be not zero", 0, choiceAmount); + Assert.assertTrue("choice amount " + choiceAmount + "must be <= remaining " + target.getAmountRemaining(), choiceAmount <= target.getAmountRemaining()); + + for (UUID possibleTarget : target.possibleTargets(source.getSourceId(), source.getControllerId(), game)) { + MageObject objectPermanent = game.getObject(possibleTarget); + Player objectPlayer = game.getPlayer(possibleTarget); + String objectName = objectPermanent != null ? objectPermanent.getName() : objectPlayer.getName(); + if (objectName.equals(choiceName)) { + if (!target.getTargets().contains(possibleTarget) && target.canTarget(possibleTarget, source, game)) { + // can select + target.addTarget(possibleTarget, choiceAmount, source, game); + founded = true; + foundedRecord = targetRecord; + break CheckTargets; + } + } + } + } + } + + if (founded) { + // all done + targets.remove(foundedRecord); + return true; + } + } + return computerPlayer.chooseTargetAmount(outcome, target, source, game); } diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestPlayerBaseAI.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestPlayerBaseAI.java index fa1a5241d29..89e522fd5af 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestPlayerBaseAI.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestPlayerBaseAI.java @@ -1,18 +1,17 @@ - package org.mage.test.serverside.base; -import java.io.FileNotFoundException; import mage.constants.MultiplayerAttackOption; import mage.constants.RangeOfInfluence; import mage.game.Game; import mage.game.GameException; import mage.game.TwoPlayerDuel; -import mage.player.ai.ComputerPlayer7; +import org.mage.test.player.TestComputerPlayer7; import org.mage.test.player.TestPlayer; import org.mage.test.serverside.base.impl.CardTestPlayerAPIImpl; +import java.io.FileNotFoundException; + /** - * * @author LevelX2 */ public abstract class CardTestPlayerBaseAI extends CardTestPlayerAPIImpl { @@ -31,7 +30,7 @@ public abstract class CardTestPlayerBaseAI extends CardTestPlayerAPIImpl { @Override protected TestPlayer createPlayer(String name, RangeOfInfluence rangeOfInfluence) { if (name.equals("PlayerA")) { - TestPlayer testPlayer = new TestPlayer(new ComputerPlayer7("PlayerA", RangeOfInfluence.ONE, skill)); + TestPlayer testPlayer = new TestPlayer(new TestComputerPlayer7("PlayerA", RangeOfInfluence.ONE, skill)); testPlayer.setAIPlayer(true); return testPlayer; } diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestPlayerBase.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestPlayerBase.java index b514cc68b4d..c6ad3f2f681 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestPlayerBase.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestPlayerBase.java @@ -1,16 +1,6 @@ package org.mage.test.serverside.base; -import java.io.File; -import java.io.FileNotFoundException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Scanner; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import mage.cards.Card; -import mage.cards.decks.Deck; import mage.cards.decks.DeckCardLists; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; @@ -21,7 +11,6 @@ import mage.game.Game; import mage.game.match.MatchType; import mage.game.permanent.PermanentCard; import mage.game.tournament.TournamentType; -import mage.player.ai.ComputerPlayer; import mage.players.Player; import mage.server.game.GameFactory; import mage.server.util.ConfigSettings; @@ -32,8 +21,15 @@ import mage.util.Copier; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.junit.BeforeClass; +import org.mage.test.player.TestComputerPlayer; import org.mage.test.player.TestPlayer; +import java.io.File; +import java.io.FileNotFoundException; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** * Base class for all tests. * @@ -334,7 +330,7 @@ public abstract class MageTestPlayerBase { } protected TestPlayer createPlayer(String name, RangeOfInfluence rangeOfInfluence) { - return new TestPlayer(new ComputerPlayer(name, rangeOfInfluence)); + return new TestPlayer(new TestComputerPlayer(name, rangeOfInfluence)); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java index b858d8609b5..4c18ad006f2 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java @@ -24,8 +24,10 @@ import mage.game.permanent.Permanent; import mage.game.permanent.PermanentCard; import mage.players.ManaPool; import mage.players.Player; +import mage.util.CardUtil; import org.junit.Assert; import org.junit.Before; +import org.mage.test.player.PlayerAction; import org.mage.test.player.TestPlayer; import org.mage.test.serverside.base.CardTestAPI; import org.mage.test.serverside.base.MageTestPlayerBase; @@ -48,15 +50,30 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement // Defines the constant if for activate ability is not target but a ability on the stack to define public static final String NO_TARGET = "NO_TARGET"; + // TODO: add target player param to commands public static final String CHECK_COMMAND_PT = "PT"; public static final String CHECK_COMMAND_LIFE = "LIFE"; public static final String CHECK_COMMAND_ABILITY = "ABILITY"; public static final String CHECK_COMMAND_PERMANENT_COUNT = "PERMANENT_COUNT"; public static final String CHECK_COMMAND_EXILE_COUNT = "EXILE_COUNT"; public static final String CHECK_COMMAND_HAND_COUNT = "HAND_COUNT"; + public static final String CHECK_COMMAND_HAND_CARD_COUNT = "HAND_CARD_COUNT"; public static final String CHECK_COMMAND_COLOR = "COLOR"; public static final String CHECK_COMMAND_SUBTYPE = "SUBTYPE"; public static final String CHECK_COMMAND_MANA_POOL = "MANA_POOL"; + public static final String CHECK_COMMAND_ALIAS_ZONE = "ALIAS_ZONE"; + + // TODO: add target player param to commands + public static final String SHOW_COMMAND_LIBRARY = "LIBRARY"; + public static final String SHOW_COMMAND_HAND = "HAND"; + public static final String SHOW_COMMAND_BATTLEFIELD = "BATTLEFIELD"; + public static final String SHOW_COMMAND_GRAVEYEARD = "GRAVEYARD"; + public static final String SHOW_COMMAND_EXILE = "EXILE"; + public static final String SHOW_COMMAND_AVAILABLE_ABILITIES = "AVAILABLE_ABILITIES"; + public static final String SHOW_COMMAND_ALIASES = "ALIASES"; + + // TODO: add target player param to commands + public static final String ALIAS_COMMAND_ADD = "ADD"; protected GameOptions gameOptions; @@ -211,6 +228,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement logger.debug("Winner: " + currentGame.getWinner()); logger.info("Test has been executed. Execution time: " + (t2 - t1) / 1000000 + " ms"); + // TODO: 01.12.2018, JayDi85 - uncomment and fix MANY broken tests with wrong commands + //assertAllCommandsUsed(); } protected TestPlayer createNewPlayer(String playerName, RangeOfInfluence rangeOfInfluence) { @@ -238,6 +257,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement return player; } + // check commands + private void check(String checkName, int turnNum, PhaseStep step, TestPlayer player, String command, String... params) { String res = "check:" + command; for (String param : params) { @@ -247,6 +268,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement } public void checkPT(String checkName, int turnNum, PhaseStep step, TestPlayer player, String permanentName, Integer power, Integer toughness) { + //Assert.assertNotEquals("", permanentName); check(checkName, turnNum, step, player, CHECK_COMMAND_PT, permanentName, power.toString(), toughness.toString()); } @@ -255,14 +277,17 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement } public void checkAbility(String checkName, int turnNum, PhaseStep step, TestPlayer player, String permanentName, Class abilityClass, Boolean mustHave) { + //Assert.assertNotEquals("", permanentName); check(checkName, turnNum, step, player, CHECK_COMMAND_ABILITY, permanentName, abilityClass.getName(), mustHave.toString()); } public void checkPermanentCount(String checkName, int turnNum, PhaseStep step, TestPlayer player, String permanentName, Integer count) { + //Assert.assertNotEquals("", permanentName); check(checkName, turnNum, step, player, CHECK_COMMAND_PERMANENT_COUNT, permanentName, count.toString()); } public void checkExileCount(String checkName, int turnNum, PhaseStep step, TestPlayer player, String permanentName, Integer count) { + //Assert.assertNotEquals("", permanentName); check(checkName, turnNum, step, player, CHECK_COMMAND_EXILE_COUNT, permanentName, count.toString()); } @@ -270,11 +295,18 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement check(checkName, turnNum, step, player, CHECK_COMMAND_HAND_COUNT, count.toString()); } + public void checkHandCardCount(String checkName, int turnNum, PhaseStep step, TestPlayer player, String cardName, Integer count) { + //Assert.assertNotEquals("", cardName); + check(checkName, turnNum, step, player, CHECK_COMMAND_HAND_CARD_COUNT, cardName, count.toString()); + } + public void checkColor(String checkName, int turnNum, PhaseStep step, TestPlayer player, String permanentName, String colors, Boolean mustHave) { + //Assert.assertNotEquals("", permanentName); check(checkName, turnNum, step, player, CHECK_COMMAND_COLOR, permanentName, colors, mustHave.toString()); } public void checkSubType(String checkName, int turnNum, PhaseStep step, TestPlayer player, String permanentName, SubType subType, Boolean mustHave) { + //Assert.assertNotEquals("", permanentName); check(checkName, turnNum, step, player, CHECK_COMMAND_SUBTYPE, permanentName, subType.toString(), mustHave.toString()); } @@ -282,6 +314,52 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement check(checkName, turnNum, step, player, CHECK_COMMAND_MANA_POOL, colors, amount.toString()); } + public void checkAliasZone(String checkName, int turnNum, PhaseStep step, TestPlayer player, String alias, Zone zone) { + checkAliasZone(checkName, turnNum, step, player, alias, zone, true); + } + + public void checkAliasZone(String checkName, int turnNum, PhaseStep step, TestPlayer player, String alias, Zone zone, Boolean mustHave) { + check(checkName, turnNum, step, player, CHECK_COMMAND_ALIAS_ZONE, alias, zone.toString(), mustHave.toString()); + } + + // show commands + + private void show(String showName, int turnNum, PhaseStep step, TestPlayer player, String command, String... params) { + String res = "show:" + command; + for (String param : params) { + res += "@" + param; + } + player.addAction(showName, turnNum, step, res); + } + + public void showLibrary(String showName, int turnNum, PhaseStep step, TestPlayer player) { + show(showName, turnNum, step, player, SHOW_COMMAND_LIBRARY); + } + + public void showHand(String showName, int turnNum, PhaseStep step, TestPlayer player) { + show(showName, turnNum, step, player, SHOW_COMMAND_HAND); + } + + public void showBattlefield(String showName, int turnNum, PhaseStep step, TestPlayer player) { + show(showName, turnNum, step, player, SHOW_COMMAND_BATTLEFIELD); + } + + public void showGraveyard(String showName, int turnNum, PhaseStep step, TestPlayer player) { + show(showName, turnNum, step, player, SHOW_COMMAND_GRAVEYEARD); + } + + public void showExile(String showName, int turnNum, PhaseStep step, TestPlayer player) { + show(showName, turnNum, step, player, SHOW_COMMAND_EXILE); + } + + public void showAvaileableAbilities(String showName, int turnNum, PhaseStep step, TestPlayer player) { + show(showName, turnNum, step, player, SHOW_COMMAND_AVAILABLE_ABILITIES); + } + + public void showAliases(String showName, int turnNum, PhaseStep step, TestPlayer player) { + show(showName, turnNum, step, player, SHOW_COMMAND_ALIASES); + } + /** * Removes all cards from player's library from the game. Usually this * should be used once before initialization to form the library in certain @@ -346,6 +424,19 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement @Override public void addCard(Zone gameZone, TestPlayer player, String cardName, int count, boolean tapped) { + // aliases for mage objects + String aliasName = ""; + boolean useAliasMultiNames = (count != 1); + if (cardName.contains("@")) { + aliasName = cardName.substring(cardName.indexOf("@") + 1); + cardName = cardName.substring(0, cardName.indexOf("@")); + } + + // one card = one aliase, massive adds can use auto-name + if (!useAliasMultiNames && !aliasName.isEmpty() && player.getAliasByName(aliasName) != null) { + Assert.fail("Can't add card " + cardName + " - alias " + aliasName + " already exists for " + player.getName()); + } + if (gameZone == Zone.BATTLEFIELD) { for (int i = 0; i < count; i++) { CardInfo cardInfo = CardRepository.instance.findCard(cardName); @@ -356,6 +447,10 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement PermanentCard p = new PermanentCard(card.copy(), player.getId(), currentGame); p.setTapped(tapped); getBattlefieldCards(player).add(p); + + if (!aliasName.isEmpty()) { + player.addAlias(player.generateAliasName(aliasName, useAliasMultiNames, i + 1), p.getId()); + } } } else { if (tapped) { @@ -369,6 +464,10 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement throw new AssertionError("Couldn't find a card: " + cardName); } cards.add(card); + + if (!aliasName.isEmpty()) { + player.addAlias(player.generateAliasName(aliasName, useAliasMultiNames, i + 1), card.getId()); + } } } } @@ -403,7 +502,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement */ @Override public void setLife(TestPlayer player, int life) { - getCommands(player).put(Zone.OUTSIDE, "life:" + String.valueOf(life)); + getCommands(player).put(Zone.OUTSIDE, "life:" + life); } /** @@ -505,6 +604,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement @Override public void assertPowerToughness(Player player, String cardName, int power, int toughness, Filter.ComparisonScope scope) throws AssertionError { + //Assert.assertNotEquals("", cardName); int count = 0; int fit = 0; int foundPower = 0; @@ -559,6 +659,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement @Override public void assertAbilities(Player player, String cardName, List abilities) throws AssertionError { + //Assert.assertNotEquals("", cardName); int count = 0; Permanent found = null; for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents(player.getId())) { @@ -594,6 +695,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @throws AssertionError */ public void assertAbility(Player player, String cardName, Ability ability, boolean mustHave, int count) throws AssertionError { + //Assert.assertNotEquals("", cardName); int foundCount = 0; Permanent found = null; for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents(player.getId())) { @@ -644,6 +746,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement */ @Override public void assertPermanentCount(Player player, String cardName, int count) throws AssertionError { + //Assert.assertNotEquals("", cardName); int actualCount = 0; for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) { if (permanent.getControllerId().equals(player.getId())) { @@ -657,6 +760,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement @Override public void assertCommandZoneCount(Player player, String commandZoneObjectName, int count) throws AssertionError { + //Assert.assertNotEquals("", commandZoneObjectName); int actualCount = 0; for (CommandObject commandObject : currentGame.getState().getCommand()) { if (commandObject.getControllerId().equals(player.getId()) && commandObject.getName().equals(commandZoneObjectName)) { @@ -696,6 +800,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement } public void assertCounterCount(Player player, String cardName, CounterType type, int count) throws AssertionError { + //Assert.assertNotEquals("", cardName); Permanent found = null; for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) { if (permanent.getName().equals(cardName) && (player == null || permanent.getControllerId().equals(player.getId()))) { @@ -715,11 +820,12 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param count Expected count. */ public void assertCounterOnExiledCardCount(String cardName, CounterType type, int count) throws AssertionError { + //Assert.assertNotEquals("", cardName); Card found = null; if (found == null) { for (Card card : currentGame.getExile().getAllCards(currentGame)) { - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName, true)) { found = card; break; } @@ -749,6 +855,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param mustHave true if creature should have type, false if it should not */ public void assertType(String cardName, CardType type, boolean mustHave) throws AssertionError { + //Assert.assertNotEquals("", cardName); Permanent found = null; for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) { if (permanent.getName().equals(cardName)) { @@ -771,6 +878,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param subType a subtype to test for */ public void assertType(String cardName, CardType type, SubType subType) throws AssertionError { + //Assert.assertNotEquals("", cardName); Permanent found = getPermanent(cardName); Assert.assertTrue("(Battlefield) card type not found (" + cardName + ':' + type + ')', found.getCardType().contains(type)); if (subType != null) { @@ -785,6 +893,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param type A type to test for */ public void assertNotType(String cardName, CardType type) throws AssertionError { + //Assert.assertNotEquals("", cardName); Permanent found = getPermanent(cardName); Assert.assertFalse("(Battlefield) card type found (" + cardName + ':' + type + ')', found.getCardType().contains(type)); } @@ -796,6 +905,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param subType a subtype to test for */ public void assertNotSubtype(String cardName, SubType subType) throws AssertionError { + //Assert.assertNotEquals("", cardName); Permanent found = getPermanent(cardName); if (subType != null) { Assert.assertFalse("(Battlefield) card sub-type equal (" + cardName + ':' + subType.getDescription() + ')', found.getSubtype(currentGame).contains(subType)); @@ -811,6 +921,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param mustHave must or not must have that colors */ public void assertColor(Player player, String cardName, ObjectColor searchColors, boolean mustHave) { + //Assert.assertNotEquals("", cardName); Assert.assertNotEquals("must setup colors to search", 0, searchColors.getColorCount()); Permanent card = getPermanent(cardName, player); @@ -845,6 +956,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param tapped Whether the permanent is tapped or not */ public void assertTapped(String cardName, boolean tapped) throws AssertionError { + //Assert.assertNotEquals("", cardName); Permanent found = null; for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) { if (permanent.getName().equals(cardName)) { @@ -870,6 +982,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param count The amount of this permanents that should be tapped */ public void assertTappedCount(String cardName, boolean tapped, int count) throws AssertionError { + //Assert.assertNotEquals("", cardName); int tappedAmount = 0; Permanent found = null; for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) { @@ -891,6 +1004,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param attacking Whether the permanent is attacking or not */ public void assertAttacking(String cardName, boolean attacking) throws AssertionError { + //Assert.assertNotEquals("", cardName); Permanent found = null; for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) { if (permanent.getName().equals(cardName)) { @@ -922,17 +1036,18 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param count Expected count. */ public void assertHandCount(Player player, String cardName, int count) throws AssertionError { + //Assert.assertNotEquals("", cardName); int actual; if (cardName.contains("//")) { // special logic for cheched split cards, because in game logic of card name filtering is different than for test actual = 0; for (Card card : currentGame.getPlayer(player.getId()).getHand().getCards(currentGame)) { - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName, true)) { actual++; } } } else { FilterCard filter = new FilterCard(); - filter.add(new NamePredicate(cardName)); + filter.add(new NamePredicate(cardName, true)); // must find any cards even without names actual = currentGame.getPlayer(player.getId()).getHand().count(filter, player.getId(), currentGame); } Assert.assertEquals("(Hand) Card counts for card " + cardName + " for " + player.getName() + " are not equal ", count, actual); @@ -981,10 +1096,11 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param count Expected count. */ public void assertExileCount(String cardName, int count) throws AssertionError { + //Assert.assertNotEquals("", cardName); int actualCount = 0; for (ExileZone exile : currentGame.getExile().getExileZones()) { for (Card card : exile.getCards(currentGame)) { - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName, true)) { actualCount++; } } @@ -1020,6 +1136,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param count Expected count. */ public void assertExileCount(Player owner, String cardName, int count) throws AssertionError { + //Assert.assertNotEquals("", cardName); int actualCount = 0; for (ExileZone exile : currentGame.getExile().getExileZones()) { for (Card card : exile.getCards(currentGame)) { @@ -1039,9 +1156,10 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param count Expected count. */ public void assertGraveyardCount(Player player, String cardName, int count) throws AssertionError { + //Assert.assertNotEquals("", cardName); int actualCount = 0; for (Card card : player.getGraveyard().getCards(currentGame)) { - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName, true)) { actualCount++; } } @@ -1056,7 +1174,6 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param count Expected count. */ public void assertLibraryCount(Player player, int count) throws AssertionError { - List libraryList = player.getLibrary().getCards(currentGame); int actualCount = libraryList != null && !libraryList.isEmpty() ? libraryList.size() : 0; Assert.assertEquals("(Library " + player.getName() + ") counts are not equal", count, actualCount); @@ -1070,9 +1187,10 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param count Expected count. */ public void assertLibraryCount(Player player, String cardName, int count) throws AssertionError { + //Assert.assertNotEquals("", cardName); int actualCount = 0; for (Card card : player.getLibrary().getCards(currentGame)) { - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName, true)) { actualCount++; } } @@ -1080,15 +1198,27 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement Assert.assertEquals("(Library " + player.getName() + ") Card counts are not equal (" + cardName + ')', count, actualCount); } - /** - * Asserts added actions count. Useful to make sure that all actions were - * executed. - * - * @param player - * @param count - */ - public void assertActionCount(TestPlayer player, int count) { - Assert.assertEquals("Actions left are not equal: ", count, player.getActionCount()); + public void assertActionsCount(TestPlayer player, int count) throws AssertionError { + Assert.assertEquals("(Actions of " + player.getName() + ") Count are not equel (founded [" + + player.getActions().stream().map(PlayerAction::getAction).collect(Collectors.joining(", ")) + + "])", count, player.getActions().size()); + } + + public void assertChoicesCount(TestPlayer player, int count) throws AssertionError { + Assert.assertEquals("(Choices of " + player.getName() + ") Count are not equel (founded " + player.getChoices() + ")", count, player.getChoices().size()); + } + + public void assertTargetsCount(TestPlayer player, int count) throws AssertionError { + Assert.assertEquals("(Targets of " + player.getName() + ") Count are not equel (founded " + player.getTargets() + ")", count, player.getTargets().size()); + } + + public void assertAllCommandsUsed() throws AssertionError { + for (Player player : currentGame.getPlayers().values()) { + TestPlayer testPlayer = (TestPlayer) player; + assertActionsCount(testPlayer, 0); + assertChoicesCount(testPlayer, 0); + assertTargetsCount(testPlayer, 0); + } } public void assertActivePlayer(TestPlayer player) { @@ -1129,18 +1259,22 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement } public void playLand(int turnNum, PhaseStep step, TestPlayer player, String cardName) { + //Assert.assertNotEquals("", cardName); player.addAction(turnNum, step, "activate:Play " + cardName); } public void castSpell(int turnNum, PhaseStep step, TestPlayer player, String cardName) { + //Assert.assertNotEquals("", cardName); player.addAction(turnNum, step, "activate:Cast " + cardName); } public void castSpell(int turnNum, PhaseStep step, TestPlayer player, String cardName, Player target) { + //Assert.assertNotEquals("", cardName); player.addAction(turnNum, step, "activate:Cast " + cardName + "$targetPlayer=" + target.getName()); } public void castSpell(int turnNum, PhaseStep step, TestPlayer player, String cardName, Player target, int manaInPool) { + //Assert.assertNotEquals("", cardName); player.addAction(turnNum, step, "activate:Cast " + cardName + "$targetPlayer=" + target.getName() + "$manaInPool=" + manaInPool); } @@ -1177,11 +1311,11 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * multiple targets can be seperated by ^ */ public void castSpell(int turnNum, PhaseStep step, TestPlayer player, String cardName, String targetName) { + //Assert.assertNotEquals("", cardName); player.addAction(turnNum, step, "activate:Cast " + cardName + "$target=" + targetName); } public enum StackClause { - WHILE_ON_STACK, WHILE_COPY_ON_STACK, WHILE_NOT_ON_STACK @@ -1216,6 +1350,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param clause */ public void castSpell(int turnNum, PhaseStep step, TestPlayer player, String cardName, String targetName, String spellOnStack, StackClause clause) { + //Assert.assertNotEquals("", cardName); if (StackClause.WHILE_ON_STACK == clause) { player.addAction(turnNum, step, "activate:Cast " + cardName + '$' + (targetName != null && targetName.startsWith("target") ? targetName : "target=" + targetName) @@ -1228,6 +1363,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement } public void castSpell(int turnNum, PhaseStep step, TestPlayer player, String cardName, String targetName, String spellOnStack, String spellOnTopOfStack) { + //Assert.assertNotEquals("", cardName); String action = "activate:Cast " + cardName + "$target=" + targetName; if (spellOnStack != null && !spellOnStack.isEmpty()) { action += "$spellOnStack=" + spellOnStack; @@ -1243,18 +1379,22 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement } public void activateAbility(int turnNum, PhaseStep step, TestPlayer player, String ability) { + // TODO: it's uses computerPlayer to execute, only ability target will work, but choices and targets commands aren't player.addAction(turnNum, step, "activate:" + ability); } public void activateAbility(int turnNum, PhaseStep step, TestPlayer player, String ability, Player target) { + // TODO: it's uses computerPlayer to execute, only ability target will work, but choices and targets commands aren't player.addAction(turnNum, step, "activate:" + ability + "$targetPlayer=" + target.getName()); } public void activateAbility(int turnNum, PhaseStep step, TestPlayer player, String ability, String... targetNames) { + // TODO: it's uses computerPlayer to execute, only ability target will work, but choices and targets commands aren't player.addAction(turnNum, step, "activate:" + ability + "$target=" + String.join("^", targetNames)); } public void activateAbility(int turnNum, PhaseStep step, TestPlayer player, String ability, String targetName, String spellOnStack) { + // TODO: it's uses computerPlayer to execute, only ability target will work, but choices and targets commands aren't this.activateAbility(turnNum, step, player, ability, targetName, spellOnStack, StackClause.WHILE_ON_STACK); } @@ -1292,22 +1432,28 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement } public void addCounters(int turnNum, PhaseStep step, TestPlayer player, String cardName, CounterType type, int count) { + //Assert.assertNotEquals("", cardName); player.addAction(turnNum, step, "addCounters:" + cardName + '$' + type.getName() + '$' + count); } public void attack(int turnNum, TestPlayer player, String attacker) { + //Assert.assertNotEquals("", attacker); player.addAction(turnNum, PhaseStep.DECLARE_ATTACKERS, "attack:" + attacker); } public void attack(int turnNum, TestPlayer player, String attacker, TestPlayer defendingPlayer) { + //Assert.assertNotEquals("", attacker); player.addAction(turnNum, PhaseStep.DECLARE_ATTACKERS, "attack:" + attacker + "$defendingPlayer=" + defendingPlayer.getName()); } public void attack(int turnNum, TestPlayer player, String attacker, String planeswalker) { + //Assert.assertNotEquals("", attacker); player.addAction(turnNum, PhaseStep.DECLARE_ATTACKERS, new StringBuilder("attack:").append(attacker).append("$planeswalker=").append(planeswalker).toString()); } public void block(int turnNum, TestPlayer player, String blocker, String attacker) { + //Assert.assertNotEquals("", blocker); + //Assert.assertNotEquals("", attacker); player.addAction(turnNum, PhaseStep.DECLARE_BLOCKERS, "block:" + blocker + '$' + attacker); } @@ -1401,6 +1547,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement } public void assertDamageReceived(Player player, String cardName, int expected) { + //Assert.assertNotEquals("", cardName); Permanent p = getPermanent(cardName, player.getId()); if (p != null) { Assert.assertEquals("Wrong damage received: ", expected, p.getDamage()); diff --git a/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java b/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java index 810c068ccf6..360bd942514 100644 --- a/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java +++ b/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java @@ -597,6 +597,9 @@ public class PlayerStub implements Player { return false; } + @Override + public void lookAtAllLibraries(Ability source, Game game) {} + @Override public boolean canPlayLand() { return false; diff --git a/Mage.Tests/src/test/java/org/mage/test/testapi/TestAliases.java b/Mage.Tests/src/test/java/org/mage/test/testapi/TestAliases.java new file mode 100644 index 00000000000..13d6915f92f --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/testapi/TestAliases.java @@ -0,0 +1,128 @@ +package org.mage.test.testapi; + +import mage.constants.EmptyNames; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.util.CardUtil; +import org.junit.Assert; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author JayDi85 + */ + +public class TestAliases extends CardTestPlayerBase { + + @Test + public void test_NamesEquals() { + // empty names for face down cards + Assert.assertTrue(CardUtil.haveEmptyName("")); + Assert.assertTrue(CardUtil.haveEmptyName(EmptyNames.FACE_DOWN_CREATURE.toString())); + Assert.assertFalse(CardUtil.haveEmptyName(" ")); + Assert.assertFalse(CardUtil.haveEmptyName("123")); + Assert.assertFalse(CardUtil.haveEmptyName("Sample Name")); + + // same names (empty names can't be same) + Assert.assertFalse(CardUtil.haveSameNames("", "")); + Assert.assertFalse(CardUtil.haveSameNames(EmptyNames.FACE_DOWN_CREATURE.toString(), "")); + Assert.assertFalse(CardUtil.haveSameNames(EmptyNames.FACE_DOWN_CREATURE.toString(), EmptyNames.FACE_DOWN_CREATURE.toString())); + Assert.assertFalse(CardUtil.haveSameNames(EmptyNames.FACE_DOWN_TOKEN.toString(), "")); + Assert.assertFalse(CardUtil.haveSameNames(EmptyNames.FACE_DOWN_TOKEN.toString(), EmptyNames.FACE_DOWN_CREATURE.toString())); + Assert.assertTrue(CardUtil.haveSameNames("Name", "Name")); + Assert.assertFalse(CardUtil.haveSameNames("Name", "")); + Assert.assertFalse(CardUtil.haveSameNames("Name", " ")); + Assert.assertFalse(CardUtil.haveSameNames("Name", "123")); + Assert.assertFalse(CardUtil.haveSameNames("Name", EmptyNames.FACE_DOWN_CREATURE.toString())); + Assert.assertFalse(CardUtil.haveSameNames("Name1", "Name2")); + + // ignore mtg rules (empty names must be same) + Assert.assertTrue(CardUtil.haveSameNames("", "", true)); + Assert.assertTrue(CardUtil.haveSameNames(EmptyNames.FACE_DOWN_CREATURE.toString(), EmptyNames.FACE_DOWN_CREATURE.toString(), true)); + Assert.assertTrue(CardUtil.haveSameNames("Name", "Name", true)); + Assert.assertFalse(CardUtil.haveSameNames("Name", "", true)); + Assert.assertFalse(CardUtil.haveSameNames("Name", " ", true)); + Assert.assertFalse(CardUtil.haveSameNames("Name", "123", true)); + Assert.assertFalse(CardUtil.haveSameNames("Name", EmptyNames.FACE_DOWN_CREATURE.toString(), true)); + Assert.assertFalse(CardUtil.haveSameNames("Name1", "Name2", true)); + } + + @Test + public void test_DifferentZones() { + addCard(Zone.LIBRARY, playerA, "Swamp@lib", 1); + addCard(Zone.HAND, playerA, "Swamp@hand", 1); + addCard(Zone.BATTLEFIELD, playerA, "Swamp@battle", 1); + addCard(Zone.GRAVEYARD, playerA, "Swamp@grave", 1); + + showAliases("A aliases", 1, PhaseStep.UPKEEP, playerA); + checkAliasZone("lib", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "lib", Zone.LIBRARY); + checkAliasZone("hand", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "hand", Zone.HAND); + checkAliasZone("battle", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "battle", Zone.BATTLEFIELD); + checkAliasZone("grave", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "grave", Zone.GRAVEYARD); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + } + + @Test + public void test_MultipleNames() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 5); + addCard(Zone.BATTLEFIELD, playerA, "Island@isl", 5); + addCard(Zone.BATTLEFIELD, playerB, "Plains", 5); + addCard(Zone.BATTLEFIELD, playerB, "Mountain@mnt", 5); + + checkPermanentCount("Swamp must exists", 1, PhaseStep.UPKEEP, playerA, "Swamp", 5); + checkPermanentCount("Island must exists", 1, PhaseStep.UPKEEP, playerA, "Island", 5); + checkPermanentCount("Plains must exists", 1, PhaseStep.UPKEEP, playerB, "Plains", 5); + checkPermanentCount("Mountain must exists", 1, PhaseStep.UPKEEP, playerB, "Mountain", 5); + // + showAliases("A aliases", 1, PhaseStep.UPKEEP, playerA); + showAliases("B aliases", 1, PhaseStep.UPKEEP, playerB); + // A + checkAliasZone("Swamp must not", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Swamp", Zone.BATTLEFIELD, false); + checkAliasZone("Swamp.1 must not", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Swamp.1", Zone.BATTLEFIELD, false); + checkAliasZone("Island must not", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Island", Zone.BATTLEFIELD, false); + checkAliasZone("isl must not", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "isl", Zone.BATTLEFIELD, false); + checkAliasZone("isl.1 must", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "isl.1", Zone.BATTLEFIELD, true); + checkAliasZone("isl.2 must", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "isl.2", Zone.BATTLEFIELD, true); + checkAliasZone("isl.5 must", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "isl.5", Zone.BATTLEFIELD, true); + // B + checkAliasZone("Plains must not", 1, PhaseStep.PRECOMBAT_MAIN, playerB, "Plains", Zone.BATTLEFIELD, false); + checkAliasZone("Plains.1 must not", 1, PhaseStep.PRECOMBAT_MAIN, playerB, "Plains.1", Zone.BATTLEFIELD, false); + checkAliasZone("Plains must not", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Plains", Zone.BATTLEFIELD, false); + checkAliasZone("mnt must not", 1, PhaseStep.PRECOMBAT_MAIN, playerB, "mnt", Zone.BATTLEFIELD, false); + checkAliasZone("mnt.1 must", 1, PhaseStep.PRECOMBAT_MAIN, playerB, "mnt.1", Zone.BATTLEFIELD, true); + checkAliasZone("mnt.2 must", 1, PhaseStep.PRECOMBAT_MAIN, playerB, "mnt.2", Zone.BATTLEFIELD, true); + checkAliasZone("mnt.5 must", 1, PhaseStep.PRECOMBAT_MAIN, playerB, "mnt.5", Zone.BATTLEFIELD, true); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + } + + @Test + public void test_CastTarget() { + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion@lion", 5); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); + addCard(Zone.HAND, playerA, "Lightning Bolt", 3); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "@lion.1"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "@lion.3"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "@lion.5"); + + showAliases("A aliases", 1, PhaseStep.POSTCOMBAT_MAIN, playerA); + checkAliasZone("1", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "lion.1", Zone.BATTLEFIELD, false); + checkAliasZone("2", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "lion.2", Zone.BATTLEFIELD, true); + checkAliasZone("3", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "lion.3", Zone.BATTLEFIELD, false); + checkAliasZone("4", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "lion.4", Zone.BATTLEFIELD, true); + checkAliasZone("5", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "lion.5", Zone.BATTLEFIELD, false); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertGraveyardCount(playerA, "Lightning Bolt", 3); + assertGraveyardCount(playerA, "Silvercoat Lion", 3); + } +} \ No newline at end of file diff --git a/Mage.Updater/pom.xml b/Mage.Updater/pom.xml index c9ab517c295..183b4f90e1e 100644 --- a/Mage.Updater/pom.xml +++ b/Mage.Updater/pom.xml @@ -5,7 +5,7 @@ mage-root org.mage - 1.4.31 + 1.4.32 4.0.0 diff --git a/Mage.Verify/pom.xml b/Mage.Verify/pom.xml index cb1f3be8672..fb561bf2371 100644 --- a/Mage.Verify/pom.xml +++ b/Mage.Verify/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.31 + 1.4.32 mage-verify @@ -49,7 +49,7 @@ org.mage mage-client - 1.4.31 + 1.4.32 diff --git a/Mage.Verify/src/main/java/mage/verify/JsonCard.java b/Mage.Verify/src/main/java/mage/verify/JsonCard.java index a17d1a7b6bb..d01d9c8ba02 100644 --- a/Mage.Verify/src/main/java/mage/verify/JsonCard.java +++ b/Mage.Verify/src/main/java/mage/verify/JsonCard.java @@ -3,38 +3,51 @@ package mage.verify; import java.util.List; class JsonCard { - public String layout; - public String name; - public List names; // flip cards - public String manaCost; - public int cmc; - public List colors; - public List colorIdentity; - public String type; - public List supertypes; - public List types; - public List subtypes; - public String text; - public String power; - public String toughness; - public String loyalty; - public String imageName; - public boolean starter; // only available in boxed sets and not in boosters - public int hand; // vanguard - public int life; // vanguard + // docs: https://mtgjson.com/v4/docs.html - // only available in AllSets.json public String artist; - public String flavor; - public String id; - public int multiverseid; - public String rarity; - public boolean reserved; - public int[] variations; + public String borderColor; + public List colorIdentity; + public List colorIndicator; + public List colors; + public float convertedManaCost; + public float faceConvertedManaCost; + public String flavorText; + public List foreignData; + public String frameVersion; + public boolean hasFoil; + public boolean hasNonFoil; + public boolean isOnlineOnly; + public boolean isOversized; + public boolean isReserved; + public boolean isTimeshifted; + public String layout; + public JsonLegalities legalities; + public String loyalty; + public String manaCost; + public int multiverseId; + public String name; + public List names; public String number; - public String mciNumber; - public String releaseDate; // promos - public String border; + public String originalText; + public String originalType; + public List printings; + public String power; + public String rarity; + public boolean starter; + public String side; + public List rulings; + public List subtypes; + public List supertypes; + public String text; + public String toughness; + public String type; + public List types; + public String uuid; + public List variations; public String watermark; - public boolean timeshifted; + public String tcgplayerProductId; + public String scryfallId; + public boolean isAlternative; + public String frameEffect; } diff --git a/Mage.Verify/src/main/java/mage/verify/JsonForeignData.java b/Mage.Verify/src/main/java/mage/verify/JsonForeignData.java new file mode 100644 index 00000000000..c6ca9353e46 --- /dev/null +++ b/Mage.Verify/src/main/java/mage/verify/JsonForeignData.java @@ -0,0 +1,10 @@ +package mage.verify; + +public class JsonForeignData { + public String flavorText; + public String language; + public int multiverseId; + public String name; + public String text; + public String type; +} diff --git a/Mage.Verify/src/main/java/mage/verify/JsonLegalities.java b/Mage.Verify/src/main/java/mage/verify/JsonLegalities.java new file mode 100644 index 00000000000..064838754ed --- /dev/null +++ b/Mage.Verify/src/main/java/mage/verify/JsonLegalities.java @@ -0,0 +1,19 @@ +package mage.verify; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class JsonLegalities { + @JsonProperty("1v1") + public String oneVersusOne; + public String brawl; + public String commander; + public String duel; + public String frontier; + public String future; + public String legacy; + public String modern; + public String penny; + public String pauper; + public String standard; + public String vintage; +} diff --git a/Mage.Verify/src/main/java/mage/verify/JsonMeta.java b/Mage.Verify/src/main/java/mage/verify/JsonMeta.java new file mode 100644 index 00000000000..4d68703479a --- /dev/null +++ b/Mage.Verify/src/main/java/mage/verify/JsonMeta.java @@ -0,0 +1,6 @@ +package mage.verify; + +public class JsonMeta { + public String date; + public String version; +} diff --git a/Mage.Verify/src/main/java/mage/verify/JsonRuling.java b/Mage.Verify/src/main/java/mage/verify/JsonRuling.java new file mode 100644 index 00000000000..1576700d581 --- /dev/null +++ b/Mage.Verify/src/main/java/mage/verify/JsonRuling.java @@ -0,0 +1,6 @@ +package mage.verify; + +public class JsonRuling { + public String date; + public String text; +} diff --git a/Mage.Verify/src/main/java/mage/verify/JsonSet.java b/Mage.Verify/src/main/java/mage/verify/JsonSet.java index 831721937fd..614d73123d2 100644 --- a/Mage.Verify/src/main/java/mage/verify/JsonSet.java +++ b/Mage.Verify/src/main/java/mage/verify/JsonSet.java @@ -1,24 +1,21 @@ package mage.verify; import java.util.List; -import java.util.Map; class JsonSet { - public String name; - public String code; - public String oldCode; - public String gathererCode; - public String magicCardsInfoCode; - public String[] magicRaritiesCodes; - public String[] alternativeNames; - public String releaseDate; - public String border; - public String type; - public List booster; // [String|[String]] - public List cards; + public int baseSetSize; public String block; - public boolean onlineOnly; - public String mkm_id; - public String mkm_name; - public Map translations; + public List boosterV3; // [["rare", "mythic rare"], "uncommon", "uncommon", "uncommon", "common"] + public List cards; + public String code; + public boolean isFoilOnly; + public boolean isOnlineOnly; + public JsonMeta meta; + public String mtgoCode; + public String name; + public String releaseDate; + public List tokens; + public int totalSetSize; + public String type; + public String tcgplayerGroupId; } diff --git a/Mage.Verify/src/main/java/mage/verify/JsonToken.java b/Mage.Verify/src/main/java/mage/verify/JsonToken.java new file mode 100644 index 00000000000..92237ae01f9 --- /dev/null +++ b/Mage.Verify/src/main/java/mage/verify/JsonToken.java @@ -0,0 +1,24 @@ +package mage.verify; + +import java.util.List; + +public class JsonToken { + public String artist; + public String borderColor; + public List colorIdentity; + public List colorIndicator; + public List colors; + public String loyalty; + public String name; + public String number; + public String power; + public List reverseRelated; + public String side; + public String text; + public String toughness; + public String type; + public String uuid; + public String watermark; + public boolean isOnlineOnly; + public String scryfallId; +} diff --git a/Mage.Verify/src/main/java/mage/verify/MtgJson.java b/Mage.Verify/src/main/java/mage/verify/MtgJson.java index 1919f8db0f8..11f147029a7 100644 --- a/Mage.Verify/src/main/java/mage/verify/MtgJson.java +++ b/Mage.Verify/src/main/java/mage/verify/MtgJson.java @@ -9,10 +9,13 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; +import java.net.URLConnection; import java.nio.file.Files; import java.nio.file.StandardCopyOption; import java.text.Normalizer; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.zip.ZipInputStream; @@ -61,6 +64,29 @@ public final class MtgJson { static { try { cards = loadAllCards(); + + List keysToDelete = new ArrayList<>(); + + // fix names + Map newKeys = new HashMap<>(); + for (String key : cards.keySet()) { + if (key.contains("(")) { + newKeys.put(key.replaceAll("\\(.*\\)", "").trim(), cards.get(key)); + keysToDelete.add(key); + } + } + cards.putAll(newKeys); + cards.keySet().removeAll(keysToDelete); + + // remove wrong data (tokens) + keysToDelete.clear(); + for (Map.Entry record : cards.entrySet()) { + if (record.getValue().layout.equals("token") || record.getValue().layout.equals("double_faced_token")) { + keysToDelete.add(record.getKey()); + } + } + cards.keySet().removeAll(keysToDelete); + addAliases(cards); } catch (IOException e) { throw new RuntimeException(e); @@ -95,7 +121,9 @@ public final class MtgJson { if (stream == null) { File file = new File(filename); if (!file.exists()) { - InputStream download = new URL("http://mtgjson.com/json/" + filename).openStream(); + URLConnection connection = new URL("https://mtgjson.com/json/" + filename).openConnection(); + connection.setRequestProperty("user-agent", "xmage"); + InputStream download = connection.getInputStream(); Files.copy(download, file.toPath(), StandardCopyOption.REPLACE_EXISTING); System.out.println("Downloaded " + filename + " to " + file.getAbsolutePath()); } else { @@ -133,6 +161,7 @@ public final class MtgJson { name = name.replace("'", "\""); // for Kongming, "Sleeping Dragon" & Pang Tong, "Young Phoenix" ref = reference.get(name); } + return ref; } diff --git a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java index 991315438a3..6dc4d002136 100644 --- a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java +++ b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java @@ -1,14 +1,12 @@ package mage.verify; import mage.ObjectColor; -import mage.abilities.Ability; import mage.abilities.keyword.MultikickerAbility; import mage.cards.*; import mage.cards.basiclands.BasicLand; -import mage.cards.repository.CardRepository; -import mage.cards.repository.CardScanner; import mage.constants.CardType; import mage.constants.Rarity; +import mage.constants.SubType; import mage.constants.SuperType; import mage.game.permanent.token.Token; import mage.game.permanent.token.TokenImpl; @@ -16,7 +14,7 @@ import org.junit.Assert; import org.junit.Ignore; import org.junit.Test; import org.mage.plugins.card.images.CardDownloadData; -import org.mage.plugins.card.images.DownloadPictures; +import org.mage.plugins.card.images.DownloadPicturesService; import org.reflections.Reflections; import java.io.IOException; @@ -61,18 +59,25 @@ public class VerifyCardDataTest { skipListCreate("PT"); skipListAddName("PT", "UST", "Garbage Elemental"); skipListAddName("PT", "UST", "Infinity Elemental"); + skipListAddName("PT", "UNH", "Old Fogey"); // color skipListCreate("COLOR"); // cost skipListCreate("COST"); + skipListAddName("COST", "KTK", "Erase"); + skipListAddName("COST", "M13", "Erase"); + skipListAddName("COST", "ULG", "Erase"); + skipListAddName("COST", "H17", "Grimlock, Dinobot Leader"); // supertype skipListCreate("SUPERTYPE"); // type skipListCreate("TYPE"); + skipListAddName("TYPE", "UNH", "Old Fogey"); + skipListAddName("TYPE", "UST", "capital offense"); // subtype skipListCreate("SUBTYPE"); @@ -109,7 +114,7 @@ public class VerifyCardDataTest { } private int failed = 0; - private ArrayList outputMessages = new ArrayList<>(); + private final ArrayList outputMessages = new ArrayList<>(); @Test public void verifyCards() throws IOException { @@ -232,7 +237,7 @@ public class VerifyCardDataTest { // replace codes for aliases String searchSet = MtgJson.mtgJsonToXMageCodes.getOrDefault(refSet.code, refSet.code); - ExpansionSet mageSet = Sets.findSet(searchSet); + ExpansionSet mageSet = Sets.findSet(searchSet.toUpperCase()); if (mageSet == null) { totalMissingSets = totalMissingSets + 1; totalMissingCards = totalMissingCards + refSet.cards.size(); @@ -354,7 +359,6 @@ public class VerifyCardDataTest { } // TODO: add test to check num cards for rarity (rarityStats > 0 and numRarity > 0) - printMessages(warningsList); printMessages(errorsList); if (errorsList.size() > 0) { @@ -369,7 +373,6 @@ public class VerifyCardDataTest { Collection sets = Sets.getInstance().values(); - // 1. wrong UsesVariousArt settings (set have duplicated card name without that setting -- e.g. cards will have same image) for (ExpansionSet set : sets) { @@ -383,7 +386,7 @@ public class VerifyCardDataTest { // check for (ExpansionSet.SetCardInfo card : set.getSetCardInfo()) { boolean cardHaveDoubleName = (doubleNames.getOrDefault(card.getName(), 0) > 1); - boolean cardHaveVariousSetting = card.getGraphicInfo() == null ? false : card.getGraphicInfo().getUsesVariousArt(); + boolean cardHaveVariousSetting = card.getGraphicInfo() != null && card.getGraphicInfo().getUsesVariousArt(); if (cardHaveDoubleName && !cardHaveVariousSetting) { errorsList.add("error, founded double card names, but UsesVariousArt is not true: " + set.getCode() + " - " + set.getName() + " - " + card.getName() + " - " + card.getCardNumber()); @@ -422,7 +425,7 @@ public class VerifyCardDataTest { } // tok file's data - ArrayList tokFileTokens = DownloadPictures.getTokenCardUrls(); + ArrayList tokFileTokens = DownloadPicturesService.getTokenCardUrls(); LinkedHashMap tokDataClassesIndex = new LinkedHashMap<>(); LinkedHashMap tokDataNamesIndex = new LinkedHashMap<>(); for (CardDownloadData tokData : tokFileTokens) { @@ -569,17 +572,22 @@ public class VerifyCardDataTest { return; } - Collection expected = ref.colors; - ObjectColor color = card.getColor(null); - if (expected == null) { - expected = Collections.emptyList(); + Set expected = new HashSet<>(); + if (ref.colors != null) { + expected.addAll(ref.colors); } + if (card.isFlipCard()) { + expected.addAll(ref.colorIdentity); + } + + ObjectColor color = card.getColor(null); + if (expected.size() != color.getColorCount() - || (color.isBlack() && !expected.contains("Black")) - || (color.isBlue() && !expected.contains("Blue")) - || (color.isGreen() && !expected.contains("Green")) - || (color.isRed() && !expected.contains("Red")) - || (color.isWhite() && !expected.contains("White"))) { + || (color.isBlack() && !expected.contains("B")) + || (color.isBlue() && !expected.contains("U")) + || (color.isGreen() && !expected.contains("G")) + || (color.isRed() && !expected.contains("R")) + || (color.isWhite() && !expected.contains("W"))) { fail(card, "colors", color + " != " + expected); } } @@ -601,7 +609,7 @@ public class VerifyCardDataTest { } } - if (!eqSet(card.getSubtype(null).stream().map(p -> p.toString()).collect(Collectors.toSet()), expected)) { + if (!eqSet(card.getSubtype(null).stream().map(SubType::toString).collect(Collectors.toSet()), expected)) { fail(card, "subtypes", card.getSubtype(null) + " != " + expected); } } @@ -628,11 +636,11 @@ public class VerifyCardDataTest { } // special check: kicker ability must be in rules - if (card.getAbilities().containsClass(MultikickerAbility.class) && !card.getRules().stream().anyMatch(rule -> rule.contains("Multikicker"))) { + if (card.getAbilities().containsClass(MultikickerAbility.class) && card.getRules().stream().noneMatch(rule -> rule.contains("Multikicker"))) { fail(card, "abilities", "card have Multikicker ability, but missing it in rules text"); } - // spells have only 1 abilities + // spells have only 1 ability if (card.isSorcery() || card.isInstant()) { return; } @@ -697,7 +705,7 @@ public class VerifyCardDataTest { String expected = ref.manaCost; String cost = join(card.getManaCost().getSymbols()); - if (cost != null && cost.isEmpty()) { + if (cost.isEmpty()) { cost = null; } if (cost != null) { diff --git a/Mage/manifest.mf b/Mage/manifest.mf deleted file mode 100644 index 1574df4a2de..00000000000 --- a/Mage/manifest.mf +++ /dev/null @@ -1,3 +0,0 @@ -Manifest-Version: 1.0 -X-COMMENT: Main-Class will be added automatically by build - diff --git a/Mage/pom.xml b/Mage/pom.xml index 5666f64aff8..ecb37107e1a 100644 --- a/Mage/pom.xml +++ b/Mage/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.31 + 1.4.32 mage diff --git a/Mage/src/main/java/mage/MageObject.java b/Mage/src/main/java/mage/MageObject.java index b65f1721739..cb1812c44fb 100644 --- a/Mage/src/main/java/mage/MageObject.java +++ b/Mage/src/main/java/mage/MageObject.java @@ -64,20 +64,14 @@ public interface MageObject extends MageItem, Serializable { void adjustTargets(Ability ability, Game game); + // memory object copy (not mtg) MageObject copy(); - /** - * Defines that MageObject is a copy of another object - * - * @param isCopy - */ - void setCopy(boolean isCopy); + // copied card info (mtg) + void setCopy(boolean isCopy, MageObject copiedFrom); + + MageObject getCopyFrom(); - /** - * Checks if current MageObject is a copy of another object - * - * @return - */ boolean isCopy(); int getZoneChangeCounter(Game game); diff --git a/Mage/src/main/java/mage/MageObjectImpl.java b/Mage/src/main/java/mage/MageObjectImpl.java index 051b9584573..7592cb770f3 100644 --- a/Mage/src/main/java/mage/MageObjectImpl.java +++ b/Mage/src/main/java/mage/MageObjectImpl.java @@ -1,11 +1,5 @@ - package mage; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.Iterator; -import java.util.List; -import java.util.UUID; import mage.abilities.Abilities; import mage.abilities.AbilitiesImpl; import mage.abilities.Ability; @@ -20,16 +14,14 @@ import mage.abilities.mana.ActivatedManaAbilityImpl; import mage.abilities.text.TextPart; import mage.abilities.text.TextPartSubType; import mage.cards.FrameStyle; -import mage.constants.CardType; -import mage.constants.SubLayer; -import mage.constants.SubType; -import mage.constants.SubTypeSet; -import mage.constants.SuperType; +import mage.constants.*; import mage.game.Game; import mage.game.events.ZoneChangeEvent; import mage.util.GameLog; import mage.util.SubTypeList; +import java.util.*; + public abstract class MageObjectImpl implements MageObject { protected UUID objectId; @@ -48,6 +40,7 @@ public abstract class MageObjectImpl implements MageObject { protected MageInt power; protected MageInt toughness; protected boolean copy; + protected MageObject copyFrom; // copied card INFO (used to call original adjusters) protected List textParts; public MageObjectImpl() { @@ -82,6 +75,7 @@ public abstract class MageObjectImpl implements MageObject { isAllCreatureTypes = object.isAllCreatureTypes; supertype.addAll(object.supertype); this.copy = object.copy; + this.copyFrom = (object.copyFrom != null ? object.copyFrom.copy() : null); textParts = new ArrayList<>(); textParts.addAll(object.textParts); } @@ -263,8 +257,14 @@ public abstract class MageObjectImpl implements MageObject { } @Override - public void setCopy(boolean isCopy) { + public void setCopy(boolean isCopy, MageObject copyFrom) { this.copy = isCopy; + this.copyFrom = (copyFrom != null ? copyFrom.copy() : null); + } + + @Override + public MageObject getCopyFrom() { + return this.copyFrom; } @Override @@ -322,7 +322,7 @@ public abstract class MageObjectImpl implements MageObject { */ @Override public void removePTCDA() { - for (Iterator iter = this.getAbilities().iterator(); iter.hasNext();) { + for (Iterator iter = this.getAbilities().iterator(); iter.hasNext(); ) { Ability ability = iter.next(); for (Effect effect : ability.getEffects()) { if (effect instanceof ContinuousEffect && ((ContinuousEffect) effect).getSublayer() == SubLayer.CharacteristicDefining_7a) { diff --git a/Mage/src/main/java/mage/abilities/ActivatedAbilityImpl.java b/Mage/src/main/java/mage/abilities/ActivatedAbilityImpl.java index 21fac77d7aa..8ebc0a44a66 100644 --- a/Mage/src/main/java/mage/abilities/ActivatedAbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/ActivatedAbilityImpl.java @@ -1,4 +1,3 @@ - package mage.abilities; import java.util.UUID; @@ -154,13 +153,19 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa @Override public ActivationStatus canActivate(UUID playerId, Game game) { //20091005 - 602.2 - if (!(hasMoreActivationsThisTurn(game) && (condition == null || condition.apply(game, this)))) { + if (!(hasMoreActivationsThisTurn(game) + && (condition == null + || condition.apply(game, this)))) { return ActivationStatus.getFalse(); } switch (mayActivate) { case ANY: break; - + case ACTIVE: + if (game.getActivePlayerId() != playerId) { + return ActivationStatus.getFalse(); + } + break; case NOT_YOU: if (controlsAbility(playerId, game)) { return ActivationStatus.getFalse(); @@ -198,9 +203,17 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa return ActivationStatus.getFalse(); } //20091005 - 602.5d/602.5e - MageObjectReference permittingObject = game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.ACTIVATE_AS_INSTANT, this, controllerId, game); - if (timing == TimingRule.INSTANT || game.canPlaySorcery(playerId) || null != permittingObject) { - if (costs.canPay(this, sourceId, playerId, game) && canChooseTarget(game)) { + MageObjectReference permittingObject = game.getContinuousEffects() + .asThough(sourceId, + AsThoughEffectType.ACTIVATE_AS_INSTANT, + this, + controllerId, + game); + if (timing == TimingRule.INSTANT + || game.canPlaySorcery(playerId) + || null != permittingObject) { + if (costs.canPay(this, sourceId, playerId, game) + && canChooseTarget(game)) { this.activatorId = playerId; return new ActivationStatus(true, permittingObject); } @@ -297,8 +310,10 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa } protected ActivationInfo getActivationInfo(Game game) { - Integer turnNum = (Integer) game.getState().getValue(CardUtil.getCardZoneString("activationsTurn" + originalId, sourceId, game)); - Integer activationCount = (Integer) game.getState().getValue(CardUtil.getCardZoneString("activationsCount" + originalId, sourceId, game)); + Integer turnNum = (Integer) game.getState() + .getValue(CardUtil.getCardZoneString("activationsTurn" + originalId, sourceId, game)); + Integer activationCount = (Integer) game.getState() + .getValue(CardUtil.getCardZoneString("activationsCount" + originalId, sourceId, game)); if (turnNum == null || activationCount == null) { return null; } @@ -306,7 +321,9 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa } protected void setActivationInfo(ActivationInfo activationInfo, Game game) { - game.getState().setValue(CardUtil.getCardZoneString("activationsTurn" + originalId, sourceId, game), activationInfo.turnNum); - game.getState().setValue(CardUtil.getCardZoneString("activationsCount" + originalId, sourceId, game), activationInfo.activationCounter); + game.getState().setValue(CardUtil + .getCardZoneString("activationsTurn" + originalId, sourceId, game), activationInfo.turnNum); + game.getState().setValue(CardUtil + .getCardZoneString("activationsCount" + originalId, sourceId, game), activationInfo.activationCounter); } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/SpectacleCondition.java b/Mage/src/main/java/mage/abilities/condition/common/SpectacleCondition.java new file mode 100644 index 00000000000..80824119441 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/SpectacleCondition.java @@ -0,0 +1,33 @@ + +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.abilities.keyword.SpectacleAbility; +import mage.constants.AbilityType; +import mage.game.Game; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author TheElk801 + */ +public enum SpectacleCondition implements Condition { + + instance; + + @Override + public boolean apply(Game game, Ability source) { + if (source.getAbilityType() == AbilityType.TRIGGERED) { + @SuppressWarnings("unchecked") + List spectacleActivations = (ArrayList) game.getState().getValue(SpectacleAbility.SPECTACLE_ACTIVATION_VALUE_KEY + source.getSourceId()); + if (spectacleActivations != null) { + return spectacleActivations.contains(game.getState().getZoneChangeCounter(source.getSourceId()) - 1); + } + return false; + } else { + return source instanceof SpectacleAbility; + } + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/CopyEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CopyEffect.java index b582f291303..da0131ace96 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CopyEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CopyEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common; import mage.MageObject; @@ -16,7 +15,6 @@ import mage.util.functions.ApplyToPermanent; import java.util.UUID; /** - * * @author BetaSteward_at_googlemail.com */ public class CopyEffect extends ContinuousEffectImpl { @@ -90,7 +88,13 @@ public class CopyEffect extends ContinuousEffectImpl { } protected boolean copyToPermanent(Permanent permanent, Game game, Ability source) { - permanent.setCopy(true); + if (copyFromObject.getCopyFrom() != null) { + // copy from temp blueprints (they are already copies) + permanent.setCopy(true, copyFromObject.getCopyFrom()); + } else { + // copy object to object + permanent.setCopy(true, copyFromObject); + } permanent.setName(copyFromObject.getName()); permanent.getColor(game).setColor(copyFromObject.getColor(game)); permanent.getManaCost().clear(); diff --git a/Mage/src/main/java/mage/abilities/effects/common/CopyTargetSpellEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CopyTargetSpellEffect.java index 040be4c85d7..93c6712292a 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CopyTargetSpellEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CopyTargetSpellEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common; import mage.abilities.Ability; @@ -13,7 +12,6 @@ import mage.players.Player; /** * @author BetaSteward_at_googlemail.com - * */ public class CopyTargetSpellEffect extends OneShotEffect { @@ -79,7 +77,14 @@ public class CopyTargetSpellEffect extends OneShotEffect { return staticText; } StringBuilder sb = new StringBuilder(); - sb.append("copy target ").append(mode.getTargets().get(0).getTargetName()).append(". You may choose new targets for the copy"); + sb.append("copy "); + if (!mode.getTargets().isEmpty()) { + sb.append("target ").append(mode.getTargets().get(0).getTargetName()); + } else { + sb.append("that spell"); + } + sb.append(". You may choose new targets for the copy"); + return sb.toString(); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/DestroyAllNamedPermanentsEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DestroyAllNamedPermanentsEffect.java index a2ef730ccde..cc767a1a600 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DestroyAllNamedPermanentsEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DestroyAllNamedPermanentsEffect.java @@ -1,5 +1,3 @@ - - package mage.abilities.effects.common; import mage.abilities.Ability; @@ -11,9 +9,9 @@ import mage.filter.predicate.mageobject.NamePredicate; import mage.filter.predicate.permanent.PermanentIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.util.CardUtil; /** - * * @author BetaSteward_at_googlemail.com */ public class DestroyAllNamedPermanentsEffect extends OneShotEffect { @@ -38,12 +36,12 @@ public class DestroyAllNamedPermanentsEffect extends OneShotEffect { return false; } FilterPermanent filter = new FilterPermanent(); - if (targetPermanent.getName().isEmpty()) { + if (CardUtil.haveEmptyName(targetPermanent)) { filter.add(new PermanentIdPredicate(targetPermanent.getId())); // if no name (face down creature) only the creature itself is selected } else { filter.add(new NamePredicate(targetPermanent.getName())); } - for (Permanent perm: game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { + for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { perm.destroy(source.getSourceId(), game, false); } return true; diff --git a/Mage/src/main/java/mage/abilities/effects/common/DoIfCostPaid.java b/Mage/src/main/java/mage/abilities/effects/common/DoIfCostPaid.java index 845fe9e5a43..5a8c7f408d3 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DoIfCostPaid.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DoIfCostPaid.java @@ -1,6 +1,5 @@ package mage.abilities.effects.common; -import java.util.Locale; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.Mode; @@ -14,6 +13,8 @@ import mage.game.Game; import mage.players.Player; import mage.util.CardUtil; +import java.util.Locale; + public class DoIfCostPaid extends OneShotEffect { protected Effects executingEffects = new Effects(); @@ -27,9 +28,10 @@ public class DoIfCostPaid extends OneShotEffect { } public DoIfCostPaid(Effect effect, Effect effect2, Cost cost) { - this(effect,effect2,cost,true); + this(effect, effect2, cost, true); } - public DoIfCostPaid(Effect effect, Effect effect2, Cost cost,boolean optional) { + + public DoIfCostPaid(Effect effect, Effect effect2, Cost cost, boolean optional) { this(effect, cost, null, optional); this.otherwiseEffects.add(effect2); } @@ -62,6 +64,14 @@ public class DoIfCostPaid extends OneShotEffect { return this; } + public Effects getExecutingEffects() { + return this.executingEffects; + } + + public Effects getOtherwiseEffects() { + return this.otherwiseEffects; + } + @Override public boolean apply(Game game, Ability source) { Player player = getPayingPlayer(game, source); diff --git a/Mage/src/main/java/mage/abilities/effects/common/ExileSpellEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ExileSpellEffect.java index 08100530054..f828e713ef8 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ExileSpellEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ExileSpellEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common; import mage.abilities.Ability; @@ -12,7 +11,6 @@ import mage.game.stack.Spell; import mage.players.Player; /** - * * @author BetaSteward_at_googlemail.com */ public class ExileSpellEffect extends OneShotEffect implements MageSingleton { @@ -38,7 +36,7 @@ public class ExileSpellEffect extends OneShotEffect implements MageSingleton { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { Spell spell = game.getStack().getSpell(source.getId()); - if (spell != null && !spell.isCopiedSpell()) { + if (spell != null && !spell.isCopy()) { Card spellCard = spell.getCard(); if (spellCard != null) { controller.moveCards(spellCard, Zone.EXILED, source, game); diff --git a/Mage/src/main/java/mage/abilities/effects/keyword/AdaptEffect.java b/Mage/src/main/java/mage/abilities/effects/keyword/AdaptEffect.java new file mode 100644 index 00000000000..0bbc9ebbb52 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/keyword/AdaptEffect.java @@ -0,0 +1,48 @@ +package mage.abilities.effects.keyword; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.util.CardUtil; + +/** + * @author TheElk801 + */ +public class AdaptEffect extends OneShotEffect { + + private final int adaptNumber; + + public AdaptEffect(int adaptNumber) { + super(Outcome.BoostCreature); + this.adaptNumber = adaptNumber; + staticText = "Adapt " + adaptNumber + + " (If this creature has no +1/+1 counters on it, put " + + CardUtil.numberToText(adaptNumber) + " +1/+1 counter" + + (adaptNumber > 1 ? "s" : "") + " on it.)"; + } + + private AdaptEffect(final AdaptEffect effect) { + super(effect); + this.adaptNumber = effect.adaptNumber; + } + + @Override + public AdaptEffect copy() { + return new AdaptEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent == null) { + return false; + } + if (permanent.getCounters(game).getCount(CounterType.P1P1) == 0) { + permanent.addCounters(CounterType.P1P1.createInstance(adaptNumber), source, game); + } + return true; + } +} diff --git a/Mage/src/main/java/mage/abilities/keyword/AfterlifeAbility.java b/Mage/src/main/java/mage/abilities/keyword/AfterlifeAbility.java new file mode 100644 index 00000000000..ba71038869d --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/AfterlifeAbility.java @@ -0,0 +1,34 @@ +package mage.abilities.keyword; + +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.game.permanent.token.WhiteBlackSpiritToken; +import mage.util.CardUtil; + +public class AfterlifeAbility extends DiesTriggeredAbility { + private final int tokenCount; + + public AfterlifeAbility(int tokenCount) { + super(new CreateTokenEffect(new WhiteBlackSpiritToken(), tokenCount), false); + this.tokenCount = tokenCount; + } + + public AfterlifeAbility(final AfterlifeAbility ability) { + super(ability); + this.tokenCount = ability.tokenCount; + } + + @Override + public String getRule() { + return "Afterlife " + tokenCount + " (When this creature dies, create " + + CardUtil.numberToText(tokenCount, "a") + + " white and black Spirit creature token" + + (tokenCount > 1 ? "s" : "") + + " with flying)"; + } + + @Override + public AfterlifeAbility copy() { + return new AfterlifeAbility(this); + } +} diff --git a/Mage/src/main/java/mage/abilities/keyword/ReboundAbility.java b/Mage/src/main/java/mage/abilities/keyword/ReboundAbility.java index 885d0a3b662..6afa7afdf0c 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ReboundAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ReboundAbility.java @@ -1,7 +1,5 @@ - package mage.abilities.keyword; -import java.util.UUID; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; @@ -21,6 +19,8 @@ import mage.game.events.ZoneChangeEvent; import mage.game.stack.Spell; import mage.players.Player; +import java.util.UUID; + /** * This ability has no effect by default and will always return false on the * call to apply. This is because of how the {@link ReboundEffect} works. It @@ -93,7 +93,7 @@ class ReboundCastFromHandReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Spell sourceSpell = game.getStack().getSpell(source.getSourceId()); - if (sourceSpell != null && sourceSpell.isCopiedSpell()) { + if (sourceSpell != null && sourceSpell.isCopy()) { return false; } else { Card sourceCard = game.getCard(source.getSourceId()); diff --git a/Mage/src/main/java/mage/abilities/keyword/RiotAbility.java b/Mage/src/main/java/mage/abilities/keyword/RiotAbility.java new file mode 100644 index 00000000000..47ca943dcb7 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/RiotAbility.java @@ -0,0 +1,96 @@ + +package mage.abilities.keyword; + +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * @author TheElk801 + */ +public class RiotAbility extends SimpleStaticAbility { + + public RiotAbility() { + super(Zone.ALL, new RiotReplacementEffect()); + } + + private RiotAbility(final RiotAbility ability) { + super(ability); + } + + @Override + public RiotAbility copy() { + return new RiotAbility(this); + } + + @Override + public String getRule() { + return "Riot (This creature enters the battlefield with your choice of a +1/+1 counter or haste.)"; + } +} + +class RiotReplacementEffect extends ReplacementEffectImpl { + + RiotReplacementEffect() { + super(Duration.EndOfGame, Outcome.Detriment); + } + + private RiotReplacementEffect(final RiotReplacementEffect effect) { + super(effect); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == EventType.ENTERS_THE_BATTLEFIELD; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return event.getTargetId().equals(source.getSourceId()); + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); + Player controller = game.getPlayer(source.getControllerId()); + if (creature != null && controller != null) { + if (controller.chooseUse(outcome, "Have " + creature.getLogName() + " enter the battlefield with a +1/+1 counter on it? (If you don't it has haste)", source, game)) { + if (!game.isSimulation()) { + game.informPlayers(controller.getLogName() + " choose to put a +1/+1 counter on " + creature.getName()); + } + creature.addCounters(CounterType.P1P1.createInstance(), source, game, event.getAppliedEffects()); + } else { + game.addEffect(new GainAbilitySourceEffect(HasteAbility.getInstance(), Duration.Custom), source); + } + } + return false; + } + + @Override + public String getText(Mode mode) { + return staticText; + } + + @Override + public RiotReplacementEffect copy() { + return new RiotReplacementEffect(this); + } + +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/abilities/keyword/SpectacleAbility.java b/Mage/src/main/java/mage/abilities/keyword/SpectacleAbility.java new file mode 100644 index 00000000000..e646742d6ab --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/SpectacleAbility.java @@ -0,0 +1,80 @@ + +package mage.abilities.keyword; + +import mage.abilities.SpellAbility; +import mage.abilities.costs.mana.ManaCost; +import mage.cards.Card; +import mage.constants.SpellAbilityType; +import mage.constants.Zone; +import mage.game.Game; +import mage.watchers.common.PlayerLostLifeWatcher; + +import java.util.ArrayList; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public class SpectacleAbility extends SpellAbility { + + public static final String SPECTACLE_ACTIVATION_VALUE_KEY = "spectacleActivation"; + + private String rule; + + public SpectacleAbility(Card card, ManaCost spectacleCosts) { + super(spectacleCosts, card.getName() + " with spectacle", Zone.HAND, SpellAbilityType.BASE_ALTERNATE); + this.getCosts().addAll(card.getSpellAbility().getCosts().copy()); + this.getEffects().addAll(card.getSpellAbility().getEffects().copy()); + this.getTargets().addAll(card.getSpellAbility().getTargets().copy()); + this.spellAbilityType = SpellAbilityType.BASE_ALTERNATE; + this.timing = card.getSpellAbility().getTiming(); + this.setRuleAtTheTop(true); + this.rule = "Spectacle " + spectacleCosts.getText() + + " (You may cast this spell for its spectacle cost rather than its mana cost if an opponent lost life this turn.)"; + } + + public SpectacleAbility(final SpectacleAbility ability) { + super(ability); + this.rule = ability.rule; + } + + @Override + public ActivationStatus canActivate(UUID playerId, Game game) { + PlayerLostLifeWatcher watcher = (PlayerLostLifeWatcher) game.getState().getWatchers().get(PlayerLostLifeWatcher.class.getSimpleName()); + if (watcher != null && watcher.getAllOppLifeLost(playerId, game) > 0) { + return super.canActivate(playerId, game); + } + return ActivationStatus.getFalse(); + } + + @Override + @SuppressWarnings("unchecked") + public boolean activate(Game game, boolean noMana) { + if (super.activate(game, noMana)) { + ArrayList spectacleActivations = (ArrayList) game.getState().getValue(SPECTACLE_ACTIVATION_VALUE_KEY + getSourceId()); + if (spectacleActivations == null) { + spectacleActivations = new ArrayList<>(); // zoneChangeCounter + game.getState().setValue(SPECTACLE_ACTIVATION_VALUE_KEY + getSourceId(), spectacleActivations); + } + spectacleActivations.add(game.getState().getZoneChangeCounter(getSourceId())); + return true; + } + return false; + } + + @Override + public SpectacleAbility copy() { + return new SpectacleAbility(this); + } + + @Override + public String getRule(boolean all) { + return getRule(); + } + + @Override + public String getRule() { + return rule; + } + +} diff --git a/Mage/src/main/java/mage/abilities/meta/OrTriggeredAbility.java b/Mage/src/main/java/mage/abilities/meta/OrTriggeredAbility.java index 1f0723298d2..0a4a17cb4c2 100644 --- a/Mage/src/main/java/mage/abilities/meta/OrTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/meta/OrTriggeredAbility.java @@ -1,5 +1,8 @@ package mage.abilities.meta; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; import mage.abilities.TriggeredAbility; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; @@ -8,10 +11,6 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.watchers.Watcher; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - /** * A triggered ability that combines several others and triggers whenever one or * more of them would. The abilities passed in should have null as their effect, @@ -56,7 +55,6 @@ public class OrTriggeredAbility extends TriggeredAbilityImpl { public boolean checkEventType(GameEvent event, Game game) { for (TriggeredAbility ability : triggeredAbilities) { if (ability.checkEventType(event, game)) { - System.out.println("Correct event type (" + event.getType() + ")"); return true; } } @@ -69,11 +67,9 @@ public class OrTriggeredAbility extends TriggeredAbilityImpl { for (int i = 0; i < triggeredAbilities.length; i++) { TriggeredAbility ability = triggeredAbilities[i]; if (ability.checkEventType(event, game) && ability.checkTrigger(event, game)) { - System.out.println("Triggered from " + ability.getRule()); triggeringAbilities.add(i); toRet = true; } - System.out.println("Checked " + ability.getRule()); } return toRet; } diff --git a/Mage/src/main/java/mage/cards/CardImpl.java b/Mage/src/main/java/mage/cards/CardImpl.java index 8b19cf5d3f8..56cad1816ca 100644 --- a/Mage/src/main/java/mage/cards/CardImpl.java +++ b/Mage/src/main/java/mage/cards/CardImpl.java @@ -327,7 +327,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card { return spellAbility; } -// @Override + // @Override // public void adjustCosts(Ability ability, Game game) { // } @Override @@ -720,7 +720,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card { @Override public String getLogName() { if (name.isEmpty()) { - return GameLog.getNeutralColoredText("face down card"); + return GameLog.getNeutralColoredText(EmptyNames.FACE_DOWN_CREATURE.toString()); } else { return GameLog.getColoredObjectIdName(this); } diff --git a/Mage/src/main/java/mage/cards/ExpansionSet.java b/Mage/src/main/java/mage/cards/ExpansionSet.java index 488b32b0441..bc0bdc90593 100644 --- a/Mage/src/main/java/mage/cards/ExpansionSet.java +++ b/Mage/src/main/java/mage/cards/ExpansionSet.java @@ -2,22 +2,21 @@ package mage.cards; import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.keyword.PartnerWithAbility; import mage.cards.repository.CardCriteria; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; -import mage.abilities.Ability; import mage.constants.Rarity; import mage.constants.SetType; import mage.util.CardUtil; import mage.util.RandomUtil; +import org.apache.log4j.Logger; import java.io.Serializable; import java.util.*; import java.util.stream.Collectors; -import mage.abilities.keyword.PartnerWithAbility; -import org.apache.log4j.Logger; - /** * @author BetaSteward_at_googlemail.com */ @@ -610,6 +609,11 @@ public abstract class ExpansionSet implements Serializable { return setType == SetType.CUSTOM_SET; } + public boolean isEternalLegal() { + return setType != SetType.CUSTOM_SET + && setType != SetType.JOKESET; + } + public void removeSavedCards() { savedCards.clear(); } diff --git a/Mage/src/main/java/mage/cards/SplitCard.java b/Mage/src/main/java/mage/cards/SplitCard.java index b8102f7ae4c..a602c2a6635 100644 --- a/Mage/src/main/java/mage/cards/SplitCard.java +++ b/Mage/src/main/java/mage/cards/SplitCard.java @@ -1,9 +1,6 @@ - package mage.cards; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; +import mage.MageObject; import mage.abilities.Abilities; import mage.abilities.AbilitiesImpl; import mage.abilities.Ability; @@ -13,8 +10,11 @@ import mage.constants.SpellAbilityType; import mage.constants.Zone; import mage.game.Game; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** - * * @author LevelX2 */ public abstract class SplitCard extends CardImpl { @@ -58,10 +58,10 @@ public abstract class SplitCard extends CardImpl { } @Override - public void setCopy(boolean isCopy) { - super.setCopy(isCopy); - leftHalfCard.setCopy(isCopy); - rightHalfCard.setCopy(isCopy); + public void setCopy(boolean isCopy, MageObject copiedFrom) { + super.setCopy(isCopy, copiedFrom); + leftHalfCard.setCopy(isCopy, copiedFrom); + rightHalfCard.setCopy(isCopy, copiedFrom); } @Override diff --git a/Mage/src/main/java/mage/cards/repository/CardRepository.java b/Mage/src/main/java/mage/cards/repository/CardRepository.java index 229b6351a23..93363d0a30a 100644 --- a/Mage/src/main/java/mage/cards/repository/CardRepository.java +++ b/Mage/src/main/java/mage/cards/repository/CardRepository.java @@ -10,9 +10,6 @@ import com.j256.ormlite.stmt.Where; import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.support.DatabaseConnection; import com.j256.ormlite.table.TableUtils; -import java.io.File; -import java.sql.SQLException; -import java.util.*; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SetType; @@ -20,6 +17,10 @@ import mage.constants.SuperType; import mage.util.RandomUtil; import org.apache.log4j.Logger; +import java.io.File; +import java.sql.SQLException; +import java.util.*; + /** * @author North */ @@ -32,7 +33,7 @@ public enum CardRepository { // raise this if db structure was changed private static final long CARD_DB_VERSION = 51; // raise this if new cards were added to the server - private static final long CARD_CONTENT_VERSION = 122; + private static final long CARD_CONTENT_VERSION = 123; private Dao cardDao; private Set classNames; @@ -43,9 +44,10 @@ public enum CardRepository { } try { ConnectionSource connectionSource = new JdbcConnectionSource(JDBC_URL); - boolean obsolete = RepositoryUtil.isDatabaseObsolete(connectionSource, VERSION_ENTITY_NAME, CARD_DB_VERSION); - if (obsolete) { + boolean isObsolete = RepositoryUtil.isDatabaseObsolete(connectionSource, VERSION_ENTITY_NAME, CARD_DB_VERSION); + boolean isNewBuild = RepositoryUtil.isNewBuildRun(connectionSource, VERSION_ENTITY_NAME, CardRepository.class); // recreate db on new build + if (isObsolete || isNewBuild) { TableUtils.dropTable(connectionSource, CardInfo.class, true); } @@ -483,9 +485,7 @@ public enum CardRepository { DatabaseConnection conn = cardDao.getConnectionSource().getReadWriteConnection(); conn.executeStatement("shutdown compact", 0); } - } catch (SQLException ex) { - } } diff --git a/Mage/src/main/java/mage/cards/repository/CardScanner.java b/Mage/src/main/java/mage/cards/repository/CardScanner.java index c098a939a5f..8a551411398 100644 --- a/Mage/src/main/java/mage/cards/repository/CardScanner.java +++ b/Mage/src/main/java/mage/cards/repository/CardScanner.java @@ -49,7 +49,7 @@ public final class CardScanner { ExpansionRepository.instance.setContentVersion(ExpansionRepository.instance.getContentVersionConstant()); if (setsAddedCount > 0) { - logger.info("DB: need to add " + setsUpdatedCount + " new sets"); + logger.info("DB: need to add " + setsAddedCount + " new sets"); } if (setsUpdatedCount > 0) { logger.info("DB: need to update " + setsUpdatedCount + " sets"); diff --git a/Mage/src/main/java/mage/cards/repository/DatabaseBuild.java b/Mage/src/main/java/mage/cards/repository/DatabaseBuild.java new file mode 100644 index 00000000000..9914b5246f8 --- /dev/null +++ b/Mage/src/main/java/mage/cards/repository/DatabaseBuild.java @@ -0,0 +1,33 @@ +package mage.cards.repository; + +import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.table.DatabaseTable; + +/** + * @author JayDi85 + */ +@DatabaseTable(tableName = "build") +public class DatabaseBuild { + + @DatabaseField + protected String entity; + + @DatabaseField(columnName = "last_build") + protected String lastBuild; + + public String getEntity() { + return entity; + } + + public void setEntity(String entity) { + this.entity = entity; + } + + public String getLastBuild() { + return lastBuild; + } + + public void setLastBuild(String lastBuild) { + this.lastBuild = lastBuild; + } +} diff --git a/Mage/src/main/java/mage/cards/repository/ExpansionRepository.java b/Mage/src/main/java/mage/cards/repository/ExpansionRepository.java index b36b5cc9e90..fe53c4c32cc 100644 --- a/Mage/src/main/java/mage/cards/repository/ExpansionRepository.java +++ b/Mage/src/main/java/mage/cards/repository/ExpansionRepository.java @@ -8,16 +8,16 @@ import com.j256.ormlite.stmt.QueryBuilder; import com.j256.ormlite.stmt.SelectArg; import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.table.TableUtils; +import org.apache.log4j.Logger; + import java.io.File; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; -import org.apache.log4j.Logger; /** - * * @author North */ public enum ExpansionRepository { @@ -42,9 +42,10 @@ public enum ExpansionRepository { } try { ConnectionSource connectionSource = new JdbcConnectionSource(JDBC_URL); - boolean obsolete = RepositoryUtil.isDatabaseObsolete(connectionSource, VERSION_ENTITY_NAME, EXPANSION_DB_VERSION); - if (obsolete) { + boolean isObsolete = RepositoryUtil.isDatabaseObsolete(connectionSource, VERSION_ENTITY_NAME, EXPANSION_DB_VERSION); + boolean isNewBuild = RepositoryUtil.isNewBuildRun(connectionSource, VERSION_ENTITY_NAME, ExpansionRepository.class); // recreate db on new build + if (isObsolete || isNewBuild) { TableUtils.dropTable(connectionSource, ExpansionInfo.class, true); } @@ -93,9 +94,9 @@ public enum ExpansionRepository { // only with boosters and cards GenericRawResults setsList = expansionDao.queryRaw( "select * from expansion e " - + " where e.boosters = 1 " - + " and exists(select (1) from card c where c.setcode = e.code) " - + " order by e.releasedate desc", + + " where e.boosters = 1 " + + " and exists(select (1) from card c where c.setcode = e.code) " + + " order by e.releasedate desc", expansionDao.getRawRowMapper()); List resList = new ArrayList<>(); diff --git a/Mage/src/main/java/mage/cards/repository/RepositoryUtil.java b/Mage/src/main/java/mage/cards/repository/RepositoryUtil.java index 15f4921f594..b794e8a4e79 100644 --- a/Mage/src/main/java/mage/cards/repository/RepositoryUtil.java +++ b/Mage/src/main/java/mage/cards/repository/RepositoryUtil.java @@ -7,6 +7,8 @@ import com.j256.ormlite.stmt.QueryBuilder; import com.j256.ormlite.stmt.SelectArg; import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.table.TableUtils; +import mage.util.JarVersion; + import java.sql.SQLException; import java.util.List; @@ -33,6 +35,29 @@ public final class RepositoryUtil { return dbVersions.isEmpty(); } + public static boolean isNewBuildRun(ConnectionSource connectionSource, String entityName, Class clazz) throws SQLException { + // build time checks only for releases, not runtime (e.g. IDE debug) + String currentBuild = JarVersion.getBuildTime(clazz); + if (!JarVersion.isBuildTimeOk(currentBuild)) { + return false; + } + + TableUtils.createTableIfNotExists(connectionSource, DatabaseBuild.class); + Dao dbBuildDao = DaoManager.createDao(connectionSource, DatabaseBuild.class); + + QueryBuilder queryBuilder = dbBuildDao.queryBuilder(); + queryBuilder.where().eq("entity", new SelectArg(entityName)).and().eq("last_build", currentBuild); + List dbBuilds = dbBuildDao.query(queryBuilder.prepare()); + + if (dbBuilds.isEmpty()) { + DatabaseBuild dbBuild = new DatabaseBuild(); + dbBuild.setEntity(entityName); + dbBuild.setLastBuild(currentBuild); + dbBuildDao.create(dbBuild); + } + return dbBuilds.isEmpty(); + } + public static void updateVersion(ConnectionSource connectionSource, String entityName, long version) throws SQLException { TableUtils.createTableIfNotExists(connectionSource, DatabaseVersion.class); Dao dbVersionDao = DaoManager.createDao(connectionSource, DatabaseVersion.class); diff --git a/Mage/src/main/java/mage/constants/AbilityWord.java b/Mage/src/main/java/mage/constants/AbilityWord.java index 408e590c662..898cc8ea6cb 100644 --- a/Mage/src/main/java/mage/constants/AbilityWord.java +++ b/Mage/src/main/java/mage/constants/AbilityWord.java @@ -7,6 +7,7 @@ package mage.constants; */ public enum AbilityWord { + ADDENDUM("Addendum"), BATTALION("Battalion"), BLOODRUSH("Bloodrush"), CHANNEL("Channel"), diff --git a/Mage/src/main/java/mage/constants/EmptyNames.java b/Mage/src/main/java/mage/constants/EmptyNames.java new file mode 100644 index 00000000000..998e75714a2 --- /dev/null +++ b/Mage/src/main/java/mage/constants/EmptyNames.java @@ -0,0 +1,24 @@ +package mage.constants; + +/** + * + * @author JayDi85 + */ +public enum EmptyNames { + + // TODO: make names for that cards and enable Assert.assertNotEquals("", permanentName); for assertXXX tests + // TODO: replace all getName().equals to haveSameNames and haveEmptyName + FACE_DOWN_CREATURE(""), // "Face down creature" + FACE_DOWN_TOKEN(""); // "Face down token" + + private final String cardName; + + EmptyNames(String cardName) { + this.cardName = cardName; + } + + @Override + public String toString() { + return cardName; + } +} diff --git a/Mage/src/main/java/mage/counters/CounterType.java b/Mage/src/main/java/mage/counters/CounterType.java index a5ce8b6a603..98e2cd259ff 100644 --- a/Mage/src/main/java/mage/counters/CounterType.java +++ b/Mage/src/main/java/mage/counters/CounterType.java @@ -91,6 +91,7 @@ public enum CounterType { P2P2(new BoostCounter(2, 2).name), PAGE("page"), PAIN("pain"), + PARALYZATION("paralyzation"), PETAL("petal"), PETRIFICATION("petrification"), PHYLACTERY("phylactery"), diff --git a/Mage/src/main/java/mage/designations/CitysBlessing.java b/Mage/src/main/java/mage/designations/CitysBlessing.java index ca5aaa74766..9e803a6b676 100644 --- a/Mage/src/main/java/mage/designations/CitysBlessing.java +++ b/Mage/src/main/java/mage/designations/CitysBlessing.java @@ -1,8 +1,6 @@ - package mage.designations; /** - * * @author LevelX2 */ public class CitysBlessing extends Designation { @@ -10,4 +8,13 @@ public class CitysBlessing extends Designation { public CitysBlessing() { super(DesignationType.CITYS_BLESSING, "RIX"); } + + private CitysBlessing(final CitysBlessing card) { + super(card); + } + + @Override + public CitysBlessing copy() { + return new CitysBlessing(this); + } } diff --git a/Mage/src/main/java/mage/designations/Designation.java b/Mage/src/main/java/mage/designations/Designation.java index 44d7ba62ab7..943e757e778 100644 --- a/Mage/src/main/java/mage/designations/Designation.java +++ b/Mage/src/main/java/mage/designations/Designation.java @@ -1,14 +1,5 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ package mage.designations; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.List; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.ObjectColor; @@ -28,8 +19,12 @@ import mage.game.events.ZoneChangeEvent; import mage.util.GameLog; import mage.util.SubTypeList; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; +import java.util.UUID; + /** - * * @author LevelX2 */ public abstract class Designation implements MageObject { @@ -43,6 +38,8 @@ public abstract class Designation implements MageObject { private DesignationType designationType; private UUID id; private FrameStyle frameStyle; + private boolean copy; + private MageObject copyFrom; // copied card INFO (used to call original adjusters) private Abilities abilites = new AbilitiesImpl<>(); private String expansionSetCodeForImage; private final boolean unique; // can a designation be added multiple times (false) or only once to an object (true) @@ -65,6 +62,8 @@ public abstract class Designation implements MageObject { this.name = designation.name; this.designationType = designation.designationType; this.frameStyle = designation.frameStyle; + this.copy = designation.copy; + this.copyFrom = (designation.copyFrom != null ? designation.copyFrom.copy() : null); this.abilites = designation.abilites.copy(); this.unique = designation.unique; } @@ -78,6 +77,22 @@ public abstract class Designation implements MageObject { this.id = UUID.randomUUID(); } + @Override + public void setCopy(boolean isCopy, MageObject copyFrom) { + this.copy = isCopy; + this.copyFrom = (copyFrom != null ? copyFrom.copy() : null); + } + + @Override + public boolean isCopy() { + return this.copy; + } + + @Override + public MageObject getCopyFrom() { + return this.copyFrom; + } + @Override public String getName() { return name; @@ -198,20 +213,6 @@ public abstract class Designation implements MageObject { public void adjustTargets(Ability ability, Game game) { } - @Override - public void setCopy(boolean isCopy) { - } - - @Override - public boolean isCopy() { - return false; - } - - @Override - public Designation copy() { - return this; - } - @Override public int getZoneChangeCounter(Game game) { return 1; // Emblems can't move zones until now so return always 1 @@ -232,7 +233,6 @@ public abstract class Designation implements MageObject { } /** - * * @param game * @param controllerId */ diff --git a/Mage/src/main/java/mage/designations/Monarch.java b/Mage/src/main/java/mage/designations/Monarch.java index 0281b3c4590..d178838970e 100644 --- a/Mage/src/main/java/mage/designations/Monarch.java +++ b/Mage/src/main/java/mage/designations/Monarch.java @@ -1,4 +1,3 @@ - package mage.designations; import mage.MageObject; @@ -15,7 +14,6 @@ import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; /** - * * @author LevelX2 */ public class Monarch extends Designation { @@ -25,6 +23,15 @@ public class Monarch extends Designation { addAbility(new MonarchDrawTriggeredAbility()); addAbility(new MonarchDealsCombatDamageToAPlayerTriggeredAbility()); } + + private Monarch(final Monarch monarch) { + super(monarch); + } + + @Override + public Monarch copy() { + return new Monarch(this); + } } // At the beginning of the monarch's end step, that player draws a card diff --git a/Mage/src/main/java/mage/filter/FilterPlayer.java b/Mage/src/main/java/mage/filter/FilterPlayer.java index 907dfb34340..8f085ddd67c 100644 --- a/Mage/src/main/java/mage/filter/FilterPlayer.java +++ b/Mage/src/main/java/mage/filter/FilterPlayer.java @@ -44,12 +44,12 @@ public class FilterPlayer extends FilterImpl { return object instanceof Player; } - public boolean match(Player player, UUID sourceId, UUID playerId, Game game) { - if (!this.match(player, game)) { + public boolean match(Player checkPlayer, UUID sourceId, UUID sourceControllerId, Game game) { + if (!this.match(checkPlayer, game)) { return false; } - return Predicates.and(extraPredicates).apply(new ObjectSourcePlayer(player, sourceId, playerId), game); + return Predicates.and(extraPredicates).apply(new ObjectSourcePlayer(checkPlayer, sourceId, sourceControllerId), game); } @Override diff --git a/Mage/src/main/java/mage/filter/common/FilterPlaneswalkerOrPlayer.java b/Mage/src/main/java/mage/filter/common/FilterPlaneswalkerOrPlayer.java index f587236ac42..601bb952bc4 100644 --- a/Mage/src/main/java/mage/filter/common/FilterPlaneswalkerOrPlayer.java +++ b/Mage/src/main/java/mage/filter/common/FilterPlaneswalkerOrPlayer.java @@ -47,6 +47,14 @@ public class FilterPlaneswalkerOrPlayer extends FilterImpl { this.playerFilter = filter.playerFilter.copy(); } + public FilterPlaneswalkerPermanent getFilterPermanent() { + return this.planeswalkerFilter; + } + + public FilterPlayer getFilterPlayer() { + return this.playerFilter; + } + @Override public boolean checkObjectClass(Object object) { return true; diff --git a/Mage/src/main/java/mage/filter/predicate/ObjectSourcePlayer.java b/Mage/src/main/java/mage/filter/predicate/ObjectSourcePlayer.java index aa73a7d466f..671c8abf0ca 100644 --- a/Mage/src/main/java/mage/filter/predicate/ObjectSourcePlayer.java +++ b/Mage/src/main/java/mage/filter/predicate/ObjectSourcePlayer.java @@ -12,8 +12,8 @@ public class ObjectSourcePlayer extends ObjectPlayer { protected final UUID sourceId; - public ObjectSourcePlayer(T object, UUID sourceId, UUID playerId) { - super(object, playerId); + public ObjectSourcePlayer(T object, UUID sourceId, UUID sourceControllerId) { + super(object, sourceControllerId); this.sourceId = sourceId; } diff --git a/Mage/src/main/java/mage/filter/predicate/mageobject/NamePredicate.java b/Mage/src/main/java/mage/filter/predicate/mageobject/NamePredicate.java index 65ac53f8d4d..b80f7766a70 100644 --- a/Mage/src/main/java/mage/filter/predicate/mageobject/NamePredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/mageobject/NamePredicate.java @@ -1,4 +1,3 @@ - package mage.filter.predicate.mageobject; import mage.MageObject; @@ -7,17 +6,23 @@ import mage.constants.SpellAbilityType; import mage.filter.predicate.Predicate; import mage.game.Game; import mage.game.stack.Spell; +import mage.util.CardUtil; /** - * * @author North */ public class NamePredicate implements Predicate { private final String name; + private final Boolean ignoreMtgRuleForEmptyNames; // NamePredicate uses at test and checks, it's must ignore that rules (empty names is not equals in mtg) public NamePredicate(String name) { + this(name, false); + } + + public NamePredicate(String name, Boolean ignoreMtgRuleForEmptyNames) { this.name = name; + this.ignoreMtgRuleForEmptyNames = ignoreMtgRuleForEmptyNames; } @Override @@ -25,17 +30,20 @@ public class NamePredicate implements Predicate { // If a player names a card, the player may name either half of a split card, but not both. // A split card has the chosen name if one of its two names matches the chosen name. if (input instanceof SplitCard) { - return name.equals(((SplitCard)input).getLeftHalfCard().getName()) || name.equals(((SplitCard)input).getRightHalfCard().getName()); - } else if (input instanceof Spell && ((Spell) input).getSpellAbility().getSpellAbilityType() == SpellAbilityType.SPLIT_FUSED){ - SplitCard card = (SplitCard) ((Spell)input).getCard(); - return name.equals(card.getLeftHalfCard().getName()) || name.equals(card.getRightHalfCard().getName()); + return CardUtil.haveSameNames(name, ((SplitCard) input).getLeftHalfCard().getName(), this.ignoreMtgRuleForEmptyNames) || + CardUtil.haveSameNames(name, ((SplitCard) input).getRightHalfCard().getName(), this.ignoreMtgRuleForEmptyNames); + } else if (input instanceof Spell && ((Spell) input).getSpellAbility().getSpellAbilityType() == SpellAbilityType.SPLIT_FUSED) { + SplitCard card = (SplitCard) ((Spell) input).getCard(); + return CardUtil.haveSameNames(name, card.getLeftHalfCard().getName(), this.ignoreMtgRuleForEmptyNames) || + CardUtil.haveSameNames(name, card.getRightHalfCard().getName(), this.ignoreMtgRuleForEmptyNames); } else { if (name.contains(" // ")) { String leftName = name.substring(0, name.indexOf(" // ")); String rightName = name.substring(name.indexOf(" // ") + 4, name.length()); - return leftName.equals(input.getName()) || rightName.equals(input.getName()); + return CardUtil.haveSameNames(leftName, input.getName(), this.ignoreMtgRuleForEmptyNames) || + CardUtil.haveSameNames(rightName, input.getName(), this.ignoreMtgRuleForEmptyNames); } else { - return name.equals(input.getName()); + return CardUtil.haveSameNames(name, input.getName(), this.ignoreMtgRuleForEmptyNames); } } } diff --git a/Mage/src/main/java/mage/filter/predicate/other/AuraCardCanAttachToPermanentId.java b/Mage/src/main/java/mage/filter/predicate/other/AuraCardCanAttachToPermanentId.java index 54e8e558536..54d3c490ed4 100644 --- a/Mage/src/main/java/mage/filter/predicate/other/AuraCardCanAttachToPermanentId.java +++ b/Mage/src/main/java/mage/filter/predicate/other/AuraCardCanAttachToPermanentId.java @@ -1,4 +1,3 @@ - package mage.filter.predicate.other; import java.util.UUID; @@ -14,7 +13,6 @@ import mage.target.Target; * @author jeffwadsworth */ // Use this predicate if a aura card comes into play attached to a permanent without targeting - public class AuraCardCanAttachToPermanentId implements Predicate { private final UUID toBeCheckedPermanentId; @@ -27,10 +25,14 @@ public class AuraCardCanAttachToPermanentId implements Predicate { public boolean apply(Card input, Game game) { final Permanent permanent = game.getPermanent(toBeCheckedPermanentId); Filter filter; - for (Target target : input.getSpellAbility().getTargets()) { - filter = target.getFilter(); - if (filter.match(permanent, game)) { - return true; + if (permanent != null + && input != null + && input.isEnchantment()) { + for (Target target : input.getSpellAbility().getTargets()) { + filter = target.getFilter(); + if (filter.match(permanent, game)) { + return true; + } } } return false; @@ -40,4 +42,4 @@ public class AuraCardCanAttachToPermanentId implements Predicate { public String toString() { return "AuraCardCanAttachToPermanentId(" + toBeCheckedPermanentId + ')'; } -} \ No newline at end of file +} diff --git a/Mage/src/main/java/mage/filter/predicate/other/TargetsOnlyOnePlayerPredicate.java b/Mage/src/main/java/mage/filter/predicate/other/TargetsOnlyOnePlayerPredicate.java new file mode 100644 index 00000000000..08433ae0890 --- /dev/null +++ b/Mage/src/main/java/mage/filter/predicate/other/TargetsOnlyOnePlayerPredicate.java @@ -0,0 +1,48 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.filter.predicate.other; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Mode; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.game.stack.StackObject; +import mage.players.Player; +import mage.target.Target; + +/** + * + * @author jeffwadsworth + */ +public class TargetsOnlyOnePlayerPredicate implements ObjectSourcePlayerPredicate> { + + public TargetsOnlyOnePlayerPredicate() { + } + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + StackObject object = game.getStack().getStackObject(input.getObject().getId()); + if (object != null) { + for (UUID modeId : object.getStackAbility().getModes().getSelectedModes()) { + Mode mode = object.getStackAbility().getModes().get(modeId); + for (Target target : mode.getTargets()) { + if (target.getTargets().size() == 1) { // only one player targeted + Player player = game.getPlayer(target.getFirstTarget()); + return player != null; + } + } + } + } + return false; + } + + @Override + public String toString() { + return "that targets only one player"; + } +} diff --git a/Mage/src/main/java/mage/filter/predicate/other/TargetsPlayerPredicate.java b/Mage/src/main/java/mage/filter/predicate/other/TargetsPlayerPredicate.java new file mode 100644 index 00000000000..af8f556bc4d --- /dev/null +++ b/Mage/src/main/java/mage/filter/predicate/other/TargetsPlayerPredicate.java @@ -0,0 +1,48 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.filter.predicate.other; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Mode; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.game.stack.StackObject; +import mage.players.Player; +import mage.target.Target; + +/** + * + * @author jeffwadsworth + */ +public class TargetsPlayerPredicate implements ObjectSourcePlayerPredicate> { + + public TargetsPlayerPredicate() { + } + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + StackObject object = game.getStack().getStackObject(input.getObject().getId()); + if (object != null) { + for (UUID modeId : object.getStackAbility().getModes().getSelectedModes()) { + Mode mode = object.getStackAbility().getModes().get(modeId); + for (Target target : mode.getTargets()) { + for (UUID targetId : target.getTargets()) { + Player player = game.getPlayer(targetId); + return player != null; + } + } + } + } + return false; + } + + @Override + public String toString() { + return "that targets a player"; + } +} diff --git a/Mage/src/main/java/mage/game/Exile.java b/Mage/src/main/java/mage/game/Exile.java index 3fc2a7ab7bc..304bbe07ec7 100644 --- a/Mage/src/main/java/mage/game/Exile.java +++ b/Mage/src/main/java/mage/game/Exile.java @@ -9,7 +9,10 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.UUID; +import java.util.stream.Collectors; + import mage.cards.Card; +import mage.filter.FilterCard; import mage.util.Copyable; /** @@ -70,6 +73,11 @@ public class Exile implements Serializable, Copyable { return null; } + public List getCards(FilterCard filter, Game game) { + List allCards = getAllCards(game); + return allCards.stream().filter(card -> filter.match(card, game)).collect(Collectors.toList()); + } + public List getAllCards(Game game) { List cards = new ArrayList<>(); for (ExileZone exile : exileZones.values()) { diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index c0fa488e204..a6eb99e1415 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -1638,6 +1638,7 @@ public abstract class GameImpl implements Game, Serializable { if (newBluePrint == null) { newBluePrint = copyFromPermanent.copy(); newBluePrint.reset(this); + //getState().addCard(permanent); if (copyFromPermanent.isMorphed() || copyFromPermanent.isManifested()) { MorphAbility.setPermanentToFaceDownCreature(newBluePrint); @@ -1651,6 +1652,9 @@ public abstract class GameImpl implements Game, Serializable { applier.apply(this, newBluePrint, source, copyToPermanentId); } + // save original copy link (handle copy of copies too) + newBluePrint.setCopy(true, (copyFromPermanent.getCopyFrom() != null ? copyFromPermanent.getCopyFrom() : copyFromPermanent)); + CopyEffect newEffect = new CopyEffect(duration, newBluePrint, copyToPermanentId); newEffect.newId(); newEffect.setApplier(applier); diff --git a/Mage/src/main/java/mage/game/GameState.java b/Mage/src/main/java/mage/game/GameState.java index e18fc41b72f..b98810d1794 100644 --- a/Mage/src/main/java/mage/game/GameState.java +++ b/Mage/src/main/java/mage/game/GameState.java @@ -1,8 +1,5 @@ package mage.game; -import java.io.Serializable; -import java.util.*; -import java.util.stream.Collectors; import mage.MageObject; import mage.abilities.*; import mage.abilities.effects.ContinuousEffect; @@ -35,15 +32,17 @@ import mage.util.ThreadLocalStringBuilder; import mage.watchers.Watcher; import mage.watchers.Watchers; +import java.io.Serializable; +import java.util.*; +import java.util.stream.Collectors; + /** - * * @author BetaSteward_at_googlemail.com - * + *

    * since at any time the game state may be copied and restored you cannot rely * on any object maintaining it's instance it then becomes necessary to only * refer to objects by their ids since these will always remain constant * throughout its lifetime - * */ public class GameState implements Serializable, Copyable { @@ -590,6 +589,7 @@ public class GameState implements Serializable, Copyable { // public void addMessage(String message) { // this.messages.add(message); // } + /** * Returns a list of all players of the game ignoring range or if a player * has lost or left the game. @@ -758,7 +758,7 @@ public class GameState implements Serializable, Copyable { } for (Map.Entry> entry : eventsByKey.entrySet()) { Set movedCards = new LinkedHashSet<>(); - for (Iterator it = entry.getValue().iterator(); it.hasNext();) { + for (Iterator it = entry.getValue().iterator(); it.hasNext(); ) { GameEvent event = it.next(); ZoneChangeEvent castEvent = (ZoneChangeEvent) event; UUID targetId = castEvent.getTargetId(); @@ -943,7 +943,7 @@ public class GameState implements Serializable, Copyable { /** * Other abilities are used to implement some special kind of continuous * effects that give abilities to non permanents. - * + *

    * Crucible of Worlds - You may play land cards from your graveyard. Past in * Flames - Each instant and sorcery card in your graveyard gains flashback * until end of turn. The flashback cost is equal to its mana cost. Varolz, @@ -984,7 +984,7 @@ public class GameState implements Serializable, Copyable { * @param attachedTo * @param ability * @param copyAbility copies non MageSingleton abilities before adding to - * state + * state */ public void addOtherAbility(Card attachedTo, Ability ability, boolean copyAbility) { Ability newAbility; @@ -1134,7 +1134,7 @@ public class GameState implements Serializable, Copyable { Card copiedCard = cardToCopy.copy(); copiedCard.assignNewId(); copiedCard.setOwnerId(source.getControllerId()); - copiedCard.setCopy(true); + copiedCard.setCopy(true, cardToCopy); copiedCards.put(copiedCard.getId(), copiedCard); addCard(copiedCard); if (copiedCard.isSplitCard()) { diff --git a/Mage/src/main/java/mage/game/command/Commander.java b/Mage/src/main/java/mage/game/command/Commander.java index 966133e5dd4..7163f8683ef 100644 --- a/Mage/src/main/java/mage/game/command/Commander.java +++ b/Mage/src/main/java/mage/game/command/Commander.java @@ -1,10 +1,7 @@ - package mage.game.command; -import java.util.EnumSet; -import java.util.List; -import java.util.UUID; import mage.MageInt; +import mage.MageObject; import mage.ObjectColor; import mage.abilities.Abilities; import mage.abilities.AbilitiesImpl; @@ -24,9 +21,15 @@ import mage.game.events.ZoneChangeEvent; import mage.util.GameLog; import mage.util.SubTypeList; +import java.util.EnumSet; +import java.util.List; +import java.util.UUID; + public class Commander implements CommandObject { private final Card sourceObject; + private boolean copy; + private MageObject copyFrom; // copied card INFO (used to call original adjusters) private final Abilities abilities = new AbilitiesImpl<>(); public Commander(Card card) { @@ -40,8 +43,10 @@ public class Commander implements CommandObject { } } - private Commander(Commander copy) { - this.sourceObject = copy.sourceObject; + private Commander(final Commander commander) { + this.sourceObject = commander.sourceObject; + this.copy = commander.copy; + this.copyFrom = (commander.copyFrom != null ? commander.copyFrom.copy() : null); } @Override @@ -68,6 +73,22 @@ public class Commander implements CommandObject { return new Commander(this); } + @Override + public void setCopy(boolean isCopy, MageObject copyFrom) { + this.copy = isCopy; + this.copyFrom = (copyFrom != null ? copyFrom.copy() : null); + } + + @Override + public boolean isCopy() { + return this.copy; + } + + @Override + public MageObject getCopyFrom() { + return this.copyFrom; + } + @Override public String getName() { return sourceObject.getName(); @@ -170,15 +191,6 @@ public class Commander implements CommandObject { public void adjustTargets(Ability ability, Game game) { } - @Override - public void setCopy(boolean isCopy) { - } - - @Override - public boolean isCopy() { - return false; - } - @Override public UUID getId() { return sourceObject.getId(); diff --git a/Mage/src/main/java/mage/game/command/Emblem.java b/Mage/src/main/java/mage/game/command/Emblem.java index d95cfb659d6..7a4a8896aa7 100644 --- a/Mage/src/main/java/mage/game/command/Emblem.java +++ b/Mage/src/main/java/mage/game/command/Emblem.java @@ -1,8 +1,5 @@ package mage.game.command; -import java.util.EnumSet; -import java.util.List; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.ObjectColor; @@ -25,6 +22,10 @@ import mage.game.events.ZoneChangeEvent; import mage.util.GameLog; import mage.util.SubTypeList; +import java.util.EnumSet; +import java.util.List; +import java.util.UUID; + /** * @author nantuko */ @@ -38,6 +39,8 @@ public class Emblem implements CommandObject { private UUID id; private UUID controllerId; private MageObject sourceObject; + private boolean copy; + private MageObject copyFrom; // copied card INFO (used to call original adjusters) private FrameStyle frameStyle; private Abilities abilites = new AbilitiesImpl<>(); private String expansionSetCodeForImage = ""; @@ -52,6 +55,8 @@ public class Emblem implements CommandObject { this.frameStyle = emblem.frameStyle; this.controllerId = emblem.controllerId; this.sourceObject = emblem.sourceObject; + this.copy = emblem.copy; + this.copyFrom = (emblem.copyFrom != null ? emblem.copyFrom : null); this.abilites = emblem.abilites.copy(); this.expansionSetCodeForImage = emblem.expansionSetCodeForImage; } @@ -101,6 +106,22 @@ public class Emblem implements CommandObject { this.abilites.setControllerId(controllerId); } + @Override + public void setCopy(boolean isCopy, MageObject copyFrom) { + this.copy = isCopy; + this.copyFrom = (copyFrom != null ? copyFrom.copy() : null); + } + + @Override + public boolean isCopy() { + return this.copy; + } + + @Override + public MageObject getCopyFrom() { + return this.copyFrom; + } + @Override public String getName() { return name; @@ -204,15 +225,6 @@ public class Emblem implements CommandObject { return this.id; } - @Override - public void setCopy(boolean isCopy) { - } - - @Override - public boolean isCopy() { - return false; - } - @Override public Emblem copy() { return new Emblem(this); diff --git a/Mage/src/main/java/mage/game/command/Plane.java b/Mage/src/main/java/mage/game/command/Plane.java index ae34edade03..d05b0ceed36 100644 --- a/Mage/src/main/java/mage/game/command/Plane.java +++ b/Mage/src/main/java/mage/game/command/Plane.java @@ -41,6 +41,8 @@ public class Plane implements CommandObject { private UUID id; private UUID controllerId; private MageObject sourceObject; + private boolean copy; + private MageObject copyFrom; // copied card INFO (used to call original adjusters) private FrameStyle frameStyle; private Abilities abilites = new AbilitiesImpl<>(); private String expansionSetCodeForImage = ""; @@ -56,6 +58,8 @@ public class Plane implements CommandObject { this.frameStyle = plane.frameStyle; this.controllerId = plane.controllerId; this.sourceObject = plane.sourceObject; + this.copy = plane.copy; + this.copyFrom = (plane.copyFrom != null ? plane.copyFrom.copy() : null); this.abilites = plane.abilites.copy(); this.expansionSetCodeForImage = plane.expansionSetCodeForImage; } @@ -105,6 +109,22 @@ public class Plane implements CommandObject { this.abilites.setControllerId(controllerId); } + @Override + public void setCopy(boolean isCopy, MageObject copyFrom) { + this.copy = isCopy; + this.copyFrom = (copyFrom != null ? copyFrom.copy() : null); + } + + @Override + public boolean isCopy() { + return this.copy; + } + + @Override + public MageObject getCopyFrom() { + return this.copyFrom; + } + @Override public String getName() { return name; @@ -208,15 +228,6 @@ public class Plane implements CommandObject { return this.id; } - @Override - public void setCopy(boolean isCopy) { - } - - @Override - public boolean isCopy() { - return false; - } - @Override public Plane copy() { return new Plane(this); diff --git a/Mage/src/main/java/mage/game/command/emblems/MomirEmblem.java b/Mage/src/main/java/mage/game/command/emblems/MomirEmblem.java index 272a96ba410..ae721d6d070 100644 --- a/Mage/src/main/java/mage/game/command/emblems/MomirEmblem.java +++ b/Mage/src/main/java/mage/game/command/emblems/MomirEmblem.java @@ -1,7 +1,5 @@ - package mage.game.command.emblems; -import java.util.List; import mage.abilities.Ability; import mage.abilities.common.LimitedTimesPerTurnActivatedAbility; import mage.abilities.costs.common.DiscardCardCost; @@ -13,19 +11,16 @@ import mage.cards.Sets; import mage.cards.repository.CardCriteria; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SetType; -import mage.constants.TimingRule; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.command.Emblem; import mage.game.permanent.token.EmptyToken; import mage.util.CardUtil; import mage.util.RandomUtil; +import java.util.List; + /** - * * @author spjspj */ public final class MomirEmblem extends Emblem { @@ -70,7 +65,7 @@ class MomirEffect extends OneShotEffect { return false; } EmptyToken token = new EmptyToken(); // search for a non custom set creature - while (token.getName().isEmpty() && !options.isEmpty()) { + while (!options.isEmpty()) { int index = RandomUtil.nextInt(options.size()); ExpansionSet expansionSet = Sets.findSet(options.get(index).getSetCode()); if (expansionSet == null || expansionSet.getSetType() == SetType.CUSTOM_SET) { @@ -79,6 +74,7 @@ class MomirEffect extends OneShotEffect { Card card = options.get(index).getCard(); if (card != null) { CardUtil.copyTo(token).from(card); + break; } else { options.remove(index); } diff --git a/Mage/src/main/java/mage/game/draft/DraftCube.java b/Mage/src/main/java/mage/game/draft/DraftCube.java index 439a5c6a6d2..7854940ccbd 100644 --- a/Mage/src/main/java/mage/game/draft/DraftCube.java +++ b/Mage/src/main/java/mage/game/draft/DraftCube.java @@ -46,6 +46,7 @@ public abstract class DraftCube { private static final Logger logger = Logger.getLogger(DraftCube.class); private final String name; + private final String code; private static final int boosterSize = 15; protected List cubeCards = new ArrayList<>(); @@ -53,12 +54,17 @@ public abstract class DraftCube { public DraftCube(String name) { this.name = name; + this.code = getClass().getSimpleName(); } public String getName() { return name; } + public String getCode() { + return code; + } + public List getCubeCards() { return cubeCards; } diff --git a/Mage/src/main/java/mage/game/match/MatchOptions.java b/Mage/src/main/java/mage/game/match/MatchOptions.java index 02e6808416c..47ad873e631 100644 --- a/Mage/src/main/java/mage/game/match/MatchOptions.java +++ b/Mage/src/main/java/mage/game/match/MatchOptions.java @@ -37,6 +37,7 @@ public class MatchOptions implements Serializable { protected boolean spectatorsAllowed; protected boolean planeChase; protected int quitRatio; + protected int minimumRating; protected int edhPowerLevel; protected boolean rated; protected int numSeatsForMatch; @@ -205,6 +206,10 @@ public class MatchOptions implements Serializable { this.quitRatio = quitRatio; } + public int getMinimumRating() { return minimumRating; } + + public void setMinimumRating(int minimumRating) { this.minimumRating = minimumRating; } + public int getEdhPowerLevel() { return edhPowerLevel; } diff --git a/Mage/src/main/java/mage/game/permanent/PermanentCard.java b/Mage/src/main/java/mage/game/permanent/PermanentCard.java index eef81055552..f6436ee4511 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentCard.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentCard.java @@ -21,6 +21,8 @@ public class PermanentCard extends PermanentImpl { protected int maxLevelCounters; // A copy of the origin card that was cast (this is not the original card, so it's possible to chnage some attribute to this blueprint to change attributes to the permanent if it enters the battlefield with e.g. a subtype) protected Card card; + // A copy of original card that was used for copy and create current permanent (used in copy effects and special commands like adjustTargets) + protected Card copiedFromCard; // the number this permanent instance had protected int zoneChangeCounter; @@ -153,7 +155,13 @@ public class PermanentCard extends PermanentImpl { if (this.isTransformed() && card.getSecondCardFace() != null) { card.getSecondCardFace().adjustTargets(ability, game); } else { - card.adjustTargets(ability, game); + if (this.isCopy()) { + // if COPIED card have adjuster then it's must be called instead own -- see OathOfLieges tests + // raise null error on wrong copy + this.getCopyFrom().adjustTargets(ability, game); + } else { + card.adjustTargets(ability, game); + } } } diff --git a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java index 776f0b775dd..800ccba21d0 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java @@ -1,4 +1,3 @@ - package mage.game.permanent; import mage.MageObject; @@ -50,6 +49,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { this.counter = counter; this.sourceObject = sourceObject; } + Counter counter; MageObject sourceObject; } @@ -164,7 +164,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { @Override public String toString() { StringBuilder sb = threadLocalBuilder.get(); - sb.append(this.name).append('-').append(this.expansionSetCode); + sb.append(this.getName()).append('-').append(this.expansionSetCode); if (copy) { sb.append(" [Copy]"); } @@ -195,10 +195,23 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { } } + @Override + public String getName() { + if (name.isEmpty()) { + if (faceDown) { + return EmptyNames.FACE_DOWN_CREATURE.toString(); + } else { + return ""; + } + } else { + return name; + } + } + @Override public String getValue(GameState state) { StringBuilder sb = threadLocalBuilder.get(); - sb.append(controllerId).append(name).append(tapped).append(damage); + sb.append(controllerId).append(getName()).append(tapped).append(damage); sb.append(subtype).append(supertype).append(power.getValue()).append(toughness.getValue()); sb.append(abilities.getValue()); for (Counter counter : getCounters(state).values()) { @@ -245,7 +258,6 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { } /** - * * @param ability * @param game */ @@ -665,7 +677,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { this.attachedTo = attachToObjectId; this.attachedToZoneChangeCounter = game.getState().getZoneChangeCounter(attachToObjectId); for (Ability ability : this.getAbilities()) { - for (Iterator ite = ability.getEffects(game, EffectType.CONTINUOUS).iterator(); ite.hasNext();) { + for (Iterator ite = ability.getEffects(game, EffectType.CONTINUOUS).iterator(); ite.hasNext(); ) { ContinuousEffect effect = (ContinuousEffect) ite.next(); game.getContinuousEffects().setOrder(effect); // It's important to update the timestamp of the copied effect in ContinuousEffects because it does the action @@ -715,8 +727,8 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { * @param game * @param preventable * @param combat - * @param markDamage If true, damage will be dealt later in applyDamage - * method + * @param markDamage If true, damage will be dealt later in applyDamage + * method * @return */ private int damage(int damageAmount, UUID sourceId, Game game, boolean preventable, boolean combat, boolean markDamage, List appliedEffects) { @@ -1441,20 +1453,20 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { //If an object leaves the zone it's in, all attached permanents become unattached //note that this code doesn't actually detach anything, and is a bit of a bandaid public void detachAllAttachments(Game game) { - for(UUID attachmentId : getAttachments()) { + for (UUID attachmentId : getAttachments()) { Permanent attachment = game.getPermanent(attachmentId); Card attachmentCard = game.getCard(attachmentId); - if(attachment != null && attachmentCard != null) { + if (attachment != null && attachmentCard != null) { //make bestow cards and licids into creatures //aura test to stop bludgeon brawl shenanigans from using this code //consider adding code to handle that case? - if(attachment.hasSubtype(SubType.AURA, game) && attachmentCard.isCreature()) { + if (attachment.hasSubtype(SubType.AURA, game) && attachmentCard.isCreature()) { BestowAbility.becomeCreature(attachment, game); } } } } - + @Override public boolean moveToZone(Zone toZone, UUID sourceId, Game game, boolean flag, List appliedEffects) { Zone fromZone = game.getState().getZone(objectId); @@ -1480,7 +1492,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { Zone fromZone = game.getState().getZone(objectId); ZoneChangeEvent event = new ZoneChangeEvent(this, sourceId, ownerId, fromZone, Zone.EXILED, appliedEffects); ZoneChangeInfo.Exile info = new ZoneChangeInfo.Exile(event, exileId, name); - + boolean successfullyMoved = ZonesHandler.moveCard(info, game); //20180810 - 701.3d detachAllAttachments(game); diff --git a/Mage/src/main/java/mage/game/permanent/PermanentToken.java b/Mage/src/main/java/mage/game/permanent/PermanentToken.java index bb04a3916df..ba809c20565 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentToken.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentToken.java @@ -1,15 +1,15 @@ - package mage.game.permanent; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCost; +import mage.constants.EmptyNames; import mage.game.Game; import mage.game.permanent.token.Token; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public class PermanentToken extends PermanentImpl { @@ -42,6 +42,15 @@ public class PermanentToken extends PermanentImpl { this.toughness.resetToBaseValue(); } + @Override + public String getName() { + if (name.isEmpty()) { + return EmptyNames.FACE_DOWN_TOKEN.toString(); + } else { + return name; + } + } + private void copyFromToken(Token token, Game game, boolean reset) { this.name = token.getName(); this.abilities.clear(); diff --git a/Mage/src/main/java/mage/game/permanent/token/BeckonApparitionToken.java b/Mage/src/main/java/mage/game/permanent/token/BeckonApparitionToken.java deleted file mode 100644 index 199457fcc2f..00000000000 --- a/Mage/src/main/java/mage/game/permanent/token/BeckonApparitionToken.java +++ /dev/null @@ -1,34 +0,0 @@ - - -package mage.game.permanent.token; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.MageInt; -import mage.abilities.keyword.FlyingAbility; - -/** - * - * @author spjspj - */ -public final class BeckonApparitionToken extends TokenImpl { - - public BeckonApparitionToken() { - super("Spirit", "1/1 white and black Spirit creature token with flying"); - this.setOriginalExpansionSetCode("GTC"); - cardType.add(CardType.CREATURE); - color.setWhite(true); - color.setBlack(true); - subtype.add(SubType.SPIRIT); - power = new MageInt(1); - toughness = new MageInt(1); - this.addAbility(FlyingAbility.getInstance()); - } - public BeckonApparitionToken(final BeckonApparitionToken token) { - super(token); - } - - public BeckonApparitionToken copy() { - return new BeckonApparitionToken(this); - } - -} diff --git a/Mage/src/main/java/mage/game/permanent/token/RapidHybridizationToken.java b/Mage/src/main/java/mage/game/permanent/token/FrogLizardToken.java similarity index 66% rename from Mage/src/main/java/mage/game/permanent/token/RapidHybridizationToken.java rename to Mage/src/main/java/mage/game/permanent/token/FrogLizardToken.java index 0f3b2c7dd9f..bf46efa927b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/RapidHybridizationToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/FrogLizardToken.java @@ -9,9 +9,9 @@ import mage.MageInt; * * @author spjspj */ -public final class RapidHybridizationToken extends TokenImpl { +public final class FrogLizardToken extends TokenImpl { - public RapidHybridizationToken() { + public FrogLizardToken() { super("Frog Lizard", "3/3 green Frog Lizard creature token"); this.setOriginalExpansionSetCode("GTC"); cardType.add(CardType.CREATURE); @@ -25,11 +25,11 @@ public final class RapidHybridizationToken extends TokenImpl { toughness = new MageInt(3); } - public RapidHybridizationToken(final RapidHybridizationToken token) { + public FrogLizardToken(final FrogLizardToken token) { super(token); } - public RapidHybridizationToken copy() { - return new RapidHybridizationToken(this); + public FrogLizardToken copy() { + return new FrogLizardToken(this); } } diff --git a/Mage/src/main/java/mage/game/permanent/token/StarfishToken.java b/Mage/src/main/java/mage/game/permanent/token/StarfishToken.java new file mode 100644 index 00000000000..3e2b867fb3a --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/StarfishToken.java @@ -0,0 +1,34 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * + * @author spike + */ +public final class StarfishToken extends TokenImpl { + + public StarfishToken() { + this(null, 0); + } + + public StarfishToken(String setCode, int tokenType) { + super("Starfish", "0/1 blue Starfish creature token"); + cardType.add(CardType.CREATURE); + subtype.add(SubType.STARFISH); + color.setBlue(true); + power = new MageInt(0); + toughness = new MageInt(1); + } + + public StarfishToken(final StarfishToken token) { + super(token); + } + + @Override + public StarfishToken copy() { + return new StarfishToken(this); + } +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/game/permanent/token/TeysaEnvoyOfGhostsToken.java b/Mage/src/main/java/mage/game/permanent/token/WhiteBlackSpiritToken.java similarity index 67% rename from Mage/src/main/java/mage/game/permanent/token/TeysaEnvoyOfGhostsToken.java rename to Mage/src/main/java/mage/game/permanent/token/WhiteBlackSpiritToken.java index 19ccedcc362..7bf6156883e 100644 --- a/Mage/src/main/java/mage/game/permanent/token/TeysaEnvoyOfGhostsToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/WhiteBlackSpiritToken.java @@ -1,18 +1,18 @@ package mage.game.permanent.token; -import mage.constants.CardType; -import mage.constants.SubType; + import mage.MageInt; import mage.abilities.keyword.FlyingAbility; +import mage.constants.CardType; +import mage.constants.SubType; /** - * * @author spjspj */ -public final class TeysaEnvoyOfGhostsToken extends TokenImpl { +public final class WhiteBlackSpiritToken extends TokenImpl { - public TeysaEnvoyOfGhostsToken() { + public WhiteBlackSpiritToken() { super("Spirit", "1/1 white and black Spirit creature token with flying"); cardType.add(CardType.CREATURE); color.setWhite(true); @@ -23,11 +23,11 @@ public final class TeysaEnvoyOfGhostsToken extends TokenImpl { this.addAbility(FlyingAbility.getInstance()); } - public TeysaEnvoyOfGhostsToken(final TeysaEnvoyOfGhostsToken token) { + public WhiteBlackSpiritToken(final WhiteBlackSpiritToken token) { super(token); } - public TeysaEnvoyOfGhostsToken copy() { - return new TeysaEnvoyOfGhostsToken(this); + public WhiteBlackSpiritToken copy() { + return new WhiteBlackSpiritToken(this); } } diff --git a/Mage/src/main/java/mage/game/stack/Spell.java b/Mage/src/main/java/mage/game/stack/Spell.java index 281a6485dd7..bfc8fce81c2 100644 --- a/Mage/src/main/java/mage/game/stack/Spell.java +++ b/Mage/src/main/java/mage/game/stack/Spell.java @@ -1,10 +1,5 @@ - package mage.game.stack; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.List; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.Mana; @@ -39,8 +34,12 @@ import mage.players.Player; import mage.util.GameLog; import mage.util.SubTypeList; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public class Spell extends StackObjImpl implements Card { @@ -63,7 +62,8 @@ public class Spell extends StackObjImpl implements Card { private final UUID id; private UUID controllerId; - private boolean copiedSpell; + private boolean copy; + private MageObject copyFrom; // copied card INFO (used to call original adjusters) private boolean faceDown; private boolean countered; private boolean resolving = false; @@ -118,7 +118,8 @@ public class Spell extends StackObjImpl implements Card { this.frameStyle = spell.frameStyle; this.controllerId = spell.controllerId; - this.copiedSpell = spell.copiedSpell; + this.copy = spell.copy; + this.copyFrom = (spell.copyFrom != null ? spell.copyFrom.copy() : null); this.faceDown = spell.faceDown; this.countered = spell.countered; this.resolving = spell.resolving; @@ -155,7 +156,7 @@ public class Spell extends StackObjImpl implements Card { public String getActivatedMessage(Game game) { StringBuilder sb = new StringBuilder(); - if (isCopiedSpell()) { + if (isCopy()) { sb.append(" copies "); } else { sb.append(" casts "); @@ -362,7 +363,7 @@ public class Spell extends StackObjImpl implements Card { @Override public void counter(UUID sourceId, Game game, Zone zone, boolean owner, ZoneDetail zoneDetail) { this.countered = true; - if (!isCopiedSpell()) { + if (!isCopy()) { Player player = game.getPlayer(game.getControllerId(sourceId)); if (player == null) { player = game.getPlayer(getControllerId()); @@ -706,7 +707,7 @@ public class Spell extends StackObjImpl implements Card { newAbility.newId(); copy.addSpellAbility(newAbility); } - copy.setCopy(true); + copy.setCopy(true, this); copy.setControllerId(newController); return copy; } @@ -740,7 +741,7 @@ public class Spell extends StackObjImpl implements Card { // 706.10a If a copy of a spell is in a zone other than the stack, it ceases to exist. // If a copy of a card is in any zone other than the stack or the battlefield, it ceases to exist. // These are state-based actions. See rule 704. - if (this.isCopiedSpell() && zone != Zone.STACK) { + if (this.isCopy() && zone != Zone.STACK) { return true; } return card.moveToZone(zone, sourceId, game, flag, appliedEffects); @@ -753,7 +754,7 @@ public class Spell extends StackObjImpl implements Card { @Override public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game, List appliedEffects) { - if (this.isCopiedSpell()) { + if (this.isCopy()) { game.getStack().remove(this, game); return true; } @@ -835,26 +836,24 @@ public class Spell extends StackObjImpl implements Card { // do nothing } - public void setCopiedSpell(boolean isCopied) { - this.copiedSpell = isCopied; - } - - public boolean isCopiedSpell() { - return this.copiedSpell; - } - public Zone getFromZone() { return this.fromZone; } @Override - public void setCopy(boolean isCopy) { - setCopiedSpell(isCopy); + public void setCopy(boolean isCopy, MageObject copyFrom) { + this.copy = isCopy; + this.copyFrom = (copyFrom != null ? copyFrom.copy() : null); } @Override public boolean isCopy() { - return isCopiedSpell(); + return this.copy; + } + + @Override + public MageObject getCopyFrom() { + return this.copyFrom; } @Override diff --git a/Mage/src/main/java/mage/game/stack/StackAbility.java b/Mage/src/main/java/mage/game/stack/StackAbility.java index 02546c99c23..2fcadf1147b 100644 --- a/Mage/src/main/java/mage/game/stack/StackAbility.java +++ b/Mage/src/main/java/mage/game/stack/StackAbility.java @@ -1,9 +1,5 @@ package mage.game.stack; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.List; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.ObjectColor; @@ -32,8 +28,12 @@ import mage.util.GameLog; import mage.util.SubTypeList; import mage.watchers.Watcher; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public class StackAbility extends StackObjImpl implements Ability { @@ -47,6 +47,8 @@ public class StackAbility extends StackObjImpl implements Ability { private final Ability ability; private UUID controllerId; + private boolean copy; + private MageObject copyFrom; // copied card INFO (used to call original adjusters) private String name; private String expansionSetCode; private TargetAdjuster targetAdjuster = null; @@ -60,6 +62,8 @@ public class StackAbility extends StackObjImpl implements Ability { public StackAbility(final StackAbility stackAbility) { this.ability = stackAbility.ability.copy(); this.controllerId = stackAbility.controllerId; + this.copy = stackAbility.copy; + this.copyFrom = (stackAbility.copyFrom != null ? stackAbility.copyFrom.copy() : null); this.name = stackAbility.name; this.expansionSetCode = stackAbility.expansionSetCode; this.targetAdjuster = stackAbility.targetAdjuster; @@ -104,6 +108,22 @@ public class StackAbility extends StackObjImpl implements Ability { } } + @Override + public void setCopy(boolean isCopy, MageObject copyFrom) { + this.copy = isCopy; + this.copyFrom = (copyFrom != null ? copyFrom.copy() : null); + } + + @Override + public boolean isCopy() { + return this.copy; + } + + @Override + public MageObject getCopyFrom() { + return this.copyFrom; + } + @Override public String getName() { return name; @@ -408,15 +428,6 @@ public class StackAbility extends StackObjImpl implements Ability { throw new UnsupportedOperationException("Not supported."); } - @Override - public void setCopy(boolean isCopy) { - } - - @Override - public boolean isCopy() { - return false; - } - @Override public boolean getRuleAtTheTop() { return this.ability.getRuleAtTheTop(); diff --git a/Mage/src/main/java/mage/game/stack/StackObjImpl.java b/Mage/src/main/java/mage/game/stack/StackObjImpl.java index 12d49f57499..beadf908f5e 100644 --- a/Mage/src/main/java/mage/game/stack/StackObjImpl.java +++ b/Mage/src/main/java/mage/game/stack/StackObjImpl.java @@ -1,12 +1,5 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ package mage.game.stack; -import java.util.Set; -import java.util.UUID; import mage.MageObject; import mage.abilities.Abilities; import mage.abilities.AbilitiesImpl; @@ -21,8 +14,10 @@ import mage.players.Player; import mage.target.Target; import mage.target.TargetAmount; +import java.util.Set; +import java.util.UUID; + /** - * * @author LevelX2 */ public abstract class StackObjImpl implements StackObject { @@ -44,47 +39,47 @@ public abstract class StackObjImpl implements StackObject { * 114.6. Some effects allow a player to change the target(s) of a spell or * ability, and other effects allow a player to choose new targets for a * spell or ability. - * + *

    * 114.6a If an effect allows a player to "change the target(s)" of a spell * or ability, each target can be changed only to another legal target. If a * target can't be changed to another legal target, the original target is * unchanged, even if the original target is itself illegal by then. If all * the targets aren't changed to other legal targets, none of them are * changed. - * + *

    * 114.6b If an effect allows a player to "change a target" of a spell or * ability, the process described in rule 114.6a is followed, except that * only one of those targets may be changed (rather than all of them or none * of them). - * + *

    * 114.6c If an effect allows a player to "change any targets" of a spell or * ability, the process described in rule 114.6a is followed, except that * any number of those targets may be changed (rather than all of them or * none of them). - * + *

    * 114.6d If an effect allows a player to "choose new targets" for a spell * or ability, the player may leave any number of the targets unchanged, * even if those targets would be illegal. If the player chooses to change * some or all of the targets, the new targets must be legal and must not * cause any unchanged targets to become illegal. - * + *

    * 114.6e When changing targets or choosing new targets for a spell or * ability, only the final set of targets is evaluated to determine whether * the change is legal. - * + *

    * Example: Arc Trail is a sorcery that reads "Arc Trail deals 2 damage to * any target and 1 damage to another target creature or player." The * current targets of Arc Trail are Runeclaw Bear and Llanowar Elves, in * that order. You cast Redirect, an instant that reads "You may choose new * targets for target spell," targeting Arc Trail. You can change the first * target to Llanowar Elves and change the second target to Runeclaw Bear. - * + *

    * 114.7. Modal spells and abilities may have different targeting * requirements for each mode. An effect that allows a player to change the * target(s) of a modal spell or ability, or to choose new targets for a * modal spell or ability, doesn't allow that player to change its mode. * (See rule 700.2.) - * + *

    * 706.10c Some effects copy a spell or ability and state that its * controller may choose new targets for the copy. The player may leave any * number of the targets unchanged, even if those targets would be illegal. @@ -94,13 +89,13 @@ public abstract class StackObjImpl implements StackObject { * * @param game * @param targetControllerId - player that can/has to change the target of - * the spell - * @param forceChange - does only work for targets with maximum of one - * targetId - * @param onlyOneTarget - 114.6b one target must be changed to another - * target - * @param filterNewTarget restriction for the new target, if null nothing is - * cheched + * the spell + * @param forceChange - does only work for targets with maximum of one + * targetId + * @param onlyOneTarget - 114.6b one target must be changed to another + * target + * @param filterNewTarget restriction for the new target, if null nothing is + * cheched * @return */ @Override @@ -163,10 +158,15 @@ public abstract class StackObjImpl implements StackObject { newTarget.clearChosen(); for (UUID targetId : target.getTargets()) { String targetNames = getNamesOftargets(targetId, game); + String targetAmount = ""; + if (target.getTargetAmount(targetId) > 0) { + targetAmount = " (amount: " + target.getTargetAmount(targetId) + ")"; + } // change the target? Outcome outcome = mode.getEffects().isEmpty() ? Outcome.Detriment : mode.getEffects().get(0).getOutcome(); + if (targetNames != null - && (forceChange || targetController.chooseUse(outcome, "Change this target: " + targetNames + '?', ability, game))) { + && (forceChange || targetController.chooseUse(outcome, "Change this target: " + targetNames + targetAmount + '?', ability, game))) { Set possibleTargets = target.possibleTargets(this.getSourceId(), getControllerId(), game); // choose exactly one other target - already targeted objects are not counted if (forceChange && possibleTargets != null && possibleTargets.size() > 1) { // controller of spell must be used (e.g. TargetOpponent) @@ -179,7 +179,8 @@ public abstract class StackObjImpl implements StackObject { newTarget.clearChosen(); newTarget.chooseTarget(outcome, getControllerId(), ability, game); - // check target restriction + + // check target restriction TODO: add multiple target checks if (newTarget.getFirstTarget() != null && filterNewTarget != null) { Permanent newTargetPermanent = game.getPermanent(newTarget.getFirstTarget()); if (newTargetPermanent == null || !filterNewTarget.match(newTargetPermanent, game)) { @@ -187,7 +188,8 @@ public abstract class StackObjImpl implements StackObject { newTarget.clearChosen(); } } - } while (targetController.canRespond() && (targetId.equals(newTarget.getFirstTarget()) || newTarget.getTargets().size() != 1)); + } + while (targetController.canRespond() && (targetId.equals(newTarget.getFirstTarget()) || newTarget.getTargets().size() != 1)); // choose a new target } else { // build a target definition with exactly one possible target to select that replaces old target diff --git a/Mage/src/main/java/mage/game/tournament/TournamentOptions.java b/Mage/src/main/java/mage/game/tournament/TournamentOptions.java index 2b042d19a1d..c81294ce3ee 100644 --- a/Mage/src/main/java/mage/game/tournament/TournamentOptions.java +++ b/Mage/src/main/java/mage/game/tournament/TournamentOptions.java @@ -24,6 +24,7 @@ public class TournamentOptions implements Serializable { protected int numberRounds; protected String password; protected int quitRatio; + protected int minimumRating; public TournamentOptions(String name, String matchType, int numSeats) { this.name = name; @@ -98,4 +99,8 @@ public class TournamentOptions implements Serializable { public void setQuitRatio(int quitRatio) { this.quitRatio = quitRatio; } + + public int getMinimumRating() { return minimumRating; } + + public void setMinimumRating(int minimumRating) { this.minimumRating = minimumRating; } } diff --git a/Mage/src/main/java/mage/players/Player.java b/Mage/src/main/java/mage/players/Player.java index 1aa52abe55d..dab98647ec4 100644 --- a/Mage/src/main/java/mage/players/Player.java +++ b/Mage/src/main/java/mage/players/Player.java @@ -349,6 +349,15 @@ public interface Player extends MageItem, Copyable { */ boolean searchLibrary(TargetCardInLibrary target, Game game, UUID targetPlayerId, boolean triggerEvents); + /** + * Reveals all players' libraries. Useful for abilities like Jace, Architect of Thought's -8 + * that have effects that require information from all libraries. + * @param source + * @param game + * @return + */ + void lookAtAllLibraries(Ability source, Game game); + boolean canPlayLand(); /** diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index ec355521d91..4961d501b03 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -1,9 +1,5 @@ package mage.players; -import java.io.Serializable; -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.Map.Entry; import mage.ConditionalMana; import mage.MageObject; import mage.MageObjectReference; @@ -72,6 +68,11 @@ import mage.util.GameLog; import mage.util.RandomUtil; import org.apache.log4j.Logger; +import java.io.Serializable; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.Map.Entry; + public abstract class PlayerImpl implements Player, Serializable { private static final Logger logger = Logger.getLogger(PlayerImpl.class); @@ -2488,6 +2489,17 @@ public abstract class PlayerImpl implements Player, Serializable { return false; } + @Override + public void lookAtAllLibraries(Ability source, Game game) { + for(UUID playerId : game.getState().getPlayersInRange(this.getId(), game)){ + Player player = game.getPlayer(playerId); + String playerName = this.getName().equals(player.getName()) ? "Your " : player.getName() + "'s "; + playerName += "library"; + Cards cardsInLibrary = new CardsImpl(player.getLibrary().getTopCards(game, player.getLibrary().size())); + lookAtCards(playerName, cardsInLibrary, game); + } + } + private boolean handleLibraryCastableCards(Library library, Game game, UUID targetPlayerId) { // for handling Panglacial Wurm boolean alreadyChosenUse = false; @@ -2573,7 +2585,7 @@ public abstract class PlayerImpl implements Player, Serializable { /** * @param game * @param appliedEffects - * @param numSides Number of sides the dice has + * @param numSides Number of sides the dice has * @return the number that the player rolled */ @Override @@ -2607,10 +2619,10 @@ public abstract class PlayerImpl implements Player, Serializable { /** * @param game * @param appliedEffects - * @param numberChaosSides The number of chaos sides the planar die - * currently has (normally 1 but can be 5) + * @param numberChaosSides The number of chaos sides the planar die + * currently has (normally 1 but can be 5) * @param numberPlanarSides The number of chaos sides the planar die - * currently has (normally 1) + * currently has (normally 1) * @return the outcome that the player rolled. Either ChaosRoll, PlanarRoll * or NilRoll */ @@ -2767,7 +2779,7 @@ public abstract class PlayerImpl implements Player, Serializable { /** * @param ability - * @param available if null, it won't be checked if enough mana is available + * @param available if null, it won't be checked if enough mana is available * @param sourceObject * @param game * @return @@ -3319,7 +3331,7 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean canPaySacrificeCost(Permanent permanent, UUID sourceId, - UUID controllerId, Game game + UUID controllerId, Game game ) { return sacrificeCostFilter == null || !sacrificeCostFilter.match(permanent, sourceId, controllerId, game); } @@ -3467,8 +3479,8 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCards(Card card, Zone toZone, - Ability source, Game game, - boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects + Ability source, Game game, + boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects ) { Set cardList = new HashSet<>(); if (card != null) { @@ -3479,22 +3491,22 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCards(Cards cards, Zone toZone, - Ability source, Game game + Ability source, Game game ) { return moveCards(cards.getCards(game), toZone, source, game); } @Override public boolean moveCards(Set cards, Zone toZone, - Ability source, Game game + Ability source, Game game ) { return moveCards(cards, toZone, source, game, false, false, false, null); } @Override public boolean moveCards(Set cards, Zone toZone, - Ability source, Game game, - boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects + Ability source, Game game, + boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects ) { if (cards.isEmpty()) { return true; @@ -3580,8 +3592,8 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardsToExile(Card card, Ability source, - Game game, boolean withName, UUID exileId, - String exileZoneName + Game game, boolean withName, UUID exileId, + String exileZoneName ) { Set cards = new HashSet<>(); cards.add(card); @@ -3590,8 +3602,8 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardsToExile(Set cards, Ability source, - Game game, boolean withName, UUID exileId, - String exileZoneName + Game game, boolean withName, UUID exileId, + String exileZoneName ) { if (cards.isEmpty()) { return true; @@ -3606,14 +3618,14 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardToHandWithInfo(Card card, UUID sourceId, - Game game + Game game ) { return this.moveCardToHandWithInfo(card, sourceId, game, true); } @Override public boolean moveCardToHandWithInfo(Card card, UUID sourceId, - Game game, boolean withName + Game game, boolean withName ) { boolean result = false; Zone fromZone = game.getState().getZone(card.getId()); @@ -3638,7 +3650,7 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public Set moveCardsToGraveyardWithInfo(Set allCards, Ability source, - Game game, Zone fromZone + Game game, Zone fromZone ) { UUID sourceId = source == null ? null : source.getSourceId(); Set movedCards = new LinkedHashSet<>(); @@ -3646,7 +3658,7 @@ public abstract class PlayerImpl implements Player, Serializable { // identify cards from one owner Cards cards = new CardsImpl(); UUID ownerId = null; - for (Iterator it = allCards.iterator(); it.hasNext();) { + for (Iterator it = allCards.iterator(); it.hasNext(); ) { Card card = it.next(); if (cards.isEmpty()) { ownerId = card.getOwnerId(); @@ -3707,7 +3719,7 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardToGraveyardWithInfo(Card card, UUID sourceId, - Game game, Zone fromZone + Game game, Zone fromZone ) { if (card == null) { return false; @@ -3736,8 +3748,8 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardToLibraryWithInfo(Card card, UUID sourceId, - Game game, Zone fromZone, - boolean toTop, boolean withName + Game game, Zone fromZone, + boolean toTop, boolean withName ) { if (card == null) { return false; @@ -3771,7 +3783,7 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardToExileWithInfo(Card card, UUID exileId, String exileName, UUID sourceId, - Game game, Zone fromZone, boolean withName) { + Game game, Zone fromZone, boolean withName) { if (card == null) { return false; } @@ -3786,7 +3798,7 @@ public abstract class PlayerImpl implements Player, Serializable { } } else if (card instanceof Spell) { final Spell spell = (Spell) card; - if (spell.isCopiedSpell()) { + if (spell.isCopy()) { // Copied spell, only remove from stack game.getStack().remove(spell, game); } diff --git a/Mage/src/main/java/mage/util/CardUtil.java b/Mage/src/main/java/mage/util/CardUtil.java index 53da40ceef7..9b3cfe75ca1 100644 --- a/Mage/src/main/java/mage/util/CardUtil.java +++ b/Mage/src/main/java/mage/util/CardUtil.java @@ -1,9 +1,5 @@ - package mage.util; -import java.util.UUID; -import java.util.stream.Stream; - import mage.MageObject; import mage.Mana; import mage.abilities.Ability; @@ -12,11 +8,14 @@ import mage.abilities.SpellAbility; import mage.abilities.costs.VariableCost; import mage.abilities.costs.mana.*; import mage.cards.Card; +import mage.constants.EmptyNames; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.Token; import mage.util.functions.CopyTokenFunction; +import java.util.UUID; + /** * @author nantuko */ @@ -25,10 +24,10 @@ public final class CardUtil { private static final String SOURCE_EXILE_ZONE_TEXT = "SourceExileZone"; static final String[] numberStrings = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", - "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty"}; + "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty"}; static final String[] ordinalStrings = {"first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eightth", "ninth", - "tenth", "eleventh", "twelfth", "thirteenth", "fourteenth", "fifteenth", "sixteenth", "seventeenth", "eighteenth", "nineteenth", "twentieth"}; + "tenth", "eleventh", "twelfth", "thirteenth", "fourteenth", "fifteenth", "sixteenth", "seventeenth", "eighteenth", "nineteenth", "twentieth"}; /** * Increase spell or ability cost to be paid. @@ -129,8 +128,8 @@ public final class CardUtil { * * @param spellAbility * @param manaCostsToReduce costs to reduce - * @param convertToGeneric colored mana does reduce generic mana if no - * appropriate colored mana is in the costs included + * @param convertToGeneric colored mana does reduce generic mana if no + * appropriate colored mana is in the costs included */ public static void adjustCost(SpellAbility spellAbility, ManaCosts manaCostsToReduce, boolean convertToGeneric) { ManaCosts previousCost = spellAbility.getManaCostsToPay(); @@ -315,7 +314,7 @@ public final class CardUtil { * * @param number number to convert to text * @param forOne if the number is 1, this string will be returnedinstead of - * "one". + * "one". * @return */ public static String numberToText(int number, String forOne) { @@ -346,7 +345,7 @@ public final class CardUtil { if (number >= 1 && number < 21) { return ordinalStrings[number - 1]; } - return Integer.toString(number) + "th"; + return number + "th"; } public static String replaceSourceName(String message, String sourceName) { @@ -388,7 +387,7 @@ public final class CardUtil { /** * Creates and saves a (card + zoneChangeCounter) specific exileId. * - * @param game the current game + * @param game the current game * @param source source ability * @return the specific UUID */ @@ -423,9 +422,9 @@ public final class CardUtil { * be specific to a permanent instance. So they won't match, if a permanent * was e.g. exiled and came back immediately. * - * @param text short value to describe the value + * @param text short value to describe the value * @param cardId id of the card - * @param game the game + * @param game the game * @return */ public static String getCardZoneString(String text, UUID cardId, Game game) { @@ -525,9 +524,39 @@ public final class CardUtil { title = textSuffix == null ? "" : textSuffix; } } else { - title = textSuffix == null ? "" : textSuffix;; + title = textSuffix == null ? "" : textSuffix; + ; } return title; } + + /** + * Face down cards and their copy tokens don't have names and that's "empty" names is not equals + */ + public static boolean haveSameNames(String name1, String name2, Boolean ignoreMtgRuleForEmptyNames) { + if (ignoreMtgRuleForEmptyNames) { + // simple compare for tests and engine + return name1 != null && name2 != null && name1.equals(name2); + } else { + // mtg logic compare for game (empty names can't be same) + return !haveEmptyName(name1) && !haveEmptyName(name2) && name1.equals(name2); + } + } + + public static boolean haveSameNames(String name1, String name2) { + return haveSameNames(name1, name2, false); + } + + public static boolean haveSameNames(MageObject object1, MageObject object2) { + return object1 != null && object2 != null && haveSameNames(object1.getName(), object2.getName()); + } + + public static boolean haveEmptyName(String name) { + return name == null || name.isEmpty() || name.equals(EmptyNames.FACE_DOWN_CREATURE.toString()) || name.equals(EmptyNames.FACE_DOWN_TOKEN.toString()); + } + + public static boolean haveEmptyName(MageObject object) { + return object == null || haveEmptyName(object.getName()); + } } diff --git a/Mage/src/main/java/mage/util/JarVersion.java b/Mage/src/main/java/mage/util/JarVersion.java new file mode 100644 index 00000000000..e79adbbc2f9 --- /dev/null +++ b/Mage/src/main/java/mage/util/JarVersion.java @@ -0,0 +1,57 @@ +package mage.util; + +import org.apache.log4j.Logger; + +import java.net.URL; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.util.jar.Attributes; +import java.util.jar.Manifest; + +/** + * @author JayDi85 + */ +public class JarVersion { + + private static final Logger logger = Logger.getLogger(JarVersion.class); + private static final String JAR_BUILD_TIME_FROM_CLASSES = "runtime"; + private static final String JAR_BUILD_TIME_ERROR = "n/a"; + + public static String getBuildTime(Class clazz) { + // build time info inserted by maven on jar build phase (see root pom.xml) + String className = clazz.getSimpleName() + ".class"; + String classPath = clazz.getResource(className).toString(); + + // https://stackoverflow.com/a/1273432/1276632 + String manifestPath; + if (classPath.startsWith("jar")) { + // jar source + manifestPath = classPath.substring(0, classPath.lastIndexOf("!") + 1) + "/META-INF/MANIFEST.MF"; + } else { + // dir source (e.g. IDE's debug) + // it's can be generated by runtime, but need extra code and performance: https://stackoverflow.com/questions/34674073/how-to-generate-manifest-mf-file-during-compile-phase + // manifestPath = classPath.substring(0, classPath.lastIndexOf("/" + className)) + "/META-INF/MANIFEST.MF"; + return JAR_BUILD_TIME_FROM_CLASSES; + } + + try { + Manifest manifest = new Manifest(new URL(manifestPath).openStream()); + Attributes attr = manifest.getMainAttributes(); + String buildTime = attr.getValue("Build-Time"); + Instant instant = Instant.parse(buildTime); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").withZone(ZoneOffset.UTC); + return formatter.format(instant); + } catch (Throwable e) { + logger.error("Can't read build time in jar manifest for class " + clazz.getName() + " and path " + manifestPath, e); + return JAR_BUILD_TIME_ERROR; + } + } + + public static boolean isBuildTimeOk(String buildTime) { + return buildTime != null + && !buildTime.isEmpty() + && !buildTime.equals(JAR_BUILD_TIME_ERROR) + && !buildTime.equals(JAR_BUILD_TIME_FROM_CLASSES); + } +} diff --git a/Utils/cardClass.tmpl b/Utils/cardClass.tmpl index cfad53cb344..c78080f860f 100644 --- a/Utils/cardClass.tmpl +++ b/Utils/cardClass.tmpl @@ -39,7 +39,7 @@ if ($power || $power eq 0) { =][=$abilities=] } - public [=$className=](final [=$className=] card) { + private [=$className=](final [=$className=] card) { super(card); } diff --git a/Utils/cardExtendedClass.tmpl b/Utils/cardExtendedClass.tmpl index 79d978519b8..5ea23f3f711 100644 --- a/Utils/cardExtendedClass.tmpl +++ b/Utils/cardExtendedClass.tmpl @@ -14,7 +14,7 @@ public final class [=$className=] extends mage.sets.[=$baseSet=].[=$className=] this.expansionSetCode = "[=$expansionSetCode=]";[=$rarityExtended=] } - public [=$className=](final [=$className=] card) { + private [=$className=](final [=$className=] card) { super(card); } diff --git a/Utils/cardExtendedLandClass.tmpl b/Utils/cardExtendedLandClass.tmpl index 00b9cac234a..0d73918d6f8 100644 --- a/Utils/cardExtendedLandClass.tmpl +++ b/Utils/cardExtendedLandClass.tmpl @@ -13,7 +13,7 @@ public final class [=$className=][=$landNr=] extends mage.cards.basiclands.[=$cl this.expansionSetCode = "[=$expansionSetCode=]"; } - public [=$className=][=$landNr=](final [=$className=][=$landNr=] card) { + private [=$className=][=$landNr=](final [=$className=][=$landNr=] card) { super(card); } diff --git a/Utils/cardSplitClass.tmpl b/Utils/cardSplitClass.tmpl index b836f087a88..c9d9200ba43 100644 --- a/Utils/cardSplitClass.tmpl +++ b/Utils/cardSplitClass.tmpl @@ -24,7 +24,7 @@ public final class [=$className=] extends SplitCard { } - public [=$className=](final [=$className=] card) { + private [=$className=](final [=$className=] card) { super(card); } diff --git a/Utils/keywords.txt b/Utils/keywords.txt index b965d6b3aea..f32a5b30284 100644 --- a/Utils/keywords.txt +++ b/Utils/keywords.txt @@ -1,4 +1,5 @@ Afflict|number| +Afterlife|number| Annihilator|number| Ascend|new| Assist|new| @@ -75,12 +76,14 @@ Prowess|new| Reach|instance| Rebound|new| Renown|number| +Riot|new| Scavenge|cost| Shadow|instance| Shroud|instance| Soulbond|instance| Soulshift|number| Skulk|new| +Spectacle|card, cost| Storm|new| Sunburst|new| Swampcycling|cost| diff --git a/Utils/known-sets.txt b/Utils/known-sets.txt index 8930efa5479..dc8d45e3793 100644 --- a/Utils/known-sets.txt +++ b/Utils/known-sets.txt @@ -160,6 +160,7 @@ Premium Deck Series: Fire and Lightning|PremiumDeckSeriesFireAndLightning| Premium Deck Series: Slivers|PremiumDeckSeriesSlivers| Prerelease Events|PrereleaseEvents| Prophecy|Prophecy| +Ravnica Allegiance|RavnicaAllegiance| Ravnica: City of Guilds|RavnicaCityOfGuilds| Return to Ravnica|ReturnToRavnica| Revised Edition|RevisedEdition| diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 4859b6ceed0..0373c2c8b21 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -34575,4 +34575,25 @@ Vraska, Regal Gorgon|Guilds of Ravnica|269|M|{5}{B}{G}|Legendary Planeswalker - Kraul Raider|Guilds of Ravnica|270|C|{2}{B}|Creature - Insect Warrior|2|3|Menace| Attendant of Vraska|Guilds of Ravnica|271|U|{1}{B}{G}|Creature - Zombie Soldier|3|3|When Attendant of Vraska dies, if you control a Vraska planeswalker, you gain life equal to Attendant of Vraska's power.| Vraska's Stoneglare|Guilds of Ravnica|272|R|{4}{B}{G}|Sorcery|||Destroy target creature. You gain life equal to its toughness. You may search your library and/or graveyard for a card named Vraska, Regal Gorgon, reveal it, and put it into your hand. If you search your library this way, shuffle it.| -Impervious Greatwurm|Guilds of Ravnica|273|M|{7}{G}{G}{G}|Creature - Wurm|16|16|Convoke$Indestructible| \ No newline at end of file +Impervious Greatwurm|Guilds of Ravnica|273|M|{7}{G}{G}{G}|Creature - Wurm|16|16|Convoke$Indestructible| +Tithe Taker|Ravnica Allegiance|27|R|{1}{W}|Creature - Human Soldier|2|1|During your turn, spells your opponents cast cost {1} more to cast and abilities your opponents activate cost {1} more to activate unless they're mana abilities.$Afterlife 1| +Light Up the Stage|Ravnica Allegiance|107|U|{2}{R}|Sorcery|||Spectacle {R}$Exile the top two cards of your library. Until the end of your next turn, you may play those cards.| +Rix Maadi Reveler|Ravnica Allegiance|109|R|{1}{R}|Creature - Human Shaman|2|2|Spectacle {2}{B}{R}$When Rix Maadi Reveler enters the battlefield, discard a card, then draw a card. If Rix Maadi Reveler's spectacle cost was paid, instead discard your hand, then draw three cards.| +Aeromunculus|Ravnica Allegiance|152|C|{1}{G}{U}|Creature - Homunculus Mutant|2|3|Flying${2}{G}{U}: Adapt 1.| +Bedevil|Ravnica Allegiance|157|R|{B}{B}{R}|Instant|||Destroy target artifact, creature, or planeswalker.| +Emergency Powers|Ravnica Allegiance|169|M|{5}{W}{U}|Instant|||Each player shuffles their hand and graveyard into their library, then draws seven cards. Exile Emergency Powers.$Addendum — If you cast this spell during your main phase, you may put a permanent card with converted mana cost 7 or less from your hand onto the battlefield.| +Frenzied Arynx|Ravnica Allegiance|173|C|{2}{R}{G}|Creature - Cat Beast|3|3|Riot$Trample${4}{R}{G}: Frenzied Arynx gets +3/+0 until end of turn.| +Growth Spiral|Ravnica Allegiance|178|C|{G}{U}|Instant|||Draw a card. You may put a land card from your hand onto the battlefield.| +Gruul Spellbreaker|Ravnica Allegiance|179|R|{1}{R}{G}|Creature - Ogre Warrior|3|3|Riot$Trample$As long as it's your turn, you and Gruul Spellbreaker have hexproof.| +Imperious Oligarch|Ravnica Allegiance|184|C|{W}{B}|Creature - Human Cleric|2|1|Vigilance$Afterlife 1| +Lavinia, Azorius Renegade|Ravnica Allegiance|189|R|{W}{U}|Legendary Creature - Human Soldier|2|2|Each opponent can't cast noncreature spells with converted mana cost greater than the number of lands that player controls.$Whenever an opponent casts a spell, if no mana was spent to cast it, counter that spell.| +Mortify|Ravnica Allegiance|192|U|{1}{W}{B}|Instant|||Destroy target creature or enchantment.| +Rafter Demon|Ravnica Allegiance|196|C|{2}{B}{R}|Creature - Demon|4|2|Spectacle {3}{B}{R}$When Rafter Demon enters the battlefield, if its spectacle cost was paid, each opponent discards a card.| +Rakdos Firewheeler|Ravnica Allegiance|197|U|{B}{B}{R}{R}|Creature - Human Rogue|4|3|When Rakdos Firewheeler enters the battlefield, it deals 2 damage to target opponent and 2 damage to up to one target creature or planeswalker.| +Simic Ascendancy|Ravnica Allegiance|207|R|{G}{U}|Enchantment|||{1}{G}{U}: Put a +1/+1 counter on target creature you control.$Whenever one or more +1/+1 counters are put on a creature you control, put that many growth counters on Simic Ascendancy.$At the beginning of your upkeep, if Simic Ascendancy has twenty or more growth counters on it, you win the game.| +Sphinx's Insight|Ravnica Allegiance|209|C|{2}{W}{U}|Instant|||Draw two cards.$Addendum — If you cast this spell during your main phase, you gain 2 life.| +Zegana, Utopian Speaker|Ravnica Allegiance|214|R|{2}{G}{U}|Legendary Creature - Merfolk Wizard|4|4|When Zegana, Utopian Speaker enters the battlefield, if you control another creature with a +1/+1 counter on it, draw a card.${4}{G}{U}: Adapt 4.$Each creature you control with a +1/+1 counter on it has trample.| +Incongruity|Ravnica Allegiance|226|U|{1}{G}{U}|Instant|||Exile target creature. That creature's controller creates a 3/3 green Frog Lizard creature token.| +Incubation|Ravnica Allegiance|226|U|{G/U}|Sorcery|||Look at the top five cards of your library. You may reveal a creature card from among them and put it into your hand. Put the rest on the bottom of your library in a random order.| +Gate Colossus|Ravnica Allegiance|232|U|{8}|Artifact Creature - Construct|8|8|This spell costs {1} less to cast for each Gate you control.$Gate Colossus can't be blocked by creatures with power 2 or less.$Whenever a Gate enters the battlefield under your control, you may put Gate Colossus from your graveyard on top of your library.| +The Haunt of Hightower|Ravnica Allegiance|273|M|{4}{B}{B}|Legendary Creature - Vampire|3|3|Flying, lifelink$Whenever The Haunt of Hightower attacks, defending player discards a card.$Whenever a card is put into an opponent's graveyard from anywhere, put a +1/+1 counter on The Haunt of Hightower.| \ No newline at end of file diff --git a/Utils/mtg-sets-data.txt b/Utils/mtg-sets-data.txt index 797a5ba7722..60d08073cfb 100644 --- a/Utils/mtg-sets-data.txt +++ b/Utils/mtg-sets-data.txt @@ -165,6 +165,7 @@ Planeshift|PLS| Portal|POR| Prerelease Events|PTC| Portal Three Kingdoms|PTK| +Ravnica Allegiance|RNA| Ravnica: City of Guilds|RAV| Rivals of Ixalan|RIX| Rise of the Eldrazi|ROE| diff --git a/pom.xml b/pom.xml index 62c3c3a0d9a..e4f8e8f1ee1 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.31 + 1.4.32 pom Mage Root Mage Root POM @@ -29,6 +29,7 @@ + maven-resources-plugin 2.7 @@ -36,6 +37,8 @@ UTF-8 + + maven-jar-plugin 2.5 @@ -43,6 +46,7 @@ MageTeam + ${maven.build.timestamp} @@ -84,7 +88,7 @@ - 1.4.31 + 1.4.32 UTF-8 diff --git a/readme.md b/readme.md index 4c25a0bdad9..043c124dbd3 100644 --- a/readme.md +++ b/readme.md @@ -12,6 +12,9 @@ XMage community: * [Reddit XMage group](https://www.reddit.com/r/XMage/); * [Reddit XMage discord channel](https://discord.gg/Pqf42yn). +Servers status: +* http://xmageservers.online/ + ## Features * Deck editor (load and save decks)