diff --git a/Mage.Client/src/main/java/mage/client/MageFrame.java b/Mage.Client/src/main/java/mage/client/MageFrame.java index 77d7ebf6ef4..10ad84de4a4 100644 --- a/Mage.Client/src/main/java/mage/client/MageFrame.java +++ b/Mage.Client/src/main/java/mage/client/MageFrame.java @@ -613,7 +613,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { } } - private static MagePane getTopMost(MagePane exclude) { + public static MagePane getTopMost(MagePane exclude) { MagePane topmost = null; int best = Integer.MAX_VALUE; for (Component frame : desktopPane.getComponentsInLayer(JLayeredPane.DEFAULT_LAYER)) { diff --git a/Mage.Client/src/main/java/mage/client/components/HoverButton.java b/Mage.Client/src/main/java/mage/client/components/HoverButton.java index bd288506cf8..7dbf3891525 100644 --- a/Mage.Client/src/main/java/mage/client/components/HoverButton.java +++ b/Mage.Client/src/main/java/mage/client/components/HoverButton.java @@ -3,6 +3,7 @@ package mage.client.components; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; +import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; @@ -40,6 +41,7 @@ public class HoverButton extends JPanel implements MouseListener { private String topText; private Image topTextImage; private Image topTextImageRight; + private String centerText; private boolean isHovered = false; private boolean isSelected = false; @@ -49,12 +51,15 @@ public class HoverButton extends JPanel implements MouseListener { private Command observer = null; private Command onHover = null; private Color textColor = Color.white; + private final Rectangle centerTextArea = new Rectangle(5, 18, 75, 40); + private final Color centerTextColor = Color.YELLOW; private final Color textBGColor = Color.black; static final Font textFont = new Font("Arial", Font.PLAIN, 12); static final Font textFontMini = new Font("Arial", Font.PLAIN, 11); static final Font textSetFontBoldMini = new Font("Arial", Font.BOLD, 12); static final Font textSetFontBold = new Font("Arial", Font.BOLD, 14); + private boolean useMiniFont = false; private boolean alignTextLeft = false; @@ -134,6 +139,21 @@ public class HoverButton extends JPanel implements MouseListener { if (topTextImageRight != null) { g.drawImage(topTextImageRight, this.getWidth() - 20, 3, this); } + + if (centerText != null) { + g2d.setColor(centerTextColor); + int fontSize = 40; + int val = Integer.parseInt(centerText); + if (val > 9999) { + fontSize = 24; + } else if (val > 999) { + fontSize = 28; + } else if (val > 99) { + fontSize = 34; + } + drawCenteredString(g2d, centerText, centerTextArea, new Font("Arial", Font.BOLD, fontSize)); + } + g2d.setColor(textColor); if (overlayImage != null) { g.drawImage(overlayImage, (imageSize.width - overlayImageSize.width) / 2, 10, this); } else if (set != null) { @@ -298,13 +318,17 @@ public class HoverButton extends JPanel implements MouseListener { public void setTopTextImage(Image topTextImage) { this.topTextImage = topTextImage; - this.textOffsetX = -1; // rest for new clculation + this.textOffsetX = -1; // rest for new calculation } public void setTopTextImageRight(Image topTextImage) { this.topTextImageRight = topTextImage; } + public void setCenterText(String centerText) { + this.centerText = centerText; + } + public void setTextAlwaysVisible(boolean textAlwaysVisible) { this.textAlwaysVisible = textAlwaysVisible; } @@ -313,4 +337,24 @@ public class HoverButton extends JPanel implements MouseListener { this.alignTextLeft = alignTextLeft; } + /** + * Draw a String centered in the middle of a Rectangle. + * + * @param g The Graphics instance. + * @param text The String to draw. + * @param rect The Rectangle to center the text in. + * @param font + */ + public void drawCenteredString(Graphics g, String text, Rectangle rect, Font font) { + // Get the FontMetrics + FontMetrics metrics = g.getFontMetrics(font); + // Determine the X coordinate for the text + int x = rect.x + (rect.width - metrics.stringWidth(text)) / 2; + // Determine the Y coordinate for the text (note we add the ascent, as in java 2d 0 is top of the screen) + int y = rect.y + ((rect.height - metrics.getHeight()) / 2) + metrics.getAscent(); + // Set the font + g.setFont(font); + // Draw the String + g.drawString(text, x, y); + } } diff --git a/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.form b/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.form index 6db932f598b..53405d95e3a 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.form +++ b/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.form @@ -7,6 +7,11 @@ + + + + + @@ -29,40 +34,62 @@ - + - - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + + @@ -79,35 +106,54 @@ + - - - + + + + + + - - - + + + + + + - - - + + + + + + - - - + + + + + + - + + + + + + + @@ -120,7 +166,7 @@ - + @@ -130,9 +176,23 @@ + + + + + + + + + + + + + + - + @@ -142,9 +202,22 @@ + + + + + + + + + + + + + - + @@ -154,9 +227,22 @@ + + + + + + + + + + + + + - + @@ -166,9 +252,22 @@ + + + + + + + + + + + + + - + @@ -178,9 +277,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -194,14 +328,6 @@ - - - - - - - - diff --git a/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.java b/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.java index 792c4dd9014..19c3db50f8e 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.java @@ -27,12 +27,13 @@ */ package mage.client.dialog; -import java.util.HashSet; +import java.awt.image.BufferedImage; import java.util.List; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import javax.swing.DefaultComboBoxModel; +import javax.swing.ImageIcon; import javax.swing.JLayeredPane; import mage.Mana; import mage.cards.Card; @@ -49,6 +50,7 @@ import mage.client.util.gui.FastSearchUtil; import mage.constants.Rarity; import mage.util.RandomUtil; import org.apache.log4j.Logger; +import org.mage.card.arcane.ManaSymbols; /** * @@ -59,7 +61,6 @@ public class AddLandDialog extends MageDialog { private static final Logger logger = Logger.getLogger(MageDialog.class); private Deck deck; - private final Set landSetCodes = new HashSet<>(); private static final int DEFAULT_SEALED_DECK_CARD_NUMBER = 40; @@ -131,6 +132,27 @@ public class AddLandDialog extends MageDialog { } else { MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER); } + spnDeckSize.setValue(DEFAULT_SEALED_DECK_CARD_NUMBER); + BufferedImage image = ManaSymbols.getSizedManaSymbol("G", 15); + if (image != null) { + lblForestIcon.setIcon(new ImageIcon(image)); + } + image = ManaSymbols.getSizedManaSymbol("U", 15); + if (image != null) { + lblIslandIcon.setIcon(new ImageIcon(image)); + } + image = ManaSymbols.getSizedManaSymbol("W", 15); + if (image != null) { + lblPlainsIcon.setIcon(new ImageIcon(image)); + } + image = ManaSymbols.getSizedManaSymbol("R", 15); + if (image != null) { + lblMountainIcon.setIcon(new ImageIcon(image)); + } + image = ManaSymbols.getSizedManaSymbol("B", 15); + if (image != null) { + lblSwampIcon.setIcon(new ImageIcon(image)); + } this.setVisible(true); } @@ -139,9 +161,7 @@ public class AddLandDialog extends MageDialog { String landSetName = (String) cbLandSet.getSelectedItem(); CardCriteria criteria = new CardCriteria(); - if (landSetName.equals("")) { - criteria.setCodes(landSetCodes.toArray(new String[landSetCodes.size()])); - } else { + if (!landSetName.equals("")) { ExpansionInfo expansionInfo = ExpansionRepository.instance.getSetByName(landSetName); if (expansionInfo == null) { throw new IllegalArgumentException("Code of Set " + landSetName + " not found"); @@ -193,20 +213,28 @@ public class AddLandDialog extends MageDialog { private void initComponents() { jButton2 = new javax.swing.JButton(); + jLabel1 = new javax.swing.JLabel(); lblLandSet = new javax.swing.JLabel(); lblForest = new javax.swing.JLabel(); spnForest = new javax.swing.JSpinner(); + lblForestIcon = new javax.swing.JLabel(); lblIsland = new javax.swing.JLabel(); spnIsland = new javax.swing.JSpinner(); + lblIslandIcon = new javax.swing.JLabel(); lblMountain = new javax.swing.JLabel(); spnMountain = new javax.swing.JSpinner(); + lblMountainIcon = new javax.swing.JLabel(); lblPains = new javax.swing.JLabel(); spnPlains = new javax.swing.JSpinner(); + lblPlainsIcon = new javax.swing.JLabel(); lblSwamp = new javax.swing.JLabel(); spnSwamp = new javax.swing.JSpinner(); + lblSwampIcon = new javax.swing.JLabel(); + lblDeckSize = new javax.swing.JLabel(); + spnDeckSize = new javax.swing.JSpinner(); + btnAutoAdd = new javax.swing.JButton(); btnAdd = new javax.swing.JButton(); btnCancel = new javax.swing.JButton(); - btnAutoAdd = new javax.swing.JButton(); panelSet = new javax.swing.JPanel(); cbLandSet = new javax.swing.JComboBox(); btnSetFastSearch = new javax.swing.JButton(); @@ -214,31 +242,67 @@ public class AddLandDialog extends MageDialog { jButton2.setText("jButton2"); + jLabel1.setText("jLabel1"); + setTitle("Add Land"); lblLandSet.setText("Set:"); - lblForest.setText("Forest"); + lblForest.setText("Forest:"); spnForest.setModel(new javax.swing.SpinnerNumberModel(0, 0, null, 1)); - lblIsland.setText("Island"); + lblForestIcon.setToolTipText(""); + lblForestIcon.setMaximumSize(new java.awt.Dimension(22, 20)); + lblForestIcon.setMinimumSize(new java.awt.Dimension(22, 20)); + lblForestIcon.setPreferredSize(new java.awt.Dimension(22, 20)); + + lblIsland.setText("Island:"); spnIsland.setModel(new javax.swing.SpinnerNumberModel(0, 0, null, 1)); - lblMountain.setText("Mountain"); + lblIslandIcon.setMaximumSize(new java.awt.Dimension(22, 20)); + lblIslandIcon.setMinimumSize(new java.awt.Dimension(22, 20)); + lblIslandIcon.setPreferredSize(new java.awt.Dimension(22, 20)); + + lblMountain.setText("Mountain:"); spnMountain.setModel(new javax.swing.SpinnerNumberModel(0, 0, null, 1)); - lblPains.setText("Plains"); + lblMountainIcon.setMaximumSize(new java.awt.Dimension(22, 20)); + lblMountainIcon.setMinimumSize(new java.awt.Dimension(22, 20)); + lblMountainIcon.setPreferredSize(new java.awt.Dimension(22, 20)); + + lblPains.setText("Plains:"); spnPlains.setModel(new javax.swing.SpinnerNumberModel(0, 0, null, 1)); - lblSwamp.setText("Swamp"); + lblPlainsIcon.setMaximumSize(new java.awt.Dimension(22, 20)); + lblPlainsIcon.setMinimumSize(new java.awt.Dimension(22, 20)); + lblPlainsIcon.setPreferredSize(new java.awt.Dimension(22, 20)); + + lblSwamp.setText("Swamp:"); spnSwamp.setModel(new javax.swing.SpinnerNumberModel(0, 0, null, 1)); + lblSwampIcon.setMaximumSize(new java.awt.Dimension(22, 20)); + lblSwampIcon.setMinimumSize(new java.awt.Dimension(22, 20)); + lblSwampIcon.setPreferredSize(new java.awt.Dimension(22, 20)); + + lblDeckSize.setText("Deck size:"); + + spnDeckSize.setModel(new javax.swing.SpinnerNumberModel(0, 0, null, 1)); + + btnAutoAdd.setText("Suggest"); + btnAutoAdd.setToolTipText("Propose related to the mana costs of the cards in the deck
\nthe number of lands to add to get to the set deck size."); + btnAutoAdd.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnAutoAddActionPerformed(evt); + } + }); + btnAdd.setText("Add"); + btnAdd.setToolTipText("Add the selected number of basic lands to the deck."); btnAdd.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { btnAddActionPerformed(evt); @@ -252,13 +316,6 @@ public class AddLandDialog extends MageDialog { } }); - btnAutoAdd.setText("Suggest"); - btnAutoAdd.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - btnAutoAddActionPerformed(evt); - } - }); - panelSet.setLayout(new javax.swing.BoxLayout(panelSet, javax.swing.BoxLayout.LINE_AXIS)); cbLandSet.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" })); @@ -285,32 +342,50 @@ public class AddLandDialog extends MageDialog { layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lblMountain) - .addComponent(lblForest, javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(lblLandSet, javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(lblIsland, javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(lblPains, javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(lblSwamp, javax.swing.GroupLayout.Alignment.TRAILING)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lblMountain) + .addComponent(lblForest, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(lblLandSet, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(lblIsland, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(lblPains, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(lblSwamp, javax.swing.GroupLayout.Alignment.TRAILING)) + .addComponent(lblDeckSize)) .addGap(18, 18, 18) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(ckbFullArtLands) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(btnAdd) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnCancel) + .addContainerGap()) + .addComponent(ckbFullArtLands) + .addComponent(panelSet, javax.swing.GroupLayout.PREFERRED_SIZE, 219, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(layout.createSequentialGroup() + .addComponent(spnForest, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblForestIcon, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(spnIsland, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblIslandIcon, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(spnMountain, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblMountainIcon, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(spnSwamp, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblSwampIcon, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(spnDeckSize, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(btnAutoAdd))) .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) - .addComponent(btnAutoAdd, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 85, Short.MAX_VALUE) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) - .addComponent(spnMountain, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 85, Short.MAX_VALUE) - .addComponent(spnIsland, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 85, Short.MAX_VALUE) - .addComponent(spnForest, javax.swing.GroupLayout.Alignment.LEADING)) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) - .addComponent(spnSwamp, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 85, Short.MAX_VALUE) - .addComponent(spnPlains, javax.swing.GroupLayout.Alignment.LEADING)))) + .addComponent(spnPlains, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnAdd) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnCancel)) - .addComponent(panelSet, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addComponent(lblPlainsIcon, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(36, 36, 36)))) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -322,30 +397,44 @@ public class AddLandDialog extends MageDialog { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(lblForest) - .addComponent(spnForest, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(spnForest, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblForestIcon, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lblIsland) - .addComponent(spnIsland, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblIsland) + .addComponent(spnIsland, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(lblIslandIcon, 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(lblMountain) - .addComponent(spnMountain, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblMountain) + .addComponent(spnMountain, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(lblMountainIcon, 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(lblPains) - .addComponent(spnPlains, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblPains) + .addComponent(spnPlains, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(lblPlainsIcon, 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) + .addComponent(lblSwamp) + .addComponent(spnSwamp, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(lblSwampIcon, 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(lblSwamp) - .addComponent(spnSwamp, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(ckbFullArtLands) .addGap(2, 2, 2) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(btnAutoAdd) + .addComponent(lblDeckSize) + .addComponent(spnDeckSize, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(18, 18, 18) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(btnAdd) - .addComponent(btnCancel))) + .addComponent(btnCancel)) + .addContainerGap()) ); pack(); @@ -386,7 +475,7 @@ public class AddLandDialog extends MageDialog { int blue = 0; int white = 0; Set cards = deck.getCards(); - int land_number = DEFAULT_SEALED_DECK_CARD_NUMBER - cards.size(); + int land_number = ((Number) spnDeckSize.getValue()).intValue() - cards.size(); if (land_number < 0) { land_number = 0; } @@ -427,13 +516,21 @@ public class AddLandDialog extends MageDialog { private javax.swing.JComboBox cbLandSet; private javax.swing.JCheckBox ckbFullArtLands; private javax.swing.JButton jButton2; + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel lblDeckSize; private javax.swing.JLabel lblForest; + private javax.swing.JLabel lblForestIcon; private javax.swing.JLabel lblIsland; + private javax.swing.JLabel lblIslandIcon; private javax.swing.JLabel lblLandSet; private javax.swing.JLabel lblMountain; + private javax.swing.JLabel lblMountainIcon; private javax.swing.JLabel lblPains; + private javax.swing.JLabel lblPlainsIcon; private javax.swing.JLabel lblSwamp; + private javax.swing.JLabel lblSwampIcon; private javax.swing.JPanel panelSet; + private javax.swing.JSpinner spnDeckSize; private javax.swing.JSpinner spnForest; private javax.swing.JSpinner spnIsland; private javax.swing.JSpinner spnMountain; 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 337475674ed..56a70a81860 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java @@ -27,6 +27,12 @@ */ package mage.client.dialog; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import javax.swing.*; import mage.cards.decks.importer.DeckImporterUtil; import mage.client.MageFrame; import mage.client.SessionHandler; @@ -45,13 +51,6 @@ import mage.view.GameTypeView; import mage.view.TableView; import org.apache.log4j.Logger; -import javax.swing.*; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - /** * @author BetaSteward_at_googlemail.com */ @@ -623,17 +622,22 @@ public class NewTableDialog extends MageDialog { * set the table settings from java prefs */ int currentSettingVersion = 0; + private void setGameSettingsFromPrefs(int version) { currentSettingVersion = version; String versionStr = ""; - if (currentSettingVersion == 1) { - versionStr = "1"; - btnPreviousConfiguration1.requestFocus(); - } else if (currentSettingVersion == 2) { - versionStr = "2"; - btnPreviousConfiguration2.requestFocus(); - } else { - btnPreviousConfiguration2.getParent().requestFocus(); + switch (currentSettingVersion) { + case 1: + versionStr = "1"; + btnPreviousConfiguration1.requestFocus(); + break; + case 2: + versionStr = "2"; + btnPreviousConfiguration2.requestFocus(); + break; + default: + btnPreviousConfiguration2.getParent().requestFocus(); + break; } txtName.setText(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_NAME + versionStr, "Game")); txtPassword.setText(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_PASSWORD + versionStr, "")); @@ -724,6 +728,7 @@ public class NewTableDialog extends MageDialog { PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_RANGE + versionStr, Integer.toString(options.getRange().getRange())); PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_ATTACK_OPTION + versionStr, options.getAttackOption().toString()); PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_SKILL_LEVEL + versionStr, options.getSkillLevel().toString()); + PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_SPECTATORS_ALLOWED + versionStr, options.isSpectatorsAllowed() ? "Yes" : "No"); PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_QUIT_RATIO + versionStr, Integer.toString(options.getQuitRatio())); StringBuilder playerTypesString = new StringBuilder(); for (Object player : players) { 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 17a376f4dca..5bf1e16a951 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.java @@ -35,11 +35,13 @@ package mage.client.dialog; import java.awt.*; import java.io.File; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; +import java.util.UUID; import javax.swing.*; import javax.swing.filechooser.FileFilter; - import mage.cards.decks.Deck; import mage.cards.decks.importer.DeckImporterUtil; import mage.cards.repository.ExpansionInfo; @@ -589,9 +591,9 @@ public class NewTournamentDialog extends MageDialog { } else { for (JPanel panel : packPanels) { JComboBox combo = findComboInComponent(panel); - if(combo != null) { + if (combo != null) { tOptions.getLimitedOptions().getSetCodes().add(((ExpansionInfo) combo.getSelectedItem()).getCode()); - }else{ + } else { logger.error("Can't find combo component in " + panel.toString()); } } @@ -764,7 +766,6 @@ public class NewTournamentDialog extends MageDialog { this.spnNumPlayers.setModel(new SpinnerNumberModel(numPlayers, tournamentType.getMinPlayers(), tournamentType.getMaxPlayers(), 1)); this.spnNumPlayers.setEnabled(tournamentType.getMinPlayers() != tournamentType.getMaxPlayers()); createPlayers((Integer) spnNumPlayers.getValue() - 1); - this.spnNumSeats.setModel(new SpinnerNumberModel(2, 2, tournamentType.getMaxPlayers(), 1)); if (tournamentType.isLimited()) { @@ -926,7 +927,7 @@ public class NewTournamentDialog extends MageDialog { public void actionPerformed(java.awt.event.ActionEvent evt) { // search combo box near button (must be only one combo in panel) - JButton button = (JButton)evt.getSource(); + JButton button = (JButton) evt.getSource(); JComboBox combo = findComboInComponent(button.getParent()); if (combo != null) { @@ -941,12 +942,12 @@ public class NewTournamentDialog extends MageDialog { this.repaint(); } - private JComboBox findComboInComponent(Container panel){ + private JComboBox findComboInComponent(Container panel) { // search combo box near button (must be only one combo in panel) JComboBox combo = null; - for(Component comp: panel.getComponents()){ - if (comp instanceof JComboBox){ - combo = (JComboBox)comp; + for (Component comp : panel.getComponents()) { + if (comp instanceof JComboBox) { + combo = (JComboBox) comp; break; } } @@ -955,21 +956,21 @@ public class NewTournamentDialog extends MageDialog { private void packActionPerformed(java.awt.event.ActionEvent evt) { // fill all bottom combobox with same value - JComboBox curentCombo = (JComboBox)evt.getSource(); + JComboBox curentCombo = (JComboBox) evt.getSource(); int newValue = curentCombo.getSelectedIndex(); // search start index int startIndex = 0; - for(int i = 0; i < packPanels.size(); i++){ + for (int i = 0; i < packPanels.size(); i++) { JComboBox pack = findComboInComponent(packPanels.get(i)); - if (pack.equals(curentCombo)){ + if (pack.equals(curentCombo)) { startIndex = i + 1; break; } } // change all from start index - for(int i = startIndex; i < packPanels.size(); i++){ + for (int i = startIndex; i < packPanels.size(); i++) { JComboBox pack = findComboInComponent(packPanels.get(i)); pack.setSelectedIndex(newValue); } @@ -1128,7 +1129,7 @@ public class NewTournamentDialog extends MageDialog { break; } } - }else{ + } else { logger.error("Can't find combo component in " + panel.toString()); } } 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 fc3c45de371..f122cdc1c44 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form +++ b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form @@ -95,10 +95,10 @@ - + - + @@ -200,7 +200,7 @@ - + @@ -295,16 +295,22 @@ - - - - - - - - + + + + + + + + + + + + + + - + @@ -315,6 +321,8 @@ + + @@ -324,7 +332,6 @@ - @@ -354,6 +361,17 @@ + + + + + + + + + + + @@ -4274,7 +4292,7 @@ - + @@ -4847,7 +4865,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 ba94fc5d2f9..76aeb4619e4 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java @@ -96,6 +96,7 @@ public class PreferencesDialog extends javax.swing.JDialog { public static final String KEY_SHOW_FULL_IMAGE_PATH = "showFullImagePath"; public static final String KEY_PERMANENTS_IN_ONE_PILE = "nonLandPermanentsInOnePile"; public static final String KEY_SHOW_PLAYER_NAMES_PERMANENTLY = "showPlayerNamesPermanently"; + public static final String KEY_DISPLAY_LIVE_ON_AVATAR = "displayLiveOnAvatar"; public static final String KEY_SHOW_ABILITY_PICKER_FORCED = "showAbilityPicker"; public static final String KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS = "gameAllowRequestShowHandCards"; public static final String KEY_GAME_SHOW_STORM_COUNTER = "gameShowStormCounter"; @@ -421,6 +422,7 @@ public class PreferencesDialog extends javax.swing.JDialog { main_game = new javax.swing.JPanel(); nonLandPermanentsInOnePile = new javax.swing.JCheckBox(); showPlayerNamesPermanently = new javax.swing.JCheckBox(); + displayLifeOnAvatar = new javax.swing.JCheckBox(); showAbilityPickerForced = new javax.swing.JCheckBox(); cbAllowRequestToShowHandCards = new javax.swing.JCheckBox(); cbShowStormCounter = new javax.swing.JCheckBox(); @@ -700,7 +702,7 @@ public class PreferencesDialog extends javax.swing.JDialog { .add(6, 6, 6) .add(main_cardLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(main_cardLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING, false) - .add(tooltipDelayLabel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 308, Short.MAX_VALUE) + .add(tooltipDelayLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .add(tooltipDelay, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .add(main_cardLayout.createSequentialGroup() .add(showCardName) @@ -741,6 +743,16 @@ public class PreferencesDialog extends javax.swing.JDialog { } }); + displayLifeOnAvatar.setSelected(true); + displayLifeOnAvatar.setText("Display life on avatar image"); + displayLifeOnAvatar.setToolTipText("Display the player's life over its avatar image."); + displayLifeOnAvatar.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); + displayLifeOnAvatar.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + displayLifeOnAvatarActionPerformed(evt); + } + }); + showAbilityPickerForced.setSelected(true); showAbilityPickerForced.setText("Show ability picker for abilities or spells without costs"); showAbilityPickerForced.setToolTipText("This prevents you from accidently activating abilities without other costs than tapping or casting spells with 0 mana costs."); @@ -797,15 +809,19 @@ public class PreferencesDialog extends javax.swing.JDialog { main_gameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(main_gameLayout.createSequentialGroup() .addContainerGap() - .add(main_gameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false) - .add(showPlayerNamesPermanently, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .add(nonLandPermanentsInOnePile, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .add(cbConfirmEmptyManaPool, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .add(cbAllowRequestToShowHandCards, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .add(cbShowStormCounter, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .add(cbAskMoveToGraveOrder, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .add(showAbilityPickerForced, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap(177, Short.MAX_VALUE)) + .add(main_gameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(main_gameLayout.createSequentialGroup() + .add(main_gameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false) + .add(showPlayerNamesPermanently, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .add(nonLandPermanentsInOnePile, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .add(cbConfirmEmptyManaPool, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .add(cbAllowRequestToShowHandCards, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .add(cbShowStormCounter, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .add(cbAskMoveToGraveOrder, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .add(showAbilityPickerForced, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .add(0, 0, Short.MAX_VALUE)) + .add(displayLifeOnAvatar, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) ); main_gameLayout.setVerticalGroup( main_gameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) @@ -814,6 +830,8 @@ public class PreferencesDialog extends javax.swing.JDialog { .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(showPlayerNamesPermanently) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(displayLifeOnAvatar) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(showAbilityPickerForced) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(cbAllowRequestToShowHandCards) @@ -822,8 +840,7 @@ public class PreferencesDialog extends javax.swing.JDialog { .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(cbConfirmEmptyManaPool) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(cbAskMoveToGraveOrder) - .addContainerGap()) + .add(cbAskMoveToGraveOrder)) ); nonLandPermanentsInOnePile.getAccessibleContext().setAccessibleName("nonLandPermanentsInOnePile"); @@ -880,10 +897,10 @@ public class PreferencesDialog extends javax.swing.JDialog { .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(main_game, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(main_gamelog, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 107, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(main_gamelog, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(main_battlefield, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .addContainerGap(121, Short.MAX_VALUE)) + .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); main_card.getAccessibleContext().setAccessibleName("Game panel"); @@ -1797,7 +1814,7 @@ public class PreferencesDialog extends javax.swing.JDialog { .add(panelCardImages, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(panelBackgroundImages, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .addContainerGap(125, Short.MAX_VALUE)) + .addContainerGap(133, Short.MAX_VALUE)) ); tabsPanel.addTab("Images", tabImages); @@ -2372,7 +2389,7 @@ public class PreferencesDialog extends javax.swing.JDialog { tabAvatarsLayout.setVerticalGroup( tabAvatarsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(tabAvatarsLayout.createSequentialGroup() - .add(avatarPane, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 584, Short.MAX_VALUE) + .add(avatarPane, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 620, Short.MAX_VALUE) .addContainerGap()) ); @@ -2762,6 +2779,7 @@ public class PreferencesDialog extends javax.swing.JDialog { save(prefs, dialog.showFullImagePath, KEY_SHOW_FULL_IMAGE_PATH, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.nonLandPermanentsInOnePile, KEY_PERMANENTS_IN_ONE_PILE, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.showPlayerNamesPermanently, KEY_SHOW_PLAYER_NAMES_PERMANENTLY, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.displayLifeOnAvatar, KEY_DISPLAY_LIVE_ON_AVATAR, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.showAbilityPickerForced, KEY_SHOW_ABILITY_PICKER_FORCED, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.cbAllowRequestToShowHandCards, KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.cbShowStormCounter, KEY_GAME_SHOW_STORM_COUNTER, "true", "false", UPDATE_CACHE_POLICY); @@ -3225,6 +3243,10 @@ public class PreferencesDialog extends javax.swing.JDialog { } }//GEN-LAST:event_cbGameJsonLogAutoSaveActionPerformed + private void displayLifeOnAvatarActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_displayLifeOnAvatarActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_displayLifeOnAvatarActionPerformed + private void showProxySettings() { Connection.ProxyType proxyType = (Connection.ProxyType) cbProxyType.getSelectedItem(); switch (proxyType) { @@ -3331,6 +3353,7 @@ public class PreferencesDialog extends javax.swing.JDialog { load(prefs, dialog.showFullImagePath, KEY_SHOW_FULL_IMAGE_PATH, "true"); load(prefs, dialog.nonLandPermanentsInOnePile, KEY_PERMANENTS_IN_ONE_PILE, "true"); load(prefs, dialog.showPlayerNamesPermanently, KEY_SHOW_PLAYER_NAMES_PERMANENTLY, "true"); + load(prefs, dialog.displayLifeOnAvatar, KEY_DISPLAY_LIVE_ON_AVATAR, "true"); load(prefs, dialog.showAbilityPickerForced, KEY_SHOW_ABILITY_PICKER_FORCED, "true"); load(prefs, dialog.cbAllowRequestToShowHandCards, KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS, "true"); load(prefs, dialog.cbShowStormCounter, KEY_GAME_SHOW_STORM_COUNTER, "true"); @@ -3928,6 +3951,7 @@ public class PreferencesDialog extends javax.swing.JDialog { private javax.swing.JCheckBox checkBoxUpkeepYou; private javax.swing.JPanel connection_servers; private javax.swing.JLabel controlsDescriptionLabel; + private javax.swing.JCheckBox displayLifeOnAvatar; private javax.swing.JButton exitButton; private javax.swing.JLabel fontSizeLabel; private javax.swing.JPanel guiSizeBasic; diff --git a/Mage.Client/src/main/java/mage/client/game/PlayerPanelExt.java b/Mage.Client/src/main/java/mage/client/game/PlayerPanelExt.java index 5722b74785d..cf7b843556e 100644 --- a/Mage.Client/src/main/java/mage/client/game/PlayerPanelExt.java +++ b/Mage.Client/src/main/java/mage/client/game/PlayerPanelExt.java @@ -77,7 +77,6 @@ import mage.constants.ManaType; import mage.counters.Counter; import mage.counters.CounterType; import mage.designations.DesignationType; -import mage.remote.Session; import mage.utils.timer.PriorityTimer; import mage.view.CardView; import mage.view.ManaPoolView; @@ -93,13 +92,10 @@ public class PlayerPanelExt extends javax.swing.JPanel { private UUID playerId; private UUID gameId; - private Session session; private PlayerView player; private BigCard bigCard; - private static final int AVATAR_COUNT = 77; - private static final String DEFAULT_AVATAR_PATH = "/avatars/" + DEFAULT_AVATAR_ID + ".jpg"; private static final int PANEL_WIDTH = 94; @@ -179,8 +175,11 @@ public class PlayerPanelExt extends javax.swing.JPanel { public void update(PlayerView player) { this.player = player; - updateAvatar(); int playerLife = player.getLife(); + avatar.setCenterText("true".equals(MageFrame.getPreferences().get(PreferencesDialog.KEY_DISPLAY_LIVE_ON_AVATAR, "true")) + ? String.valueOf(playerLife) : null); + updateAvatar(); + if (playerLife > 99) { Font font = lifeLabel.getFont(); font = font.deriveFont(9f); @@ -701,8 +700,6 @@ public class PlayerPanelExt extends javax.swing.JPanel { .addComponent(btnPlayer, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(timerLabel, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(avatar, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 80, Short.MAX_VALUE)) - // .addGroup(gl_panelBackground.createSequentialGroup() - // .addComponent(avatarFlag, GroupLayout.PREFERRED_SIZE, 16, GroupLayout.PREFERRED_SIZE)) .addGap(8)) .addGroup(gl_panelBackground.createSequentialGroup() .addGap(6) @@ -824,16 +821,12 @@ public class PlayerPanelExt extends javax.swing.JPanel { protected void sizePlayerPanel(boolean smallMode) { if (smallMode) { avatar.setVisible(false); -// avatarFlag.setVisible(false); -// monarchIcon.setVisible(false); btnPlayer.setVisible(true); timerLabel.setVisible(true); panelBackground.setPreferredSize(new Dimension(PANEL_WIDTH - 2, PANEL_HEIGHT_SMALL)); panelBackground.setBounds(0, 0, PANEL_WIDTH - 2, PANEL_HEIGHT_SMALL); } else { avatar.setVisible(true); -// avatarFlag.setVisible(true); -// monarchIcon.setVisible(true); btnPlayer.setVisible(false); timerLabel.setVisible(false); panelBackground.setPreferredSize(new Dimension(PANEL_WIDTH - 2, PANEL_HEIGHT)); @@ -887,8 +880,6 @@ public class PlayerPanelExt extends javax.swing.JPanel { } private HoverButton avatar; -// private JLabel avatarFlag; -// private JLabel monarchIcon; private JButton btnPlayer; private ImagePanel life; private ImagePanel poison; @@ -918,7 +909,6 @@ public class PlayerPanelExt extends javax.swing.JPanel { private JPanel energyExperiencePanel; private HoverButton exileZone; private HoverButton commandZone; - private HoverButton enchantPlayerViewZone; private final Map manaLabels = new HashMap<>(); } diff --git a/Mage.Client/src/main/java/mage/client/plugins/adapters/MageActionCallback.java b/Mage.Client/src/main/java/mage/client/plugins/adapters/MageActionCallback.java index 8c6e8538596..d428ad1f658 100644 --- a/Mage.Client/src/main/java/mage/client/plugins/adapters/MageActionCallback.java +++ b/Mage.Client/src/main/java/mage/client/plugins/adapters/MageActionCallback.java @@ -26,10 +26,12 @@ import mage.cards.MageCard; import mage.cards.action.ActionCallback; import mage.cards.action.TransferData; import mage.client.MageFrame; +import mage.client.MagePane; import mage.client.SessionHandler; import mage.client.cards.BigCard; import mage.client.components.MageComponents; import mage.client.dialog.PreferencesDialog; +import mage.client.game.GamePane; import mage.client.plugins.impl.Plugins; import mage.client.util.DefaultActionCallback; import mage.client.util.gui.ArrowBuilder; @@ -367,6 +369,16 @@ public class MageActionCallback implements ActionCallback { } private void handleOverNewView(TransferData data) { + // Prevent to show tooltips from panes not in front + MagePane topPane = MageFrame.getTopMost(null); + if (topPane instanceof GamePane) { + if (!((GamePane) topPane).getGameId().equals(data.gameId)) { + return; + } + } else if (data.gameId != null) { + return; + } + hideTooltipPopup(); cancelTimeout(); Component parentComponent = SwingUtilities.getRoot(data.component); diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/ManaSymbols.java b/Mage.Client/src/main/java/org/mage/card/arcane/ManaSymbols.java index 8b3c5d9589b..e8f7b6c0888 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/ManaSymbols.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/ManaSymbols.java @@ -554,8 +554,8 @@ public final class ManaSymbols { public static void draw(Graphics g, String manaCost, int x, int y, int symbolWidth, Color symbolsTextColor, int symbolMarginX) { if (!manaImages.containsKey(symbolWidth)) { loadSymbolImages(symbolWidth); - } - + } + // TODO: replace with jlabel render (look at table rendere)? /* @@ -605,12 +605,16 @@ public final class ManaSymbols { return; } - manaCost = manaCost.replace("\\", ""); + manaCost = manaCost.replace("\\", ""); manaCost = UI.getDisplayManaCost(manaCost); StringTokenizer tok = new StringTokenizer(manaCost, " "); while (tok.hasMoreTokens()) { String symbol = tok.nextToken(); Image image = sizedSymbols.get(symbol); + if (image == null && symbol != null) { + String symbol2 = "" + symbol.charAt(1) + symbol.charAt(0); + image = sizedSymbols.get(symbol2); + } if (image == null) { // TEXT draw diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/ModernCardRenderer.java b/Mage.Client/src/main/java/org/mage/card/arcane/ModernCardRenderer.java index 67e5192061d..20eb2520863 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/ModernCardRenderer.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/ModernCardRenderer.java @@ -34,6 +34,7 @@ import mage.util.SubTypeList; import mage.view.CardView; import mage.view.PermanentView; import org.apache.log4j.Logger; +import static org.mage.card.arcane.ManaSymbols.getSizedManaSymbol; /* @@ -72,13 +73,13 @@ public class ModernCardRenderer extends CardRenderer { BufferedImage img = CardRendererUtils.toBufferedImage(icon.getImage()); return new TexturePaint(img, new Rectangle(0, 0, img.getWidth(), img.getHeight())); } - + private static BufferedImage loadBackgroundImage(String name) { URL url = ModernCardRenderer.class.getResource("/cardrender/background_texture_" + name + ".png"); ImageIcon icon = new ImageIcon(url); BufferedImage img = CardRendererUtils.toBufferedImage(icon.getImage()); return img; - } + } private static BufferedImage loadFramePart(String name) { URL url = ModernCardRenderer.class.getResource("/cardrender/" + name + ".png"); @@ -108,7 +109,7 @@ public class ModernCardRenderer extends CardRenderer { public static final Paint BG_TEXTURE_ARTIFACT = loadBackgroundTexture("artifact"); public static final Paint BG_TEXTURE_LAND = loadBackgroundTexture("land"); public static final Paint BG_TEXTURE_VEHICLE = loadBackgroundTexture("vehicle"); - + public static final BufferedImage BG_IMG_WHITE = loadBackgroundImage("white"); public static final BufferedImage BG_IMG_BLUE = loadBackgroundImage("blue"); public static final BufferedImage BG_IMG_BLACK = loadBackgroundImage("black"); @@ -119,7 +120,8 @@ public class ModernCardRenderer extends CardRenderer { public static final BufferedImage BG_IMG_LAND = loadBackgroundImage("land"); public static final BufferedImage BG_IMG_VEHICLE = loadBackgroundImage("vehicle"); public static final BufferedImage BG_IMG_COLORLESS = loadBackgroundImage("colorless"); - + public static final BufferedImage BG_IMG_EXPEDITION = loadBackgroundImage("expedition"); + public static final BufferedImage FRAME_INVENTION = loadFramePart("invention_frame"); public static final Color BORDER_WHITE = new Color(216, 203, 188); @@ -301,7 +303,11 @@ public class ModernCardRenderer extends CardRenderer { // Just draw a brown rectangle drawCardBack(g); } else { - BufferedImage bg = getBackgroundImage(cardView.getColor(), cardView.getCardTypes(), cardView.getSubTypes()); + boolean isExped = false; + if (cardView.getExpansionSetCode().equals("EXP")) { + isExped = true; + } + BufferedImage bg = getBackgroundImage(cardView.getColor(), cardView.getCardTypes(), cardView.getSubTypes(), isExped); if (bg == null) { return; } @@ -318,12 +324,12 @@ public class ModernCardRenderer extends CardRenderer { cardWidth - borderWidth * 2, cornerRadius * 4, cornerRadius * 2, cornerRadius * 2); a.add(new Area(rr2)); - + // Draw the M15 rounded "swoosh" at the bottom Rectangle r = new Rectangle(borderWidth + contentInset, cardHeight - borderWidth * 5, cardWidth - borderWidth * 2 - contentInset * 2, borderWidth * 2); a.add(new Area(r)); g.setClip(a); - g.drawImage(bg, 0, 0, cardWidth, cardHeight, 0, 0, bgw, bgh, BOX_BLUE, null); + g.drawImage(bg, 0, 0, cardWidth, cardHeight, 0, 0, bgw, bgh, BOX_BLUE, null); g.setClip(null); } } @@ -545,24 +551,13 @@ public class ModernCardRenderer extends CardRenderer { if (!isZendikarFullArtLand()) { drawRulesText(g, textboxKeywords, textboxRules, totalContentInset + 2, typeLineY + boxHeight + 2, - contentWidth - 4, cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3); + contentWidth - 4, cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3, false); } else { int x = totalContentInset; int y = typeLineY + boxHeight + (cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3) / 2 - contentInset; int w = contentWidth; int h = boxHeight - 4; - CardRendererUtils.drawZendikarLandBox(g, - x, y, w, h, - contentInset, - borderPaint, boxColor); - drawTypeLine(g, getCardSuperTypeLine(), - totalContentInset + contentInset, typeLineY + boxHeight + (cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3) / 2 - contentInset, - contentWidth / 2 - boxHeight, boxHeight - 4, false); - drawTypeLine(g, getCardSubTypeLine(), - totalContentInset + 4 * contentWidth / 7 + boxHeight, typeLineY + boxHeight + (cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3) / 2 - contentInset, - 3 * contentWidth / 7 - boxHeight - contentInset, boxHeight - 4, true); - if (cardView.getFrameStyle() == FrameStyle.ZEN_FULL_ART_BASIC) { // Draw curved lines (old Zendikar land style) - bigger (around 6%) inset on curve on bottom than inset (around 4.5%) on top... int x2 = x + contentWidth; @@ -584,9 +579,49 @@ public class ModernCardRenderer extends CardRenderer { boxColor, borderPaint); } + // If an expedition, needs the rules box to be visible. + if (cardView.getExpansionSetCode().equals("EXP")) { + // Draw a small separator between the type line and box, and shadow + // at the left of the texbox, and above the name line + g.setPaint(textboxPaint); + float alpha = 0.55f; + AlphaComposite comp = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha); + Composite origc = g.getComposite(); + g.setComposite(comp); + g.setBackground(new Color(155, 0, 0, 150)); + + g.fillRect( + totalContentInset + 1, typeLineY - boxHeight, + contentWidth - 2, cardHeight - borderWidth * 3 - typeLineY - 1); + + g.setComposite(origc); + + g.fillRect( + totalContentInset - 1, totalContentInset - 1, + contentWidth + 1, 1); + + g.fillRect( + totalContentInset + 1, typeLineY - boxHeight, + contentWidth - 2, 1); + + drawRulesText(g, textboxKeywords, textboxRules, + totalContentInset + 2, typeLineY - boxHeight, + contentWidth - 4, cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3, true); + } + + CardRendererUtils.drawZendikarLandBox(g, + x, y, w, h, + contentInset, + borderPaint, boxColor); + drawTypeLine(g, getCardSuperTypeLine(), + totalContentInset + contentInset, typeLineY + boxHeight + (cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3) / 2 - contentInset, + contentWidth / 2 - boxHeight, boxHeight - 4, false); + drawTypeLine(g, getCardSubTypeLine(), + totalContentInset + 4 * contentWidth / 7 + boxHeight, typeLineY + boxHeight + (cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3) / 2 - contentInset, + 3 * contentWidth / 7 - boxHeight - contentInset, boxHeight - 4, true); drawRulesText(g, textboxKeywords, textboxRules, x, y, - w, h); + w, h, false); } // Draw the bottom right stuff @@ -962,7 +997,7 @@ public class ModernCardRenderer extends CardRenderer { return layout; } - protected void drawRulesText(Graphics2D g, ArrayList keywords, ArrayList rules, int x, int y, int w, int h) { + protected void drawRulesText(Graphics2D g, ArrayList keywords, ArrayList rules, int x, int y, int w, int h, boolean forceRules) { // Gather all rules to render List allRules = new ArrayList<>(rules); @@ -974,14 +1009,19 @@ public class ModernCardRenderer extends CardRenderer { } // Basic mana draw mana symbol in textbox (for basic lands) - if (allRules.size() == 1 && (allRules.get(0) instanceof TextboxBasicManaRule) && cardView.isLand() || isZendikarFullArtLand()) { + if (!forceRules && (allRules.size() == 1 && (allRules.get(0) instanceof TextboxBasicManaRule) && cardView.isLand() || isZendikarFullArtLand())) { if (!isZendikarFullArtLand()) { drawBasicManaTextbox(g, x, y, w, h, ((TextboxBasicManaRule) allRules.get(0)).getBasicManaSymbol()); return; } else // Big circle in the middle for Zendikar lands - if (allRules.size() == 1) { + { + if (allRules.size() == 1) { // Size of mana symbol = 9/4 * h, 3/4h above line - drawBasicManaSymbol(g, x + w / 2 - 9 * h / 8 + 1, y - 3 * h / 4, 9 * h / 4, 9 * h / 4, ((TextboxBasicManaRule) allRules.get(0)).getBasicManaSymbol()); + if (allRules.get(0) instanceof TextboxBasicManaRule) { + drawBasicManaSymbol(g, x + w / 2 - 9 * h / 8 + 1, y - 3 * h / 4, 9 * h / 4, 9 * h / 4, ((TextboxBasicManaRule) allRules.get(0)).getBasicManaSymbol()); + } else { + drawBasicManaSymbol(g, x + w / 2 - h - h / 8, y - 3 * h / 4, 9 * h / 4, 9 * h / 4, cardView.getFrameColor().toString()); + } return; } else { if (allRules.size() > 1) { @@ -989,6 +1029,7 @@ public class ModernCardRenderer extends CardRenderer { } return; } + } } // Go through possible font sizes in descending order to find the best fit @@ -1043,7 +1084,15 @@ public class ModernCardRenderer extends CardRenderer { private void drawBasicManaSymbol(Graphics2D g, int x, int y, int w, int h, String symbol) { String symbs = symbol; - ManaSymbols.draw(g, symbs, x, y, w, Color.black, 2); + if (getSizedManaSymbol(symbol) != null) { + ManaSymbols.draw(g, symbs, x, y, w, Color.black, 2); + } + if (symbol.length() == 2) { + String symbs2 = "" + symbol.charAt(1) + symbol.charAt(0); + if (getSizedManaSymbol(symbs2) != null) { + ManaSymbols.draw(g, symbs2, x, y, w, Color.black, 2); + } + } } // Get the first line of the textbox, the keyword string @@ -1272,13 +1321,16 @@ public class ModernCardRenderer extends CardRenderer { return new Color(71, 86, 101); } } - + // Determine which background image to use from a set of colors // and the current card. - protected static BufferedImage getBackgroundImage(ObjectColor colors, Collection types, SubTypeList subTypes) { + protected static BufferedImage getBackgroundImage(ObjectColor colors, Collection types, SubTypeList subTypes, boolean isExped) { if (subTypes.contains(SubType.VEHICLE)) { return BG_IMG_VEHICLE; } else if (types.contains(CardType.LAND)) { + if (isExped) { + return BG_IMG_EXPEDITION; + } return BG_IMG_LAND; } else if (types.contains(CardType.ARTIFACT)) { return BG_IMG_ARTIFACT; @@ -1299,7 +1351,7 @@ public class ModernCardRenderer extends CardRenderer { return BG_IMG_COLORLESS; } } - + // Get the box color for the given colors protected Color getBoxColor(ObjectColor colors, Collection types, boolean isNightCard) { if (cardView.isAbility()) { diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/ModernSplitCardRenderer.java b/Mage.Client/src/main/java/org/mage/card/arcane/ModernSplitCardRenderer.java index 0310d8e3acc..7e09c8a266c 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/ModernSplitCardRenderer.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/ModernSplitCardRenderer.java @@ -272,7 +272,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer { // Draw the textbox rules drawRulesText(g, half.keywords, half.rules, 2, typeLineY + boxHeight + 2 - 4, - half.cw - 4, half.ch - typeLineY - boxHeight); + half.cw - 4, half.ch - typeLineY - boxHeight, false); } private Graphics2D getUnmodifiedHalfContext(Graphics2D g) { diff --git a/Mage.Client/src/main/resources/cardrender/background_texture_expedition.png b/Mage.Client/src/main/resources/cardrender/background_texture_expedition.png new file mode 100644 index 00000000000..9ccb96d7750 Binary files /dev/null and b/Mage.Client/src/main/resources/cardrender/background_texture_expedition.png differ diff --git a/Mage.Common/src/main/java/mage/view/GameView.java b/Mage.Common/src/main/java/mage/view/GameView.java index b354503c567..6dc733112f0 100644 --- a/Mage.Common/src/main/java/mage/view/GameView.java +++ b/Mage.Common/src/main/java/mage/view/GameView.java @@ -27,18 +27,14 @@ */ package mage.view; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import java.io.Serializable; -import java.io.BufferedWriter; -import java.io.PrintWriter; -import java.io.FileWriter; -import java.io.IOException; - import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; - import mage.MageObject; import mage.abilities.costs.Cost; import mage.cards.Card; @@ -60,8 +56,6 @@ import mage.game.stack.StackObject; import mage.players.Player; import mage.watchers.common.CastSpellLastTurnWatcher; import org.apache.log4j.Logger; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; /** * @@ -105,7 +99,12 @@ public class GameView implements Serializable { } } for (StackObject stackObject : state.getStack()) { - if (stackObject instanceof StackAbility) { + if (stackObject instanceof Spell) { + // Spell + CardView spellView = new CardView((Spell) stackObject, game, stackObject.getControllerId().equals(createdForPlayerId)); + spellView.paid = ((Spell) stackObject).getSpellAbility().getManaCostsToPay().isPaid(); + stack.put(stackObject.getId(), spellView); + } else if (stackObject instanceof StackAbility) { // Stack Ability MageObject object = game.getObject(stackObject.getSourceId()); Card card = game.getCard(stackObject.getSourceId()); @@ -161,9 +160,7 @@ public class GameView implements Serializable { LOGGER.debug("Stack Object for stack ability not found: " + stackObject.getStackAbility().getRule()); } } else { - // Spell - stack.put(stackObject.getId(), new CardView((Spell) stackObject, game, stackObject.getControllerId().equals(createdForPlayerId))); - checkPaid(stackObject.getId(), (Spell) stackObject); + LOGGER.fatal("Unknown type of StackObject: " + stackObject.getName() + ' ' + stackObject.toString() + ' ' + stackObject.getClass().toString()); } //stackOrder.add(stackObject.getId()); } @@ -223,21 +220,6 @@ public class GameView implements Serializable { cardView.paid = true; } - private void checkPaid(UUID uuid, Spell spell) { - for (Cost cost : spell.getSpellAbility().getManaCostsToPay()) { - if (!cost.isPaid()) { - return; - } - } - CardView cardView = stack.get(uuid); - cardView.paid = true; - } - - private void setPaid(UUID uuid) { - CardView cardView = stack.get(uuid); - cardView.paid = true; - } - private void updateLatestCardView(Game game, Card card, UUID stackId) { if (!card.isTransformable()) { return; diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java index 287b31752c6..a7c5a914c97 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java @@ -617,7 +617,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { } // end of for (allActions) if (depth == maxDepth) { - logger.info(new StringBuilder("Sim Prio [").append(depth).append("] -- End for Max Depth -- Nodes calculated: ").append(SimulationNode2.nodeCount)); + logger.info("Sim Prio [" + depth + "] -- End for Max Depth -- Nodes calculated: " + SimulationNode2.nodeCount); } if (bestNode != null) { node.children.clear(); diff --git a/Mage.Sets/src/mage/cards/a/AcrobaticManeuver.java b/Mage.Sets/src/mage/cards/a/AcrobaticManeuver.java index 79d5c8820ce..dc93cd129d6 100644 --- a/Mage.Sets/src/mage/cards/a/AcrobaticManeuver.java +++ b/Mage.Sets/src/mage/cards/a/AcrobaticManeuver.java @@ -44,12 +44,11 @@ import mage.target.common.TargetControlledCreaturePermanent; public class AcrobaticManeuver extends CardImpl { public AcrobaticManeuver(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}"); // Exile target creature you control, then return that card to the battlefield under its owner's control. this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); Effect effect = new ExileTargetForSourceEffect(); - effect.setApplyEffectsAfter(); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addEffect(new ReturnToBattlefieldUnderOwnerControlTargetEffect()); diff --git a/Mage.Sets/src/mage/cards/a/ActOfTreason.java b/Mage.Sets/src/mage/cards/a/ActOfTreason.java index bed4e24e0c3..d8285a01dcb 100644 --- a/Mage.Sets/src/mage/cards/a/ActOfTreason.java +++ b/Mage.Sets/src/mage/cards/a/ActOfTreason.java @@ -1,16 +1,16 @@ /* * 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 @@ -20,7 +20,7 @@ * 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. diff --git a/Mage.Sets/src/mage/cards/a/Ambuscade.java b/Mage.Sets/src/mage/cards/a/Ambuscade.java index dc4f37d9670..e97592cb703 100644 --- a/Mage.Sets/src/mage/cards/a/Ambuscade.java +++ b/Mage.Sets/src/mage/cards/a/Ambuscade.java @@ -52,14 +52,12 @@ public class Ambuscade extends CardImpl { static { filter.add(new ControllerPredicate(TargetController.NOT_YOU)); } - + public Ambuscade(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{G}"); - // Target creature you control gets +1/+0 until end of turn. Effect effect = new BoostTargetEffect(1, 0, Duration.EndOfTurn); - effect.setApplyEffectsAfter(); // needed to count the boost for the second effect this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); this.getSpellAbility().addEffect(effect); diff --git a/Mage.Sets/src/mage/cards/b/BarrelDownSokenzan.java b/Mage.Sets/src/mage/cards/b/BarrelDownSokenzan.java index 931cc8fe137..ae2f5fedbe3 100644 --- a/Mage.Sets/src/mage/cards/b/BarrelDownSokenzan.java +++ b/Mage.Sets/src/mage/cards/b/BarrelDownSokenzan.java @@ -46,13 +46,12 @@ import mage.target.common.TargetCreaturePermanent; public class BarrelDownSokenzan extends CardImpl { public BarrelDownSokenzan(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}"); this.subtype.add(SubType.ARCANE); - // Sweep - Return any number of Mountains you control to their owner's hand. Barrel Down Sokenzan deals damage to target creature equal to twice the number of Mountains returned this way. this.getSpellAbility().addEffect(new SweepEffect(SubType.MOUNTAIN)); - DynamicValue sweepValue = new MultipliedValue(new SweepNumber("Mountain", false), 2); + DynamicValue sweepValue = new MultipliedValue(new SweepNumber("Mountain"), 2); this.getSpellAbility().addEffect(new DamageTargetEffect(sweepValue)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/b/BragoKingEternal.java b/Mage.Sets/src/mage/cards/b/BragoKingEternal.java index 91743d6bcf9..c69b88afc32 100644 --- a/Mage.Sets/src/mage/cards/b/BragoKingEternal.java +++ b/Mage.Sets/src/mage/cards/b/BragoKingEternal.java @@ -53,7 +53,7 @@ import mage.target.common.TargetControlledPermanent; public class BragoKingEternal extends CardImpl { public BragoKingEternal(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{U}"); addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.SPIRIT); @@ -65,7 +65,6 @@ public class BragoKingEternal extends CardImpl { // When Brago, King Eternal deals combat damage to a player, exile any number of target nonland permanents you control, then return those cards to the battlefield under their owner's control. Effect effect = new ExileTargetEffect(this.getId(), this.getName(), Zone.BATTLEFIELD); effect.setText("exile any number of target nonland permanents you control"); - effect.setApplyEffectsAfter(); Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(effect, false); FilterControlledPermanent filterControlledNonlandPermanent = new FilterControlledPermanent(); filterControlledNonlandPermanent.add(Predicates.not(new CardTypePredicate(CardType.LAND))); diff --git a/Mage.Sets/src/mage/cards/c/CauldronHaze.java b/Mage.Sets/src/mage/cards/c/CauldronHaze.java index 7f3fbe6ed50..6521ec0c8c2 100644 --- a/Mage.Sets/src/mage/cards/c/CauldronHaze.java +++ b/Mage.Sets/src/mage/cards/c/CauldronHaze.java @@ -41,17 +41,16 @@ import mage.target.common.TargetCreaturePermanent; * @author jeffwadsworth */ public class CauldronHaze extends CardImpl { - - private String rule = "Choose any number of target creatures. Each of those creatures gains persist until end of turn"; + + private final String rule = "Choose any number of target creatures. Each of those creatures gains persist until end of turn"; public CauldronHaze(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{W/B}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W/B}"); // Choose any number of target creatures. Each of those creatures gains persist until end of turn. this.getSpellAbility().addEffect(new GainAbilityTargetEffect(new PersistAbility(), Duration.EndOfTurn, rule)); this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, Integer.MAX_VALUE)); - + } public CauldronHaze(final CauldronHaze card) { diff --git a/Mage.Sets/src/mage/cards/c/ChargeAcrossTheAraba.java b/Mage.Sets/src/mage/cards/c/ChargeAcrossTheAraba.java index 9cbb73c1995..d7467b824a4 100644 --- a/Mage.Sets/src/mage/cards/c/ChargeAcrossTheAraba.java +++ b/Mage.Sets/src/mage/cards/c/ChargeAcrossTheAraba.java @@ -1,4 +1,4 @@ - /* +/* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -27,16 +27,16 @@ */ package mage.cards.c; - import java.util.UUID; - import mage.abilities.dynamicvalue.DynamicValue; - import mage.abilities.dynamicvalue.common.SweepNumber; - import mage.abilities.effects.common.continuous.BoostControlledEffect; - import mage.abilities.effects.keyword.SweepEffect; - import mage.cards.CardImpl; - import mage.cards.CardSetInfo; - import mage.constants.CardType; - import mage.constants.Duration; - import mage.constants.SubType; +import java.util.UUID; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.SweepNumber; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.keyword.SweepEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; /** * @@ -45,14 +45,13 @@ package mage.cards.c; public class ChargeAcrossTheAraba extends CardImpl { public ChargeAcrossTheAraba(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{4}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{W}"); this.subtype.add(SubType.ARCANE); - // Sweep - Return any number of Plains you control to their owner's hand. Creatures you control get +1/+1 until end of turn for each Plains returned this way. this.getSpellAbility().addEffect(new SweepEffect(SubType.PLAINS)); - DynamicValue sweepValue = new SweepNumber("Plains", true); - this.getSpellAbility().addEffect(new BoostControlledEffect(sweepValue, sweepValue, Duration.EndOfTurn)); + DynamicValue sweepValue = new SweepNumber("Plains"); + this.getSpellAbility().addEffect(new BoostControlledEffect(sweepValue, sweepValue, Duration.EndOfTurn, null, false, true)); } diff --git a/Mage.Sets/src/mage/cards/c/ClearShot.java b/Mage.Sets/src/mage/cards/c/ClearShot.java index cab3685ca7a..65597c5b025 100644 --- a/Mage.Sets/src/mage/cards/c/ClearShot.java +++ b/Mage.Sets/src/mage/cards/c/ClearShot.java @@ -58,7 +58,6 @@ public class ClearShot extends CardImpl { // Target creature you control gets +1/+1 until end of turn. Effect effect = new BoostTargetEffect(1, 1, Duration.EndOfTurn); - effect.setApplyEffectsAfter(); // needed to count the boost for the second effect this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); this.getSpellAbility().addEffect(effect); diff --git a/Mage.Sets/src/mage/cards/c/Cloudshift.java b/Mage.Sets/src/mage/cards/c/Cloudshift.java index b1119bd4b9a..5f6941023f7 100644 --- a/Mage.Sets/src/mage/cards/c/Cloudshift.java +++ b/Mage.Sets/src/mage/cards/c/Cloudshift.java @@ -43,12 +43,11 @@ import mage.target.common.TargetControlledCreaturePermanent; public class Cloudshift extends CardImpl { public Cloudshift(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{W}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}"); // Exile target creature you control, then return that card to the battlefield under your control. this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); Effect effect = new ExileTargetForSourceEffect(); - effect.setApplyEffectsAfter(); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addEffect(new ReturnToBattlefieldUnderYourControlTargetEffect(true)); } diff --git a/Mage.Sets/src/mage/cards/c/Cultivate.java b/Mage.Sets/src/mage/cards/c/Cultivate.java index 0fd4bc30e58..2959af31e44 100644 --- a/Mage.Sets/src/mage/cards/c/Cultivate.java +++ b/Mage.Sets/src/mage/cards/c/Cultivate.java @@ -27,6 +27,7 @@ */ package mage.cards.c; +import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -41,8 +42,6 @@ import mage.players.Player; import mage.target.TargetCard; import mage.target.common.TargetCardInLibrary; -import java.util.UUID; - /** * * @author BetaSteward_at_googlemail.com @@ -50,7 +49,7 @@ import java.util.UUID; public class Cultivate extends CardImpl { public Cultivate(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}"); // Search your library for up to two basic land cards, reveal those cards, and put one onto the battlefield tapped and the other into your hand. Then shuffle your library. this.getSpellAbility().addEffect(new CultivateEffect()); @@ -96,11 +95,7 @@ class CultivateEffect extends OneShotEffect { TargetCardInLibrary target = new TargetCardInLibrary(0, 2, StaticFilters.FILTER_BASIC_LAND_CARD); if (controller.searchLibrary(target, game)) { if (!target.getTargets().isEmpty()) { - Cards revealed = new CardsImpl(); - for (UUID cardId : target.getTargets()) { - Card card = controller.getLibrary().getCard(cardId, game); - revealed.add(card); - } + Cards revealed = new CardsImpl(target.getTargets()); controller.revealCards(sourceObject.getIdName(), revealed, game); if (target.getTargets().size() == 2) { TargetCard target2 = new TargetCard(Zone.LIBRARY, filter); @@ -120,13 +115,10 @@ class CultivateEffect extends OneShotEffect { controller.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, false, null); } } - } - controller.shuffleLibrary(source, game); - return true; } controller.shuffleLibrary(source, game); - return false; + return true; } diff --git a/Mage.Sets/src/mage/cards/c/Cytoshape.java b/Mage.Sets/src/mage/cards/c/Cytoshape.java new file mode 100644 index 00000000000..72bddeb4f4b --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/Cytoshape.java @@ -0,0 +1,113 @@ +/* + * 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.cards.c; + +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.Duration; +import mage.constants.Outcome; +import mage.constants.SuperType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SupertypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.Target; +import mage.target.common.TargetCreaturePermanent; +import mage.util.functions.EmptyApplyToPermanent; + +/** + * + * @author jeffwadsworth + */ +public class Cytoshape extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nonlegendary creature"); + + static { + filter.add(Predicates.not(new SupertypePredicate(SuperType.LEGENDARY))); + } + + public Cytoshape(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}{U}"); + + // Choose a nonlegendary creature on the battlefield. Target creature becomes a copy of that creature until end of turn. + this.getSpellAbility().addEffect(new CytoshapeEffect()); + Target target = new TargetCreaturePermanent(1, 1, filter, true); + target.setTargetTag(1); + this.getSpellAbility().addTarget(target); + + FilterCreaturePermanent filter2 = new FilterCreaturePermanent("target creature that will become a copy of that chosen creature"); + target = new TargetCreaturePermanent(filter2); + target.setTargetTag(2); + this.getSpellAbility().addTarget(target); + + } + + public Cytoshape(final Cytoshape card) { + super(card); + } + + @Override + public Cytoshape copy() { + return new Cytoshape(this); + } +} + +class CytoshapeEffect extends OneShotEffect { + + public CytoshapeEffect() { + super(Outcome.Copy); + this.staticText = "Choose a nonlegendary creature on the battlefield. Target creature becomes a copy of that creature until end of turn."; + } + + public CytoshapeEffect(final CytoshapeEffect effect) { + super(effect); + } + + @Override + public CytoshapeEffect copy() { + return new CytoshapeEffect(this); + } + + @Override + public boolean apply(Game game, Ability ability) { + Permanent copyFrom = game.getPermanent(getTargetPointer().getFirst(game, ability)); + if (copyFrom != null) { + Permanent copyTo = game.getPermanentOrLKIBattlefield(ability.getTargets().get(1).getFirstTarget()); + if (copyTo != null) { + game.copyPermanent(Duration.EndOfTurn, copyFrom, copyTo.getId(), ability, new EmptyApplyToPermanent()); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/d/DromokasCommand.java b/Mage.Sets/src/mage/cards/d/DromokasCommand.java index 51bb89c387e..f825b0d34c0 100644 --- a/Mage.Sets/src/mage/cards/d/DromokasCommand.java +++ b/Mage.Sets/src/mage/cards/d/DromokasCommand.java @@ -78,7 +78,6 @@ public class DromokasCommand extends CardImpl { Mode mode = new Mode(); Effect effect = new SacrificeEffect(filterEnchantment, 1, "target player"); effect.setText("Target player sacrifices an enchantment"); - effect.setApplyEffectsAfter(); // so P/T chnaging effects take place before the fighting effect is applied mode.getEffects().add(effect); mode.getTargets().add(new TargetPlayer()); this.getSpellAbility().getModes().addMode(mode); @@ -87,7 +86,6 @@ public class DromokasCommand extends CardImpl { mode = new Mode(); effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance()); effect.setText("Put a +1/+1 counter on target creature"); - effect.setApplyEffectsAfter(); // so the counter is taken into account if the target is also used in mode 4 mode.getEffects().add(effect); mode.getTargets().add(new TargetCreaturePermanent(filterCreature)); this.getSpellAbility().getModes().addMode(mode); diff --git a/Mage.Sets/src/mage/cards/e/EldraziDisplacer.java b/Mage.Sets/src/mage/cards/e/EldraziDisplacer.java index ceaa7cfbf9b..1252e16a38a 100644 --- a/Mage.Sets/src/mage/cards/e/EldraziDisplacer.java +++ b/Mage.Sets/src/mage/cards/e/EldraziDisplacer.java @@ -58,7 +58,7 @@ public class EldraziDisplacer extends CardImpl { } public EldraziDisplacer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); this.subtype.add(SubType.ELDRAZI); this.power = new MageInt(3); this.toughness = new MageInt(3); @@ -69,7 +69,6 @@ public class EldraziDisplacer extends CardImpl { // {2}{C}: Exile another target creature, then return it to the battlefield tapped under its owner's control. Effect effect = new ExileTargetForSourceEffect(); effect.setText("Exile another target creature"); - effect.setApplyEffectsAfter(); // Needed to let temporary continuous effects end if a permanent is blinked Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{2}{C}")); effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(true); effect.setText(", then return it to the battlefield tapped under its owner's control"); diff --git a/Mage.Sets/src/mage/cards/e/EndlessWhispers.java b/Mage.Sets/src/mage/cards/e/EndlessWhispers.java index 36e78b8071d..c7976f063ea 100644 --- a/Mage.Sets/src/mage/cards/e/EndlessWhispers.java +++ b/Mage.Sets/src/mage/cards/e/EndlessWhispers.java @@ -56,7 +56,7 @@ import mage.target.common.TargetOpponent; public class EndlessWhispers extends CardImpl { public EndlessWhispers(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}"); // Each creature has "When this creature dies, choose target opponent. That player puts this card from its owner's graveyard onto the battlefield under his or her control at the beginning of the next end step." DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new ReturnSourceToBattlefieldEffect()); diff --git a/Mage.Sets/src/mage/cards/e/EntreatTheAngels.java b/Mage.Sets/src/mage/cards/e/EntreatTheAngels.java index 8c6b068c01d..e0a0f4cc418 100644 --- a/Mage.Sets/src/mage/cards/e/EntreatTheAngels.java +++ b/Mage.Sets/src/mage/cards/e/EntreatTheAngels.java @@ -40,15 +40,14 @@ import mage.game.permanent.token.AngelToken; /** * * @author noxx - + * */ public class EntreatTheAngels extends CardImpl { public EntreatTheAngels(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{X}{W}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{X}{W}{W}{W}"); - - // create X 4/4 white Angel creature tokens with flying. + // Create X 4/4 white Angel creature tokens with flying. this.getSpellAbility().addEffect(new CreateTokenEffect(new AngelToken(), new ManacostVariableValue())); // Miracle {X}{W}{W} diff --git a/Mage.Sets/src/mage/cards/e/EpicConfrontation.java b/Mage.Sets/src/mage/cards/e/EpicConfrontation.java index 30f6f9e8842..8fa809a30e1 100644 --- a/Mage.Sets/src/mage/cards/e/EpicConfrontation.java +++ b/Mage.Sets/src/mage/cards/e/EpicConfrontation.java @@ -47,6 +47,7 @@ import mage.target.common.TargetCreaturePermanent; * @author fireshoes */ public class EpicConfrontation extends CardImpl { + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you don't control"); static { @@ -54,18 +55,17 @@ public class EpicConfrontation extends CardImpl { } public EpicConfrontation(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{G}"); // Target creature you control gets +1/+2 until end of turn. It fights target creature you don't control. - Effect effect = new BoostTargetEffect(1,2,Duration.EndOfTurn); - effect.setApplyEffectsAfter(); + Effect effect = new BoostTargetEffect(1, 2, Duration.EndOfTurn); this.getSpellAbility().addEffect(effect); effect = new FightTargetsEffect(); effect.setText("It fights target creature you don't control"); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); Target target = new TargetCreaturePermanent(filter); - this.getSpellAbility().addTarget(target); + this.getSpellAbility().addTarget(target); } public EpicConfrontation(final EpicConfrontation card) { diff --git a/Mage.Sets/src/mage/cards/e/EssenceFlux.java b/Mage.Sets/src/mage/cards/e/EssenceFlux.java index 2c7a534e996..d96176c17bd 100644 --- a/Mage.Sets/src/mage/cards/e/EssenceFlux.java +++ b/Mage.Sets/src/mage/cards/e/EssenceFlux.java @@ -54,12 +54,11 @@ import mage.util.CardUtil; public class EssenceFlux extends CardImpl { public EssenceFlux(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{U}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}"); // Exile target creature you control, then return that card to the battlefield under its owner's control. If it's a Spirit, put a +1/+1 counter on it. this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); Effect effect = new ExileTargetForSourceEffect(); - effect.setApplyEffectsAfter(); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addEffect(new EssenceFluxEffect()); } @@ -102,8 +101,7 @@ class EssenceFluxEffect extends OneShotEffect { for (UUID targetId : this.getTargetPointer().getTargets(game, source)) { if (exileZone.contains(targetId)) { cardsToBattlefield.add(targetId); - } - else { + } else { Card card = game.getCard(targetId); if (card != null && card instanceof MeldCard) { MeldCard meldCard = (MeldCard) card; diff --git a/Mage.Sets/src/mage/cards/f/FelidarGuardian.java b/Mage.Sets/src/mage/cards/f/FelidarGuardian.java index c7acc317d93..020fb9748c5 100644 --- a/Mage.Sets/src/mage/cards/f/FelidarGuardian.java +++ b/Mage.Sets/src/mage/cards/f/FelidarGuardian.java @@ -64,7 +64,6 @@ public class FelidarGuardian extends CardImpl { // When Felidar Guardian enters the battlefield, you may exile another target permanent you control, then return that card to the battlefield under its owner's control. Effect effect = new ExileTargetForSourceEffect(); - effect.setApplyEffectsAfter(); Ability ability = new EntersBattlefieldTriggeredAbility(effect, true); ability.addEffect(new ReturnToBattlefieldUnderOwnerControlTargetEffect()); ability.addTarget(new TargetControlledPermanent(filter)); diff --git a/Mage.Sets/src/mage/cards/g/GrabTheReins.java b/Mage.Sets/src/mage/cards/g/GrabTheReins.java index 5782572e465..0a0e42f590d 100644 --- a/Mage.Sets/src/mage/cards/g/GrabTheReins.java +++ b/Mage.Sets/src/mage/cards/g/GrabTheReins.java @@ -51,12 +51,12 @@ import mage.target.common.TargetCreaturePermanent; /** * * @author LoneFox - + * */ public class GrabTheReins extends CardImpl { public GrabTheReins(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{R}"); // Choose one - this.getSpellAbility().getModes().setMinModes(1); @@ -64,7 +64,6 @@ public class GrabTheReins extends CardImpl { // Until end of turn, you gain control of target creature and it gains haste; Effect effect = new GainControlTargetEffect(Duration.EndOfTurn); effect.setText("Until end of turn, you gain control of target creature"); - effect.setApplyEffectsAfter(); this.getSpellAbility().addEffect(effect); effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn); effect.setText("and it gains haste"); @@ -111,15 +110,15 @@ class GrabTheReinsEffect extends OneShotEffect { Target target = new TargetCreaturePermanent(); target.setNotTarget(true); target.setTargetName("a creature to sacrifice"); - if(!target.canChoose(source.getSourceId(), controllerId, game)) { + if (!target.canChoose(source.getSourceId(), controllerId, game)) { return false; } Player player = game.getPlayer(controllerId); - if(player != null) { + if (player != null) { player.chooseTarget(Outcome.Sacrifice, target, source, game); Permanent creatureToSacrifice = game.getPermanent(target.getTargets().get(0)); int amount = creatureToSacrifice.getPower().getValue(); - if(!creatureToSacrifice.sacrifice(creatureToSacrifice.getId(), game)) { + if (!creatureToSacrifice.sacrifice(creatureToSacrifice.getId(), game)) { return false; } if (amount > 0) { @@ -133,8 +132,7 @@ class GrabTheReinsEffect extends OneShotEffect { player.damage(amount, source.getSourceId(), game, false, true); return true; } - } - else { + } else { return true; } } diff --git a/Mage.Sets/src/mage/cards/h/HuntTheHunter.java b/Mage.Sets/src/mage/cards/h/HuntTheHunter.java index 9c35eb5c08d..9a2dc29460f 100644 --- a/Mage.Sets/src/mage/cards/h/HuntTheHunter.java +++ b/Mage.Sets/src/mage/cards/h/HuntTheHunter.java @@ -53,6 +53,7 @@ public class HuntTheHunter extends CardImpl { private static final FilterControlledCreaturePermanent filterControlledGreen = new FilterControlledCreaturePermanent("green creature you control"); private static final FilterCreaturePermanent filterOpponentGreen = new FilterCreaturePermanent("green creature an opponent controls"); + static { filterControlledGreen.add(new ColorPredicate(ObjectColor.GREEN)); filterOpponentGreen.add(new ControllerPredicate(TargetController.OPPONENT)); @@ -60,14 +61,12 @@ public class HuntTheHunter extends CardImpl { } public HuntTheHunter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{G}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{G}"); // Target green creature you control gets +2/+2 until end of turn. It fights target green creature an opponent controls. - Effect effect = new BoostTargetEffect(2,2, Duration.EndOfTurn); - effect.setApplyEffectsAfter(); + Effect effect = new BoostTargetEffect(2, 2, Duration.EndOfTurn); this.getSpellAbility().addEffect(effect); - this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(1,1,filterControlledGreen, false)); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(1, 1, filterControlledGreen, false)); effect = new FightTargetsEffect(); effect.setText("It fights target green creature an opponent controls"); diff --git a/Mage.Sets/src/mage/cards/h/HuntTheWeak.java b/Mage.Sets/src/mage/cards/h/HuntTheWeak.java index 4b026e2b9e6..4670631262e 100644 --- a/Mage.Sets/src/mage/cards/h/HuntTheWeak.java +++ b/Mage.Sets/src/mage/cards/h/HuntTheWeak.java @@ -49,17 +49,16 @@ import mage.target.common.TargetCreaturePermanent; public class HuntTheWeak extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you don't control"); + static { filter.add(new ControllerPredicate(TargetController.NOT_YOU)); } public HuntTheWeak(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{G}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{G}"); // Put a +1/+1 counter on target creature you control. Then that creature fights target creature you don't control. Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance()); - effect.setApplyEffectsAfter(); this.getSpellAbility().addEffect(effect); effect = new FightTargetsEffect(); effect.setText("Then that creature fights target creature you don't control"); diff --git a/Mage.Sets/src/mage/cards/n/NissasJudgment.java b/Mage.Sets/src/mage/cards/n/NissasJudgment.java index e2c2e3b44cc..f0c9807ad18 100644 --- a/Mage.Sets/src/mage/cards/n/NissasJudgment.java +++ b/Mage.Sets/src/mage/cards/n/NissasJudgment.java @@ -60,11 +60,10 @@ public class NissasJudgment extends CardImpl { } public NissasJudgment(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{G}"); // Support 2. Effect effect = new SupportEffect(this, 2, false); - effect.setApplyEffectsAfter(); getSpellAbility().addEffect(effect); // Choose up to one target creature an opponent controls. Each creature you control with a +1/+1 counter on it deals damage equal to its power to that creature. diff --git a/Mage.Sets/src/mage/cards/p/PlowThroughReito.java b/Mage.Sets/src/mage/cards/p/PlowThroughReito.java index 1b573a46561..24edcbcd25a 100644 --- a/Mage.Sets/src/mage/cards/p/PlowThroughReito.java +++ b/Mage.Sets/src/mage/cards/p/PlowThroughReito.java @@ -46,14 +46,13 @@ import mage.target.common.TargetCreaturePermanent; public class PlowThroughReito extends CardImpl { public PlowThroughReito(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); this.subtype.add(SubType.ARCANE); - // 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. this.getSpellAbility().addEffect(new SweepEffect(SubType.PLAINS)); - DynamicValue sweepValue = new SweepNumber("Plains", true); - this.getSpellAbility().addEffect(new BoostTargetEffect(sweepValue, sweepValue, Duration.EndOfTurn)); + DynamicValue sweepValue = new SweepNumber("Plains"); + this.getSpellAbility().addEffect(new BoostTargetEffect(sweepValue, sweepValue, Duration.EndOfTurn, true)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/s/SavagePunch.java b/Mage.Sets/src/mage/cards/s/SavagePunch.java index 9599a521e56..486b48dcf87 100644 --- a/Mage.Sets/src/mage/cards/s/SavagePunch.java +++ b/Mage.Sets/src/mage/cards/s/SavagePunch.java @@ -45,7 +45,6 @@ import mage.target.Target; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; - /** * * @author LevelX2 @@ -59,14 +58,13 @@ public class SavagePunch extends CardImpl { } public SavagePunch(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{G}"); // Ferocious - The creature you control gets +2/+2 until end of turn before it fights if you control a creature with power 4 or greater. Effect effect = new ConditionalContinuousEffect( - new BoostTargetEffect(2,2,Duration.EndOfTurn), + new BoostTargetEffect(2, 2, Duration.EndOfTurn), new LockedInCondition(FerociousCondition.instance), "Ferocious — The creature you control gets +2/+2 until end of turn before it fights if you control a creature with power 4 or greater"); - effect.setApplyEffectsAfter(); this.getSpellAbility().addEffect(effect); // Target creature you control fights target creature you don't control. diff --git a/Mage.Sets/src/mage/cards/s/SavageStomp.java b/Mage.Sets/src/mage/cards/s/SavageStomp.java index 96c8084d4c5..50890212100 100644 --- a/Mage.Sets/src/mage/cards/s/SavageStomp.java +++ b/Mage.Sets/src/mage/cards/s/SavageStomp.java @@ -75,7 +75,6 @@ public class SavageStomp extends CardImpl { // Put a +1/+1 counter on target creature you control. Then that creature fights target creature you don't control. Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance()); - effect.setApplyEffectsAfter(); this.getSpellAbility().addEffect(effect); effect = new FightTargetsEffect(); effect.setText("Then that creature fights target creature you don't control"); diff --git a/Mage.Sets/src/mage/cards/s/SinkIntoTakenuma.java b/Mage.Sets/src/mage/cards/s/SinkIntoTakenuma.java index f4691dd9c67..99e5c2edb8d 100644 --- a/Mage.Sets/src/mage/cards/s/SinkIntoTakenuma.java +++ b/Mage.Sets/src/mage/cards/s/SinkIntoTakenuma.java @@ -45,13 +45,12 @@ import mage.target.TargetPlayer; public class SinkIntoTakenuma extends CardImpl { public SinkIntoTakenuma(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}"); this.subtype.add(SubType.ARCANE); - // Sweep - Return any number of Swamps you control to their owner's hand. Target player discards a card for each Swamp returned this way. this.getSpellAbility().addEffect(new SweepEffect(SubType.SWAMP)); - DynamicValue sweepValue = new SweepNumber("Swamp", false); + DynamicValue sweepValue = new SweepNumber("Swamp"); this.getSpellAbility().addEffect(new DiscardTargetEffect(sweepValue)); this.getSpellAbility().addTarget(new TargetPlayer()); } diff --git a/Mage.Sets/src/mage/cards/s/SkyshroudWarBeast.java b/Mage.Sets/src/mage/cards/s/SkyshroudWarBeast.java index 25705180cda..f74d9cb92da 100644 --- a/Mage.Sets/src/mage/cards/s/SkyshroudWarBeast.java +++ b/Mage.Sets/src/mage/cards/s/SkyshroudWarBeast.java @@ -36,7 +36,6 @@ import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.common.ChooseOpponentEffect; -import mage.constants.SubType; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -45,6 +44,7 @@ import mage.constants.Duration; import mage.constants.Layer; import mage.constants.Outcome; import mage.constants.SubLayer; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterLandPermanent; import mage.filter.predicate.permanent.ControllerIdPredicate; @@ -107,7 +107,7 @@ class SkyshroudWarBeastEffect extends ContinuousEffectImpl { MageObject target = game.getObject(source.getSourceId()); if (target != null) { UUID playerId = (UUID) game.getState().getValue(source.getSourceId().toString() + ChooseOpponentEffect.VALUE_KEY); - FilterLandPermanent filter = new FilterLandPermanent(); + FilterLandPermanent filter = FilterLandPermanent.nonbasicLand(); filter.add(new ControllerIdPredicate(playerId)); int number = new PermanentsOnBattlefieldCount(filter).calculate(game, source, this); target.getPower().setValue(number); diff --git a/Mage.Sets/src/mage/cards/s/StartYourEngines.java b/Mage.Sets/src/mage/cards/s/StartYourEngines.java index 4cc5a1ad2eb..c4e0b086579 100644 --- a/Mage.Sets/src/mage/cards/s/StartYourEngines.java +++ b/Mage.Sets/src/mage/cards/s/StartYourEngines.java @@ -27,6 +27,7 @@ */ package mage.cards.s; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.Effect; @@ -37,8 +38,6 @@ import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; -import java.util.UUID; - /** * * @author LevelX2 @@ -46,11 +45,10 @@ import java.util.UUID; public class StartYourEngines extends CardImpl { public StartYourEngines(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}"); // Vehicles you control becomes artifact creatures until end of turn. Effect effect = new StartYourEnginesEffect(); - effect.setApplyEffectsAfter(); // needed to recognize vehicle as creatures by the next effect this.getSpellAbility().addEffect(effect); // Creatures you control get +2/+0 until end of turn. diff --git a/Mage.Sets/src/mage/cards/s/SwiftKick.java b/Mage.Sets/src/mage/cards/s/SwiftKick.java index c34d8f1e9f7..f83098c618c 100644 --- a/Mage.Sets/src/mage/cards/s/SwiftKick.java +++ b/Mage.Sets/src/mage/cards/s/SwiftKick.java @@ -49,23 +49,22 @@ import mage.target.common.TargetCreaturePermanent; public class SwiftKick extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you don't control"); + static { filter.add(new ControllerPredicate(TargetController.NOT_YOU)); } public SwiftKick(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{R}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{R}"); // Target creature you control gets +1/+0 until end of turn. It fights target creature you don't control. - Effect effect = new BoostTargetEffect(1,0,Duration.EndOfTurn); - effect.setApplyEffectsAfter(); + Effect effect = new BoostTargetEffect(1, 0, Duration.EndOfTurn); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - + effect = new FightTargetsEffect(); effect.setText("It fights target creature you don't control"); - this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addEffect(effect); Target target = new TargetCreaturePermanent(filter); this.getSpellAbility().addTarget(target); diff --git a/Mage.Sets/src/mage/cards/s/SylvanLibrary.java b/Mage.Sets/src/mage/cards/s/SylvanLibrary.java index c0acfd38018..27106b90094 100644 --- a/Mage.Sets/src/mage/cards/s/SylvanLibrary.java +++ b/Mage.Sets/src/mage/cards/s/SylvanLibrary.java @@ -132,7 +132,7 @@ class SylvanLibraryEffect extends OneShotEffect { } } } - controller.putCardsOnTopOfLibrary(cardsPutBack, game, source, applyEffectsAfter); + controller.putCardsOnTopOfLibrary(cardsPutBack, game, source, false); } } return true; diff --git a/Mage.Sets/src/mage/cards/t/TemurCharm.java b/Mage.Sets/src/mage/cards/t/TemurCharm.java index 88a27cfcde4..cf9306775a3 100644 --- a/Mage.Sets/src/mage/cards/t/TemurCharm.java +++ b/Mage.Sets/src/mage/cards/t/TemurCharm.java @@ -57,39 +57,37 @@ public class TemurCharm extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you don't control"); private static final FilterCreaturePermanent filterCantBlock = new FilterCreaturePermanent("Creatures with power 3 or less"); - + static { filter.add(new ControllerPredicate(TargetController.NOT_YOU)); filterCantBlock.add(new PowerPredicate(ComparisonType.FEWER_THAN, 4)); } - - public TemurCharm(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{G}{U}{R}"); + public TemurCharm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{G}{U}{R}"); // Choose one - // Target creature you control gets +1/+1 until end of turn. That creature fights target creature you don't control. - Effect effect = new BoostTargetEffect(1,1,Duration.EndOfTurn); - effect.setApplyEffectsAfter(); + Effect effect = new BoostTargetEffect(1, 1, Duration.EndOfTurn); this.getSpellAbility().addEffect(effect); effect = new FightTargetsEffect(); effect.setText("That creature fights target creature you don't control"); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); Target target = new TargetCreaturePermanent(filter); - this.getSpellAbility().addTarget(target); - + this.getSpellAbility().addTarget(target); + // Counter target spell unless its controller pays {3}. Mode mode = new Mode(); mode.getEffects().add(new CounterUnlessPaysEffect(new GenericManaCost(3))); mode.getTargets().add(new TargetSpell()); this.getSpellAbility().addMode(mode); - + // Creatures with power 3 or less can't block this turn. mode = new Mode(); mode.getEffects().add(new CantBlockAllEffect(filterCantBlock, Duration.EndOfTurn)); this.getSpellAbility().addMode(mode); - + } public TemurCharm(final TemurCharm card) { diff --git a/Mage.Sets/src/mage/cards/w/WildInstincts.java b/Mage.Sets/src/mage/cards/w/WildInstincts.java index 845c74b808e..0dea866d011 100644 --- a/Mage.Sets/src/mage/cards/w/WildInstincts.java +++ b/Mage.Sets/src/mage/cards/w/WildInstincts.java @@ -54,11 +54,10 @@ public class WildInstincts extends CardImpl { } public WildInstincts(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{G}"); // Target creature you control gets +2/+2 until end of turn. It fights target creature an opponent controls. Effect effect = new BoostTargetEffect(2, 2, Duration.EndOfTurn); - effect.setApplyEffectsAfter(); getSpellAbility().addEffect(effect); getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); effect = new FightTargetsEffect(); diff --git a/Mage.Sets/src/mage/cards/w/WispweaverAngel.java b/Mage.Sets/src/mage/cards/w/WispweaverAngel.java index 21c0c3db4f3..7adfdf9fa97 100644 --- a/Mage.Sets/src/mage/cards/w/WispweaverAngel.java +++ b/Mage.Sets/src/mage/cards/w/WispweaverAngel.java @@ -42,8 +42,8 @@ import mage.cards.Cards; import mage.cards.CardsImpl; import mage.cards.MeldCard; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.permanent.AnotherPredicate; @@ -66,7 +66,7 @@ public class WispweaverAngel extends CardImpl { } public WispweaverAngel(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.ANGEL); this.power = new MageInt(4); this.toughness = new MageInt(4); @@ -76,7 +76,6 @@ public class WispweaverAngel extends CardImpl { // When Wispweaver Angel enters the battlefield, you may exile another target creature you control, then return that card to the battlefield under its owner's control. Effect effect = new ExileTargetForSourceEffect(); - effect.setApplyEffectsAfter(); Ability ability = new EntersBattlefieldTriggeredAbility(effect, true); ability.addTarget(new TargetControlledCreaturePermanent(1, 1, filter, false)); ability.addEffect(new WispweaverAngelEffect()); diff --git a/Mage.Sets/src/mage/cards/z/ZealousConscripts.java b/Mage.Sets/src/mage/cards/z/ZealousConscripts.java index 4b8ef517ddc..ffb48ffb74d 100644 --- a/Mage.Sets/src/mage/cards/z/ZealousConscripts.java +++ b/Mage.Sets/src/mage/cards/z/ZealousConscripts.java @@ -49,7 +49,7 @@ import mage.target.TargetPermanent; public class ZealousConscripts extends CardImpl { public ZealousConscripts(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}"); this.subtype.add(SubType.HUMAN, SubType.WARRIOR); this.power = new MageInt(3); diff --git a/Mage.Sets/src/mage/sets/Dissension.java b/Mage.Sets/src/mage/sets/Dissension.java index 58724c4ca45..3b8878f876d 100644 --- a/Mage.Sets/src/mage/sets/Dissension.java +++ b/Mage.Sets/src/mage/sets/Dissension.java @@ -85,6 +85,7 @@ public class Dissension extends ExpansionSet { cards.add(new SetCardInfo("Crypt Champion", 40, Rarity.UNCOMMON, mage.cards.c.CryptChampion.class)); cards.add(new SetCardInfo("Cytoplast Manipulator", 23, Rarity.RARE, mage.cards.c.CytoplastManipulator.class)); cards.add(new SetCardInfo("Cytoplast Root-Kin", 81, Rarity.RARE, mage.cards.c.CytoplastRootKin.class)); + cards.add(new SetCardInfo("Cytoshape", 108, Rarity.RARE, mage.cards.c.Cytoshape.class)); cards.add(new SetCardInfo("Cytospawn Shambler", 82, Rarity.COMMON, mage.cards.c.CytospawnShambler.class)); cards.add(new SetCardInfo("Delirium Skeins", 41, Rarity.COMMON, mage.cards.d.DeliriumSkeins.class)); cards.add(new SetCardInfo("Demonfire", 60, Rarity.RARE, mage.cards.d.Demonfire.class)); diff --git a/Mage.Sets/src/mage/sets/ZendikarExpeditions.java b/Mage.Sets/src/mage/sets/ZendikarExpeditions.java index 002d5f4b485..b004407fbaa 100644 --- a/Mage.Sets/src/mage/sets/ZendikarExpeditions.java +++ b/Mage.Sets/src/mage/sets/ZendikarExpeditions.java @@ -47,50 +47,50 @@ public class ZendikarExpeditions extends ExpansionSet { super("Zendikar Expeditions", "EXP", ExpansionSet.buildDate(2015, 10, 2), SetType.PROMOTIONAL); this.hasBoosters = false; this.hasBasicLands = false; - cards.add(new SetCardInfo("Ancient Tomb", 36, Rarity.MYTHIC, mage.cards.a.AncientTomb.class)); - cards.add(new SetCardInfo("Arid Mesa", 24, Rarity.MYTHIC, mage.cards.a.AridMesa.class)); - cards.add(new SetCardInfo("Blood Crypt", 8, Rarity.MYTHIC, mage.cards.b.BloodCrypt.class)); - cards.add(new SetCardInfo("Bloodstained Mire", 18, Rarity.MYTHIC, mage.cards.b.BloodstainedMire.class)); - cards.add(new SetCardInfo("Breeding Pool", 15, Rarity.MYTHIC, mage.cards.b.BreedingPool.class)); - cards.add(new SetCardInfo("Canopy Vista", 5, Rarity.MYTHIC, mage.cards.c.CanopyVista.class)); - cards.add(new SetCardInfo("Cascade Bluffs", 32, Rarity.MYTHIC, mage.cards.c.CascadeBluffs.class)); - cards.add(new SetCardInfo("Cinder Glade", 4, Rarity.MYTHIC, mage.cards.c.CinderGlade.class)); - cards.add(new SetCardInfo("Dust Bowl", 37, Rarity.MYTHIC, mage.cards.d.DustBowl.class)); - cards.add(new SetCardInfo("Eye of Ugin", 38, Rarity.MYTHIC, mage.cards.e.EyeOfUgin.class)); - cards.add(new SetCardInfo("Fetid Heath", 31, Rarity.MYTHIC, mage.cards.f.FetidHeath.class)); - cards.add(new SetCardInfo("Fire-Lit Thicket", 29, Rarity.MYTHIC, mage.cards.f.FireLitThicket.class)); - cards.add(new SetCardInfo("Flooded Grove", 35, Rarity.MYTHIC, mage.cards.f.FloodedGrove.class)); - cards.add(new SetCardInfo("Flooded Strand", 16, Rarity.MYTHIC, mage.cards.f.FloodedStrand.class)); - cards.add(new SetCardInfo("Forbidden Orchard", 39, Rarity.MYTHIC, mage.cards.f.ForbiddenOrchard.class)); - cards.add(new SetCardInfo("Godless Shrine", 11, Rarity.MYTHIC, mage.cards.g.GodlessShrine.class)); - cards.add(new SetCardInfo("Graven Cairns", 28, Rarity.MYTHIC, mage.cards.g.GravenCairns.class)); - cards.add(new SetCardInfo("Hallowed Fountain", 6, Rarity.MYTHIC, mage.cards.h.HallowedFountain.class)); - cards.add(new SetCardInfo("Horizon Canopy", 40, Rarity.MYTHIC, mage.cards.h.HorizonCanopy.class)); - cards.add(new SetCardInfo("Kor Haven", 41, Rarity.MYTHIC, mage.cards.k.KorHaven.class)); - cards.add(new SetCardInfo("Mana Confluence", 42, Rarity.MYTHIC, mage.cards.m.ManaConfluence.class)); - cards.add(new SetCardInfo("Marsh Flats", 21, Rarity.MYTHIC, mage.cards.m.MarshFlats.class)); - cards.add(new SetCardInfo("Misty Rainforest", 25, Rarity.MYTHIC, mage.cards.m.MistyRainforest.class)); - cards.add(new SetCardInfo("Mystic Gate", 26, Rarity.MYTHIC, mage.cards.m.MysticGate.class)); - cards.add(new SetCardInfo("Overgrown Tomb", 13, Rarity.MYTHIC, mage.cards.o.OvergrownTomb.class)); - cards.add(new SetCardInfo("Polluted Delta", 17, Rarity.MYTHIC, mage.cards.p.PollutedDelta.class)); - cards.add(new SetCardInfo("Prairie Stream", 1, Rarity.MYTHIC, mage.cards.p.PrairieStream.class)); - cards.add(new SetCardInfo("Rugged Prairie", 34, Rarity.MYTHIC, mage.cards.r.RuggedPrairie.class)); - cards.add(new SetCardInfo("Sacred Foundry", 14, Rarity.MYTHIC, mage.cards.s.SacredFoundry.class)); - cards.add(new SetCardInfo("Scalding Tarn", 22, Rarity.MYTHIC, mage.cards.s.ScaldingTarn.class)); - cards.add(new SetCardInfo("Smoldering Marsh", 3, Rarity.MYTHIC, mage.cards.s.SmolderingMarsh.class)); - cards.add(new SetCardInfo("Steam Vents", 12, Rarity.MYTHIC, mage.cards.s.SteamVents.class)); - cards.add(new SetCardInfo("Stomping Ground", 9, Rarity.MYTHIC, mage.cards.s.StompingGround.class)); - cards.add(new SetCardInfo("Strip Mine", 43, Rarity.MYTHIC, mage.cards.s.StripMine.class)); - cards.add(new SetCardInfo("Sunken Hollow", 2, Rarity.MYTHIC, mage.cards.s.SunkenHollow.class)); - cards.add(new SetCardInfo("Sunken Ruins", 27, Rarity.MYTHIC, mage.cards.s.SunkenRuins.class)); - cards.add(new SetCardInfo("Tectonic Edge", 44, Rarity.MYTHIC, mage.cards.t.TectonicEdge.class)); - cards.add(new SetCardInfo("Temple Garden", 10, Rarity.MYTHIC, mage.cards.t.TempleGarden.class)); - cards.add(new SetCardInfo("Twilight Mire", 33, Rarity.MYTHIC, mage.cards.t.TwilightMire.class)); - cards.add(new SetCardInfo("Verdant Catacombs", 23, Rarity.MYTHIC, mage.cards.v.VerdantCatacombs.class)); - cards.add(new SetCardInfo("Wasteland", 45, Rarity.MYTHIC, mage.cards.w.Wasteland.class)); - cards.add(new SetCardInfo("Watery Grave", 7, Rarity.MYTHIC, mage.cards.w.WateryGrave.class)); - cards.add(new SetCardInfo("Windswept Heath", 20, Rarity.MYTHIC, mage.cards.w.WindsweptHeath.class)); - cards.add(new SetCardInfo("Wooded Bastion", 30, Rarity.MYTHIC, mage.cards.w.WoodedBastion.class)); - cards.add(new SetCardInfo("Wooded Foothills", 19, Rarity.MYTHIC, mage.cards.w.WoodedFoothills.class)); + cards.add(new SetCardInfo("Ancient Tomb", 36, Rarity.MYTHIC, mage.cards.a.AncientTomb.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Arid Mesa", 24, Rarity.MYTHIC, mage.cards.a.AridMesa.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Blood Crypt", 8, Rarity.MYTHIC, mage.cards.b.BloodCrypt.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Bloodstained Mire", 18, Rarity.MYTHIC, mage.cards.b.BloodstainedMire.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Breeding Pool", 15, Rarity.MYTHIC, mage.cards.b.BreedingPool.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Canopy Vista", 5, Rarity.MYTHIC, mage.cards.c.CanopyVista.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Cascade Bluffs", 32, Rarity.MYTHIC, mage.cards.c.CascadeBluffs.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Cinder Glade", 4, Rarity.MYTHIC, mage.cards.c.CinderGlade.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Dust Bowl", 37, Rarity.MYTHIC, mage.cards.d.DustBowl.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Eye of Ugin", 38, Rarity.MYTHIC, mage.cards.e.EyeOfUgin.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Fetid Heath", 31, Rarity.MYTHIC, mage.cards.f.FetidHeath.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Fire-Lit Thicket", 29, Rarity.MYTHIC, mage.cards.f.FireLitThicket.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Flooded Grove", 35, Rarity.MYTHIC, mage.cards.f.FloodedGrove.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Flooded Strand", 16, Rarity.MYTHIC, mage.cards.f.FloodedStrand.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Forbidden Orchard", 39, Rarity.MYTHIC, mage.cards.f.ForbiddenOrchard.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Godless Shrine", 11, Rarity.MYTHIC, mage.cards.g.GodlessShrine.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Graven Cairns", 28, Rarity.MYTHIC, mage.cards.g.GravenCairns.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Hallowed Fountain", 6, Rarity.MYTHIC, mage.cards.h.HallowedFountain.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Horizon Canopy", 40, Rarity.MYTHIC, mage.cards.h.HorizonCanopy.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Kor Haven", 41, Rarity.MYTHIC, mage.cards.k.KorHaven.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Mana Confluence", 42, Rarity.MYTHIC, mage.cards.m.ManaConfluence.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Marsh Flats", 21, Rarity.MYTHIC, mage.cards.m.MarshFlats.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Misty Rainforest", 25, Rarity.MYTHIC, mage.cards.m.MistyRainforest.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Mystic Gate", 26, Rarity.MYTHIC, mage.cards.m.MysticGate.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Overgrown Tomb", 13, Rarity.MYTHIC, mage.cards.o.OvergrownTomb.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Polluted Delta", 17, Rarity.MYTHIC, mage.cards.p.PollutedDelta.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Prairie Stream", 1, Rarity.MYTHIC, mage.cards.p.PrairieStream.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Rugged Prairie", 34, Rarity.MYTHIC, mage.cards.r.RuggedPrairie.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Sacred Foundry", 14, Rarity.MYTHIC, mage.cards.s.SacredFoundry.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Scalding Tarn", 22, Rarity.MYTHIC, mage.cards.s.ScaldingTarn.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Smoldering Marsh", 3, Rarity.MYTHIC, mage.cards.s.SmolderingMarsh.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Steam Vents", 12, Rarity.MYTHIC, mage.cards.s.SteamVents.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Stomping Ground", 9, Rarity.MYTHIC, mage.cards.s.StompingGround.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Strip Mine", 43, Rarity.MYTHIC, mage.cards.s.StripMine.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Sunken Hollow", 2, Rarity.MYTHIC, mage.cards.s.SunkenHollow.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Sunken Ruins", 27, Rarity.MYTHIC, mage.cards.s.SunkenRuins.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Tectonic Edge", 44, Rarity.MYTHIC, mage.cards.t.TectonicEdge.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Temple Garden", 10, Rarity.MYTHIC, mage.cards.t.TempleGarden.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Twilight Mire", 33, Rarity.MYTHIC, mage.cards.t.TwilightMire.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Verdant Catacombs", 23, Rarity.MYTHIC, mage.cards.v.VerdantCatacombs.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Wasteland", 45, Rarity.MYTHIC, mage.cards.w.Wasteland.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Watery Grave", 7, Rarity.MYTHIC, mage.cards.w.WateryGrave.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Windswept Heath", 20, Rarity.MYTHIC, mage.cards.w.WindsweptHeath.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Wooded Bastion", 30, Rarity.MYTHIC, mage.cards.w.WoodedBastion.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Wooded Foothills", 19, Rarity.MYTHIC, mage.cards.w.WoodedFoothills.class, FULL_ART_BFZ_VARIOUS)); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/AnnihilatorTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/AnnihilatorTest.java index 79e622d52d0..7c84ee87c5e 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/AnnihilatorTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/AnnihilatorTest.java @@ -31,5 +31,52 @@ public class AnnihilatorTest extends CardTestPlayerBase { assertPermanentCount(playerA, 1); } + /** + * I was attacked with an It that Betrays while i had an Academy Rector and + * with the annihilator trigger on the stack i cast Cauldron Haze targeting + * academy rector then sacrificed her to the annihilator trigger and chose + * not to exile her. My persist resolved before the second ability of it + * that betrays because i was not the active player, the game log shows: + * + * 9:18 AM: Ability triggers: Academy Rector [e15] - Persist (When this + * creature dies, if it had no -1/-1 counters on it, return it to the + * battlefield under its owner's control with a -1/-1 counter on it.) + * + * 9:19 AM: EllNubNub puts Academy Rector [e15] from graveyard onto the + * Battlefield + * + * 9:20 AM: hellmo puts Academy Rector [e15] from battlefield onto the + * Battlefield + * + * The It that Betrays trigger should have fissled, instead it stole her + * from my battlefield and removed the persist counter. + */ + @Test + public void testCardItThatBetrays() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + // Choose any number of target creatures. Each of those creatures gains persist until end of turn. + // Persist (When this creature dies, if it had no -1/-1 counters on it, return it to the battlefield under its owner's control with a -1/-1 counter on it.) + addCard(Zone.HAND, playerA, "Cauldron Haze", 1); // Instant {1}{W/B} + + // When Academy Rector dies, you may exile it. If you do, search your library for an enchantment card, put that card onto the battlefield, then shuffle your library. + addCard(Zone.BATTLEFIELD, playerA, "Academy Rector", 1); + + // Annihilator 2 (Whenever this creature attacks, defending player sacrifices two permanents.) + // Whenever an opponent sacrifices a nontoken permanent, put that card onto the battlefield under your control. + addCard(Zone.BATTLEFIELD, playerB, "It That Betrays"); + + attack(2, playerB, "It That Betrays"); + setChoice(playerA, "Academy Rector"); // Annihilator + setChoice(playerA, "Plains"); // Annihilator + castSpell(2, PhaseStep.DECLARE_ATTACKERS, playerA, "Cauldron Haze", "Academy Rector", "Annihilator"); + setChoice(playerA, "No"); // Academy Rector No Exile + + setStopAt(2, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertGraveyardCount(playerA, "Cauldron Haze", 1); + assertPermanentCount(playerB, "Academy Rector", 0); + assertPowerToughness(playerA, "Academy Rector", 0, 1); + } } 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 8c8733d57dc..045c436d8e4 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 @@ -853,4 +853,45 @@ public class MorphTest extends CardTestPlayerBase { assertTappedCount("Island", true, 3); } + + /** + * If you have Endless Whispers in play and a morph creature dies, it should + * be returned to play face up at end of turn under the control of an + * opponent. + */ + @Test + public void testMorphEndlessWhispers() { + /* + Quicksilver Dragon {4}{U}{U} + Creature - Dragon + 5/5 + Flying + {U}: If target spell has only one target and that target is Quicksilver Dragon, change that spell's target to another creature. + Morph {4}{U} + */ + addCard(Zone.HAND, playerA, "Quicksilver Dragon"); + addCard(Zone.BATTLEFIELD, playerA, "Island", 3); + + // Each creature has "When this creature dies, choose target opponent. That player puts this card from its owner's graveyard + // onto the battlefield under his or her control at the beginning of the next end step." + addCard(Zone.BATTLEFIELD, playerA, "Endless Whispers", 1); + + addCard(Zone.HAND, playerB, "Lightning Bolt"); + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1); + + 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", ""); + + setStopAt(2, PhaseStep.UPKEEP); + execute(); + + assertGraveyardCount(playerB, "Lightning Bolt", 1); + assertGraveyardCount(playerA, "Quicksilver Dragon", 0); + + assertPermanentCount(playerA, "Quicksilver Dragon", 0); + assertPermanentCount(playerB, "Quicksilver Dragon", 1); + + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/ShapeStealerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/ShapeStealerTest.java new file mode 100644 index 00000000000..5908aed99fc --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/ShapeStealerTest.java @@ -0,0 +1,25 @@ +package org.mage.test.cards.triggers; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +public class ShapeStealerTest extends CardTestPlayerBase { + + private String shapeStealer = "Shape Stealer"; + private String myojinOfCleansingFire = "Myojin of Cleansing Fire"; + + @Test + public void testShapeStealerSingleBlocker() { + addCard(Zone.BATTLEFIELD, playerA, shapeStealer); + addCard(Zone.BATTLEFIELD, playerB, myojinOfCleansingFire); + attack(1, playerA, shapeStealer); + block(1, playerB, myojinOfCleansingFire, shapeStealer); + setStopAt(1, PhaseStep.END_COMBAT); + execute(); + assertDamageReceived(playerA, shapeStealer, 4); + assertPowerToughness(playerA, shapeStealer, 4, 6); + assertDamageReceived(playerB, myojinOfCleansingFire, 4); + } +} diff --git a/Mage/src/main/java/mage/abilities/AbilityImpl.java b/Mage/src/main/java/mage/abilities/AbilityImpl.java index 25528d242b6..0a4d9588731 100644 --- a/Mage/src/main/java/mage/abilities/AbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/AbilityImpl.java @@ -220,10 +220,8 @@ public abstract class AbilityImpl implements Ability { * too late Example: * {@link org.mage.test.cards.replacement.DryadMilitantTest#testDiesByDestroy testDiesByDestroy} */ - if (effect.applyEffectsAfter()) { - game.applyEffects(); - game.getState().getTriggers().checkStateTriggers(game); - } + game.applyEffects(); + game.getState().getTriggers().checkStateTriggers(game); } } return result; diff --git a/Mage/src/main/java/mage/abilities/TriggeredAbilities.java b/Mage/src/main/java/mage/abilities/TriggeredAbilities.java index 5feca7f7afb..c04367f5576 100644 --- a/Mage/src/main/java/mage/abilities/TriggeredAbilities.java +++ b/Mage/src/main/java/mage/abilities/TriggeredAbilities.java @@ -28,6 +28,8 @@ */ package mage.abilities; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import mage.MageObject; import mage.constants.Zone; import mage.game.Game; @@ -36,15 +38,12 @@ import mage.game.events.NumberOfTriggersEvent; import mage.game.permanent.Permanent; import mage.game.stack.Spell; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; - /** * @author BetaSteward_at_googlemail.com - *

- * This class uses ConcurrentHashMap to avoid ConcurrentModificationExceptions. - * See ticket https://github.com/magefree/mage/issues/966 and - * https://github.com/magefree/mage/issues/473 + *

+ * This class uses ConcurrentHashMap to avoid ConcurrentModificationExceptions. + * See ticket https://github.com/magefree/mage/issues/966 and + * https://github.com/magefree/mage/issues/473 */ public class TriggeredAbilities extends ConcurrentHashMap { @@ -63,7 +62,7 @@ public class TriggeredAbilities extends ConcurrentHashMap it = this.values().iterator(); it.hasNext(); ) { + for (Iterator it = this.values().iterator(); it.hasNext();) { TriggeredAbility ability = it.next(); if (ability instanceof StateTriggeredAbility && ((StateTriggeredAbility) ability).canTrigger(game)) { checkTrigger(ability, null, game); @@ -72,7 +71,7 @@ public class TriggeredAbilities extends ConcurrentHashMap it = this.values().iterator(); it.hasNext(); ) { + for (Iterator it = this.values().iterator(); it.hasNext();) { TriggeredAbility ability = it.next(); if (ability.checkEventType(event, game)) { checkTrigger(ability, event, game); @@ -98,7 +97,10 @@ public class TriggeredAbilities extends ConcurrentHashMap so it should work + && !ability.getWorksFaceDown()) { // the ability is declared to work also face down + // Not all triggered abilities of face down creatures work if they are faced down return; } controllerSet = true; @@ -130,8 +132,8 @@ public class TriggeredAbilities extends ConcurrentHashMap key.endsWith(sourceId.toString())); } @@ -171,6 +172,10 @@ public class TriggeredAbilities extends ConcurrentHashMapInspired - Whenever {this} becomes untapped, ").append(super.getRule()).toString(); + return "Inspired - Whenever {this} becomes untapped, " + super.getRule(); } } diff --git a/Mage/src/main/java/mage/abilities/keyword/MiracleAbility.java b/Mage/src/main/java/mage/abilities/keyword/MiracleAbility.java index 20996fb6625..8c50e898c0a 100644 --- a/Mage/src/main/java/mage/abilities/keyword/MiracleAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/MiracleAbility.java @@ -24,11 +24,11 @@ * 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 mage.abilities.Ability; +import mage.abilities.SpellAbility; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCosts; @@ -45,61 +45,67 @@ import mage.watchers.common.MiracleWatcher; /** * 702.92. Miracle * - * 702.92a Miracle is a static ability linked to a triggered ability (see rule 603.10). - * "Miracle [cost]" means "You may reveal this card from your hand as you draw it if - * it's the first card you've drawn this turn. When you reveal this card this way, - * you may cast it by paying [cost] rather than its mana cost." + * 702.92a Miracle is a static ability linked to a triggered ability (see rule + * 603.10). "Miracle [cost]" means "You may reveal this card from your hand as + * you draw it if it's the first card you've drawn this turn. When you reveal + * this card this way, you may cast it by paying [cost] rather than its mana + * cost." * - * 702.92b If a player chooses to reveal a card using its miracle ability, he or she - * plays with that card revealed until that card leaves his or her hand, that ability - * resolves, or that ability otherwise leaves the stack. + * 702.92b If a player chooses to reveal a card using its miracle ability, he or + * she plays with that card revealed until that card leaves his or her hand, + * that ability resolves, or that ability otherwise leaves the stack. * - * You can cast a card for its miracle cost only as the miracle triggered ability resolves. - * If you don't want to cast it at that time (or you can't cast it, perhaps because - * there are no legal targets available), you won't be able to cast it later for the miracle cost. + * You can cast a card for its miracle cost only as the miracle triggered + * ability resolves. If you don't want to cast it at that time (or you can't + * cast it, perhaps because there are no legal targets available), you won't be + * able to cast it later for the miracle cost. * - * RULINGS: - * You still draw the card, whether you use the miracle ability or not. Any ability that - * triggers whenever you draw a card, for example, will trigger. If you don't cast the card - * using its miracle ability, it will remain in your hand. + * RULINGS: You still draw the card, whether you use the miracle ability or not. + * Any ability that triggers whenever you draw a card, for example, will + * trigger. If you don't cast the card using its miracle ability, it will remain + * in your hand. * - * You can reveal and cast a card with miracle on any turn, not just your own, if it's the - * first card you've drawn that turn. + * You can reveal and cast a card with miracle on any turn, not just your own, + * if it's the first card you've drawn that turn. * - * You don't have to reveal a drawn card with miracle if you don't wish to cast it at that time. + * You don't have to reveal a drawn card with miracle if you don't wish to cast + * it at that time. * - * You can cast a card for its miracle cost only as the miracle triggered ability resolves. - * If you don't want to cast it at that time (or you can't cast it, perhaps because there are - * no legal targets available), you won't be able to cast it later for the miracle cost. + * You can cast a card for its miracle cost only as the miracle triggered + * ability resolves. If you don't want to cast it at that time (or you can't + * cast it, perhaps because there are no legal targets available), you won't be + * able to cast it later for the miracle cost. * - * You cast the card with miracle during the resolution of the triggered ability. Ignore any timing - * restrictions based on the card's type. + * You cast the card with miracle during the resolution of the triggered + * ability. Ignore any timing restrictions based on the card's type. * - * It's important to reveal a card with miracle before it is mixed with the other cards in your hand. + * It's important to reveal a card with miracle before it is mixed with the + * other cards in your hand. * - * Multiple card draws are always treated as a sequence of individual card draws. For example, if - * you haven't drawn any cards yet during a turn and cast a spell that instructs you to draw three - * cards, you'll draw them one at a time. Only the first card drawn this way may be revealed and cast - * using its miracle ability. + * Multiple card draws are always treated as a sequence of individual card + * draws. For example, if you haven't drawn any cards yet during a turn and cast + * a spell that instructs you to draw three cards, you'll draw them one at a + * time. Only the first card drawn this way may be revealed and cast using its + * miracle ability. * - * If the card with miracle leaves your hand before the triggered ability resolves, you won't be able - * to cast it using its miracle ability. + * If the card with miracle leaves your hand before the triggered ability + * resolves, you won't be able to cast it using its miracle ability. * - * You draw your opening hand before any turn begins. Cards you draw for your opening hand - * can't be cast using miracle. + * You draw your opening hand before any turn begins. Cards you draw for your + * opening hand can't be cast using miracle. * * @author noxx, LevelX2 */ - public class MiracleAbility extends TriggeredAbilityImpl { + private static final String staticRule = " (You may cast this card for its miracle cost when you draw it if it's the first card you drew this turn.)"; private String ruleText; @SuppressWarnings("unchecked") public MiracleAbility(Card card, ManaCosts miracleCosts) { - super(Zone.HAND, new MiracleEffect((ManaCosts)miracleCosts), true); - addWatcher(new MiracleWatcher()); - ruleText = "Miracle " + miracleCosts.getText() + staticRule; + super(Zone.HAND, new MiracleEffect((ManaCosts) miracleCosts), true); + addWatcher(new MiracleWatcher()); + ruleText = "Miracle " + miracleCosts.getText() + staticRule; } public MiracleAbility(final MiracleAbility ability) { @@ -161,17 +167,12 @@ class MiracleEffect extends OneShotEffect { // use target pointer here, so it's the same card that triggered the event (not gone back to library e.g.) Card card = game.getCard(getTargetPointer().getFirst(game, source)); if (controller != null && card != null) { - ManaCosts costRef = card.getSpellAbility().getManaCostsToPay(); + SpellAbility abilityToCast = card.getSpellAbility().copy(); + ManaCosts costRef = abilityToCast.getManaCostsToPay(); // replace with the new cost costRef.clear(); costRef.add(miracleCosts); - controller.cast(card.getSpellAbility(), game, false); - - // Reset the casting costs (in case the player cancels cast and plays the card later) - costRef.clear(); - for (ManaCost manaCost : card.getSpellAbility().getManaCosts()) { - costRef.add(manaCost); - } + controller.cast(abilityToCast, game, false); return true; } return false; diff --git a/Mage/src/main/java/mage/filter/StaticFilters.java b/Mage/src/main/java/mage/filter/StaticFilters.java index e6ccc996578..a9894b4f590 100644 --- a/Mage/src/main/java/mage/filter/StaticFilters.java +++ b/Mage/src/main/java/mage/filter/StaticFilters.java @@ -179,13 +179,13 @@ public final class StaticFilters { static { FILTER_CONTROLLED_CREATURE.setLockedFilter(true); - } + } public static final FilterControlledCreaturePermanent FILTER_CONTROLLED_CREATURES = new FilterControlledCreaturePermanent("creatures you control"); static { FILTER_CONTROLLED_CREATURES.setLockedFilter(true); } - + public static final FilterControlledCreaturePermanent FILTER_CONTROLLED_A_CREATURE = new FilterControlledCreaturePermanent("a creature you control"); static { @@ -210,11 +210,15 @@ public final class StaticFilters { static { FILTER_LAND.setLockedFilter(true); } + public static final FilterLandPermanent FILTER_LANDS = new FilterLandPermanent("lands"); static { FILTER_LANDS.setLockedFilter(true); } + + public static final FilterLandPermanent FILTER_LANDS_NONBASIC = FilterLandPermanent.nonbasicLands(); + public static final FilterBasicLandCard FILTER_BASIC_LAND_CARD = new FilterBasicLandCard(); static {