diff --git a/Mage.Client/src/main/java/mage/client/MageFrame.java b/Mage.Client/src/main/java/mage/client/MageFrame.java index c9d69ca85f0..9752b1cd8a8 100644 --- a/Mage.Client/src/main/java/mage/client/MageFrame.java +++ b/Mage.Client/src/main/java/mage/client/MageFrame.java @@ -27,16 +27,20 @@ */ package mage.client; +import java.awt.AWTEvent; import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Component; import java.awt.Cursor; import java.awt.Dimension; +import java.awt.EventQueue; import java.awt.Font; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Rectangle; import java.awt.SplashScreen; +import java.awt.Toolkit; +import java.awt.event.AWTEventListener; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentAdapter; @@ -225,6 +229,26 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { return instance; } + private void handleEvent(AWTEvent event) { + MagePane frame = activeFrame; + + // support multiple mage panes + Object source = event.getSource(); + if(source instanceof Component) { + Component component = (Component)source; + while(component != null) { + if(component instanceof MagePane) { + frame = (MagePane)component; + break; + } + component = component.getParent(); + } + } + + if(frame != null) + frame.handleEvent(event); + } + /** * Creates new form MageFrame */ @@ -240,6 +264,13 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { } }); + Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() { + @Override + public void eventDispatched(AWTEvent event) { + handleEvent(event); + } + }, AWTEvent.KEY_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK); + TConfig config = TConfig.current(); config.setArchiveDetector(new TArchiveDetector("zip")); config.setAccessPreference(FsAccessOption.STORE, true); diff --git a/Mage.Client/src/main/java/mage/client/MagePane.java b/Mage.Client/src/main/java/mage/client/MagePane.java index 8ddadc66953..b4a4d474d6e 100644 --- a/Mage.Client/src/main/java/mage/client/MagePane.java +++ b/Mage.Client/src/main/java/mage/client/MagePane.java @@ -33,6 +33,7 @@ */ package mage.client; +import java.awt.AWTEvent; import java.awt.KeyboardFocusManager; import java.beans.PropertyVetoException; import javax.swing.plaf.basic.BasicInternalFrameUI; @@ -91,6 +92,9 @@ public abstract class MagePane extends javax.swing.JInternalFrame { } + public void handleEvent(AWTEvent event) { + } + /** * 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 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 87d1b0beb74..03ed4e96b4b 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form +++ b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form @@ -31,7 +31,7 @@ - + @@ -122,7 +122,7 @@ - + @@ -1719,7 +1719,7 @@ - + @@ -1744,11 +1744,11 @@ - + - - + + @@ -1756,6 +1756,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1902,7 +1939,7 @@ - + @@ -2409,11 +2446,11 @@ - - + + - + @@ -2504,11 +2541,11 @@ - - + + - + @@ -2536,7 +2573,7 @@ - + @@ -2549,7 +2586,7 @@ - + @@ -2601,11 +2638,11 @@ - - + + - + @@ -2633,7 +2670,7 @@ - + @@ -2646,7 +2683,7 @@ - + @@ -2696,11 +2733,11 @@ - - + + - + @@ -2728,7 +2765,7 @@ - + @@ -2793,11 +2830,11 @@ - - + + - + @@ -2825,7 +2862,7 @@ - + @@ -2888,11 +2925,11 @@ - - + + - + @@ -2920,7 +2957,7 @@ - + @@ -2985,11 +3022,11 @@ - - + + - + @@ -3017,7 +3054,7 @@ - + @@ -3080,7 +3117,199 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -3088,7 +3317,7 @@ - + @@ -3096,7 +3325,7 @@ - + @@ -3105,16 +3334,16 @@ - + - + - + @@ -3124,12 +3353,12 @@ - + - + @@ -3139,12 +3368,12 @@ - + - + @@ -3154,12 +3383,12 @@ - + - + @@ -3169,7 +3398,7 @@ - + @@ -3181,11 +3410,11 @@ - + - + @@ -3194,16 +3423,16 @@ - + - + - + @@ -3211,12 +3440,12 @@ - + - + @@ -3224,12 +3453,12 @@ - + - + @@ -3237,12 +3466,12 @@ - + - + @@ -3250,17 +3479,17 @@ - + - + - + @@ -3269,16 +3498,16 @@ - + - + - + @@ -3286,12 +3515,12 @@ - + - + @@ -3299,12 +3528,12 @@ - + - + @@ -3312,12 +3541,12 @@ - + - + @@ -3325,13 +3554,13 @@ - + - + @@ -4172,7 +4401,7 @@ - + @@ -5028,9 +5257,9 @@ - + - + @@ -5039,7 +5268,7 @@ - + @@ -5047,7 +5276,7 @@ - + @@ -5061,6 +5290,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -5230,83 +5536,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 ccc197fc18a..a949990fc88 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java @@ -104,7 +104,8 @@ public class PreferencesDialog extends javax.swing.JDialog { public static final String KEY_GUI_DIALOG_FONT_SIZE = "guiDialogFontSize"; public static final String KEY_GUI_FEEDBACK_AREA_SIZE = "guiFeedbackAreaSize"; public static final String KEY_GUI_CARD_OTHER_ZONES_SIZE = "guiCardOtherZonesSize"; - public static final String KEY_GUI_CARD_BATTLEFIELD_SIZE = "guiCardBattlefield"; + public static final String KEY_GUI_CARD_BATTLEFIELD_MIN_SIZE = "guiCardBattlefieldMinSize"; + public static final String KEY_GUI_CARD_BATTLEFIELD_MAX_SIZE = "guiCardBattlefieldMaxSize"; public static final String KEY_GAME_LOG_AUTO_SAVE = "gameLogAutoSave"; public static final String KEY_DRAFT_LOG_AUTO_SAVE = "draftLogAutoSave"; @@ -245,7 +246,6 @@ public class PreferencesDialog extends javax.swing.JDialog { public static final String KEY_NEW_DECK_GENERATOR_LAND_PERCENTAGE = "newDeckGeneratorLandPercentage"; public static final String KEY_NEW_DECK_GENERATOR_ADVANCED_CMC = "newDeckGeneratorAdvancedCMC"; - // used to save and restore the settings for the cardArea (draft, sideboarding, deck builder) public static final String KEY_DRAFT_VIEW = "draftView"; @@ -396,8 +396,10 @@ public class PreferencesDialog extends javax.swing.JDialog { labelCardSizeHand = new javax.swing.JLabel(); sliderCardSizeOtherZones = new javax.swing.JSlider(); labelCardSizeOtherZones = new javax.swing.JLabel(); - sliderCardSizeBattlefield = new javax.swing.JSlider(); - labelCardSizeBattlefield = new javax.swing.JLabel(); + sliderCardSizeMinBattlefield = new javax.swing.JSlider(); + labelCardSizeMinBattlefield = new javax.swing.JLabel(); + sliderCardSizeMaxBattlefield = new javax.swing.JSlider(); + labelCardSizeMaxBattlefield = new javax.swing.JLabel(); sliderStackWidth = new javax.swing.JSlider(); labelStackWidth = new javax.swing.JLabel(); sliderGameFeedbackArea = new javax.swing.JSlider(); @@ -495,6 +497,10 @@ public class PreferencesDialog extends javax.swing.JDialog { jPanel32 = new javax.swing.JPanel(); jPanel33 = new javax.swing.JPanel(); tabConnection = new javax.swing.JPanel(); + connection_servers = new javax.swing.JPanel(); + lblURLServerList = new javax.swing.JLabel(); + txtURLServerList = new javax.swing.JTextField(); + jLabel17 = new javax.swing.JLabel(); lblProxyType = new javax.swing.JLabel(); cbProxyType = new javax.swing.JComboBox<>(); pnlProxySettings = new javax.swing.JPanel(); @@ -509,10 +515,6 @@ public class PreferencesDialog extends javax.swing.JDialog { txtPasswordField = new javax.swing.JPasswordField(); rememberPswd = new javax.swing.JCheckBox(); jLabel11 = new javax.swing.JLabel(); - connection_servers = new javax.swing.JPanel(); - lblURLServerList = new javax.swing.JLabel(); - txtURLServerList = new javax.swing.JTextField(); - jLabel17 = new javax.swing.JLabel(); saveButton = new javax.swing.JButton(); exitButton = new javax.swing.JButton(); @@ -557,7 +559,7 @@ public class PreferencesDialog extends javax.swing.JDialog { .add(tooltipDelayLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 308, Short.MAX_VALUE) .add(org.jdesktop.layout.GroupLayout.LEADING, showCardName) .add(tooltipDelay, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap(183, Short.MAX_VALUE)) + .addContainerGap(233, Short.MAX_VALUE)) ); main_cardLayout.setVerticalGroup( main_cardLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) @@ -917,7 +919,7 @@ public class PreferencesDialog extends javax.swing.JDialog { guiSizeGame.setMinimumSize(new java.awt.Dimension(600, 180)); guiSizeGame.setPreferredSize(new java.awt.Dimension(600, 180)); java.awt.GridBagLayout guiSizeGameLayout = new java.awt.GridBagLayout(); - guiSizeGameLayout.columnWeights = new double[] {1.0, 1.0, 1.0}; + guiSizeGameLayout.columnWeights = new double[] {1.0, 1.0, 1.0, 1.0}; guiSizeGameLayout.rowWeights = new double[] {1.0, 0.2, 1.0, 0.2}; guiSizeGame.setLayout(guiSizeGameLayout); @@ -980,34 +982,63 @@ public class PreferencesDialog extends javax.swing.JDialog { gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; guiSizeGame.add(labelCardSizeOtherZones, gridBagConstraints); - sliderCardSizeBattlefield.setMajorTickSpacing(5); - sliderCardSizeBattlefield.setMaximum(50); - sliderCardSizeBattlefield.setMinimum(10); - sliderCardSizeBattlefield.setMinorTickSpacing(1); - sliderCardSizeBattlefield.setPaintLabels(true); - sliderCardSizeBattlefield.setPaintTicks(true); - sliderCardSizeBattlefield.setSnapToTicks(true); - sliderCardSizeBattlefield.setToolTipText("The maximum size of permanents on the battlefield"); - sliderCardSizeBattlefield.setBorder(javax.swing.BorderFactory.createEtchedBorder()); - sliderCardSizeBattlefield.setMinimumSize(new java.awt.Dimension(150, 40)); + sliderCardSizeMinBattlefield.setMajorTickSpacing(5); + sliderCardSizeMinBattlefield.setMaximum(50); + sliderCardSizeMinBattlefield.setMinimum(10); + sliderCardSizeMinBattlefield.setMinorTickSpacing(1); + sliderCardSizeMinBattlefield.setPaintLabels(true); + sliderCardSizeMinBattlefield.setPaintTicks(true); + sliderCardSizeMinBattlefield.setSnapToTicks(true); + sliderCardSizeMinBattlefield.setToolTipText("The maximum size of permanents on the battlefield"); + sliderCardSizeMinBattlefield.setBorder(javax.swing.BorderFactory.createEtchedBorder()); + sliderCardSizeMinBattlefield.setMinimumSize(new java.awt.Dimension(150, 40)); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 0; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; gridBagConstraints.insets = new java.awt.Insets(2, 2, 2, 2); - guiSizeGame.add(sliderCardSizeBattlefield, gridBagConstraints); + guiSizeGame.add(sliderCardSizeMinBattlefield, gridBagConstraints); - labelCardSizeBattlefield.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); - labelCardSizeBattlefield.setText("Permanents"); - labelCardSizeBattlefield.setToolTipText("The maximum size of permanents on the battlefield"); + labelCardSizeMinBattlefield.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); + labelCardSizeMinBattlefield.setText("Permanents min size"); + labelCardSizeMinBattlefield.setToolTipText("The minimum size of permanents on the battlefield"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 1; gridBagConstraints.ipadx = 3; gridBagConstraints.ipady = 3; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; - guiSizeGame.add(labelCardSizeBattlefield, gridBagConstraints); + guiSizeGame.add(labelCardSizeMinBattlefield, gridBagConstraints); + + sliderCardSizeMaxBattlefield.setMajorTickSpacing(5); + sliderCardSizeMaxBattlefield.setMaximum(50); + sliderCardSizeMaxBattlefield.setMinimum(10); + sliderCardSizeMaxBattlefield.setMinorTickSpacing(1); + sliderCardSizeMaxBattlefield.setPaintLabels(true); + sliderCardSizeMaxBattlefield.setPaintTicks(true); + sliderCardSizeMaxBattlefield.setSnapToTicks(true); + sliderCardSizeMaxBattlefield.setToolTipText("The maximum size of permanents on the battlefield"); + sliderCardSizeMaxBattlefield.setBorder(javax.swing.BorderFactory.createEtchedBorder()); + sliderCardSizeMaxBattlefield.setMinimumSize(new java.awt.Dimension(150, 40)); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 3; + gridBagConstraints.gridy = 0; + gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; + gridBagConstraints.insets = new java.awt.Insets(2, 2, 2, 2); + guiSizeGame.add(sliderCardSizeMaxBattlefield, gridBagConstraints); + + labelCardSizeMaxBattlefield.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); + labelCardSizeMaxBattlefield.setText("Permanents max size"); + labelCardSizeMaxBattlefield.setToolTipText("The maximum size of permanents on the battlefield"); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 3; + gridBagConstraints.gridy = 1; + gridBagConstraints.ipadx = 3; + gridBagConstraints.ipady = 3; + gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; + guiSizeGame.add(labelCardSizeMaxBattlefield, gridBagConstraints); sliderStackWidth.setMajorTickSpacing(20); sliderStackWidth.setMaximum(90); @@ -2099,7 +2130,7 @@ public class PreferencesDialog extends javax.swing.JDialog { tabAvatarsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(tabAvatarsLayout.createSequentialGroup() .add(avatarPane, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 528, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(0, 1, Short.MAX_VALUE)) + .add(0, 0, Short.MAX_VALUE)) ); tabAvatarsLayout.setVerticalGroup( tabAvatarsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) @@ -2110,6 +2141,47 @@ public class PreferencesDialog extends javax.swing.JDialog { tabsPanel.addTab("Avatars", tabAvatars); + connection_servers.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "Servers")); + + lblURLServerList.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); + lblURLServerList.setText("URL server list:"); + lblURLServerList.setToolTipText(""); + lblURLServerList.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING); + lblURLServerList.setPreferredSize(new java.awt.Dimension(110, 16)); + lblURLServerList.setVerticalTextPosition(javax.swing.SwingConstants.TOP); + + txtURLServerList.setToolTipText("The URL XMage tries to read a server list from."); + txtURLServerList.setPreferredSize(new java.awt.Dimension(300, 22)); + + jLabel17.setFont(new java.awt.Font("Tahoma", 2, 10)); // NOI18N + jLabel17.setText("e.g.: http://XMage.de/files/server-list.txt"); + + org.jdesktop.layout.GroupLayout connection_serversLayout = new org.jdesktop.layout.GroupLayout(connection_servers); + connection_servers.setLayout(connection_serversLayout); + connection_serversLayout.setHorizontalGroup( + connection_serversLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(connection_serversLayout.createSequentialGroup() + .add(connection_serversLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(connection_serversLayout.createSequentialGroup() + .addContainerGap() + .add(lblURLServerList, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 96, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(txtURLServerList, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 370, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .add(connection_serversLayout.createSequentialGroup() + .add(141, 141, 141) + .add(jLabel17))) + .addContainerGap(67, Short.MAX_VALUE)) + ); + connection_serversLayout.setVerticalGroup( + connection_serversLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(connection_serversLayout.createSequentialGroup() + .add(connection_serversLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false) + .add(lblURLServerList, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .add(txtURLServerList, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(jLabel17)) + ); + lblProxyType.setText("Proxy:"); cbProxyType.addActionListener(new java.awt.event.ActionListener() { @@ -2219,67 +2291,26 @@ public class PreferencesDialog extends javax.swing.JDialog { .addContainerGap()) ); - connection_servers.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "Servers")); - - lblURLServerList.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); - lblURLServerList.setText("URL server list:"); - lblURLServerList.setToolTipText(""); - lblURLServerList.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING); - lblURLServerList.setPreferredSize(new java.awt.Dimension(110, 16)); - lblURLServerList.setVerticalTextPosition(javax.swing.SwingConstants.TOP); - - txtURLServerList.setToolTipText("The URL XMage tries to read a server list from."); - txtURLServerList.setPreferredSize(new java.awt.Dimension(300, 22)); - - jLabel17.setFont(new java.awt.Font("Tahoma", 2, 10)); // NOI18N - jLabel17.setText("e.g.: http://XMage.de/files/server-list.txt"); - - org.jdesktop.layout.GroupLayout connection_serversLayout = new org.jdesktop.layout.GroupLayout(connection_servers); - connection_servers.setLayout(connection_serversLayout); - connection_serversLayout.setHorizontalGroup( - connection_serversLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(connection_serversLayout.createSequentialGroup() - .add(connection_serversLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(connection_serversLayout.createSequentialGroup() - .addContainerGap() - .add(lblURLServerList, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 96, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(txtURLServerList, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 370, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) - .add(connection_serversLayout.createSequentialGroup() - .add(141, 141, 141) - .add(jLabel17))) - .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - ); - connection_serversLayout.setVerticalGroup( - connection_serversLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(connection_serversLayout.createSequentialGroup() - .add(connection_serversLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false) - .add(lblURLServerList, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .add(txtURLServerList, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(jLabel17)) - ); - org.jdesktop.layout.GroupLayout tabConnectionLayout = new org.jdesktop.layout.GroupLayout(tabConnection); tabConnection.setLayout(tabConnectionLayout); tabConnectionLayout.setHorizontalGroup( tabConnectionLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(tabConnectionLayout.createSequentialGroup() + .add(org.jdesktop.layout.GroupLayout.TRAILING, tabConnectionLayout.createSequentialGroup() .addContainerGap() - .add(tabConnectionLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING, false) + .add(tabConnectionLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) .add(pnlProxySettings, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .add(org.jdesktop.layout.GroupLayout.LEADING, tabConnectionLayout.createSequentialGroup() .add(lblProxyType) .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) .add(cbProxyType, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 126, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) .add(connection_servers, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) ); tabConnectionLayout.setVerticalGroup( tabConnectionLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(tabConnectionLayout.createSequentialGroup() .addContainerGap() - .add(connection_servers, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(connection_servers, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(tabConnectionLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(lblProxyType) @@ -2325,7 +2356,7 @@ public class PreferencesDialog extends javax.swing.JDialog { .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(exitButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 100, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .add(6, 6, 6)) - .add(tabsPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 535, Short.MAX_VALUE) + .add(tabsPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 584, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) @@ -2399,8 +2430,12 @@ public class PreferencesDialog extends javax.swing.JDialog { save(prefs, dialog.sliderCardSizeOtherZones, KEY_GUI_CARD_OTHER_ZONES_SIZE, "true", "false", UPDATE_CACHE_POLICY); sizeGUIChanged = true; } - if (getCachedValue(KEY_GUI_CARD_BATTLEFIELD_SIZE, 14) != dialog.sliderCardSizeBattlefield.getValue()) { - save(prefs, dialog.sliderCardSizeBattlefield, KEY_GUI_CARD_BATTLEFIELD_SIZE, "true", "false", UPDATE_CACHE_POLICY); + if (getCachedValue(KEY_GUI_CARD_BATTLEFIELD_MIN_SIZE, 10) != dialog.sliderCardSizeMaxBattlefield.getValue()) { + save(prefs, dialog.sliderCardSizeMinBattlefield, KEY_GUI_CARD_BATTLEFIELD_MIN_SIZE, "true", "false", UPDATE_CACHE_POLICY); + sizeGUIChanged = true; + } + if (getCachedValue(KEY_GUI_CARD_BATTLEFIELD_MAX_SIZE, 14) != dialog.sliderCardSizeMaxBattlefield.getValue()) { + save(prefs, dialog.sliderCardSizeMaxBattlefield, KEY_GUI_CARD_BATTLEFIELD_MAX_SIZE, "true", "false", UPDATE_CACHE_POLICY); sizeGUIChanged = true; } if (sizeGUIChanged) { @@ -2892,7 +2927,8 @@ public class PreferencesDialog extends javax.swing.JDialog { load(prefs, dialog.sliderTooltipSize, KEY_GUI_TOOLTIP_SIZE, "14"); load(prefs, dialog.sliderGameFeedbackArea, KEY_GUI_FEEDBACK_AREA_SIZE, "14"); load(prefs, dialog.sliderCardSizeOtherZones, KEY_GUI_CARD_OTHER_ZONES_SIZE, "14"); - load(prefs, dialog.sliderCardSizeBattlefield, KEY_GUI_CARD_BATTLEFIELD_SIZE, "14"); + load(prefs, dialog.sliderCardSizeMinBattlefield, KEY_GUI_CARD_BATTLEFIELD_MIN_SIZE, "10"); + load(prefs, dialog.sliderCardSizeMaxBattlefield, KEY_GUI_CARD_BATTLEFIELD_MAX_SIZE, "14"); } private static void loadImagesSettings(Preferences prefs) { @@ -3278,7 +3314,6 @@ public class PreferencesDialog extends javax.swing.JDialog { PreferencesDialog.getCachedValue(PreferencesDialog.KEY_PASS_PRIORITY_ACTIVATION, "true").equals("true"), PreferencesDialog.getCachedValue(PreferencesDialog.KEY_AUTO_ORDER_TRIGGER, "true").equals("true"), PreferencesDialog.getCachedValue(PreferencesDialog.KEY_USE_FIRST_MANA_ABILITY, "false").equals("true") - ); } @@ -3374,8 +3409,9 @@ public class PreferencesDialog extends javax.swing.JDialog { private javax.swing.JPanel jPanel31; private javax.swing.JPanel jPanel32; private javax.swing.JPanel jPanel33; - private javax.swing.JLabel labelCardSizeBattlefield; private javax.swing.JLabel labelCardSizeHand; + private javax.swing.JLabel labelCardSizeMaxBattlefield; + private javax.swing.JLabel labelCardSizeMinBattlefield; private javax.swing.JLabel labelCardSizeOtherZones; private javax.swing.JLabel labelDialogFont; private javax.swing.JLabel labelEditorCardOffset; @@ -3404,8 +3440,9 @@ public class PreferencesDialog extends javax.swing.JDialog { private javax.swing.JCheckBox showAbilityPickerForced; private javax.swing.JCheckBox showCardName; private javax.swing.JCheckBox showPlayerNamesPermanently; - private javax.swing.JSlider sliderCardSizeBattlefield; private javax.swing.JSlider sliderCardSizeHand; + private javax.swing.JSlider sliderCardSizeMaxBattlefield; + private javax.swing.JSlider sliderCardSizeMinBattlefield; private javax.swing.JSlider sliderCardSizeOtherZones; private javax.swing.JSlider sliderChatFontSize; private javax.swing.JSlider sliderDialogFont; diff --git a/Mage.Client/src/main/java/mage/client/game/BattlefieldPanel.java b/Mage.Client/src/main/java/mage/client/game/BattlefieldPanel.java index 14659169f15..e23e22887e0 100644 --- a/Mage.Client/src/main/java/mage/client/game/BattlefieldPanel.java +++ b/Mage.Client/src/main/java/mage/client/game/BattlefieldPanel.java @@ -128,7 +128,7 @@ public class BattlefieldPanel extends javax.swing.JLayeredPane { private void setGUISize() { jScrollPane.getVerticalScrollBar().setPreferredSize(new Dimension(GUISizeHelper.scrollBarSize, 0)); jScrollPane.getHorizontalScrollBar().setPreferredSize(new Dimension(0, GUISizeHelper.scrollBarSize)); - cardDimension = GUISizeHelper.battlefieldCardDimension; + cardDimension = GUISizeHelper.battlefieldCardMaxDimension; } public void update(Map battlefield) { diff --git a/Mage.Client/src/main/java/mage/client/game/GamePane.java b/Mage.Client/src/main/java/mage/client/game/GamePane.java index 06e86103cf3..b0c445fdfa1 100644 --- a/Mage.Client/src/main/java/mage/client/game/GamePane.java +++ b/Mage.Client/src/main/java/mage/client/game/GamePane.java @@ -33,6 +33,7 @@ */ package mage.client.game; +import java.awt.AWTEvent; import java.util.UUID; import javax.swing.SwingUtilities; import mage.client.MagePane; @@ -132,8 +133,12 @@ public class GamePane extends MagePane { gamePanel.activated(); } + @Override + public void handleEvent(AWTEvent event) { + gamePanel.handleEvent(event); + } + private mage.client.game.GamePanel gamePanel; private javax.swing.JScrollPane jScrollPane1; private UUID gameId; - } diff --git a/Mage.Client/src/main/java/mage/client/game/GamePanel.java b/Mage.Client/src/main/java/mage/client/game/GamePanel.java index 2b424627a2e..a7ab2aad802 100644 --- a/Mage.Client/src/main/java/mage/client/game/GamePanel.java +++ b/Mage.Client/src/main/java/mage/client/game/GamePanel.java @@ -27,6 +27,7 @@ */ package mage.client.game; +import java.awt.AWTEvent; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; @@ -391,6 +392,7 @@ public final class GamePanel extends javax.swing.JPanel { stackObjects.setCardDimension(GUISizeHelper.handCardDimension); txtSpellsCast.setFont(new Font(GUISizeHelper.gameDialogAreaFont.getFontName(), Font.BOLD, GUISizeHelper.gameDialogAreaFont.getSize())); + txtHoldPriority.setFont(new Font(GUISizeHelper.gameDialogAreaFont.getFontName(), Font.BOLD, GUISizeHelper.gameDialogAreaFont.getSize())); GUISizeHelper.changePopupMenuFont(popupMenuTriggerOrder); int newStackWidth = pnlHelperHandButtonsStackArea.getWidth() * GUISizeHelper.stackWidth / 100; @@ -589,7 +591,8 @@ public final class GamePanel extends javax.swing.JPanel { setMenuStates( PreferencesDialog.getCachedValue(KEY_GAME_MANA_AUTOPAYMENT, "true").equals("true"), PreferencesDialog.getCachedValue(KEY_GAME_MANA_AUTOPAYMENT_ONLY_ONE, "true").equals("true"), - PreferencesDialog.getCachedValue(KEY_USE_FIRST_MANA_ABILITY, "false").equals("true") + PreferencesDialog.getCachedValue(KEY_USE_FIRST_MANA_ABILITY, "false").equals("true"), + holdingPriority ); updateGame(game); @@ -957,9 +960,9 @@ public final class GamePanel extends javax.swing.JPanel { * @param manaPoolAutomaticRestricted * @param useFirstManaAbility */ - public void setMenuStates(boolean manaPoolAutomatic, boolean manaPoolAutomaticRestricted, boolean useFirstManaAbility) { + public void setMenuStates(boolean manaPoolAutomatic, boolean manaPoolAutomaticRestricted, boolean useFirstManaAbility, boolean holdPriority) { for (PlayAreaPanel playAreaPanel : players.values()) { - playAreaPanel.setMenuStates(manaPoolAutomatic, manaPoolAutomaticRestricted, useFirstManaAbility); + playAreaPanel.setMenuStates(manaPoolAutomatic, manaPoolAutomaticRestricted, useFirstManaAbility, holdPriority); } } @@ -1201,6 +1204,14 @@ public final class GamePanel extends javax.swing.JPanel { } public void select(String message, GameView gameView, int messageId, Map options) { + holdingPriority = false; + txtHoldPriority.setVisible(false); + setMenuStates( + PreferencesDialog.getCachedValue(KEY_GAME_MANA_AUTOPAYMENT, "true").equals("true"), + PreferencesDialog.getCachedValue(KEY_GAME_MANA_AUTOPAYMENT_ONLY_ONE, "true").equals("true"), + PreferencesDialog.getCachedValue(KEY_USE_FIRST_MANA_ABILITY, "false").equals("true"), + false); + updateGame(gameView, options); boolean controllingPlayer = false; for (PlayerView playerView : gameView.getPlayers()) { @@ -1340,6 +1351,14 @@ public final class GamePanel extends javax.swing.JPanel { txtSpellsCast.setOpaque(true); txtSpellsCast.setToolTipText("spells cast during the current turn"); + txtHoldPriority = new javax.swing.JLabel(); + txtHoldPriority.setText("Hold"); + txtHoldPriority.setBorder(BorderFactory.createCompoundBorder(border, paddingBorder)); + txtHoldPriority.setBackground(Color.LIGHT_GRAY); + txtHoldPriority.setOpaque(true); + txtHoldPriority.setToolTipText("Holding priority after the next spell cast or ability activation"); + txtHoldPriority.setVisible(false); + btnCancelSkip = new javax.swing.JButton(); // F3 btnSkipToNextTurn = new javax.swing.JButton(); // F4 btnSkipToEndTurn = new javax.swing.JButton(); // F5 @@ -1670,7 +1689,8 @@ public final class GamePanel extends javax.swing.JPanel { setMenuStates( PreferencesDialog.getCachedValue(KEY_GAME_MANA_AUTOPAYMENT, "true").equals("true"), PreferencesDialog.getCachedValue(KEY_GAME_MANA_AUTOPAYMENT_ONLY_ONE, "true").equals("true"), - PreferencesDialog.getCachedValue(KEY_USE_FIRST_MANA_ABILITY, "false").equals("true")); + PreferencesDialog.getCachedValue(KEY_USE_FIRST_MANA_ABILITY, "false").equals("true"), + holdingPriority); } }); @@ -1713,7 +1733,8 @@ public final class GamePanel extends javax.swing.JPanel { setMenuStates( PreferencesDialog.getCachedValue(KEY_GAME_MANA_AUTOPAYMENT, "true").equals("true"), PreferencesDialog.getCachedValue(KEY_GAME_MANA_AUTOPAYMENT_ONLY_ONE, "true").equals("true"), - PreferencesDialog.getCachedValue(KEY_USE_FIRST_MANA_ABILITY, "false").equals("true")); + PreferencesDialog.getCachedValue(KEY_USE_FIRST_MANA_ABILITY, "false").equals("true"), + holdingPriority); } }); @@ -1829,6 +1850,7 @@ public final class GamePanel extends javax.swing.JPanel { .addComponent(btnSkipToEndStepBeforeYourTurn) ) .addGroup(gl_pnlShortCuts.createSequentialGroup() + .addComponent(txtHoldPriority) .addComponent(txtSpellsCast) .addComponent(btnSwitchHands) .addComponent(btnCancelSkip) @@ -1862,6 +1884,7 @@ public final class GamePanel extends javax.swing.JPanel { .addComponent(btnSkipToEndStepBeforeYourTurn) ) .addGroup(gl_pnlShortCuts.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(txtHoldPriority) .addComponent(txtSpellsCast) .addComponent(btnSwitchHands) .addComponent(btnCancelSkip) @@ -2343,6 +2366,48 @@ public final class GamePanel extends javax.swing.JPanel { return feedbackPanel; } + // Use Cmd on OSX since Ctrl+click is already used to simulate right click + private static int holdPriorityMask = System.getProperty("os.name").contains("Mac OS X") ? InputEvent.META_DOWN_MASK : InputEvent.CTRL_DOWN_MASK; + + public void handleEvent(AWTEvent event) { + if(event instanceof InputEvent) { + int id = event.getID(); + boolean isActionEvent = false; + if(id == MouseEvent.MOUSE_PRESSED) + isActionEvent = true; + else if(id == KeyEvent.KEY_PRESSED) + { + KeyEvent key = (KeyEvent)event; + int keyCode = key.getKeyCode(); + if(keyCode == KeyEvent.VK_ENTER || keyCode == KeyEvent.VK_SPACE) + isActionEvent = true; + } + if(isActionEvent) { + InputEvent input = (InputEvent)event; + if((input.getModifiersEx() & holdPriorityMask) != 0) { + setMenuStates( + PreferencesDialog.getCachedValue(KEY_GAME_MANA_AUTOPAYMENT, "true").equals("true"), + PreferencesDialog.getCachedValue(KEY_GAME_MANA_AUTOPAYMENT_ONLY_ONE, "true").equals("true"), + PreferencesDialog.getCachedValue(KEY_USE_FIRST_MANA_ABILITY, "false").equals("true"), + true); + holdPriority(true); + } + } + } + } + + public void holdPriority(boolean holdPriority) { + if(holdingPriority != holdPriority) { + holdingPriority = holdPriority; + txtHoldPriority.setVisible(holdPriority); + if(holdPriority) + session.sendPlayerAction(PlayerAction.HOLD_PRIORITY, gameId, null); + else + session.sendPlayerAction(PlayerAction.UNHOLD_PRIORITY, gameId, null); + } + } + + private boolean holdingPriority; private mage.client.components.ability.AbilityPicker abilityPicker; private mage.client.cards.BigCard bigCard; @@ -2397,6 +2462,7 @@ public final class GamePanel extends javax.swing.JPanel { private JPanel jPhases; private JPanel phasesContainer; private javax.swing.JLabel txtSpellsCast; + private javax.swing.JLabel txtHoldPriority; private HoverButton currentStep; private Point prevPoint; diff --git a/Mage.Client/src/main/java/mage/client/game/PlayAreaPanel.java b/Mage.Client/src/main/java/mage/client/game/PlayAreaPanel.java index e7ad6fff293..9568d51b13c 100644 --- a/Mage.Client/src/main/java/mage/client/game/PlayAreaPanel.java +++ b/Mage.Client/src/main/java/mage/client/game/PlayAreaPanel.java @@ -78,6 +78,7 @@ public class PlayAreaPanel extends javax.swing.JPanel { private JCheckBoxMenuItem manaPoolMenuItem2; private JCheckBoxMenuItem useFirstManaAbilityItem; private JCheckBoxMenuItem allowViewHandCardsMenuItem; + private JCheckBoxMenuItem holdPriorityMenuItem; public static final int PANEL_HEIGHT = 242; public static final int PANEL_HEIGHT_SMALL = 190; @@ -210,6 +211,19 @@ public class PlayAreaPanel extends javax.swing.JPanel { popupMenu.add(menuItem); menuItem.addActionListener(skipListener); + holdPriorityMenuItem = new JCheckBoxMenuItem("" + (System.getProperty("os.name").contains("Mac OS X") ? "Cmd" : "Ctrl") + "+click - Hold Priority"); + holdPriorityMenuItem.setMnemonic(KeyEvent.VK_P); + holdPriorityMenuItem.setToolTipText("Hold priority after casting a spell or activating an ability, instead of automatically passing priority."); + popupMenu.add(holdPriorityMenuItem); + holdPriorityMenuItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + boolean holdPriority = ((JCheckBoxMenuItem)e.getSource()).getState(); + gamePanel.setMenuStates(manaPoolMenuItem1.getState(), manaPoolMenuItem2.getState(), useFirstManaAbilityItem.getState(), holdPriority); + gamePanel.holdPriority(holdPriority); + } + }); + JMenu skipMenu = new JMenu("Skip"); skipMenu.setMnemonic(KeyEvent.VK_S); popupMenu.add(skipMenu); @@ -277,7 +291,7 @@ public class PlayAreaPanel extends javax.swing.JPanel { public void actionPerformed(ActionEvent e) { boolean manaPoolAutomatic = ((JCheckBoxMenuItem) e.getSource()).getState(); PreferencesDialog.saveValue(KEY_GAME_MANA_AUTOPAYMENT, manaPoolAutomatic ? "true" : "false"); - gamePanel.setMenuStates(manaPoolAutomatic, manaPoolMenuItem2.getState(), useFirstManaAbilityItem.getState()); + gamePanel.setMenuStates(manaPoolAutomatic, manaPoolMenuItem2.getState(), useFirstManaAbilityItem.getState(), holdPriorityMenuItem.getState()); gamePanel.getSession().sendPlayerAction(manaPoolAutomatic ? PlayerAction.MANA_AUTO_PAYMENT_ON : PlayerAction.MANA_AUTO_PAYMENT_OFF, gameId, null); } }); @@ -295,7 +309,7 @@ public class PlayAreaPanel extends javax.swing.JPanel { public void actionPerformed(ActionEvent e) { boolean manaPoolAutomaticRestricted = ((JCheckBoxMenuItem) e.getSource()).getState(); PreferencesDialog.saveValue(KEY_GAME_MANA_AUTOPAYMENT_ONLY_ONE, manaPoolAutomaticRestricted ? "true" : "false"); - gamePanel.setMenuStates(manaPoolMenuItem1.getState(), manaPoolAutomaticRestricted, useFirstManaAbilityItem.getState()); + gamePanel.setMenuStates(manaPoolMenuItem1.getState(), manaPoolAutomaticRestricted, useFirstManaAbilityItem.getState(), holdPriorityMenuItem.getState()); gamePanel.getSession().sendPlayerAction(manaPoolAutomaticRestricted ? PlayerAction.MANA_AUTO_PAYMENT_RESTRICTED_ON : PlayerAction.MANA_AUTO_PAYMENT_RESTRICTED_OFF, gameId, null); } }); @@ -313,7 +327,7 @@ public class PlayAreaPanel extends javax.swing.JPanel { public void actionPerformed(ActionEvent e) { boolean useFirstManaAbility = ((JCheckBoxMenuItem) e.getSource()).getState(); PreferencesDialog.saveValue(KEY_USE_FIRST_MANA_ABILITY, useFirstManaAbility ? "true" : "false"); - gamePanel.setMenuStates(manaPoolMenuItem1.getState(), manaPoolMenuItem2.getState(), useFirstManaAbility); + gamePanel.setMenuStates(manaPoolMenuItem1.getState(), manaPoolMenuItem2.getState(), useFirstManaAbility, holdPriorityMenuItem.getState()); gamePanel.getSession().sendPlayerAction(useFirstManaAbility ? PlayerAction.USE_FIRST_MANA_ABILITY_ON: PlayerAction.USE_FIRST_MANA_ABILITY_OFF, gameId, null); } }); @@ -642,7 +656,7 @@ public class PlayAreaPanel extends javax.swing.JPanel { this.playingMode = playingMode; } - public void setMenuStates(boolean manaPoolAutomatic, boolean manaPoolAutomaticRestricted, boolean useFirstManaAbility) { + public void setMenuStates(boolean manaPoolAutomatic, boolean manaPoolAutomaticRestricted, boolean useFirstManaAbility, boolean holdPriority) { if (manaPoolMenuItem1 != null) { manaPoolMenuItem1.setSelected(manaPoolAutomatic); } @@ -652,6 +666,9 @@ public class PlayAreaPanel extends javax.swing.JPanel { if (useFirstManaAbilityItem != null) { useFirstManaAbilityItem.setSelected(useFirstManaAbility); } + if (holdPriorityMenuItem != null) { + holdPriorityMenuItem.setSelected(holdPriority); + } } private mage.client.game.BattlefieldPanel battlefieldPanel; 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 326d3a3d59b..18bdfa651e7 100644 --- a/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java +++ b/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java @@ -395,7 +395,8 @@ public class CallbackClientImpl implements CallbackClient { .append("
F7 - Skip to next main phase but stop on declare attackers/blockers and something on the stack") .append("
F9 - Skip everything until your next turn") .append("
F11 - Skip everything until the end step just prior to your turn") - .append("
F3 - Undo F4/F5/F7/F9/F11").toString(), + .append("
F3 - Undo F4/F5/F7/F9/F11") + .append("
").append(System.getProperty("os.name").contains("Mac OS X") ? "Cmd" : "Ctrl").append(" + click - Hold priority while casting a spell or activating an ability").toString(), null, MessageType.USER_INFO, ChatMessage.MessageColor.BLUE); break; case TOURNAMENT: diff --git a/Mage.Client/src/main/java/mage/client/util/GUISizeHelper.java b/Mage.Client/src/main/java/mage/client/util/GUISizeHelper.java index 688a3b5dc1a..b41a55944ab 100644 --- a/Mage.Client/src/main/java/mage/client/util/GUISizeHelper.java +++ b/Mage.Client/src/main/java/mage/client/util/GUISizeHelper.java @@ -69,7 +69,8 @@ public class GUISizeHelper { public static Dimension otherZonesCardDimension; public static int otherZonesCardVerticalOffset; - public static Dimension battlefieldCardDimension; + public static Dimension battlefieldCardMinDimension; + public static Dimension battlefieldCardMaxDimension; public static Dimension editorCardDimension; public static int editorCardOffsetSize; @@ -144,8 +145,10 @@ public class GUISizeHelper { otherZonesCardVerticalOffset = otherZonesCardDimension.height / 10; } - int battlefieldCardSize = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GUI_CARD_BATTLEFIELD_SIZE, 14); - battlefieldCardDimension = new Dimension(CARD_IMAGE_WIDTH * battlefieldCardSize / 42, CARD_IMAGE_HEIGHT * battlefieldCardSize / 42); + int battlefieldCardMinSize = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GUI_CARD_BATTLEFIELD_MIN_SIZE, 10); + battlefieldCardMinDimension = new Dimension(CARD_IMAGE_WIDTH * battlefieldCardMinSize / 42, CARD_IMAGE_HEIGHT * battlefieldCardMinSize / 42); + int battlefieldCardMaxSize = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GUI_CARD_BATTLEFIELD_MAX_SIZE, 14); + battlefieldCardMaxDimension = new Dimension(CARD_IMAGE_WIDTH * battlefieldCardMaxSize / 42, CARD_IMAGE_HEIGHT * battlefieldCardMaxSize / 42); int editorCardSize = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GUI_CARD_EDITOR_SIZE, 14); editorCardDimension = new Dimension(CARD_IMAGE_WIDTH * editorCardSize / 42, CARD_IMAGE_HEIGHT * editorCardSize / 42); diff --git a/Mage.Client/src/main/java/mage/client/util/layout/impl/OldCardLayoutStrategy.java b/Mage.Client/src/main/java/mage/client/util/layout/impl/OldCardLayoutStrategy.java index 47cd0d30e87..517bab9508c 100644 --- a/Mage.Client/src/main/java/mage/client/util/layout/impl/OldCardLayoutStrategy.java +++ b/Mage.Client/src/main/java/mage/client/util/layout/impl/OldCardLayoutStrategy.java @@ -23,13 +23,12 @@ public class OldCardLayoutStrategy implements CardLayoutStrategy { /** * This offset is used once to shift all attachments */ - private static final int ATTACHMENTS_DX_OFFSET = 11; + private static final int ATTACHMENTS_MIN_DX_OFFSET = 12; /** * This offset is used for each attachment */ - private static final int ATTACHMENT_DX_OFFSET = 0; - private static final int ATTACHMENT_DY_OFFSET = 11; + private static final int ATTACHMENT_MIN_DY_OFFSET = 12; @Override public void doLayout(JLayeredPane jLayeredPane, int width) { @@ -56,7 +55,7 @@ public class OldCardLayoutStrategy implements CardLayoutStrategy { perm.getLinks().clear(); Rectangle rectangleBaseCard = perm.getBounds(); if (!Plugins.getInstance().isCardPluginLoaded()) { - for (UUID attachmentId: permanent.getAttachments()) { + for (UUID attachmentId : permanent.getAttachments()) { MagePermanent link = permanents.get(attachmentId); if (link != null) { perm.getLinks().add(link); @@ -67,15 +66,16 @@ public class OldCardLayoutStrategy implements CardLayoutStrategy { } } else { int index = permanent.getAttachments().size(); - for (UUID attachmentId: permanent.getAttachments()) { + for (UUID attachmentId : permanent.getAttachments()) { MagePermanent link = permanents.get(attachmentId); if (link != null) { link.setBounds(rectangleBaseCard); perm.getLinks().add(link); + int dyOffset = Math.max(perm.getHeight() / 10, ATTACHMENT_MIN_DY_OFFSET); if (index == 1) { - rectangleBaseCard.translate(ATTACHMENTS_DX_OFFSET, ATTACHMENT_DY_OFFSET); // do it once + rectangleBaseCard.translate(Math.max(perm.getWidth() / 10, ATTACHMENTS_MIN_DX_OFFSET), dyOffset); // do it once } else { - rectangleBaseCard.translate(ATTACHMENT_DX_OFFSET, ATTACHMENT_DY_OFFSET); + rectangleBaseCard.translate(0, dyOffset); } perm.setBounds(rectangleBaseCard); jLayeredPane.moveToFront(link); diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/CardPluginImpl.java b/Mage.Client/src/main/java/org/mage/plugins/card/CardPluginImpl.java index 99d5a8acf06..7a9f4950db9 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/CardPluginImpl.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/CardPluginImpl.java @@ -67,7 +67,8 @@ public class CardPluginImpl implements CardPlugin { private int landStackMax = 5; // private int cardWidthMin = 50, cardWidthMax = Constants.CARD_SIZE_FULL.width; - private int cardWidthMin = 50, cardWidthMax = (int) GUISizeHelper.battlefieldCardDimension.getWidth(); + private int cardWidthMin = (int) GUISizeHelper.battlefieldCardMinDimension.getWidth(); + private int cardWidthMax = (int) GUISizeHelper.battlefieldCardMaxDimension.getWidth(); private boolean stackVertical = false; @@ -101,8 +102,8 @@ public class CardPluginImpl implements CardPlugin { } private void setGUISize() { - cardWidthMin = 50; - cardWidthMax = (int) GUISizeHelper.battlefieldCardDimension.getWidth(); + cardWidthMin = (int) GUISizeHelper.battlefieldCardMinDimension.getWidth(); + cardWidthMax = (int) GUISizeHelper.battlefieldCardMaxDimension.getWidth(); } @Override @@ -261,6 +262,7 @@ public class CardPluginImpl implements CardPlugin { } //FIXME: -1 is too slow. why not binary search? cardWidth -= 3; + } // Get size of all the rows. diff --git a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java index a2a48fb1d61..203e5d45481 100644 --- a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java @@ -123,6 +123,8 @@ public class HumanPlayer extends PlayerImpl { protected Map requestAutoAnswerId = new HashMap<>(); protected Map requestAutoAnswerText = new HashMap<>(); + protected boolean holdingPriority; + public HumanPlayer(String name, RangeOfInfluence range, int skill) { super(name, range); replacementEffectChoice = new ChoiceImpl(true); @@ -565,7 +567,7 @@ public class HumanPlayer extends PlayerImpl { public boolean priority(Game game) { passed = false; if (!abort) { - if (getJustActivatedType() != null) { + if (getJustActivatedType() != null && !holdingPriority) { if (userData.isPassPriorityCast() && getJustActivatedType().equals(AbilityType.SPELL)) { setJustActivatedType(null); pass(game); @@ -661,6 +663,7 @@ public class HumanPlayer extends PlayerImpl { } while (canRespond()) { updateGameStatePriority("priority", game); + holdingPriority = false; game.firePriorityEvent(playerId); waitForResponse(game); if (game.executingRollback()) { @@ -1465,6 +1468,12 @@ public class HumanPlayer extends PlayerImpl { case REQUEST_AUTO_ANSWER_RESET_ALL: setRequestAutoAnswer(playerAction, game, data); break; + case HOLD_PRIORITY: + holdingPriority = true; + break; + case UNHOLD_PRIORITY: + holdingPriority = false; + break; default: super.sendPlayerAction(playerAction, game, data); } diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/ElderDeepFiend.java b/Mage.Sets/src/mage/sets/eldritchmoon/ElderDeepFiend.java new file mode 100644 index 00000000000..53c665fa8ad --- /dev/null +++ b/Mage.Sets/src/mage/sets/eldritchmoon/ElderDeepFiend.java @@ -0,0 +1,78 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.eldritchmoon; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CastSourceTriggeredAbility; +import mage.abilities.effects.common.TapTargetEffect; +import mage.abilities.keyword.EmergeAbility; +import mage.abilities.keyword.FlashAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.FilterPermanent; +import mage.target.TargetPermanent; + +/** + * + * @author emerald000 + */ +public class ElderDeepFiend extends CardImpl { + + public ElderDeepFiend(UUID ownerId) { + super(ownerId, 5, "Elder Deep-Fiend", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{8}"); + this.expansionSetCode = "EMN"; + this.subtype.add("Eldrazi"); + this.subtype.add("Octopus"); + this.power = new MageInt(5); + this.toughness = new MageInt(6); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // Emerge {5}{U}{U} + this.addAbility(new EmergeAbility(this, new ManaCostsImpl<>("{5}{U}{U}"))); + + // When you cast Elder Deep-Fiend, tap up to four target permanents. + Ability ability = new CastSourceTriggeredAbility(new TapTargetEffect()); + ability.addTarget(new TargetPermanent(0, 4, new FilterPermanent("permanents to tap"), false)); + this.addAbility(ability); + } + + public ElderDeepFiend(final ElderDeepFiend card) { + super(card); + } + + @Override + public ElderDeepFiend copy() { + return new ElderDeepFiend(this); + } +} diff --git a/Mage.Sets/src/mage/sets/eldritchmoon/StitchersGraft.java b/Mage.Sets/src/mage/sets/eldritchmoon/StitchersGraft.java new file mode 100644 index 00000000000..65876b2e08f --- /dev/null +++ b/Mage.Sets/src/mage/sets/eldritchmoon/StitchersGraft.java @@ -0,0 +1,119 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.eldritchmoon; + +import java.util.UUID; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.UnattachedTriggeredAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DontUntapInControllersNextUntapStepSourceEffect; +import mage.abilities.effects.common.SacrificeEquippedEffect; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EquipAbility; +import mage.cards.CardImpl; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent.EventType; +import mage.game.events.GameEvent; + +/** + * + * @author spjspj + */ +public class StitchersGraft extends CardImpl { + + public StitchersGraft(UUID ownerId) { + super(ownerId, 200, "Stitcher's Graft", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{1}"); + this.expansionSetCode = "EMN"; + this.subtype.add("Equipment"); + + // Equipped creature gets +3/+3. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(3, 3))); + + // Whenever equipped creature attacks, it doesn't untap during its controller's next untap step. + Effect effect = new GainAbilityAttachedEffect(new StitchersGraftTriggeredAbility(), AttachmentType.EQUIPMENT); + effect.setText("Equipped creature has \"Whenever equipped creature attacks, it doesn't untap during its controller's next untap step.\""); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + + // Whenever Stitcher's Graft becomes unattached from a permanent, sacrifice that permanent. + this.addAbility(new UnattachedTriggeredAbility(new SacrificeEquippedEffect(), false)); + + // Equip {2} + this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(2))); + } + + public StitchersGraft(final StitchersGraft card) { + super(card); + } + + @Override + public StitchersGraft copy() { + return new StitchersGraft(this); + } +} + +class StitchersGraftTriggeredAbility extends TriggeredAbilityImpl { + + public StitchersGraftTriggeredAbility() { + super(Zone.BATTLEFIELD, new DontUntapInControllersNextUntapStepSourceEffect()); + } + + public StitchersGraftTriggeredAbility(final StitchersGraftTriggeredAbility ability) { + super(ability); + } + + @Override + public StitchersGraftTriggeredAbility copy() { + return new StitchersGraftTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.ATTACKER_DECLARED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.ATTACKER_DECLARED && event.getSourceId().equals(this.getSourceId())) { + return true; + } + return false; + } + + @Override + public String getRule() { + return "Whenever equipped creature attacks, it doesn't untap during its controller's next untap step"; + } +} diff --git a/Mage.Sets/src/mage/sets/guildpact/EarthSurge.java b/Mage.Sets/src/mage/sets/guildpact/EarthSurge.java new file mode 100644 index 00000000000..8406d44ee8d --- /dev/null +++ b/Mage.Sets/src/mage/sets/guildpact/EarthSurge.java @@ -0,0 +1,72 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.guildpact; + +import java.util.UUID; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.CardTypePredicate; + +/** + * + * @author Styxo + */ +public class EarthSurge extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("land creatures"); + + static { + filter.add(new CardTypePredicate(CardType.LAND)); + } + + public EarthSurge(UUID ownerId) { + super(ownerId, 84, "Earth Surge", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}"); + this.expansionSetCode = "GPT"; + + //Each land gets +2/+2 as long as it's a creature. + Effect effect = new BoostControlledEffect(2, 2, Duration.WhileOnBattlefield, filter, true); + effect.setText("Each land gets +2/+2 as long as it\'s a creature"); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + } + + public EarthSurge(final EarthSurge card) { + super(card); + } + + @Override + public EarthSurge copy() { + return new EarthSurge(this); + } +} diff --git a/Mage.Sets/src/mage/sets/modernmasters2015/WorldheartPhoenix.java b/Mage.Sets/src/mage/sets/modernmasters2015/WorldheartPhoenix.java index 9961f8c2b6d..bd2b489c593 100644 --- a/Mage.Sets/src/mage/sets/modernmasters2015/WorldheartPhoenix.java +++ b/Mage.Sets/src/mage/sets/modernmasters2015/WorldheartPhoenix.java @@ -134,7 +134,7 @@ public class WorldheartPhoenix extends CardImpl { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getSourceId()); + Permanent permanent = game.getPermanentEntering(source.getSourceId()); if (permanent != null) { SpellAbility spellAbility = (SpellAbility) getValue(EntersBattlefieldEffect.SOURCE_CAST_SPELL_ABILITY); if (spellAbility != null diff --git a/Mage/src/main/java/mage/abilities/keyword/EmergeAbility.java b/Mage/src/main/java/mage/abilities/keyword/EmergeAbility.java new file mode 100644 index 00000000000..40f610c362b --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/EmergeAbility.java @@ -0,0 +1,116 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.abilities.keyword; + +import java.util.UUID; +import mage.abilities.SpellAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.mana.ManaCost; +import mage.abilities.costs.mana.ManaCosts; +import mage.cards.Card; +import mage.constants.Outcome; +import mage.constants.SpellAbilityType; +import mage.constants.Zone; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.CardIdPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.util.CardUtil; + +/** + * + * @author emerald000 + */ +public class EmergeAbility extends SpellAbility { + + private final ManaCosts emergeCost; + + public EmergeAbility(Card card, ManaCosts emergeCost) { + super(emergeCost, card.getName() + " with emerge", 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.timing = card.getSpellAbility().getTiming(); + this.setRuleAtTheTop(true); + this.emergeCost = emergeCost.copy(); + } + + public EmergeAbility(final EmergeAbility ability) { + super(ability); + this.emergeCost = ability.emergeCost.copy(); + } + + @Override + public boolean canActivate(UUID playerId, Game game) { + Player controller = game.getPlayer(this.getControllerId()); + if (controller != null) { + for (Permanent creature : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), this.getControllerId(), this.getSourceId(), game)) { + ManaCost costToPay = CardUtil.reduceCost(emergeCost.copy(), creature.getConvertedManaCost()); + if (costToPay.canPay(this, this.getSourceId(), this.getControllerId(), game)) { + return true; + } + } + } + return false; + } + + @Override + public boolean activate(Game game, boolean noMana) { + Player controller = game.getPlayer(this.getControllerId()); + if (controller != null) { + TargetPermanent target = new TargetControlledCreaturePermanent(new FilterControlledCreaturePermanent("creature to sacrifice for emerge")); + if (controller.choose(Outcome.Sacrifice, target, this.getSourceId(), game)) { + Permanent creature = game.getPermanent(target.getFirstTarget()); + CardUtil.reduceCost(this, creature.getConvertedManaCost()); + FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(creature.getLogName()); + filter.add(new CardIdPredicate(creature.getId())); + this.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(filter))); + return super.activate(game, false); + } + } + return false; + } + + @Override + public EmergeAbility copy() { + return new EmergeAbility(this); + } + + @Override + public String getRule(boolean all) { + return getRule(); + } + + @Override + public String getRule() { + return "Emerge " + emergeCost.getText() + " (You may cast this spell by sacrificing a creature and paying the emerge cost reduced by that creature's converted mana cost.)"; + } +} diff --git a/Mage/src/main/java/mage/constants/PlayerAction.java b/Mage/src/main/java/mage/constants/PlayerAction.java index c21bf05d458..cbff2a13840 100644 --- a/Mage/src/main/java/mage/constants/PlayerAction.java +++ b/Mage/src/main/java/mage/constants/PlayerAction.java @@ -82,5 +82,6 @@ public enum PlayerAction { CLIENT_DOWNLOAD_CARD_IMAGES, CLIENT_RECONNECT, CLIENT_REPLAY_ACTION, - + HOLD_PRIORITY, + UNHOLD_PRIORITY } diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 649624f6328..22e3ceab78a 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -57372,4 +57372,4 @@ Lupine Prototype|Eldritch Moon|197|R|{2}|Artifact Creature - Wolf Construct|5|5| Soul Separator|Eldritch Moon|199|R|{3}|Artifact|||{5}, {T}, Sacrifice Soul Separator: Exile target creature card from your graveyard. Put a token onto the battlefield that's a copy of that card except it's 1/1, it's a Spirit in addition to its other types, and it has flying. Put a black Zombie creature token onto the battlefield with power equal to that card's power and toughness equal that card's toughness.| Stitcher's Graft|Eldritch Moon|200|R|{1}|Artifact - Equipment|||Equipped creature gets +3/+3.$Whenever equipped creature attacks, it doesn't untap during its controller's next untap step.$Whenever Stitcher's Graft becomes unattached from a permanent, sacrifice that permanent.$Equip {2}| Geier Reach Sanitarium|Eldritch Moon|203|R||Legendary Land|||{T}: Add {C} to your mana pool.${2}, {T}: Each player draws a card, then discards a card.| -Hanweir Battlements|Eldritch Moon|204|R||Land|||{T}: Add {C} to your mana pool.${R},{T}: Target creature gains haste until end of turn.${3}{R}{R},{T}: If you both own and control Hanweir Battlements and a creature named Hanweir Garrison, exile them, then meld them into Hanweir, the Writhing Township.| \ No newline at end of file +Hanweir Battlements|Eldritch Moon|204|R||Land|||{T}: Add {C} to your mana pool.${R},{T}: Target creature gains haste until end of turn.${3}{R}{R},{T}: If you both own and control Hanweir Battlements and a creature named Hanweir Garrison, exile them, then meld them into Hanweir, the Writhing Township.|