diff --git a/Mage.Client/plugins/mage-card-plugin.jar b/Mage.Client/plugins/mage-card-plugin.jar index cf8452b5b0d..9c662a1e057 100644 Binary files a/Mage.Client/plugins/mage-card-plugin.jar and b/Mage.Client/plugins/mage-card-plugin.jar differ diff --git a/Mage.Client/src/main/java/mage/client/MageFrame.java b/Mage.Client/src/main/java/mage/client/MageFrame.java index c8bc92ee21c..91c5bb73ed5 100644 --- a/Mage.Client/src/main/java/mage/client/MageFrame.java +++ b/Mage.Client/src/main/java/mage/client/MageFrame.java @@ -50,23 +50,17 @@ import java.util.logging.Logger; import java.util.prefs.Preferences; import javax.imageio.ImageIO; -import javax.swing.Box; -import javax.swing.ImageIcon; -import javax.swing.JButton; -import javax.swing.JComponent; -import javax.swing.JDesktopPane; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JLayeredPane; -import javax.swing.JOptionPane; -import javax.swing.JPanel; +import javax.swing.*; import javax.swing.JToolBar.Separator; -import javax.swing.SwingUtilities; -import javax.swing.UIManager; +import com.sun.java.swing.Painter; +import mage.cards.decks.Deck; import mage.client.cards.CardsStorage; import mage.client.components.MageComponents; +import mage.client.components.MageJDesktop; +import mage.client.components.MageRoundPane; import mage.client.components.arcane.ManaSymbols; +import mage.client.constants.Constants.DeckEditorMode; import mage.client.dialog.*; import mage.client.plugins.impl.Plugins; import mage.client.remote.Session; @@ -122,7 +116,8 @@ public class MageFrame extends javax.swing.JFrame { }); try { - UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"); + UIManager.put("desktop", new Color(0,0,0,0)); + UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"); //MageSynthStyleFactory f = new MageSynthStyleFactory(SynthLookAndFeel.getStyleFactory()); //SynthLookAndFeel.setStyleFactory(f); } catch (Exception ex) { @@ -145,61 +140,13 @@ public class MageFrame extends javax.swing.JFrame { desktopPane.add(pickNumber, JLayeredPane.POPUP_LAYER); session.getUI().addComponent(MageComponents.DESKTOP_PANE, desktopPane); - JComponent cardInfoPane = Plugins.getInstance().getCardInfoPane(); - cardInfoPane.setSize(161, 221); - cardInfoPane.setPreferredSize(new Dimension(161, 221)); - cardInfoPane.setVisible(false); - session.getUI().addComponent(MageComponents.CARD_INFO_PANE, cardInfoPane); - desktopPane.add(cardInfoPane, JLayeredPane.POPUP_LAYER); - ManaSymbols.loadImages(); - String filename = "/background.jpg"; - try { - if (Plugins.getInstance().isThemePluginLoaded()) { - Map ui = new HashMap(); - backgroundPane = (ImagePanel) Plugins.getInstance().updateTablePanel(ui); - } else { - InputStream is = this.getClass().getResourceAsStream(filename); - BufferedImage background = ImageIO.read(is); - backgroundPane = new ImagePanel(background, ImagePanel.SCALED); - } - backgroundPane.setSize(1024, 768); - desktopPane.add(backgroundPane, JLayeredPane.DEFAULT_LAYER); - } catch (IOException e) { - e.printStackTrace(); - } - - filename = "/label-mage.png"; - try { - InputStream is = this.getClass().getResourceAsStream(filename); - - float ratio = 1179.0f / 678.0f; - titleRectangle = new Rectangle(640, (int)(640 / ratio)); - if (is != null) { - BufferedImage image = ImageIO.read(is); - //ImageIcon resized = new ImageIcon(image.getScaledInstance(titleRectangle.width, titleRectangle.height, java.awt.Image.SCALE_SMOOTH)); - title = new JLabel(); - title.setIcon(new ImageIcon(image)); - backgroundPane.setLayout(null); - backgroundPane.add(title); - } - } catch (IOException e) { - e.printStackTrace(); - } - - filename = "/icon-mage.png"; - try { - InputStream is = this.getClass().getResourceAsStream(filename); - - if (is != null) { - BufferedImage image = ImageIO.read(is); - setIconImage(image); - } - } catch (IOException e) { - e.printStackTrace(); - } - + addTooltipContainer(); + setBackground(); + addMageLabel(); + setAppIcon(); + desktopPane.add(ArrowBuilder.getArrowsPanel(), JLayeredPane.DRAG_LAYER); desktopPane.addComponentListener(new ComponentAdapter(){ @@ -270,6 +217,77 @@ public class MageFrame extends javax.swing.JFrame { } }); } + + private void addTooltipContainer() { + final JEditorPane cardInfoPane = (JEditorPane) Plugins.getInstance().getCardInfoPane(); + cardInfoPane.setSize(320, 201); + cardInfoPane.setLocation(40, 40); + cardInfoPane.setBackground(new Color(0,0,0,0)); + + MageRoundPane popupContainer = new MageRoundPane(); + popupContainer.setLayout(null); + + popupContainer.add(cardInfoPane); + popupContainer.setVisible(false); + popupContainer.setBounds(0, 0, 320 + 80, 201 + 80); + + desktopPane.add(popupContainer, JLayeredPane.POPUP_LAYER); + + session.getUI().addComponent(MageComponents.CARD_INFO_PANE, cardInfoPane); + session.getUI().addComponent(MageComponents.POPUP_CONTAINER, popupContainer); + } + + private void setBackground() { + String filename = "/background.jpg"; + try { + if (Plugins.getInstance().isThemePluginLoaded()) { + Map ui = new HashMap(); + backgroundPane = (ImagePanel) Plugins.getInstance().updateTablePanel(ui); + } else { + InputStream is = this.getClass().getResourceAsStream(filename); + BufferedImage background = ImageIO.read(is); + backgroundPane = new ImagePanel(background, ImagePanel.SCALED); + } + backgroundPane.setSize(1024, 768); + desktopPane.add(backgroundPane, JLayeredPane.DEFAULT_LAYER); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void addMageLabel() { + String filename = "/label-mage.png"; + try { + InputStream is = this.getClass().getResourceAsStream(filename); + + float ratio = 1179.0f / 678.0f; + titleRectangle = new Rectangle(640, (int)(640 / ratio)); + if (is != null) { + BufferedImage image = ImageIO.read(is); + //ImageIcon resized = new ImageIcon(image.getScaledInstance(titleRectangle.width, titleRectangle.height, java.awt.Image.SCALE_SMOOTH)); + title = new JLabel(); + title.setIcon(new ImageIcon(image)); + backgroundPane.setLayout(null); + backgroundPane.add(title); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void setAppIcon() { + String filename = "/icon-mage.png"; + try { + InputStream is = this.getClass().getResourceAsStream(filename); + + if (is != null) { + BufferedImage image = ImageIO.read(is); + setIconImage(image); + } + } catch (IOException e) { + e.printStackTrace(); + } + } private void btnImagesActionPerformed(java.awt.event.ActionEvent evt) { Plugins.getInstance().downloadImage(CardsStorage.getAllCards()); @@ -337,7 +355,7 @@ public class MageFrame extends javax.swing.JFrame { // //GEN-BEGIN:initComponents private void initComponents() { - desktopPane = new javax.swing.JDesktopPane(); + desktopPane = new MageJDesktop(); tablesPane = new mage.client.table.TablesPane(); gamePane = new mage.client.game.GamePane(); deckEditorPane = new mage.client.deckeditor.DeckEditorPane(); @@ -486,11 +504,10 @@ public class MageFrame extends javax.swing.JFrame { private void btnDeckEditorActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnDeckEditorActionPerformed this.gamePane.setVisible(false); this.tablesPane.setVisible(false); - this.deckEditorPane.setVisible(true); - this.deckEditorPane.showTables(); + showDeckEditor(DeckEditorMode.Constructed, null, null); }//GEN-LAST:event_btnDeckEditorActionPerformed - private void btnPreferencesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnDeckEditorActionPerformed + private void btnPreferencesActionPerformed(java.awt.event.ActionEvent evt) { PhasesDialog.main(new String[]{}); } @@ -546,6 +563,11 @@ public class MageFrame extends javax.swing.JFrame { this.deckEditorPane.setVisible(false); } + public void showDeckEditor(DeckEditorMode mode, Deck deck, UUID tableId) { + this.deckEditorPane.setVisible(true); + this.deckEditorPane.show(mode, deck, tableId); + } + public static CombatDialog getCombatDialog() { return combat; } @@ -595,7 +617,7 @@ public class MageFrame extends javax.swing.JFrame { private javax.swing.JButton btnExit; private javax.swing.JButton btnGames; private mage.client.deckeditor.DeckEditorPane deckEditorPane; - private static javax.swing.JDesktopPane desktopPane; + private static MageJDesktop desktopPane; private mage.client.game.GamePane gamePane; private javax.swing.JToolBar.Separator jSeparator1; private javax.swing.JToolBar.Separator jSeparator2; diff --git a/Mage.Client/src/main/java/mage/client/components/MageComponents.java b/Mage.Client/src/main/java/mage/client/components/MageComponents.java index 3259cba94b6..1a8bce85d82 100644 --- a/Mage.Client/src/main/java/mage/client/components/MageComponents.java +++ b/Mage.Client/src/main/java/mage/client/components/MageComponents.java @@ -6,7 +6,8 @@ public enum MageComponents { NEW_TABLE_OK_BUTTON("btnOK"), TABLE_WAITING_START_BUTTON("btnStart"), DESKTOP_PANE("desktopPane"), - CARD_INFO_PANE("cardInfoPane"); + CARD_INFO_PANE("cardInfoPane"), + POPUP_CONTAINER("popupContainer"); private String name; MageComponents(String name) { diff --git a/Mage.Client/src/main/java/mage/client/components/MageJDesktop.java b/Mage.Client/src/main/java/mage/client/components/MageJDesktop.java new file mode 100644 index 00000000000..a73976844ec --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/components/MageJDesktop.java @@ -0,0 +1,34 @@ +package mage.client.components; + +import com.sun.java.swing.Painter; + +import javax.swing.*; +import java.awt.*; + +/** + * Overrides JDesktopPane settings for Nimbus LAF. + * + * @author nantuko + */ +public class MageJDesktop extends JDesktopPane { + + @Override + public void updateUI() { + if ("Nimbus".equals(UIManager.getLookAndFeel().getName())) { + UIDefaults map = new UIDefaults(); + Painter painter = new Painter() { + + Color color = null; + + @Override + public void paint(Graphics2D g, Object c, int w, int h) { + g.setColor(color == null ? UIManager.getDefaults().getColor("desktop") : color); + g.fillRect(0,0,w,h); + } + }; + map.put("DesktopPane[Enabled].backgroundPainter", painter); + putClientProperty("Nimbus.Overrides", map); + } + super.updateUI(); + } +} diff --git a/Mage.Client/src/main/java/mage/client/components/MageRoundPane.java b/Mage.Client/src/main/java/mage/client/components/MageRoundPane.java new file mode 100644 index 00000000000..1460445506d --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/components/MageRoundPane.java @@ -0,0 +1,97 @@ +package mage.client.components; + +import org.jdesktop.swingx.graphics.GraphicsUtilities; +import org.jdesktop.swingx.graphics.ShadowRenderer; + +import java.awt.*; +import java.awt.geom.Rectangle2D; +import java.awt.geom.RoundRectangle2D; +import java.awt.image.BufferedImage; + +import javax.swing.JPanel; + +/** + * Mage round pane with transparency. + * Used for tooltips. + * + * @author nantuko + */ +public class MageRoundPane extends JPanel { + + private static int X_OFFSET = 30; + private static int Y_OFFSET = 30; + private BufferedImage shadow = null; + private Color backgroundColor = new Color(255, 255, 255, 220); + private int alpha = 0; + + @Override + protected void paintComponent(Graphics g) { + int x = X_OFFSET; + int y = Y_OFFSET; + int w = getWidth() - 2 * X_OFFSET; + int h = getHeight() - 2 * Y_OFFSET; + int arc = 10; + + Graphics2D g2 = (Graphics2D) g.create(); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + if (shadow != null) { + int xOffset = (shadow.getWidth() - w) / 2; + int yOffset = (shadow.getHeight() - h) / 2; + g2.drawImage(shadow, x - xOffset, y - yOffset, null); + } + + ////////////////////////////////////////////////////////////////// + // fill content + + /** + * Add white translucent substrate + */ + /*if (alpha != 0) { + g2.setColor(new Color(255, 255, 255, alpha)); + g2.fillRoundRect(x, y, w, h, arc, arc); + }*/ + + g2.setColor(backgroundColor); + g2.fillRoundRect(x, y, w, h, arc, arc); + ////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////// + // draw border + g2.setStroke(new BasicStroke(1.5f)); + g2.setColor(Color.BLACK); + g2.drawRoundRect(x, y, w, h, arc, arc); + // //////////////////////////////////////////////////////////////// + + g2.dispose(); + } + + @Override + public void setBounds(int x, int y, int width, int height) { + super.setBounds(x, y, width, height); + + int w = getWidth() - 2 * X_OFFSET; + int h = getHeight() - 2 * Y_OFFSET; + int arc = 10; + int shadowSize = 50; + + shadow = GraphicsUtilities.createCompatibleTranslucentImage(w, h); + Graphics2D g2 = shadow.createGraphics(); + g2.setColor(Color.WHITE); + g2.fillRoundRect(0, 0, w, h, arc, arc); + g2.dispose(); + + ShadowRenderer renderer = new ShadowRenderer(shadowSize, 0.5f, + Color.GRAY); + shadow = renderer.createShadow(shadow); + } + + public void showDialog(boolean bShow) { + setVisible(bShow); + } + + /** + * Default UID. + */ + private static final long serialVersionUID = 1L; +} diff --git a/Mage.Client/src/main/java/mage/client/constants/Constants.java b/Mage.Client/src/main/java/mage/client/constants/Constants.java index 2804f8d751b..a91617ed202 100644 --- a/Mage.Client/src/main/java/mage/client/constants/Constants.java +++ b/Mage.Client/src/main/java/mage/client/constants/Constants.java @@ -82,4 +82,11 @@ public final class Constants { public static final String imageBaseDir = "plugins" + File.separator + "images" + File.separator; public static final String IMAGE_PROPERTIES_FILE = "image.url.properties"; } + + public enum DeckEditorMode { + Constructed, + Limited, + Sideboard + } + } diff --git a/Mage.Client/src/main/java/mage/client/deck/generator/DeckGenerator.java b/Mage.Client/src/main/java/mage/client/deck/generator/DeckGenerator.java index 4aaddd57fa6..fc01ce9129a 100644 --- a/Mage.Client/src/main/java/mage/client/deck/generator/DeckGenerator.java +++ b/Mage.Client/src/main/java/mage/client/deck/generator/DeckGenerator.java @@ -46,6 +46,8 @@ public class DeckGenerator { private static final int MIN_SOURCE = 16; private static final int MAX_NON_BASIC_SOURCE = DECK_LANDS / 2; + private static final boolean GENERATE_RANDOM_BASIC_LAND = true; + private static Deck deck = new Deck(); private static String manaSource; @@ -283,19 +285,19 @@ public class DeckGenerator { private static Card getBestBasicLand(ColoredManaSymbol color) { manaSource = color.toString(); if (color.equals(ColoredManaSymbol.G)) { - return CardImpl.createCard(Sets.findCard("Forest")); + return CardImpl.createCard(Sets.findCard("Forest", GENERATE_RANDOM_BASIC_LAND)); } if (color.equals(ColoredManaSymbol.R)) { - return CardImpl.createCard(Sets.findCard("Mountain")); + return CardImpl.createCard(Sets.findCard("Mountain", GENERATE_RANDOM_BASIC_LAND)); } if (color.equals(ColoredManaSymbol.B)) { - return CardImpl.createCard(Sets.findCard("Swamp")); + return CardImpl.createCard(Sets.findCard("Swamp", GENERATE_RANDOM_BASIC_LAND)); } if (color.equals(ColoredManaSymbol.U)) { - return CardImpl.createCard(Sets.findCard("Island")); + return CardImpl.createCard(Sets.findCard("Island", GENERATE_RANDOM_BASIC_LAND)); } if (color.equals(ColoredManaSymbol.W)) { - return CardImpl.createCard(Sets.findCard("Plains")); + return CardImpl.createCard(Sets.findCard("Plains", GENERATE_RANDOM_BASIC_LAND)); } return null; diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPane.form b/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPane.form index 69dff9f90b4..6f2e6897658 100644 --- a/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPane.form +++ b/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPane.form @@ -1,4 +1,4 @@ - +
diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPane.java b/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPane.java index 3a39ea23f7e..2d0b9ba46b1 100644 --- a/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPane.java +++ b/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPane.java @@ -37,10 +37,13 @@ package mage.client.deckeditor; import java.awt.Component; import java.util.HashMap; import java.util.Map; +import java.util.UUID; import javax.swing.JComponent; +import mage.cards.decks.Deck; import mage.client.MagePane; +import mage.client.constants.Constants.DeckEditorMode; import mage.client.plugins.impl.Plugins; /** @@ -70,8 +73,8 @@ public class DeckEditorPane extends MagePane { } } - public void showTables() { - this.deckEditorPanel1.showDeckEditor(); + public void show(DeckEditorMode mode, Deck deck, UUID tableId) { + this.deckEditorPanel1.showDeckEditor(mode, deck, tableId); this.repaint(); } diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPanel.java b/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPanel.java index 796d54fa3ce..dc571f9ef3b 100644 --- a/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPanel.java +++ b/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPanel.java @@ -36,7 +36,6 @@ package mage.client.deckeditor; import mage.cards.Card; import mage.cards.decks.Deck; -import mage.cards.decks.DeckCardLists; import mage.client.MageFrame; import mage.client.plugins.impl.Plugins; import mage.client.util.Event; @@ -49,14 +48,13 @@ import mage.view.CardsView; import javax.swing.*; import javax.swing.filechooser.FileFilter; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.io.File; import java.io.IOException; import java.lang.reflect.Constructor; import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; +import mage.client.constants.Constants.DeckEditorMode; import mage.sets.Sets; /** @@ -69,6 +67,7 @@ public class DeckEditorPanel extends javax.swing.JPanel { private JFileChooser fcImportDeck; private Deck deck = new Deck(); private boolean isShowCardInfo = false; + private UUID tableId; /** Creates new form DeckEditorPanel */ public DeckEditorPanel() { @@ -85,10 +84,18 @@ public class DeckEditorPanel extends javax.swing.JPanel { jSplitPane1.setOpaque(false); } - public void showDeckEditor() { + public void showDeckEditor(DeckEditorMode mode, Deck deck, UUID tableId) { + if (deck != null) + this.deck = deck; + this.tableId = tableId; + showDeckEditor(mode); + } + + public void showDeckEditor(DeckEditorMode mode) { this.cardSelector.loadCards(this.bigCard); this.cardSelector.setVisible(true); this.jPanel1.setVisible(true); + this.btnSubmit.setVisible(mode == DeckEditorMode.Sideboard); this.cardSelector.getCardsList().clearCardEventListeners(); this.cardSelector.getCardsList().addCardEventListener( new Listener () { @@ -132,6 +139,7 @@ public class DeckEditorPanel extends javax.swing.JPanel { } } ); + refreshDeck(); this.setVisible(true); this.repaint(); } @@ -172,6 +180,7 @@ public class DeckEditorPanel extends javax.swing.JPanel { btnNew = new javax.swing.JButton(); btnExit = new javax.swing.JButton(); btnImport = new javax.swing.JButton(); + btnSubmit = new javax.swing.JButton(); jSplitPane1.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT); jSplitPane1.setResizeWeight(0.5); @@ -229,7 +238,15 @@ public class DeckEditorPanel extends javax.swing.JPanel { } }); - javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); + btnSubmit.setText("Submit"); + btnSubmit.setName("btnSubmit"); // NOI18N + btnSubmit.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnSubmitActionPerformed(evt); + } + }); + + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); jPanel1.setLayout(jPanel1Layout); jPanel1Layout.setHorizontalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -253,7 +270,9 @@ public class DeckEditorPanel extends javax.swing.JPanel { .addComponent(btnExit)) .addGroup(jPanel1Layout.createSequentialGroup() .addContainerGap() - .addComponent(btnImport))) + .addComponent(btnImport) + .addContainerGap() + .addComponent(btnSubmit))) .addContainerGap()) ); jPanel1Layout.setVerticalGroup( @@ -270,7 +289,9 @@ public class DeckEditorPanel extends javax.swing.JPanel { .addComponent(btnNew) .addComponent(btnExit)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnImport) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(btnImport) + .addComponent(btnSubmit)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, isShowCardInfo ? 30 : 159, Short.MAX_VALUE) .addComponent(cardInfoPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(bigCard, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) @@ -383,6 +404,11 @@ public class DeckEditorPanel extends javax.swing.JPanel { fcImportDeck.setSelectedFile(null); }//GEN-LAST:event_btnImportActionPerformed + private void btnSubmitActionPerformed(java.awt.event.ActionEvent evt) { + MageFrame.getSession().submitDeck(tableId, deck.getDeckCardLists()); + this.setVisible(false); + } + public DeckImporter getDeckImporter(String file) { if (file.toLowerCase().endsWith("dec")) return new DecDeckImporter(); @@ -410,6 +436,7 @@ public class DeckEditorPanel extends javax.swing.JPanel { // End of variables declaration//GEN-END:variables private JComponent cardInfoPane; + private javax.swing.JButton btnSubmit; } class DeckFilter extends FileFilter { diff --git a/Mage.Client/src/main/java/mage/client/dialog/JoinTableDialog.java b/Mage.Client/src/main/java/mage/client/dialog/JoinTableDialog.java index bd6cc42bf66..8b7fe1c5e7e 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/JoinTableDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/JoinTableDialog.java @@ -138,7 +138,6 @@ public class JoinTableDialog extends MageDialog { private void btnOKActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnOKActionPerformed Session session = MageFrame.getSession(); try { - PhaseManager.getInstance().setName(this.newPlayerPanel.getPlayerName()); joined = session.joinTable(roomId, tableId, this.newPlayerPanel.getPlayerName(), Sets.loadDeck(this.newPlayerPanel.getDeckFile())); } catch (Exception ex) { handleError(ex); diff --git a/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.form b/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.form index 2d483f7a68d..8e8ddc4d639 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.form +++ b/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.form @@ -23,7 +23,7 @@ - + @@ -32,7 +32,7 @@ - + @@ -41,17 +41,22 @@ - + - + - + - + - + + + + + + @@ -61,34 +66,34 @@ - + - + - + - + - + - + @@ -105,25 +110,32 @@ - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - + - + - + @@ -132,21 +144,21 @@ - + - + - + - + @@ -260,5 +272,18 @@ + + + + + + + + + + + + + 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 b18a86b8549..557e4ea3420 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java @@ -53,6 +53,7 @@ import mage.client.remote.Session; import mage.client.table.TablePlayerPanel; import mage.client.util.Event; import mage.client.util.Listener; +import mage.game.match.MatchOptions; import mage.sets.Sets; import mage.util.Logging; import mage.view.GameTypeView; @@ -77,6 +78,7 @@ public class NewTableDialog extends MageDialog { /** Creates new form NewTableDialog */ public NewTableDialog() { initComponents(); + this.spnNumWins.setModel(new SpinnerNumberModel(1, 1, 5, 1)); } /** This method is called from within the constructor to @@ -107,6 +109,8 @@ public class NewTableDialog extends MageDialog { jLabel1 = new javax.swing.JLabel(); jSeparator3 = new javax.swing.JSeparator(); jLabel2 = new javax.swing.JLabel(); + lblNumWins = new javax.swing.JLabel(); + spnNumWins = new javax.swing.JSpinner(); setTitle("New Table"); @@ -157,12 +161,21 @@ public class NewTableDialog extends MageDialog { jLabel2.setFont(new java.awt.Font("Tahoma", 1, 11)); jLabel2.setText("Other Players"); + lblNumWins.setLabelFor(spnNumWins); + lblNumWins.setText("Wins"); + + spnNumWins.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + spnNumWinsnumPlayersChanged(evt); + } + }); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addContainerGap(358, Short.MAX_VALUE) + .addContainerGap(395, Short.MAX_VALUE) .addComponent(btnOK) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(btnCancel) @@ -170,7 +183,7 @@ public class NewTableDialog extends MageDialog { .addGroup(layout.createSequentialGroup() .addContainerGap() .addComponent(lbDeckType) - .addContainerGap(426, Short.MAX_VALUE)) + .addContainerGap(463, Short.MAX_VALUE)) .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) @@ -178,43 +191,47 @@ public class NewTableDialog extends MageDialog { .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(lblNumPlayers) - .addComponent(spnNumPlayers, javax.swing.GroupLayout.PREFERRED_SIZE, 90, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(18, 18, 18) + .addComponent(spnNumPlayers, javax.swing.GroupLayout.PREFERRED_SIZE, 57, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(lblRange) - .addComponent(cbRange, javax.swing.GroupLayout.PREFERRED_SIZE, 141, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(18, 18, 18) + .addComponent(cbRange, javax.swing.GroupLayout.PREFERRED_SIZE, 143, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(lblAttack) - .addComponent(cbAttackOption, javax.swing.GroupLayout.PREFERRED_SIZE, 199, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addComponent(cbAttackOption, 0, 235, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblNumWins))) .addComponent(lblGameType) .addComponent(cbDeckType, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addContainerGap() - .addComponent(jSeparator2, javax.swing.GroupLayout.DEFAULT_SIZE, 466, Short.MAX_VALUE) + .addComponent(jSeparator2, javax.swing.GroupLayout.DEFAULT_SIZE, 503, Short.MAX_VALUE) .addContainerGap()) .addGroup(layout.createSequentialGroup() .addContainerGap() .addComponent(jLabel1) - .addContainerGap(396, Short.MAX_VALUE)) + .addContainerGap(433, Short.MAX_VALUE)) .addGroup(layout.createSequentialGroup() .addContainerGap() - .addComponent(player1Panel, javax.swing.GroupLayout.DEFAULT_SIZE, 466, Short.MAX_VALUE) + .addComponent(player1Panel, javax.swing.GroupLayout.DEFAULT_SIZE, 503, Short.MAX_VALUE) .addContainerGap()) .addGroup(layout.createSequentialGroup() .addContainerGap() .addComponent(jLabel2) - .addContainerGap(399, Short.MAX_VALUE)) + .addContainerGap(436, Short.MAX_VALUE)) .addGroup(layout.createSequentialGroup() .addContainerGap() - .addComponent(jSeparator1, javax.swing.GroupLayout.DEFAULT_SIZE, 466, Short.MAX_VALUE) + .addComponent(jSeparator1, javax.swing.GroupLayout.DEFAULT_SIZE, 503, Short.MAX_VALUE) .addContainerGap()) .addComponent(pnlOtherPlayers, javax.swing.GroupLayout.PREFERRED_SIZE, 486, javax.swing.GroupLayout.PREFERRED_SIZE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() - .addComponent(jSeparator3, javax.swing.GroupLayout.DEFAULT_SIZE, 466, Short.MAX_VALUE) + .addComponent(jSeparator3, javax.swing.GroupLayout.DEFAULT_SIZE, 503, Short.MAX_VALUE) .addContainerGap())) ); layout.setVerticalGroup( @@ -229,19 +246,24 @@ public class NewTableDialog extends MageDialog { .addGap(0, 0, 0) .addComponent(cbGameType, 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.TRAILING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(layout.createSequentialGroup() + .addComponent(lblNumPlayers) + .addGap(0, 0, 0) + .addComponent(spnNumPlayers, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(lblRange) + .addGap(0, 0, 0) + .addComponent(cbRange, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(lblAttack) + .addGap(0, 0, 0) + .addComponent(cbAttackOption, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) .addGroup(layout.createSequentialGroup() - .addComponent(lblAttack) + .addComponent(lblNumWins) .addGap(0, 0, 0) - .addComponent(cbAttackOption, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() - .addComponent(lblNumPlayers) - .addGap(0, 0, 0) - .addComponent(spnNumPlayers, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() - .addComponent(lblRange) - .addGap(0, 0, 0) - .addComponent(cbRange, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jSeparator2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) @@ -251,19 +273,19 @@ public class NewTableDialog extends MageDialog { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(jLabel2) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(pnlOtherPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, 83, Short.MAX_VALUE) + .addComponent(pnlOtherPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, 97, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jSeparator1, javax.swing.GroupLayout.DEFAULT_SIZE, 4, Short.MAX_VALUE) + .addComponent(jSeparator1, javax.swing.GroupLayout.DEFAULT_SIZE, 19, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(btnCancel) .addComponent(btnOK)) - .addGap(0, 0, 0)) + .addGap(6, 6, 6)) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGap(223, 223, 223) .addComponent(jSeparator3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(149, Short.MAX_VALUE))) + .addContainerGap(159, Short.MAX_VALUE))) ); pack(); @@ -277,18 +299,16 @@ public class NewTableDialog extends MageDialog { private void btnOKActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnOKActionPerformed GameTypeView gameType = (GameTypeView) cbGameType.getSelectedItem(); - List playerTypes = new ArrayList(); - playerTypes.add("Human"); + MatchOptions options = new MatchOptions("Quick Start Game", gameType.getName()); + options.getPlayerTypes().add("Human"); for (TablePlayerPanel player: players) { - playerTypes.add(player.getPlayerType()); + options.getPlayerTypes().add(player.getPlayerType()); } - table = session.createTable( - roomId, - gameType.getName(), - (String)this.cbDeckType.getSelectedItem(), - playerTypes, - (MultiplayerAttackOption)this.cbAttackOption.getSelectedItem(), - (RangeOfInfluence)this.cbRange.getSelectedItem()); + options.setDeckType((String) this.cbDeckType.getSelectedItem()); + options.setAttackOption((MultiplayerAttackOption) this.cbAttackOption.getSelectedItem()); + options.setRange((RangeOfInfluence) this.cbRange.getSelectedItem()); + options.setWinsNeeded((Integer)this.spnNumWins.getValue()); + table = session.createTable(roomId, options); try { if (session.joinTable(roomId, table.getTableId(), this.player1Panel.getPlayerName(), Sets.loadDeck(this.player1Panel.getDeckFile()))) { for (TablePlayerPanel player: players) { @@ -325,6 +345,10 @@ public class NewTableDialog extends MageDialog { createPlayers(numPlayers); }//GEN-LAST:event_numPlayersChanged + private void spnNumWinsnumPlayersChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spnNumWinsnumPlayersChanged + // TODO add your handling code here: + }//GEN-LAST:event_spnNumWinsnumPlayersChanged + private void setGameOptions() { GameTypeView gameType = (GameTypeView) cbGameType.getSelectedItem(); this.spnNumPlayers.setModel(new SpinnerNumberModel(gameType.getMinPlayers(), gameType.getMinPlayers(), gameType.getMaxPlayers(), 1)); @@ -423,10 +447,12 @@ public class NewTableDialog extends MageDialog { private javax.swing.JLabel lblAttack; private javax.swing.JLabel lblGameType; private javax.swing.JLabel lblNumPlayers; + private javax.swing.JLabel lblNumWins; private javax.swing.JLabel lblRange; private mage.client.table.NewPlayerPanel player1Panel; private javax.swing.JPanel pnlOtherPlayers; private javax.swing.JSpinner spnNumPlayers; + private javax.swing.JSpinner spnNumWins; // End of variables declaration//GEN-END:variables } diff --git a/Mage.Client/src/main/java/mage/client/game/BattlefieldPanel.java b/Mage.Client/src/main/java/mage/client/game/BattlefieldPanel.java index 70551b3b346..349affb8d6c 100644 --- a/Mage.Client/src/main/java/mage/client/game/BattlefieldPanel.java +++ b/Mage.Client/src/main/java/mage/client/game/BattlefieldPanel.java @@ -96,14 +96,14 @@ public class BattlefieldPanel extends javax.swing.JLayeredPane { } public void update(Map battlefield) { - boolean changed = false; - + boolean changed = false; + + List permanentsToAdd = new ArrayList(); for (PermanentView permanent: battlefield.values()) { if (!permanents.containsKey(permanent.getId())) { - addPermanent(permanent); + permanentsToAdd.add(permanent); changed = true; - } - else { + } else { MagePermanent p = permanents.get(permanent.getId()); if (!changed) { int s1 = permanent.getAttachments() == null ? 0 : permanent.getAttachments().size(); @@ -115,10 +115,15 @@ public class BattlefieldPanel extends javax.swing.JLayeredPane { permanents.get(permanent.getId()).update(permanent); } } + int count = permanentsToAdd.size(); + for (PermanentView permanent : permanentsToAdd) { + addPermanent(permanent, count); + } + for (Iterator> i = permanents.entrySet().iterator(); i.hasNext();) { Entry entry = i.next(); if (!battlefield.containsKey(entry.getKey())) { - removePermanent(entry.getKey()); + removePermanent(entry.getKey(), 1); i.remove(); changed = true; } @@ -150,12 +155,12 @@ public class BattlefieldPanel extends javax.swing.JLayeredPane { repaint(); } - private void addPermanent(PermanentView permanent) { + private void addPermanent(PermanentView permanent, final int count) { final MagePermanent perm = Plugins.getInstance().getMagePermanent(permanent, bigCard, Config.dimensions, gameId); if (!Plugins.getInstance().isCardPluginLoaded()) { perm.setBounds(findEmptySpace(new Dimension(Config.dimensions.frameWidth, Config.dimensions.frameHeight))); } else { - perm.setAlpha(0); + //perm.setAlpha(0); } permanents.put(permanent.getId(), perm); @@ -164,15 +169,16 @@ public class BattlefieldPanel extends javax.swing.JLayeredPane { moveToFront(perm); perm.update(permanent); } else { - Thread t = new Thread(new Runnable() { + Plugins.getInstance().onAddCard(perm, 1); + /*Thread t = new Thread(new Runnable() { @Override public void run() { - Plugins.getInstance().onAddCard(perm); + Plugins.getInstance().onAddCard(perm, count); } }); synchronized (this) { threads.add(t); - } + }*/ } } @@ -208,7 +214,7 @@ public class BattlefieldPanel extends javax.swing.JLayeredPane { } - private void removePermanent(UUID permanentId) { + private void removePermanent(UUID permanentId, final int count) { for (Component c: this.getComponents()) { final Component comp = c; if (comp instanceof Permanent) { @@ -220,7 +226,7 @@ public class BattlefieldPanel extends javax.swing.JLayeredPane { Thread t = new Thread(new Runnable() { @Override public void run() { - Plugins.getInstance().onRemoveCard((MagePermanent)comp); + Plugins.getInstance().onRemoveCard((MagePermanent)comp, count); BattlefieldPanel.this.remove(comp); } }); diff --git a/Mage.Client/src/main/java/mage/client/plugins/MagePlugins.java b/Mage.Client/src/main/java/mage/client/plugins/MagePlugins.java index 61807e13ed9..e2fb11d6719 100644 --- a/Mage.Client/src/main/java/mage/client/plugins/MagePlugins.java +++ b/Mage.Client/src/main/java/mage/client/plugins/MagePlugins.java @@ -32,7 +32,7 @@ public interface MagePlugins { int getGamesPlayed(); void addGamesPlayed(); Image getManaSymbolImage(String symbol); - void onAddCard(MagePermanent card); - void onRemoveCard(MagePermanent card); + void onAddCard(MagePermanent card, int count); + void onRemoveCard(MagePermanent card, int count); JComponent getCardInfoPane(); } 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 089dae89e3f..d1cabb2ffdb 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 @@ -4,6 +4,7 @@ import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; +import java.io.InterruptedIOException; import java.util.List; import java.util.UUID; @@ -16,6 +17,7 @@ import mage.cards.action.TransferData; import mage.client.MageFrame; import mage.client.cards.BigCard; import mage.client.components.MageComponents; +import mage.client.components.MageRoundPane; import mage.client.game.PlayAreaPanel; import mage.client.plugins.impl.Plugins; import mage.client.remote.Session; @@ -31,95 +33,95 @@ import org.jdesktop.swingx.JXPanel; public class MageActionCallback implements ActionCallback { - private Popup popup; + private Popup popup; private JPopupMenu jPopupMenu; - private BigCard bigCard; - protected static DefaultActionCallback defaultCallback = DefaultActionCallback.getInstance(); - protected static Session session = MageFrame.getSession(); - private CardView popupCard; - private Thread t; - private int state = 0; + private BigCard bigCard; + protected static DefaultActionCallback defaultCallback = DefaultActionCallback.getInstance(); + protected static Session session = MageFrame.getSession(); + private CardView popupCard; + private Thread t; + private int state = 0; private JComponent cardInfoPane; - - public MageActionCallback() { - } - - public void setCardPreviewComponent(BigCard bigCard) { - this.bigCard = bigCard; - } - - public void refreshSession() { - if (session == null) { - session = MageFrame.getSession(); - } + + public MageActionCallback() { + } + + public void setCardPreviewComponent(BigCard bigCard) { + this.bigCard = bigCard; + } + + public void refreshSession() { + if (session == null) { + session = MageFrame.getSession(); + } if (cardInfoPane == null) { cardInfoPane = Plugins.getInstance().getCardInfoPane(); } - } - - @Override - public void mouseClicked(MouseEvent e, TransferData data) { - } - - @Override - public void mousePressed(MouseEvent e, TransferData data) { - data.component.requestFocusInWindow(); - defaultCallback.mouseClicked(e, data.gameId, session, data.card); - } + } - @Override - public void mouseEntered(MouseEvent e, final TransferData data) { - hidePopup(); + @Override + public void mouseClicked(MouseEvent e, TransferData data) { + } + + @Override + public void mousePressed(MouseEvent e, TransferData data) { + data.component.requestFocusInWindow(); + defaultCallback.mouseClicked(e, data.gameId, session, data.card); + } + + @Override + public void mouseEntered(MouseEvent e, final TransferData data) { + hidePopup(); this.popupCard = data.card; Component parentComponent = SwingUtilities.getRoot(data.component); Point parentPoint = parentComponent.getLocationOnScreen(); - // Draw Arrows for targets - List targets = data.card.getTargets(); - if (targets != null) { - Point me = new Point(data.locationOnScreen); - me.translate(-parentPoint.x, -parentPoint.y); - for (UUID uuid : targets) { - //System.out.println("Getting play area panel for uuid: " + uuid); - - PlayAreaPanel p = session.getGame().getPlayers().get(uuid); - if (p != null) { - Point target = p.getLocationOnScreen(); - target.translate(-parentPoint.x, -parentPoint.y); - ArrowBuilder.addArrow((int)me.getX() + 35, (int)me.getY(), (int)target.getX() + 40, (int)target.getY() - 40, Color.red); - } else { - for (PlayAreaPanel pa : session.getGame().getPlayers().values()) { - MagePermanent permanent = pa.getBattlefieldPanel().getPermanents().get(uuid); - if (permanent != null) { - Point target = permanent.getLocationOnScreen(); - target.translate(-parentPoint.x, -parentPoint.y); - ArrowBuilder.addArrow((int)me.getX() + 35, (int)me.getY(), (int)target.getX() + 40, (int)target.getY() + 10, Color.red); - } - } - } - } - } - - // Draw Arrows for source - if (data.card.isAbility()) { - Point me = new Point(data.locationOnScreen); - me.translate(-parentPoint.x, -parentPoint.y); - UUID uuid = data.card.getParentId(); - for (PlayAreaPanel pa : session.getGame().getPlayers().values()) { - MagePermanent permanent = pa.getBattlefieldPanel().getPermanents().get(uuid); - if (permanent != null) { - Point source = permanent.getLocationOnScreen(); - source.translate(-parentPoint.x, -parentPoint.y); - ArrowBuilder.addArrow((int)source.getX() + 40, (int)source.getY() + 10, (int)me.getX() + 35, (int)me.getY() + 20, Color.blue); - } - } - } - - showPopup(data, parentComponent, parentPoint); - } + // Draw Arrows for targets + List targets = data.card.getTargets(); + if (targets != null) { + Point me = new Point(data.locationOnScreen); + me.translate(-parentPoint.x, -parentPoint.y); + for (UUID uuid : targets) { + //System.out.println("Getting play area panel for uuid: " + uuid); - private void showPopup(final TransferData data, final Component parentComponent, final Point parentPoint) { + PlayAreaPanel p = session.getGame().getPlayers().get(uuid); + if (p != null) { + Point target = p.getLocationOnScreen(); + target.translate(-parentPoint.x, -parentPoint.y); + ArrowBuilder.addArrow((int) me.getX() + 35, (int) me.getY(), (int) target.getX() + 40, (int) target.getY() - 40, Color.red); + } else { + for (PlayAreaPanel pa : session.getGame().getPlayers().values()) { + MagePermanent permanent = pa.getBattlefieldPanel().getPermanents().get(uuid); + if (permanent != null) { + Point target = permanent.getLocationOnScreen(); + target.translate(-parentPoint.x, -parentPoint.y); + ArrowBuilder.addArrow((int) me.getX() + 35, (int) me.getY(), (int) target.getX() + 40, (int) target.getY() + 10, Color.red); + } + } + } + } + } + + // Draw Arrows for source + if (data.card.isAbility()) { + Point me = new Point(data.locationOnScreen); + me.translate(-parentPoint.x, -parentPoint.y); + UUID uuid = data.card.getParentId(); + for (PlayAreaPanel pa : session.getGame().getPlayers().values()) { + MagePermanent permanent = pa.getBattlefieldPanel().getPermanents().get(uuid); + if (permanent != null) { + Point source = permanent.getLocationOnScreen(); + source.translate(-parentPoint.x, -parentPoint.y); + ArrowBuilder.addArrow((int) source.getX() + 40, (int) source.getY() + 10, (int) me.getX() + 35, (int) me.getY() + 20, Color.blue); + } + } + } + + showPopup(data, parentComponent, parentPoint); + } + + private void showPopup(final TransferData data, final Component parentComponent, final Point parentPoint) { if (cardInfoPane == null) { PopupFactory factory = PopupFactory.getSharedInstance(); popup = factory.getPopup(data.component, data.popupText, (int) data.locationOnScreen.getX() + data.popupOffsetX, (int) data.locationOnScreen.getY() + data.popupOffsetY + 40); @@ -133,72 +135,73 @@ public class MageActionCallback implements ActionCallback { ThreadUtils.threadPool2.submit(new Runnable() { @Override public void run() { - ThreadUtils.threadPool2.submit(new Runnable() { - @Override - public void run() { - ThreadUtils.sleep(700); + ThreadUtils.sleep(700); - if (!popupCard.equals(data.card)) { - return; - } + if (!popupCard.equals(data.card)) { + return; + } - /*PopupFactory factory = PopupFactory.getSharedInstance(); - ((CardInfoPane)cardInfoPane).setCard(data.card); - cardInfoPane.setSize(161, 221); - cardInfoPane.setPreferredSize(new Dimension(161, 221)); - popup = factory.getPopup(data.component, cardInfoPane, (int) data.locationOnScreen.getX() + data.popupOffsetX, (int) data.locationOnScreen.getY() + data.popupOffsetY + 40); - popup.show(); - */ - - try { - Component popup2 = session.getUI().getComponent(MageComponents.CARD_INFO_PANE); - ((CardInfoPane)popup2).setCard(data.card); - Point location = new Point((int) data.locationOnScreen.getX() + data.popupOffsetX, (int) data.locationOnScreen.getY() + data.popupOffsetY + 40); - location = GuiDisplayUtil.keepComponentInsideParent(location, parentPoint, popup2, parentComponent); - location.translate(-parentPoint.x, -parentPoint.y); - popup2.setLocation(location); - ThreadUtils.sleep(200); - popup2.setVisible(true); - } catch (Exception e) { - e.printStackTrace(); + try { + final Component popupContainer = session.getUI().getComponent(MageComponents.POPUP_CONTAINER); + Component popup2 = session.getUI().getComponent(MageComponents.CARD_INFO_PANE); + ((CardInfoPane) popup2).setCard(data.card); + Point location = new Point((int) data.locationOnScreen.getX() + data.popupOffsetX - 40, (int) data.locationOnScreen.getY() + data.popupOffsetY - 40); + location = GuiDisplayUtil.keepComponentInsideParent(location, parentPoint, popup2, parentComponent); + location.translate(-parentPoint.x, -parentPoint.y); + popupContainer.setLocation(location); + ThreadUtils.sleep(200); + final Component c = session.getUI().getComponent(MageComponents.DESKTOP_PANE); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + popupContainer.setVisible(true); + c.repaint(); } } - }); + ); + } catch (Exception e) { + e.printStackTrace(); + } } }); } } - - @Override - public void mouseMoved(MouseEvent e, TransferData data) { - if (!Plugins.getInstance().isCardPluginLoaded()) {return;} - if (bigCard == null) {return;} - MageCard card = (MageCard) data.component; - if (card.getOriginal().getId() != bigCard.getCardId()) { - synchronized (MageActionCallback.class) { - if (card.getOriginal().getId() != bigCard.getCardId()) { - Image image = card.getImage(); - if (image != null && image instanceof BufferedImage) { - image = ImageHelper.getResizedImage((BufferedImage) image, bigCard.getWidth(), bigCard.getHeight()); - bigCard.setCard(card.getOriginal().getId(), image, card.getOriginal().getRules()); - bigCard.showTextComponent(); - if (card.getOriginal().isAbility()) { - bigCard.showTextComponent(); - } else { - bigCard.hideTextComponent(); - }; - } else { - JXPanel panel = GuiDisplayUtil.getDescription(card.getOriginal(), bigCard.getWidth(), bigCard.getHeight()); - panel.setVisible(true); - bigCard.hideTextComponent(); - bigCard.addJXPanel(card.getOriginal().getId(), panel); - } - } - } - } - } + @Override + public void mouseMoved(MouseEvent e, TransferData data) { + if (!Plugins.getInstance().isCardPluginLoaded()) { + return; + } + if (bigCard == null) { + return; + } + + MageCard card = (MageCard) data.component; + if (card.getOriginal().getId() != bigCard.getCardId()) { + synchronized (MageActionCallback.class) { + if (card.getOriginal().getId() != bigCard.getCardId()) { + Image image = card.getImage(); + if (image != null && image instanceof BufferedImage) { + image = ImageHelper.getResizedImage((BufferedImage) image, bigCard.getWidth(), bigCard.getHeight()); + bigCard.setCard(card.getOriginal().getId(), image, card.getOriginal().getRules()); + bigCard.showTextComponent(); + if (card.getOriginal().isAbility()) { + bigCard.showTextComponent(); + } else { + bigCard.hideTextComponent(); + } + ; + } else { + JXPanel panel = GuiDisplayUtil.getDescription(card.getOriginal(), bigCard.getWidth(), bigCard.getHeight()); + panel.setVisible(true); + bigCard.hideTextComponent(); + bigCard.addJXPanel(card.getOriginal().getId(), panel); + } + } + } + } + } private void hidePopup() { this.popupCard = null; @@ -209,17 +212,17 @@ public class MageActionCallback implements ActionCallback { jPopupMenu.setVisible(false); } try { - Component popup2 = session.getUI().getComponent(MageComponents.CARD_INFO_PANE); - popup2.setVisible(false); + Component popupContainer = session.getUI().getComponent(MageComponents.POPUP_CONTAINER); + popupContainer.setVisible(false); } catch (Exception e2) { - e2.printStackTrace();; + e2.printStackTrace(); } } - @Override - public void mouseExited(MouseEvent e, final TransferData data) { + @Override + public void mouseExited(MouseEvent e, final TransferData data) { hidePopup(); - ArrowBuilder.removeAllArrows(); - } + ArrowBuilder.removeAllArrows(); + } } diff --git a/Mage.Client/src/main/java/mage/client/plugins/impl/Plugins.java b/Mage.Client/src/main/java/mage/client/plugins/impl/Plugins.java index eef3fa4139e..8b999ea4a16 100644 --- a/Mage.Client/src/main/java/mage/client/plugins/impl/Plugins.java +++ b/Mage.Client/src/main/java/mage/client/plugins/impl/Plugins.java @@ -169,16 +169,16 @@ public class Plugins implements MagePlugins { } @Override - public void onAddCard(MagePermanent card) { + public void onAddCard(MagePermanent card, int count) { if (this.cardPlugin != null) { - this.cardPlugin.onAddCard(card); + this.cardPlugin.onAddCard(card, count); } } @Override - public void onRemoveCard(MagePermanent card) { + public void onRemoveCard(MagePermanent card, int count) { if (this.cardPlugin != null) { - this.cardPlugin.onRemoveCard(card); + this.cardPlugin.onRemoveCard(card, count); } } diff --git a/Mage.Client/src/main/java/mage/client/remote/Client.java b/Mage.Client/src/main/java/mage/client/remote/Client.java index 23623b818ea..37cde55fadb 100644 --- a/Mage.Client/src/main/java/mage/client/remote/Client.java +++ b/Mage.Client/src/main/java/mage/client/remote/Client.java @@ -33,9 +33,12 @@ import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JOptionPane; +import mage.cards.decks.Deck; import mage.client.MageFrame; import mage.client.chat.ChatPanel; +import mage.client.constants.Constants.DeckEditorMode; import mage.client.plugins.impl.Plugins; +import mage.client.util.GameManager; import mage.interfaces.callback.CallbackClient; import mage.interfaces.callback.ClientCallback; import mage.util.Logging; @@ -43,6 +46,7 @@ import mage.view.AbilityPickerView; import mage.view.ChatMessage; import mage.view.GameClientMessage; import mage.view.GameView; +import mage.view.TableClientMessage; /** * @@ -72,8 +76,9 @@ public class Client implements CallbackClient { logger.info(callback.getMessageId() + " - " + callback.getMethod()); try { if (callback.getMethod().equals("startGame")) { - UUID[] data = (UUID[]) callback.getData(); - gameStarted(data[0], data[1]); + TableClientMessage message = (TableClientMessage) callback.getData(); + GameManager.getInstance().setCurrentPlayerUUID(message.getPlayerId()); + gameStarted(message.getGameId(), message.getPlayerId()); } else if (callback.getMethod().equals("replayGame")) { replayGame(); @@ -152,6 +157,10 @@ public class Client implements CallbackClient { logger.warning("message out of sequence - ignoring"); } } + else if (callback.getMethod().equals("sideboard")) { + TableClientMessage message = (TableClientMessage) callback.getData(); + sideboard(message.getDeck(), message.getTableId()); + } messageId = callback.getMessageId(); } catch (Exception ex) { @@ -197,6 +206,10 @@ public class Client implements CallbackClient { } } + protected void sideboard(Deck deck, UUID tableId) { + frame.showDeckEditor(DeckEditorMode.Sideboard, deck, tableId); + } + private void handleException(Exception ex) { logger.log(Level.SEVERE, "Client error\n", ex); JOptionPane.showMessageDialog(MageFrame.getDesktop(), "Unrecoverable client error. Disconnecting", "Error", JOptionPane.ERROR_MESSAGE); diff --git a/Mage.Client/src/main/java/mage/client/remote/Session.java b/Mage.Client/src/main/java/mage/client/remote/Session.java index af7841411d8..c3330228f85 100644 --- a/Mage.Client/src/main/java/mage/client/remote/Session.java +++ b/Mage.Client/src/main/java/mage/client/remote/Session.java @@ -40,8 +40,6 @@ import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JOptionPane; -import mage.Constants.MultiplayerAttackOption; -import mage.Constants.RangeOfInfluence; import mage.cards.decks.DeckCardLists; import mage.client.MageFrame; import mage.client.chat.ChatPanel; @@ -50,6 +48,7 @@ import mage.client.game.GamePanel; import mage.client.util.Config; import mage.game.GameException; import mage.interfaces.MageException; +import mage.game.match.MatchOptions; import mage.interfaces.Server; import mage.interfaces.ServerState; import mage.interfaces.callback.CallbackClientDaemon; @@ -396,9 +395,9 @@ public class Session { return false; } - public TableView createTable(UUID roomId, String gameType, String deckType, List playerTypes, MultiplayerAttackOption attackOption, RangeOfInfluence range) { + public TableView createTable(UUID roomId, MatchOptions matchOptions) { try { - return server.createTable(sessionId, roomId, gameType, deckType, playerTypes, attackOption, range); + return server.createTable(sessionId, roomId, matchOptions); } catch (RemoteException ex) { handleRemoteException(ex); } catch (MageException ex) { @@ -456,7 +455,7 @@ public class Session { public boolean startGame(UUID roomId, UUID tableId) { try { - server.startGame(sessionId, roomId, tableId); + server.startMatch(sessionId, roomId, tableId); return true; } catch (RemoteException ex) { handleRemoteException(ex); @@ -466,6 +465,20 @@ public class Session { return false; } + public boolean submitDeck(UUID tableId, DeckCardLists deck) { + try { + server.submitDeck(sessionId, tableId, deck); + return true; + } catch (RemoteException ex) { + handleRemoteException(ex); + } catch (MageException ex) { + handleMageException(ex); + } catch (GameException ex) { + handleGameException(ex); + } + return false; + } + public boolean concedeGame(UUID gameId) { try { server.concedeGame(gameId, sessionId); diff --git a/Mage.Client/src/main/java/mage/client/table/TablesPanel.java b/Mage.Client/src/main/java/mage/client/table/TablesPanel.java index 94f01af53ea..929c0facab9 100644 --- a/Mage.Client/src/main/java/mage/client/table/TablesPanel.java +++ b/Mage.Client/src/main/java/mage/client/table/TablesPanel.java @@ -37,9 +37,7 @@ package mage.client.table; import java.awt.Color; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Observable; import java.util.Observer; @@ -53,8 +51,9 @@ import javax.swing.JComponent; import javax.swing.JOptionPane; import javax.swing.Timer; import javax.swing.table.AbstractTableModel; +import mage.Constants.MultiplayerAttackOption; +import mage.Constants.RangeOfInfluence; -import mage.cards.decks.DeckCardLists; import mage.client.MageFrame; import mage.client.components.MageComponents; import mage.client.dialog.JoinTableDialog; @@ -63,6 +62,7 @@ import mage.client.dialog.TableWaitingDialog; import mage.client.remote.MageRemoteException; import mage.client.remote.Session; import mage.client.util.ButtonColumn; +import mage.game.match.MatchOptions; import mage.sets.Sets; import mage.util.Logging; import mage.view.TableView; @@ -280,16 +280,14 @@ public class TablesPanel extends javax.swing.JPanel implements Observer { private void btnQuickStartActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnQuickStartActionPerformed TableView table; try { - List playerTypes = new ArrayList(); - playerTypes.add("Human"); - playerTypes.add("Computer - default"); - table = session.createTable( - roomId, - "Two Player Duel", - "Constructed", - playerTypes, - null, null - ); + MatchOptions options = new MatchOptions("1", "Two Player Duel"); + options.getPlayerTypes().add("Human"); + options.getPlayerTypes().add("Computer - default"); + options.setDeckType("Limited"); + options.setAttackOption(MultiplayerAttackOption.LEFT); + options.setRange(RangeOfInfluence.ALL); + options.setWinsNeeded(1); + table = session.createTable(roomId, options); session.joinTable( roomId, table.getTableId(), diff --git a/Mage.Client/src/main/java/mage/client/util/GameManager.java b/Mage.Client/src/main/java/mage/client/util/GameManager.java index c7950a07fcf..047bb4acdc0 100644 --- a/Mage.Client/src/main/java/mage/client/util/GameManager.java +++ b/Mage.Client/src/main/java/mage/client/util/GameManager.java @@ -1,5 +1,7 @@ package mage.client.util; +import java.util.UUID; + /** * Controls game state on client side. * @@ -7,15 +9,27 @@ package mage.client.util; */ public class GameManager { private static GameManager fInstance = new GameManager(); + public static GameManager getInstance() { return fInstance; } + public void setStackSize(int stackSize) { this.stackSize = stackSize; } + public int getStackSize() { return stackSize; } + public UUID getCurrentPlayerUUID() { + return currentPlayerUUID; + } + + public void setCurrentPlayerUUID(UUID currentPlayerUUID) { + this.currentPlayerUUID = currentPlayerUUID; + } + private int stackSize; + private UUID currentPlayerUUID; } diff --git a/Mage.Client/src/main/java/mage/client/util/PhaseManager.java b/Mage.Client/src/main/java/mage/client/util/PhaseManager.java index 15e357d3fcc..7fee7768b36 100644 --- a/Mage.Client/src/main/java/mage/client/util/PhaseManager.java +++ b/Mage.Client/src/main/java/mage/client/util/PhaseManager.java @@ -2,9 +2,11 @@ package mage.client.util; import mage.client.MageFrame; import mage.view.GameView; +import mage.view.PlayerView; import java.util.HashMap; import java.util.Map; +import java.util.UUID; import java.util.prefs.Preferences; public class PhaseManager { @@ -51,21 +53,27 @@ public class PhaseManager { put("End Turn - play instants and activated abilities.", END_OF_TURN_OTHERS); }}; - private String yourName; - public static PhaseManager getInstance() { return fInstance; } - public void setName(String yourName) { - this.yourName = yourName; - } - public boolean isSkip(GameView gameView, String message) { if (GameManager.getInstance().getStackSize() > 0) { return false; } - Map map = gameView.getActivePlayerName().equals(DEFAULT_PLAYER_NAME) ? mapYou : mapOthers; + UUID activePlayer = null; + Map map = mapOthers; + for (PlayerView playerView : gameView.getPlayers()) { + if (playerView.isActive()) { + activePlayer = playerView.getPlayerId(); + if (activePlayer.equals(GameManager.getInstance().getCurrentPlayerUUID())) { + map = mapYou; + } + } + } + if (activePlayer == null) { + throw new IllegalStateException("No active player found."); + } for (Map.Entry entry : map.entrySet()) { if (message.equals(entry.getKey())) { Preferences prefs = MageFrame.getPreferences(); diff --git a/Mage.Client/src/main/java/mage/client/util/gui/GuiDisplayUtil.java b/Mage.Client/src/main/java/mage/client/util/gui/GuiDisplayUtil.java index 9da4c86c1c2..312e4966ea4 100644 --- a/Mage.Client/src/main/java/mage/client/util/gui/GuiDisplayUtil.java +++ b/Mage.Client/src/main/java/mage/client/util/gui/GuiDisplayUtil.java @@ -14,7 +14,8 @@ import org.jdesktop.swingx.JXPanel; public class GuiDisplayUtil { private static final Font cardNameFont = new Font("Calibri", Font.BOLD, 15); - private static Insets DEFAULT_INSETS = new Insets(0,0, 68, 15); + private static Insets DEFAULT_INSETS = new Insets(0, 0, 70, 25); + private static Insets COMPONENT_INSETS = new Insets(0, 0, 40, 40); public static JXPanel getDescription(CardView card, int width, int height) { JXPanel descriptionPanel = new JXPanel(); @@ -127,12 +128,12 @@ public class GuiDisplayUtil { } public static Point keepComponentInsideParent(Point l, Point parentPoint, Component c, Component parent) { - int dx = parentPoint.x + parent.getWidth() - DEFAULT_INSETS.right; + int dx = parentPoint.x + parent.getWidth() - DEFAULT_INSETS.right - COMPONENT_INSETS.right; if (l.x + c.getWidth() > dx) { l.x = dx - c.getWidth(); } - int dy = parentPoint.y + parent.getHeight() - DEFAULT_INSETS.bottom; + int dy = parentPoint.y + parent.getHeight() - DEFAULT_INSETS.bottom - COMPONENT_INSETS.bottom; if (l.y + c.getHeight() > dy) { l.y = Math.max(10, dy - c.getHeight()); } diff --git a/Mage.Common/src/mage/interfaces/Server.java b/Mage.Common/src/mage/interfaces/Server.java index 5ce8de4b8ac..fe80a748fdb 100644 --- a/Mage.Common/src/mage/interfaces/Server.java +++ b/Mage.Common/src/mage/interfaces/Server.java @@ -28,16 +28,14 @@ package mage.interfaces; +import mage.game.match.MatchOptions; import java.rmi.Remote; import java.rmi.RemoteException; import java.util.List; import java.util.UUID; -import mage.Constants.MultiplayerAttackOption; -import mage.Constants.RangeOfInfluence; import mage.cards.decks.DeckCardLists; import mage.game.GameException; import mage.interfaces.callback.CallbackServer; -import mage.view.GameTypeView; import mage.view.TableView; import mage.view.GameView; @@ -54,8 +52,9 @@ public interface Server extends Remote, CallbackServer { public ServerState getServerState() throws RemoteException, MageException; //table methods - public TableView createTable(UUID sessionId, UUID roomId, String gameType, String deckType, List playerTypes, MultiplayerAttackOption attackOption, RangeOfInfluence range) throws RemoteException, MageException; + public TableView createTable(UUID sessionId, UUID roomId, MatchOptions matchOptions) throws RemoteException, MageException; public boolean joinTable(UUID sessionId, UUID roomId, UUID tableId, String name, DeckCardLists deckList) throws RemoteException, MageException, GameException; + public boolean submitDeck(UUID sessionId, UUID tableId, DeckCardLists deckList) throws RemoteException, MageException, GameException; public boolean watchTable(UUID sessionId, UUID roomId, UUID tableId) throws RemoteException, MageException; public boolean replayTable(UUID sessionId, UUID roomId, UUID tableId) throws RemoteException, MageException; public void leaveTable(UUID sessionId, UUID roomId, UUID tableId) throws RemoteException, MageException; @@ -77,7 +76,7 @@ public interface Server extends Remote, CallbackServer { public UUID getMainRoomId() throws RemoteException, MageException; //game methods - public void startGame(UUID sessionId, UUID roomId, UUID tableId) throws RemoteException, MageException; + public void startMatch(UUID sessionId, UUID roomId, UUID tableId) throws RemoteException, MageException; public void joinGame(UUID gameId, UUID sessionId) throws RemoteException, MageException; public void watchGame(UUID gameId, UUID sessionId) throws RemoteException, MageException; public void stopWatching(UUID gameId, UUID sessionId) throws RemoteException, MageException; diff --git a/Mage.Common/src/mage/interfaces/plugin/CardPlugin.java b/Mage.Common/src/mage/interfaces/plugin/CardPlugin.java index 4ba61be4d29..7d8bf3b659e 100644 --- a/Mage.Common/src/mage/interfaces/plugin/CardPlugin.java +++ b/Mage.Common/src/mage/interfaces/plugin/CardPlugin.java @@ -31,7 +31,7 @@ public interface CardPlugin extends Plugin { void downloadImages(Set allCards); void downloadSymbols(); Image getManaSymbolImage(String symbol); - void onAddCard(MagePermanent card); - void onRemoveCard(MagePermanent card); + void onAddCard(MagePermanent card, int count); + void onRemoveCard(MagePermanent card, int count); JComponent getCardInfoPane(); } diff --git a/Mage.Common/src/mage/view/AbilityView.java b/Mage.Common/src/mage/view/AbilityView.java index 6e1035101ac..44d73318b96 100644 --- a/Mage.Common/src/mage/view/AbilityView.java +++ b/Mage.Common/src/mage/view/AbilityView.java @@ -48,7 +48,7 @@ public class AbilityView extends CardView { this.sourceName = sourceName; this.sourceCard = sourceCard; this.rules = new ArrayList(); - rules.add(formatRule(ability.getRule())); + rules.add(ability.getRule(sourceName)); this.power = ""; this.toughness = ""; this.loyalty = ""; @@ -60,13 +60,6 @@ public class AbilityView extends CardView { this.art = ""; } - @Override - protected String formatRule(String rule) { - String newRule = rule.replace("{this}", this.sourceName); - newRule.replace("{source}", this.sourceName); - return newRule; - } - public CardView getSourceCard() { return this.sourceCard; } diff --git a/Mage.Common/src/mage/view/CardView.java b/Mage.Common/src/mage/view/CardView.java index 4116c281214..4c733d5cdb5 100644 --- a/Mage.Common/src/mage/view/CardView.java +++ b/Mage.Common/src/mage/view/CardView.java @@ -76,7 +76,7 @@ public class CardView implements Serializable { public CardView(Card card) { this.id = card.getId(); this.name = card.getName(); - this.rules = formatRules(card.getRules()); + this.rules = card.getRules(); if (card instanceof Permanent) { this.power = Integer.toString(card.getPower().getValue()); this.toughness = Integer.toString(card.getToughness().getValue()); @@ -118,7 +118,7 @@ public class CardView implements Serializable { CardView(Token token) { this.id = token.getId(); this.name = token.getName(); - this.rules = formatRules(token.getAbilities().getRules()); + this.rules = token.getAbilities().getRules(this.name); this.power = token.getPower().toString(); this.toughness = token.getToughness().toString(); this.loyalty = token.getLoyalty().toString(); @@ -143,19 +143,19 @@ public class CardView implements Serializable { } } - protected List formatRules(List rules) { - List newRules = new ArrayList(); - for (String rule: rules) { - newRules.add(formatRule(rule)); - } - return newRules; - } - - protected String formatRule(String rule) { - String replace = rule.replace("{this}", this.name); - replace = replace.replace("{source}", this.name); - return replace; - } +// protected List formatRules(List rules) { +// List newRules = new ArrayList(); +// for (String rule: rules) { +// newRules.add(formatRule(rule)); +// } +// return newRules; +// } +// +// protected String formatRule(String rule) { +// String replace = rule.replace("{this}", this.name); +// replace = replace.replace("{source}", this.name); +// return replace; +// } public String getName() { return name; diff --git a/Mage.Common/src/mage/view/GameTypeView.java b/Mage.Common/src/mage/view/GameTypeView.java index 97426e47f9d..310e4057271 100644 --- a/Mage.Common/src/mage/view/GameTypeView.java +++ b/Mage.Common/src/mage/view/GameTypeView.java @@ -29,7 +29,7 @@ package mage.view; import java.io.Serializable; -import mage.game.GameType; +import mage.game.match.MatchType; /** * @@ -45,7 +45,7 @@ public class GameTypeView implements Serializable { private boolean useRange; private boolean useAttackOption; - public GameTypeView(GameType gameType) { + public GameTypeView(MatchType gameType) { this.name = gameType.getName(); this.minPlayers = gameType.getMinPlayers(); this.maxPlayers = gameType.getMaxPlayers(); diff --git a/Mage.Common/src/mage/view/StackAbilityView.java b/Mage.Common/src/mage/view/StackAbilityView.java index 5beaed5077a..d795daa7fc2 100644 --- a/Mage.Common/src/mage/view/StackAbilityView.java +++ b/Mage.Common/src/mage/view/StackAbilityView.java @@ -47,7 +47,7 @@ public class StackAbilityView extends CardView { this.sourceName = sourceName; this.sourceCard = sourceCard; this.rules = new ArrayList(); - rules.add(formatRule(ability.getRule())); + rules.add(ability.getRule(sourceName)); this.power = ability.getPower().toString(); this.toughness = ability.getToughness().toString(); this.loyalty = ability.getLoyalty().toString(); @@ -60,13 +60,6 @@ public class StackAbilityView extends CardView { setTargets(ability.getTargets()); } - @Override - protected String formatRule(String rule) { - String newRule = rule.replace("{this}", this.sourceName); - newRule.replace("{source}", this.sourceName); - return newRule; - } - public CardView getSourceCard() { return this.sourceCard; } diff --git a/Mage/src/mage/game/MatchImpl.java b/Mage.Common/src/mage/view/TableClientMessage.java similarity index 64% rename from Mage/src/mage/game/MatchImpl.java rename to Mage.Common/src/mage/view/TableClientMessage.java index 96e6243d11d..8bad71470b3 100644 --- a/Mage/src/mage/game/MatchImpl.java +++ b/Mage.Common/src/mage/view/TableClientMessage.java @@ -26,63 +26,46 @@ * or implied, of BetaSteward_at_googlemail.com. */ -package mage.game; +package mage.view; -import java.util.ArrayList; -import java.util.List; +import java.io.Serializable; +import java.util.UUID; import mage.cards.decks.Deck; -import mage.players.Player; /** * * @author BetaSteward_at_googlemail.com */ -public class MatchImpl implements Match { +public class TableClientMessage implements Serializable { - protected List players = new ArrayList(); - protected List games = new ArrayList(); - protected int winsNeeded; - protected int maxPlayers; - protected int minPlayers; - - public MatchImpl(int winsNeeded) { - this.winsNeeded = winsNeeded; + private Deck deck; + private UUID tableId; + private UUID gameId; + private UUID playerId; + + public TableClientMessage(Deck deck, UUID tableId) { + this.deck = deck; + this.tableId = tableId; } - @Override - public List getPlayers() { - return players; + public TableClientMessage(UUID gameId, UUID playerId) { + this.gameId = gameId; + this.playerId = playerId; } - @Override - public void addPlayer(Player player, Deck deck) { - MatchPlayer mPlayer = new MatchPlayer(player, deck); - players.add(mPlayer); + public Deck getDeck() { + return deck; } - @Override - public void startMatch() { - + public UUID getTableId() { + return tableId; } - @Override - public boolean isMatchOver() { - for (MatchPlayer player: players) { - if (player.getWins() >= winsNeeded) { - return true; - } - } - return false; + public UUID getGameId() { + return gameId; } - @Override - public int getMaxPlayers() { - return this.maxPlayers; + public UUID getPlayerId() { + return playerId; } - - @Override - public int getMinPlayers() { - return this.minPlayers; - } - } diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/card/arcane/Animation.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/card/arcane/Animation.java index 8f5ea355ab2..e700ed66e07 100644 --- a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/card/arcane/Animation.java +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/card/arcane/Animation.java @@ -287,8 +287,11 @@ abstract public class Animation { } } - static public void showCard(final MagePermanent card) { - new Animation(600) { + static public void showCard(final MagePermanent card, int count) { + if (count == 0) { + count = 1; + } + new Animation(600 / count) { protected void start () { } @@ -304,8 +307,11 @@ abstract public class Animation { }; } - static public void hideCard(final MagePermanent card) { - new Animation(600) { + static public void hideCard(final MagePermanent card, int count) { + if (count == 0) { + count = 1; + } + new Animation(600 / count) { protected void start () { } diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/card/arcane/CardPanel.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/card/arcane/CardPanel.java index 37a4811e4d3..aeed5363340 100644 --- a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/card/arcane/CardPanel.java +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/card/arcane/CardPanel.java @@ -65,9 +65,8 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti static private final float rotCenterToBottomCorner = 0.7071067811865475244008443621048f; public CardView gameCard; - public PermanentView gamePermanent; - public CardPanel attachedToPanel; - public List attachedPanels = new ArrayList(); + //public List attachedPanels = new ArrayList(); + private List links = new ArrayList(); public double tappedAngle = 0; public ScaledImagePanel imagePanel; public ImagePanel overlayPanel; @@ -101,8 +100,7 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti this.isPermanent = this.gameCard instanceof PermanentView; if (isPermanent) { - this.gamePermanent = (PermanentView) this.gameCard; - this.hasSickness = this.gamePermanent.hasSummoningSickness(); + this.hasSickness = ((PermanentView) this.gameCard).hasSummoningSickness(); } //for container debug (don't remove) @@ -416,6 +414,13 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti @Override public void setAlpha(float alpha) { this.alpha = alpha; + if (alpha == 0) { + this.ptText.setVisible(false); + this.titleText.setVisible(false); + } else if (alpha == 1.0f) { + this.ptText.setVisible(true); + this.titleText.setVisible(true); + } } public float getAlpha() { @@ -449,12 +454,7 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti @Override public List getLinks() { - List list = new ArrayList(); - if (attachedPanels == null) return list; - for (MagePermanent p : attachedPanels) { - list.add(p); - } - return list; + return links; } @Override diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/CardPluginImpl.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/CardPluginImpl.java index 7afd87da181..9fec2f9d2cb 100644 --- a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/CardPluginImpl.java +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/CardPluginImpl.java @@ -438,9 +438,9 @@ public class CardPluginImpl implements CardPlugin { } @Override - public void onAddCard(MagePermanent card) { + public void onAddCard(MagePermanent card, int count) { if (card != null) { - Animation.showCard((CardPanel) card); + Animation.showCard((CardPanel) card, count > 0 ? count : 1); try { while ((card).getAlpha() + 0.05f < 1) { Thread.sleep(30); @@ -452,9 +452,9 @@ public class CardPluginImpl implements CardPlugin { } @Override - public void onRemoveCard(MagePermanent card) { + public void onRemoveCard(MagePermanent card, int count) { if (card != null) { - Animation.hideCard((CardPanel) card); + Animation.hideCard((CardPanel) card, count > 0 ? count : 1); try { while ((card).getAlpha() - 0.05f > 0) { Thread.sleep(30); diff --git a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/info/CardInfoPaneImpl.java b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/info/CardInfoPaneImpl.java index f542561d5e6..ac54bf140ad 100644 --- a/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/info/CardInfoPaneImpl.java +++ b/Mage.Plugins/Mage.Card.Plugin/src/main/java/org/mage/plugins/card/info/CardInfoPaneImpl.java @@ -24,98 +24,77 @@ public class CardInfoPaneImpl extends JEditorPane implements CardInfoPane { public CardInfoPaneImpl() { UI.setHTMLEditorKit(this); - setEditable(false); - setBackground(Color.white); - setSize(170, Integer.MAX_VALUE); + setEditable(false); + setBackground(Color.white); } - public void setCard (final CardView card) { + public void setCard(final CardView card) { if (card == null) return; - if (isCurrentCard(card)) return; - currentCard = card; + if (isCurrentCard(card)) return; + currentCard = card; ThreadUtils.threadPool.submit(new Runnable() { - public void run () { - if (!card.equals(currentCard)) return; + public void run() { + if (!card.equals(currentCard)) return; String manaCost = ""; for (String m : card.getManaCost()) { manaCost += m; } String castingCost = UI.getDisplayManaCost(manaCost); - castingCost = ManaSymbols.replaceSymbolsWithHTML(castingCost, false); + castingCost = ManaSymbols.replaceSymbolsWithHTML(castingCost, false); int symbolCount = 0; - int offset = 0; - while ((offset = castingCost.indexOf(" rulings = card.getRules(); boolean smallImages = true; - int fontSize = 11; + int fontSize = 11; - String fontFamily = "tahoma"; - /*if (prefs.fontFamily == CardFontFamily.arial) - fontFamily = "arial"; - else if (prefs.fontFamily == CardFontFamily.verdana) { - fontFamily = "verdana"; - }*/ + String fontFamily = "tahoma"; + /*if (prefs.fontFamily == CardFontFamily.arial) + fontFamily = "arial"; + else if (prefs.fontFamily == CardFontFamily.verdana) { + fontFamily = "verdana"; + }*/ - final StringBuffer buffer = new StringBuffer(512); - buffer.append(""); - buffer.append(""); - buffer.append("
"); - buffer.append(card.getName()); - buffer.append(""); - buffer.append(castingCost); - buffer.append("
"); - buffer.append("
"); - buffer.append(getTypes(card)); + final StringBuffer buffer = new StringBuffer(512); + buffer.append(""); + buffer.append(""); + buffer.append("
"); + buffer.append(card.getName()); + buffer.append(""); + buffer.append(castingCost); + buffer.append("
"); + buffer.append("
"); + buffer.append(getTypes(card)); buffer.append(""); switch (card.getRarity()) { - case RARE: - buffer.append(""); - break; - case UNCOMMON: - buffer.append(""); - break; - case COMMON: - buffer.append(""); - break; + case RARE: + buffer.append(""); + break; + case UNCOMMON: + buffer.append(""); + break; + case COMMON: + buffer.append(""); + break; case MYTHIC: - buffer.append(""); - break; - } - buffer.append(card.getExpansionSetCode().toUpperCase()); + buffer.append(""); + break; + } + buffer.append(card.getExpansionSetCode().toUpperCase()); buffer.append("
"); - String legal = ""; - if (rulings.size() > 0) { - legal = legal.replaceAll("#([^#]+)#", "$1"); - legal = legal.replaceAll("\\s*//\\s*", "
"); - legal = legal.replace("\r\n", "
"); - legal += "
"; - for (String ruling : rulings) { - legal += "

"; - legal += ruling; - legal += "

"; - } - } - - if (legal.length() > 0) { - buffer.append("
"); - legal = legal.replaceAll("\\{this\\}", card.getName()); - legal = legal.replaceAll("\\{source\\}", card.getName()); - buffer.append(ManaSymbols.replaceSymbolsWithHTML(legal, smallImages)); - } - String pt = ""; if (CardUtil.isCreature(card)) { pt = card.getPower() + "/" + card.getToughness(); @@ -124,23 +103,42 @@ public class CardInfoPaneImpl extends JEditorPane implements CardInfoPane { } if (pt.length() > 0) { buffer.append("
"); - buffer.append(""); - buffer.append(""); - buffer.append(pt); - buffer.append(""); - buffer.append("
"); + buffer.append(""); + buffer.append(pt); + buffer.append(""); + buffer.append("
"); + } + + String legal = ""; + if (rulings.size() > 0) { + legal = legal.replaceAll("#([^#]+)#", "$1"); + legal = legal.replaceAll("\\s*//\\s*", "
"); + legal = legal.replace("\r\n", "
"); + legal += "
"; + for (String ruling : rulings) { + legal += "

"; + legal += ruling; + legal += "

"; + } + } + + if (legal.length() > 0) { + //buffer.append("
"); + legal = legal.replaceAll("\\{this\\}", card.getName()); + legal = legal.replaceAll("\\{source\\}", card.getName()); + buffer.append(ManaSymbols.replaceSymbolsWithHTML(legal, smallImages)); } buffer.append("
"); SwingUtilities.invokeLater(new Runnable() { - public void run () { - if (!card.equals(currentCard)) return; - setText(buffer.toString()); + public void run() { + if (!card.equals(currentCard)) return; + setText(buffer.toString()); //System.out.println(buffer.toString()); - setCaretPosition(0); - } - }); + setCaretPosition(0); + } + }); } }); } @@ -162,7 +160,7 @@ public class CardInfoPaneImpl extends JEditorPane implements CardInfoPane { return types.trim(); } - public boolean isCurrentCard (CardView card) { - return currentCard != null && card.equals(currentCard); - } + public boolean isCurrentCard(CardView card) { + return currentCard != null && card.equals(currentCard); + } } diff --git a/Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAll.java b/Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAll.java index 478dcb5b933..97c25e4c5fd 100644 --- a/Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAll.java +++ b/Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAll.java @@ -28,6 +28,7 @@ package mage.game; +import mage.game.match.MatchType; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -59,7 +60,7 @@ public class FreeForAll extends GameImpl { } @Override - public GameType getGameType() { + public MatchType getGameType() { return new FreeForAllType(); } diff --git a/Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAllMatch.java b/Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAllMatch.java new file mode 100644 index 00000000000..613fcf6af78 --- /dev/null +++ b/Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAllMatch.java @@ -0,0 +1,51 @@ +/* + * 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.game; + +import mage.game.match.MatchImpl; +import mage.game.match.MatchOptions; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class FreeForAllMatch extends MatchImpl { + + public FreeForAllMatch(MatchOptions options) { + super(options); + } + + @Override + public void startGame() throws GameException { + FreeForAll game = new FreeForAll(options.getAttackOption(), options.getRange()); + initGame(game); + games.add(game); + } + +} diff --git a/Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAllType.java b/Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAllType.java index ee24d0675a2..a7fabda1722 100644 --- a/Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAllType.java +++ b/Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAllType.java @@ -28,11 +28,13 @@ package mage.game; +import mage.game.match.MatchType; + /** * * @author BetaSteward_at_googlemail.com */ -public class FreeForAllType extends GameType { +public class FreeForAllType extends MatchType { public FreeForAllType() { this.name = "Free For All"; @@ -42,4 +44,13 @@ public class FreeForAllType extends GameType { this.useAttackOption = true; this.useRange = true; } + + protected FreeForAllType(final FreeForAllType matchType) { + super(matchType); + } + + @Override + public FreeForAllType copy() { + return new FreeForAllType(this); + } } diff --git a/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerDuel.java b/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerDuel.java index fe3b9d76fe4..09c82dba0ef 100644 --- a/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerDuel.java +++ b/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerDuel.java @@ -28,6 +28,7 @@ package mage.game; +import mage.game.match.MatchType; import java.util.HashSet; import java.util.Set; import java.util.UUID; @@ -39,7 +40,7 @@ import mage.game.turn.TurnMod; public class TwoPlayerDuel extends GameImpl { public TwoPlayerDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range) { - super(MultiplayerAttackOption.LEFT, RangeOfInfluence.ALL); + super(attackOption, range); } public TwoPlayerDuel(final TwoPlayerDuel game) { @@ -47,7 +48,7 @@ public class TwoPlayerDuel extends GameImpl { } @Override - public GameType getGameType() { + public MatchType getGameType() { return new TwoPlayerDuelType(); } @@ -62,8 +63,8 @@ public class TwoPlayerDuel extends GameImpl { } @Override - public void init() { - super.init(); + protected void init(UUID choosingPlayerId) { + super.init(choosingPlayerId); state.getTurnMods().add(new TurnMod(startingPlayerId, PhaseStep.DRAW)); } diff --git a/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerDuelType.java b/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerDuelType.java index c25aaa8dc2c..c15c12f1e4e 100644 --- a/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerDuelType.java +++ b/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerDuelType.java @@ -28,11 +28,13 @@ package mage.game; +import mage.game.match.MatchType; + /** * * @author BetaSteward_at_googlemail.com */ -public class TwoPlayerDuelType extends GameType { +public class TwoPlayerDuelType extends MatchType { public TwoPlayerDuelType() { this.name = "Two Player Duel"; @@ -43,4 +45,13 @@ public class TwoPlayerDuelType extends GameType { this.useRange = false; } + protected TwoPlayerDuelType(final TwoPlayerDuelType matchType) { + super(matchType); + } + + @Override + public TwoPlayerDuelType copy() { + return new TwoPlayerDuelType(this); + } + } diff --git a/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerMatch.java b/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerMatch.java new file mode 100644 index 00000000000..c3f7723146c --- /dev/null +++ b/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerMatch.java @@ -0,0 +1,51 @@ +/* + * 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.game; + +import mage.game.match.MatchImpl; +import mage.game.match.MatchOptions; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class TwoPlayerMatch extends MatchImpl { + + public TwoPlayerMatch(MatchOptions options) { + super(options); + } + + @Override + public void startGame() throws GameException { + TwoPlayerDuel game = new TwoPlayerDuel(options.getAttackOption(), options.getRange()); + initGame(game); + games.add(game); + } + +} diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/mage/player/ai/ComputerPlayer.java b/Mage.Server.Plugins/Mage.Player.AI/src/mage/player/ai/ComputerPlayer.java index 5923c208414..8ade76a07b6 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/src/mage/player/ai/ComputerPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.AI/src/mage/player/ai/ComputerPlayer.java @@ -86,6 +86,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterLandCard; import mage.filter.common.FilterNonlandCard; import mage.game.Game; +import mage.game.Table; import mage.game.combat.CombatGroup; import mage.game.permanent.Permanent; import mage.players.Player; @@ -111,7 +112,6 @@ import mage.util.TreeNode; public class ComputerPlayer> extends PlayerImpl implements Player { private final static transient Logger logger = Logging.getLogger(ComputerPlayer.class.getName()); - private boolean abort; private transient Map unplayable = new TreeMap(); private transient List playableNonInstant = new ArrayList(); private transient List playableInstant = new ArrayList(); @@ -128,7 +128,6 @@ public class ComputerPlayer> extends PlayerImpl i public ComputerPlayer(final ComputerPlayer player) { super(player); - this.abort = player.abort; } @Override @@ -768,6 +767,12 @@ public class ComputerPlayer> extends PlayerImpl i return super.getAvailableManaProducers(game); } + @Override + public void sideboard(Table table) { + //TODO: improve this + table.fireSubmitDeckEvent(playerId, deck); + } + protected Attackers getPotentialAttackers(Game game) { logger.fine("getAvailableAttackers"); Attackers attackers = new Attackers(); diff --git a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java index c892ecfa986..70e2fadfb06 100644 --- a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java @@ -53,6 +53,7 @@ import mage.cards.decks.Deck; import mage.choices.ChoiceImpl; import mage.filter.common.FilterCreatureForCombat; import mage.game.Game; +import mage.game.Table; import mage.game.permanent.Permanent; import mage.target.Target; import mage.target.TargetAmount; @@ -71,8 +72,6 @@ public class HumanPlayer extends PlayerImpl { final transient PlayerResponse response = new PlayerResponse(); - private boolean abort; - protected static FilterCreatureForCombat filter = new FilterCreatureForCombat(); protected static Choice replacementEffectChoice = new ChoiceImpl(true); @@ -89,7 +88,6 @@ public class HumanPlayer extends PlayerImpl { public HumanPlayer(final HumanPlayer player) { super(player); - this.abort = player.abort; } protected void waitForResponse() { @@ -474,6 +472,11 @@ public class HumanPlayer extends PlayerImpl { return response.getInteger(); } + @Override + public void sideboard(Table table) { + table.fireSideboardEvent(playerId); + } + protected void specialAction(Game game) { Map specialActions = game.getState().getSpecialActions().getControlledBy(playerId); game.fireGetChoiceEvent(playerId, name, specialActions.values()); @@ -540,6 +543,8 @@ public class HumanPlayer extends PlayerImpl { } } + + @Override public HumanPlayer copy() { return new HumanPlayer(this); diff --git a/Mage.Server/config/config.xml b/Mage.Server/config/config.xml index 9733c9db7e0..df6998b9b93 100644 --- a/Mage.Server/config/config.xml +++ b/Mage.Server/config/config.xml @@ -9,8 +9,8 @@ - - + + diff --git a/Mage.Server/plugins/mage-deck-constructed.jar b/Mage.Server/plugins/mage-deck-constructed.jar index cdcc7affaa2..022550af46c 100644 Binary files a/Mage.Server/plugins/mage-deck-constructed.jar and b/Mage.Server/plugins/mage-deck-constructed.jar differ diff --git a/Mage.Server/plugins/mage-deck-limited.jar b/Mage.Server/plugins/mage-deck-limited.jar index 8e20dbdb8ac..b4ca904cc5d 100644 Binary files a/Mage.Server/plugins/mage-deck-limited.jar and b/Mage.Server/plugins/mage-deck-limited.jar differ diff --git a/Mage.Server/plugins/mage-game-freeforall.jar b/Mage.Server/plugins/mage-game-freeforall.jar index 25f863f3dfd..e3673d7d31b 100644 Binary files a/Mage.Server/plugins/mage-game-freeforall.jar and b/Mage.Server/plugins/mage-game-freeforall.jar differ diff --git a/Mage.Server/plugins/mage-game-twoplayerduel.jar b/Mage.Server/plugins/mage-game-twoplayerduel.jar index 22b21ec61e3..95284084f59 100644 Binary files a/Mage.Server/plugins/mage-game-twoplayerduel.jar and b/Mage.Server/plugins/mage-game-twoplayerduel.jar differ diff --git a/Mage.Server/plugins/mage-player-ai.jar b/Mage.Server/plugins/mage-player-ai.jar index e7b4c9190c3..ad99bdf7176 100644 Binary files a/Mage.Server/plugins/mage-player-ai.jar and b/Mage.Server/plugins/mage-player-ai.jar differ diff --git a/Mage.Server/plugins/mage-player-aiminimax.jar b/Mage.Server/plugins/mage-player-aiminimax.jar index d2f5a8333b1..9117b83ecc5 100644 Binary files a/Mage.Server/plugins/mage-player-aiminimax.jar and b/Mage.Server/plugins/mage-player-aiminimax.jar differ diff --git a/Mage.Server/plugins/mage-player-human.jar b/Mage.Server/plugins/mage-player-human.jar index 37aa8262f09..1cb91fb2ffb 100644 Binary files a/Mage.Server/plugins/mage-player-human.jar and b/Mage.Server/plugins/mage-player-human.jar differ diff --git a/Mage.Server/src/main/java/mage/server/Main.java b/Mage.Server/src/main/java/mage/server/Main.java index e8425dbc356..9cec754fa90 100644 --- a/Mage.Server/src/main/java/mage/server/Main.java +++ b/Mage.Server/src/main/java/mage/server/Main.java @@ -35,7 +35,7 @@ import java.io.FilenameFilter; import java.net.InetAddress; import java.util.logging.Level; import java.util.logging.Logger; -import mage.game.GameType; +import mage.game.match.MatchType; import mage.server.game.DeckValidatorFactory; import mage.server.game.GameFactory; import mage.server.game.PlayerFactory; @@ -119,11 +119,11 @@ public class Main { return null; } - private static GameType loadGameType(GamePlugin plugin) { + private static MatchType loadGameType(GamePlugin plugin) { try { classLoader.addURL(new File(pluginFolder + "/" + plugin.getJar()).toURI().toURL()); logger.info("Loading game type: " + plugin.getClassName()); - return (GameType) Class.forName(plugin.getTypeName(), true, classLoader).newInstance(); + return (MatchType) Class.forName(plugin.getTypeName(), true, classLoader).newInstance(); } catch (ClassNotFoundException ex) { logger.log(Level.SEVERE, "Game type not found:" + plugin.getJar() + " - check plugin folder"); } catch (Exception ex) { diff --git a/Mage.Server/src/main/java/mage/server/ServerImpl.java b/Mage.Server/src/main/java/mage/server/ServerImpl.java index 9585c345959..11e8a938f11 100644 --- a/Mage.Server/src/main/java/mage/server/ServerImpl.java +++ b/Mage.Server/src/main/java/mage/server/ServerImpl.java @@ -39,11 +39,10 @@ import java.util.UUID; import java.util.concurrent.ExecutorService; import java.util.logging.Level; import java.util.logging.Logger; -import mage.Constants.MultiplayerAttackOption; -import mage.Constants.RangeOfInfluence; import mage.cards.decks.DeckCardLists; import mage.game.GameException; import mage.interfaces.MageException; +import mage.game.match.MatchOptions; import mage.interfaces.Server; import mage.interfaces.ServerState; import mage.interfaces.callback.ClientCallback; @@ -56,7 +55,6 @@ import mage.server.game.ReplayManager; import mage.server.game.TableManager; import mage.server.util.ThreadExecutor; import mage.util.Logging; -import mage.view.CardView; import mage.view.ChatMessage.MessageColor; import mage.view.GameView; import mage.view.TableView; @@ -117,9 +115,9 @@ public class ServerImpl extends RemoteServer implements Server { } @Override - public TableView createTable(UUID sessionId, UUID roomId, String gameType, String deckType, List playerTypes, MultiplayerAttackOption attackOption, RangeOfInfluence range) throws MageException { + public TableView createTable(UUID sessionId, UUID roomId, MatchOptions options) throws MageException { try { - TableView table = GamesRoomManager.getInstance().getRoom(roomId).createTable(sessionId, gameType, deckType, playerTypes, attackOption, range); + TableView table = GamesRoomManager.getInstance().getRoom(roomId).createTable(sessionId, options); logger.info("Table " + table.getTableId() + " created"); return table; } @@ -161,6 +159,21 @@ public class ServerImpl extends RemoteServer implements Server { return false; } + @Override + public boolean submitDeck(UUID sessionId, UUID tableId, DeckCardLists deckList) throws MageException, GameException { + try { + boolean ret = TableManager.getInstance().submitDeck(sessionId, tableId, deckList); + logger.info("Session " + sessionId + " submitted deck"); + return ret; + } + catch (Exception ex) { + if (ex instanceof GameException) + throw (GameException)ex; + handleException(ex); + } + return false; + } + @Override public List getTables(UUID roomId) throws MageException { try { @@ -202,13 +215,13 @@ public class ServerImpl extends RemoteServer implements Server { } @Override - public void startGame(final UUID sessionId, final UUID roomId, final UUID tableId) throws MageException { + public void startMatch(final UUID sessionId, final UUID roomId, final UUID tableId) throws MageException { try { rmiExecutor.execute( new Runnable() { @Override public void run() { - TableManager.getInstance().startGame(sessionId, roomId, tableId); + TableManager.getInstance().startMatch(sessionId, roomId, tableId); } } ); diff --git a/Mage.Server/src/main/java/mage/server/Session.java b/Mage.Server/src/main/java/mage/server/Session.java index bd60d395159..055d334a20d 100644 --- a/Mage.Server/src/main/java/mage/server/Session.java +++ b/Mage.Server/src/main/java/mage/server/Session.java @@ -31,11 +31,13 @@ package mage.server; import java.util.logging.Level; import java.util.UUID; import java.util.logging.Logger; +import mage.cards.decks.Deck; import mage.interfaces.callback.CallbackServerSession; import mage.interfaces.callback.ClientCallback; import mage.server.game.GameManager; import mage.server.game.TableManager; import mage.util.Logging; +import mage.view.TableClientMessage; /** * @@ -90,7 +92,11 @@ public class Session { } public void gameStarted(final UUID gameId, final UUID playerId) { - fireCallback(new ClientCallback("startGame", new UUID[] {gameId, playerId})); + fireCallback(new ClientCallback("startGame", new TableClientMessage(gameId, playerId))); + } + + public void sideboard(final Deck deck, final UUID tableId) { + fireCallback(new ClientCallback("sideboard", new TableClientMessage(deck, tableId))); } public void watchGame(final UUID gameId) { diff --git a/Mage.Server/src/main/java/mage/server/game/GameController.java b/Mage.Server/src/main/java/mage/server/game/GameController.java index 33be4d2b80d..2d1d6c5db60 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameController.java +++ b/Mage.Server/src/main/java/mage/server/game/GameController.java @@ -82,15 +82,17 @@ public class GameController implements GameCallback { private Game game; private UUID chatId; private UUID tableId; + private UUID choosingPlayerId; private Future gameFuture; - public GameController(Game game, ConcurrentHashMap sessionPlayerMap, UUID tableId) { + public GameController(Game game, ConcurrentHashMap sessionPlayerMap, UUID tableId, UUID choosingPlayerId) { gameSessionId = UUID.randomUUID(); this.sessionPlayerMap = sessionPlayerMap; chatId = ChatManager.getInstance().createChatSession(); this.game = game; this.tableId = tableId; + this.choosingPlayerId = choosingPlayerId; init(); } @@ -186,7 +188,7 @@ public class GameController implements GameCallback { return; } } - GameWorker worker = new GameWorker(game, this); + GameWorker worker = new GameWorker(game, choosingPlayerId, this); gameFuture = gameExecutor.submit(worker); } } diff --git a/Mage.Server/src/main/java/mage/server/game/GameFactory.java b/Mage.Server/src/main/java/mage/server/game/GameFactory.java index 6af3d534bd4..e35ee4b9ca2 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameFactory.java +++ b/Mage.Server/src/main/java/mage/server/game/GameFactory.java @@ -30,17 +30,15 @@ package mage.server.game; import java.lang.reflect.Constructor; import java.util.ArrayList; -import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; -import mage.Constants.MultiplayerAttackOption; -import mage.Constants.RangeOfInfluence; -import mage.game.Game; +import mage.game.match.Match; +import mage.game.match.MatchOptions; import mage.util.Logging; -import mage.game.GameType; +import mage.game.match.MatchType; import mage.view.GameTypeView; /** @@ -52,8 +50,8 @@ public class GameFactory { private final static GameFactory INSTANCE = new GameFactory(); private final static Logger logger = Logging.getLogger(GameFactory.class.getName()); - private Map> games = new HashMap>(); - private Map gameTypes = new HashMap(); + private Map> games = new HashMap>(); + private Map gameTypes = new HashMap(); private List gameTypeViews = new ArrayList(); @@ -63,31 +61,31 @@ public class GameFactory { private GameFactory() {} - public Game createGame(String gameType, MultiplayerAttackOption attackOption, RangeOfInfluence range) { + public Match createMatch(String gameType, MatchOptions options) { - Game game; - Constructor con; + Match match; + Constructor con; try { - con = games.get(gameType).getConstructor(new Class[]{MultiplayerAttackOption.class, RangeOfInfluence.class}); - game = con.newInstance(new Object[] {attackOption, range}); + con = games.get(gameType).getConstructor(new Class[]{MatchOptions.class}); + match = con.newInstance(new Object[] {options}); } catch (Exception ex) { logger.log(Level.SEVERE, null, ex); return null; } - logger.info("Game created: " + game.getId().toString()); + logger.info("Game created: " + gameType); // + game.getId().toString()); - return game; + return match; } public List getGameTypes() { return gameTypeViews; } - public void addGameType(String name, GameType gameType, Class game) { + public void addGameType(String name, MatchType matchType, Class game) { if (game != null) { this.games.put(name, game); - this.gameTypes.put(name, gameType); - this.gameTypeViews.add(new GameTypeView(gameType)); + this.gameTypes.put(name, matchType); + this.gameTypeViews.add(new GameTypeView(matchType)); } } diff --git a/Mage.Server/src/main/java/mage/server/game/GameManager.java b/Mage.Server/src/main/java/mage/server/game/GameManager.java index 14148324d28..dd44bf5eaf8 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameManager.java +++ b/Mage.Server/src/main/java/mage/server/game/GameManager.java @@ -49,8 +49,8 @@ public class GameManager { private ConcurrentHashMap gameControllers = new ConcurrentHashMap(); - public UUID createGameSession(Game game, ConcurrentHashMap sessionPlayerMap, UUID tableId) { - GameController gameController = new GameController(game, sessionPlayerMap, tableId); + public UUID createGameSession(Game game, ConcurrentHashMap sessionPlayerMap, UUID tableId, UUID choosingPlayerId) { + GameController gameController = new GameController(game, sessionPlayerMap, tableId, choosingPlayerId); gameControllers.put(game.getId(), gameController); return gameController.getSessionId(); } diff --git a/Mage.Server/src/main/java/mage/server/game/GameWorker.java b/Mage.Server/src/main/java/mage/server/game/GameWorker.java index 7566ab1dc1b..c0c15037f58 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameWorker.java +++ b/Mage.Server/src/main/java/mage/server/game/GameWorker.java @@ -28,6 +28,7 @@ package mage.server.game; +import java.util.UUID; import java.util.concurrent.Callable; import java.util.logging.Level; import java.util.logging.Logger; @@ -44,16 +45,18 @@ public class GameWorker implements Callable { private GameCallback result; private Game game; + private UUID choosingPlayerId; - public GameWorker(Game game, GameCallback result) { + public GameWorker(Game game, UUID choosingPlayerId, GameCallback result) { this.game = game; + this.choosingPlayerId = choosingPlayerId; this.result = result; } @Override public Object call() { try { - game.start(); + game.start(choosingPlayerId); result.gameResult(game.getWinner()); } catch (Exception ex) { logger.log(Level.SEVERE, null, ex); diff --git a/Mage.Server/src/main/java/mage/server/game/GamesRoom.java b/Mage.Server/src/main/java/mage/server/game/GamesRoom.java index 3e72cdaa061..39901f5103b 100644 --- a/Mage.Server/src/main/java/mage/server/game/GamesRoom.java +++ b/Mage.Server/src/main/java/mage/server/game/GamesRoom.java @@ -30,10 +30,9 @@ package mage.server.game; import java.util.List; import java.util.UUID; -import mage.Constants.MultiplayerAttackOption; -import mage.Constants.RangeOfInfluence; import mage.cards.decks.DeckCardLists; import mage.game.GameException; +import mage.game.match.MatchOptions; import mage.view.TableView; /** @@ -44,7 +43,7 @@ public interface GamesRoom extends Room { public List getTables(); public boolean joinTable(UUID sessionId, UUID tableId, String name, DeckCardLists deckList) throws GameException; - public TableView createTable(UUID sessionId, String gameType, String deckType, List playerTypes, MultiplayerAttackOption attackOption, RangeOfInfluence range); + public TableView createTable(UUID sessionId, MatchOptions options); public void removeTable(UUID sessionId, UUID tableId); public TableView getTable(UUID tableId); public void leaveTable(UUID sessionId, UUID tableId); diff --git a/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java b/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java index a4fc250fa50..51d29d8e26a 100644 --- a/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java +++ b/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java @@ -35,10 +35,9 @@ import java.util.List; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Logger; -import mage.Constants.MultiplayerAttackOption; -import mage.Constants.RangeOfInfluence; import mage.cards.decks.DeckCardLists; import mage.game.GameException; +import mage.game.match.MatchOptions; import mage.util.Logging; import mage.view.TableView; @@ -71,8 +70,8 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable { } @Override - public TableView createTable(UUID sessionId, String gameType, String deckType, List playerTypes, MultiplayerAttackOption attackOption, RangeOfInfluence range) { - Table table = TableManager.getInstance().createTable(sessionId, gameType, deckType, playerTypes, attackOption, range); + public TableView createTable(UUID sessionId, MatchOptions options) { + Table table = TableManager.getInstance().createTable(sessionId, options); tables.put(table.getId(), table); return new TableView(table); } diff --git a/Mage.Server/src/main/java/mage/server/game/TableController.java b/Mage.Server/src/main/java/mage/server/game/TableController.java index 31ef031c3b0..579b59c2e67 100644 --- a/Mage.Server/src/main/java/mage/server/game/TableController.java +++ b/Mage.Server/src/main/java/mage/server/game/TableController.java @@ -39,7 +39,6 @@ import java.io.ObjectInput; import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.io.OutputStream; -import java.util.List; import java.util.Map.Entry; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @@ -47,15 +46,18 @@ import java.util.logging.Level; import java.util.logging.Logger; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; -import mage.Constants.MultiplayerAttackOption; -import mage.Constants.RangeOfInfluence; import mage.Constants.TableState; import mage.cards.decks.Deck; import mage.cards.decks.DeckCardLists; import mage.game.Game; import mage.game.GameException; import mage.game.GameStates; +import mage.game.match.Match; import mage.game.Seat; +import mage.game.events.Listener; +import mage.game.events.TableEvent; +import mage.game.match.MatchOptions; +import mage.game.match.MatchPlayer; import mage.players.Player; import mage.server.ChatManager; import mage.server.Main; @@ -73,17 +75,36 @@ public class TableController { private UUID sessionId; private UUID chatId; - private UUID gameId; private Table table; - private Game game; + private Match match; + private MatchOptions options; private ConcurrentHashMap sessionPlayerMap = new ConcurrentHashMap(); - public TableController(UUID sessionId, String gameType, String deckType, List playerTypes, MultiplayerAttackOption attackOption, RangeOfInfluence range) { + public TableController(UUID sessionId, MatchOptions options) { this.sessionId = sessionId; chatId = ChatManager.getInstance().createChatSession(); - game = GameFactory.getInstance().createGame(gameType, attackOption, range); - gameId = game.getId(); - table = new Table(gameType, DeckValidatorFactory.getInstance().createDeckValidator(deckType), playerTypes); + this.options = options; + match = GameFactory.getInstance().createMatch(options.getGameType(), options); + table = new Table(options.getGameType(), options.getName(), DeckValidatorFactory.getInstance().createDeckValidator(options.getDeckType()), options.getPlayerTypes()); + init(); + } + + private void init() { + table.addTableEventListener( + new Listener () { + @Override + public void event(TableEvent event) { + switch (event.getEventType()) { + case SIDEBOARD: + sideboard(event.getPlayerId()); + break; + case SUBMIT_DECK: + submitDeck(event.getPlayerId(), event.getDeck()); + break; + } + } + } + ); } public synchronized boolean joinTable(UUID sessionId, String name, DeckCardLists deckList) throws GameException { @@ -100,8 +121,7 @@ public class TableController { } Player player = createPlayer(name, deck, seat.getPlayerType()); - game.loadCards(deck.getCards(), player.getId()); - game.loadCards(deck.getSideboard(), player.getId()); + match.addPlayer(player, deck); table.joinTable(player, seat); logger.info("player joined " + player.getId()); //only add human players to sessionPlayerMap @@ -112,11 +132,29 @@ public class TableController { return true; } + public synchronized boolean submitDeck(UUID sessionId, DeckCardLists deckList) throws GameException { + if (table.getState() != TableState.SIDEBOARDING) { + return false; + } + MatchPlayer player = match.getPlayer(sessionPlayerMap.get(sessionId)); + Deck deck = Deck.load(deckList); + if (!Main.server.isTestMode() && !validDeck(deck)) { + throw new GameException(player.getPlayer().getName() + " has an invalid deck for this format"); + } + submitDeck(sessionPlayerMap.get(sessionId), deck); + return true; + } + + private void submitDeck(UUID playerId, Deck deck) { + MatchPlayer player = match.getPlayer(playerId); + player.submitDeck(deck); + } + public boolean watchTable(UUID sessionId) { if (table.getState() != TableState.DUELING) { return false; } - SessionManager.getInstance().getSession(sessionId).watchGame(game.getId()); + SessionManager.getInstance().getSession(sessionId).watchGame(match.getGame().getId()); return true; } @@ -141,7 +179,7 @@ public class TableController { } private Player createPlayer(String name, Deck deck, String playerType) { - Player player = PlayerFactory.getInstance().createPlayer(playerType, name, deck, game.getRangeOfInfluence()); + Player player = PlayerFactory.getInstance().createPlayer(playerType, name, deck, options.getRange()); logger.info("Player created " + player.getId()); return player; } @@ -151,26 +189,66 @@ public class TableController { table.leaveTable(sessionPlayerMap.get(sessionId)); } - public synchronized void startGame(UUID sessionId) { + public synchronized void startMatch(UUID sessionId) { if (sessionId.equals(this.sessionId) && table.getState() == TableState.STARTING) { try { - table.initGame(game); + match.startMatch(); + startGame(null); } catch (GameException ex) { logger.log(Level.SEVERE, null, ex); } - GameManager.getInstance().createGameSession(game, sessionPlayerMap, table.getId()); - SessionManager sessionManager = SessionManager.getInstance(); - for (Entry entry: sessionPlayerMap.entrySet()) { - sessionManager.getSession(entry.getKey()).gameStarted(game.getId(), entry.getValue()); + } + } + + private void startGame(UUID choosingPlayerId) throws GameException { + match.startGame(); + table.initGame(); + GameManager.getInstance().createGameSession(match.getGame(), sessionPlayerMap, table.getId(), choosingPlayerId); + SessionManager sessionManager = SessionManager.getInstance(); + for (Entry entry: sessionPlayerMap.entrySet()) { + sessionManager.getSession(entry.getKey()).gameStarted(match.getGame().getId(), entry.getValue()); + } + } + + private void sideboard() { + table.sideboard(); + for (MatchPlayer player: match.getPlayers()) { + player.setSideboarding(); + player.getPlayer().sideboard(table); + } + while (!match.isDoneSideboarding()){} + } + + private void sideboard(UUID playerId) { + SessionManager sessionManager = SessionManager.getInstance(); + for (Entry entry: sessionPlayerMap.entrySet()) { + if (entry.getValue().equals(playerId)) { + MatchPlayer player = match.getPlayer(entry.getValue()); + sessionManager.getSession(entry.getKey()).sideboard(player.getDeck(), table.getId()); + break; } } } public void endGame() { + UUID choosingPlayerId = match.getChooser(); + match.endGame(); table.endGame(); saveGame(); - GameManager.getInstance().removeGame(game.getId()); - game = null; + GameManager.getInstance().removeGame(match.getGame().getId()); + try { + if (!match.isMatchOver()) { + sideboard(); + startGame(choosingPlayerId); + } + } catch (GameException ex) { + logger.log(Level.SEVERE, null, ex); + } + endMatch(); + } + + public void endMatch() { + match = null; } public void swapSeats(int seatNum1, int seatNum2) { @@ -188,17 +266,17 @@ public class TableController { private void saveGame() { try { - OutputStream file = new FileOutputStream("saved/" + game.getId().toString() + ".game"); + OutputStream file = new FileOutputStream("saved/" + match.getGame().getId().toString() + ".game"); OutputStream buffer = new BufferedOutputStream(file); ObjectOutput output = new ObjectOutputStream(new GZIPOutputStream(buffer)); try { - output.writeObject(game); - output.writeObject(game.getGameStates()); + output.writeObject(match.getGame()); + output.writeObject(match.getGame().getGameStates()); } finally { output.close(); } - logger.log(Level.INFO, "Saved game:" + game.getId()); + logger.log(Level.INFO, "Saved game:" + match.getGame().getId()); } catch(IOException ex) { logger.log(Level.SEVERE, "Cannot save game.", ex); @@ -207,7 +285,7 @@ public class TableController { private Game loadGame() { try{ - InputStream file = new FileInputStream("saved/" + gameId.toString() + ".game"); + InputStream file = new FileInputStream("saved/" + match.getGame().toString() + ".game"); InputStream buffer = new BufferedInputStream(file); ObjectInput input = new CopierObjectInputStream(Main.classLoader, new GZIPInputStream(buffer)); try { @@ -224,7 +302,7 @@ public class TableController { logger.log(Level.SEVERE, "Cannot load game. Class not found.", ex); } catch(IOException ex) { - logger.log(Level.SEVERE, "Cannot load game:" + game.getId(), ex); + logger.log(Level.SEVERE, "Cannot load game:" + match.getGame().getId(), ex); } return null; } diff --git a/Mage.Server/src/main/java/mage/server/game/TableManager.java b/Mage.Server/src/main/java/mage/server/game/TableManager.java index 9369d13574c..2262a96704f 100644 --- a/Mage.Server/src/main/java/mage/server/game/TableManager.java +++ b/Mage.Server/src/main/java/mage/server/game/TableManager.java @@ -30,14 +30,12 @@ package mage.server.game; import mage.game.Table; import java.util.Collection; -import java.util.List; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Logger; -import mage.Constants.MultiplayerAttackOption; -import mage.Constants.RangeOfInfluence; import mage.cards.decks.DeckCardLists; import mage.game.GameException; +import mage.game.match.MatchOptions; import mage.util.Logging; /** @@ -56,8 +54,8 @@ public class TableManager { return INSTANCE; } - public Table createTable(UUID sessionId, String gameType, String deckType, List playerTypes, MultiplayerAttackOption attackOption, RangeOfInfluence range) { - TableController tableController = new TableController(sessionId, gameType, deckType, playerTypes, attackOption, range); + public Table createTable(UUID sessionId, MatchOptions options) { + TableController tableController = new TableController(sessionId, options); controllers.put(tableController.getTable().getId(), tableController); tables.put(tableController.getTable().getId(), tableController.getTable()); return tableController.getTable(); @@ -75,6 +73,10 @@ public class TableManager { return controllers.get(tableId).joinTable(sessionId, name, deckList); } + public boolean submitDeck(UUID sessionId, UUID tableId, DeckCardLists deckList) throws GameException { + return controllers.get(tableId).submitDeck(sessionId, deckList); + } + public void removeSession(UUID sessionId) { // TODO: search through tables and remove session } @@ -100,8 +102,8 @@ public class TableManager { return controllers.get(tableId).getChatId(); } - public void startGame(UUID sessionId, UUID roomId, UUID tableId) { - controllers.get(tableId).startGame(sessionId); + public void startMatch(UUID sessionId, UUID roomId, UUID tableId) { + controllers.get(tableId).startMatch(sessionId); } public boolean watchTable(UUID sessionId, UUID tableId) { diff --git a/Mage.Sets/src/mage/sets/Sets.java b/Mage.Sets/src/mage/sets/Sets.java index fd2bb98f0fc..f40e8fdb060 100644 --- a/Mage.Sets/src/mage/sets/Sets.java +++ b/Mage.Sets/src/mage/sets/Sets.java @@ -31,11 +31,7 @@ package mage.sets; import java.io.File; import java.io.FileNotFoundException; import java.io.PrintWriter; -import java.util.HashMap; -import java.util.Map; -import java.util.Scanner; -import java.util.Set; -import java.util.TreeSet; +import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import mage.cards.Card; @@ -51,6 +47,7 @@ public class Sets extends HashMap { private static final Sets fINSTANCE = new Sets(); private static Set names; + protected static Random rnd = new Random(); public static Sets getInstance() { return fINSTANCE; @@ -93,6 +90,24 @@ public class Sets extends HashMap { } return null; } + + public static String findCard(String name, boolean random) { + if (!random) { + return findCard(name); + } else { + List cards = new ArrayList(); + for (ExpansionSet set: fINSTANCE.values()) { + String cardName = set.findCard(name, true); + if (cardName != null) { + cards.add(cardName); + } + } + if (cards.size() > 0) { + return cards.get(rnd.nextInt(cards.size())); + } + } + return null; + } public static ExpansionSet findSet(String code) { for (ExpansionSet set: fINSTANCE.values()) { diff --git a/Mage.Sets/src/mage/sets/magic2010/ProteanHydra.java b/Mage.Sets/src/mage/sets/magic2010/ProteanHydra.java index f0a6917bb3b..3363f91a653 100644 --- a/Mage.Sets/src/mage/sets/magic2010/ProteanHydra.java +++ b/Mage.Sets/src/mage/sets/magic2010/ProteanHydra.java @@ -42,11 +42,10 @@ import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.PreventionEffectImpl; -import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.AddPlusOneCountersSourceEffect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.cards.CardImpl; -import mage.counters.PlusOneCounter; +import mage.counters.common.PlusOneCounter; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/AcidWebSpider.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/AcidWebSpider.java new file mode 100644 index 00000000000..967d4ad0ae9 --- /dev/null +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/AcidWebSpider.java @@ -0,0 +1,80 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.sets.scarsofmirrodin; + +import java.util.UUID; +import mage.Constants.CardType; +import mage.Constants.Duration; +import mage.Constants.Rarity; +import mage.Constants.Zone; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.filter.Filter; +import mage.filter.FilterPermanent; +import mage.target.TargetPermanent; + +/** + * + * @author Loki + */ +public class AcidWebSpider extends CardImpl { + private static FilterPermanent filter = new FilterPermanent("Equipment"); + + static { + filter.getSubtype().add("Equipment"); + filter.setScopeSubtype(Filter.ComparisonScope.Any); + } + + public AcidWebSpider (UUID ownerId) { + super(ownerId, 108, "Acid Web Spider", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{3}{G}{G}"); + this.expansionSetCode = "SOM"; + this.subtype.add("Spider"); + this.color.setGreen(true); + this.power = new MageInt(3); + this.toughness = new MageInt(5); + this.addAbility(ReachAbility.getInstance()); + Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(), true); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + public AcidWebSpider (final AcidWebSpider card) { + super(card); + } + + @Override + public AcidWebSpider copy() { + return new AcidWebSpider(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/ArgentumArmor.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/ArgentumArmor.java new file mode 100644 index 00000000000..83580aaa738 --- /dev/null +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/ArgentumArmor.java @@ -0,0 +1,103 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.sets.scarsofmirrodin; + +import java.util.UUID; + +import mage.Constants; +import mage.Constants.CardType; +import mage.Constants.Duration; +import mage.Constants.Rarity; +import mage.Constants.Zone; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.BoostEquippedEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.keyword.EquipAbility; +import mage.cards.CardImpl; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; + +/** + * + * @author Loki + */ +public class ArgentumArmor extends CardImpl { + + public ArgentumArmor (UUID ownerId) { + super(ownerId, 137, "Argentum Armor", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{6}"); + this.expansionSetCode = "SOM"; + this.subtype.add("Equipment"); + this.addAbility(new EquipAbility(Constants.Outcome.AddAbility, new GenericManaCost(6))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(6, 6))); + this.addAbility(new ArgentumArmorAbiltity()); + } + + public ArgentumArmor (final ArgentumArmor card) { + super(card); + } + + @Override + public ArgentumArmor copy() { + return new ArgentumArmor(this); + } +} + +class ArgentumArmorAbiltity extends TriggeredAbilityImpl { + public ArgentumArmorAbiltity() { + super(Zone.BATTLEFIELD, new DestroyTargetEffect()); + this.addTarget(new TargetPermanent()); + } + + public ArgentumArmorAbiltity(final ArgentumArmorAbiltity abiltity) { + super(abiltity); + } + + @Override + public ArgentumArmorAbiltity copy() { + return new ArgentumArmorAbiltity(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Permanent equipment = game.getPermanent(this.sourceId); + if (equipment != null && equipment.getAttachedTo() != null && event.getType() == GameEvent.EventType.ATTACKER_DECLARED && event.getSourceId().equals(equipment.getAttachedTo())) { + return true; + } + return false; + } + + @Override + public String getRule() { + return "Whenever equipped creature attacks, destroy target permanent."; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/BarbedBattlegear.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/BarbedBattlegear.java new file mode 100644 index 00000000000..3baf2f5ef71 --- /dev/null +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/BarbedBattlegear.java @@ -0,0 +1,66 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.sets.scarsofmirrodin; + +import java.util.UUID; + +import mage.Constants; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.Constants.Zone; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.BoostEquippedEffect; +import mage.abilities.keyword.EquipAbility; +import mage.cards.CardImpl; + +/** + * + * @author Loki + */ +public class BarbedBattlegear extends CardImpl { + + public BarbedBattlegear (UUID ownerId) { + super(ownerId, 139, "Barbed Battlegear", Rarity.UNCOMMON, new CardType[]{CardType.ARTIFACT}, "{3}"); + this.expansionSetCode = "SOM"; + this.subtype.add("Equipment"); + this.addAbility(new EquipAbility(Constants.Outcome.AddAbility, new GenericManaCost(2))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(4, -1))); + } + + public BarbedBattlegear (final BarbedBattlegear card) { + super(card); + } + + @Override + public BarbedBattlegear copy() { + return new BarbedBattlegear(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/BladedPinions.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/BladedPinions.java new file mode 100644 index 00000000000..df6637a8f78 --- /dev/null +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/BladedPinions.java @@ -0,0 +1,69 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.sets.scarsofmirrodin; + +import java.util.UUID; + +import mage.Constants; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.Constants.Zone; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.GainAbilityAttachedEffect; +import mage.abilities.keyword.EquipAbility; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; + +/** + * + * @author Loki + */ +public class BladedPinions extends CardImpl { + + public BladedPinions (UUID ownerId) { + super(ownerId, 140, "Bladed Pinions", Rarity.COMMON, new CardType[]{CardType.ARTIFACT}, "{2}"); + this.expansionSetCode = "SOM"; + this.subtype.add("Equipment"); + this.addAbility(new EquipAbility(Constants.Outcome.AddAbility, new GenericManaCost(2))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(FlyingAbility.getInstance()))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(FirstStrikeAbility.getInstance()))); + } + + public BladedPinions (final BladedPinions card) { + super(card); + } + + @Override + public BladedPinions copy() { + return new BladedPinions(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/BlightMamba.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/BlightMamba.java new file mode 100644 index 00000000000..dd3c4a6b66c --- /dev/null +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/BlightMamba.java @@ -0,0 +1,70 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.sets.scarsofmirrodin; + +import java.util.UUID; +import mage.Constants.CardType; +import mage.Constants.Duration; +import mage.Constants.Rarity; +import mage.Constants.Zone; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.RegenerateSourceEffect; +import mage.abilities.keyword.InfectAbility; +import mage.cards.CardImpl; +import mage.sets.magic2011.InfernoTitan; + +/** + * + * @author Loki + */ +public class BlightMamba extends CardImpl { + + public BlightMamba (UUID ownerId) { + super(ownerId, 112, "Blight Mamba", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{G}"); + this.expansionSetCode = "SOM"; + this.subtype.add("Snake"); + this.color.setGreen(true); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + this.addAbility(InfectAbility.getInstance()); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new ManaCostsImpl("{1}{G}"))); + } + + public BlightMamba (final BlightMamba card) { + super(card); + } + + @Override + public BlightMamba copy() { + return new BlightMamba(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/ContagiousNim.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/ContagiousNim.java new file mode 100644 index 00000000000..53a907a18fb --- /dev/null +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/ContagiousNim.java @@ -0,0 +1,63 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.sets.scarsofmirrodin; + +import java.util.UUID; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.MageInt; +import mage.abilities.keyword.InfectAbility; +import mage.cards.CardImpl; + +/** + * + * @author Loki + */ +public class ContagiousNim extends CardImpl { + + public ContagiousNim (UUID ownerId) { + super(ownerId, 58, "Contagious Nim", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{B}"); + this.expansionSetCode = "SOM"; + this.subtype.add("Zombie"); + this.color.setBlack(true); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + this.addAbility(InfectAbility.getInstance()); + } + + public ContagiousNim (final ContagiousNim card) { + super(card); + } + + @Override + public ContagiousNim copy() { + return new ContagiousNim(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/Cystbearer.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/Cystbearer.java new file mode 100644 index 00000000000..793d65af82f --- /dev/null +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/Cystbearer.java @@ -0,0 +1,70 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.sets.scarsofmirrodin; + +import java.util.UUID; + +import mage.Constants.CardType; +import mage.Constants.Duration; +import mage.Constants.Rarity; +import mage.Constants.Zone; +import mage.MageInt; +import mage.abilities.StaticAbility; +import mage.abilities.keyword.InfectAbility; +import mage.cards.CardImpl; + +/** + * Cystbearer + * + * @author nantuko + */ +public class Cystbearer extends CardImpl { + + public Cystbearer(UUID ownerId) { + super(ownerId, 117, "Cystbearer", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{G}"); + this.expansionSetCode = "SOM"; + this.subtype.add("Beast"); + + this.color.setGreen(true); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + this.addAbility(InfectAbility.getInstance()); + } + + public Cystbearer(final Cystbearer card) { + super(card); + } + + @Override + public Cystbearer copy() { + return new Cystbearer(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/ElspethTirel.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/ElspethTirel.java new file mode 100644 index 00000000000..069549ed152 --- /dev/null +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/ElspethTirel.java @@ -0,0 +1,133 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.sets.scarsofmirrodin; + +import java.util.UUID; + +import mage.Constants; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.filter.common.FilterCreaturePermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.PermanentToken; +import mage.game.permanent.token.SoldierToken; +import mage.players.Player; + +/** + * + * @author Loki + */ +public class ElspethTirel extends CardImpl { + + public ElspethTirel (UUID ownerId) { + super(ownerId, 6, "Elspeth Tirel", Rarity.MYTHIC, new CardType[]{CardType.PLANESWALKER}, "{3}{W}{W}"); + this.expansionSetCode = "SOM"; + this.subtype.add("Elspeth"); + this.color.setWhite(true); + this.loyalty = new MageInt(4); + this.addAbility(new LoyaltyAbility(new ElspethTirelFirstEffect(), 2)); + this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new SoldierToken(), 3), -2)); + this.addAbility(new LoyaltyAbility(new ElspethTirelThirdEffect(), -5)); + } + + public ElspethTirel (final ElspethTirel card) { + super(card); + } + + @Override + public ElspethTirel copy() { + return new ElspethTirel(this); + } +} + +class ElspethTirelFirstEffect extends OneShotEffect { + public ElspethTirelFirstEffect() { + super(Constants.Outcome.GainLife); + } + + public ElspethTirelFirstEffect(final ElspethTirelFirstEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + int amount = game.getBattlefield().countAll(new FilterCreaturePermanent(), source.getControllerId()); + Player player = game.getPlayer(source.getControllerId()); + if (player != null) { + player.gainLife(amount, game); + } + return true; + } + + @Override + public ElspethTirelFirstEffect copy() { + return new ElspethTirelFirstEffect(this); + } + + @Override + public String getText(Ability source) { + return "You gain 1 life for each creature you control"; + } +} + +class ElspethTirelThirdEffect extends OneShotEffect { + public ElspethTirelThirdEffect() { + super(Constants.Outcome.DestroyPermanent); + } + + public ElspethTirelThirdEffect(final ElspethTirelThirdEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + for (Permanent perm: game.getBattlefield().getActivePermanents(source.getControllerId(), game)) { + if (!perm.getId().equals(source.getSourceId()) && !(perm instanceof PermanentToken) && ! (perm.getCardType().contains(CardType.LAND))) + perm.destroy(source.getId(), game, false); + } + return true; + } + + @Override + public ElspethTirelThirdEffect copy() { + return new ElspethTirelThirdEffect(this); + } + + @Override + public String getText(Ability source) { + return "Destroy all other permanents except for lands and tokens"; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/KothoftheHammer.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/KothoftheHammer.java new file mode 100644 index 00000000000..186db635b7c --- /dev/null +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/KothoftheHammer.java @@ -0,0 +1,222 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.sets.scarsofmirrodin; + +import java.util.UUID; + +import mage.Constants; +import mage.Constants.CardType; +import mage.Constants.Duration; +import mage.Constants.Rarity; +import mage.Constants.Zone; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.ManaEffect; +import mage.abilities.effects.common.UntapTargetEffect; +import mage.cards.CardImpl; +import mage.filter.Filter; +import mage.filter.common.FilterLandPermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCreatureOrPlayer; +import mage.target.common.TargetLandPermanent; + +/** + * + * @author Loki + */ +public class KothoftheHammer extends CardImpl { + static FilterLandPermanent filter = new FilterLandPermanent("Mountain"); + + static { + filter.getSubtype().add("Mountain"); + filter.setScopeSubtype(Filter.ComparisonScope.Any); + } + + public KothoftheHammer (UUID ownerId) { + super(ownerId, 94, "Koth of the Hammer", Rarity.MYTHIC, new CardType[]{CardType.PLANESWALKER}, "{2}{R}{R}"); + this.expansionSetCode = "SOM"; + this.subtype.add("Koth"); + this.color.setRed(true); + this.loyalty = new MageInt(3); + Ability ability = new LoyaltyAbility(new UntapTargetEffect(), 1); + ability.addEffect(new KothoftheHammerFirstEffect()); + ability.addTarget(new TargetLandPermanent(filter)); + this.addAbility(ability); + this.addAbility(new LoyaltyAbility(new KothoftheHammerSecondEffect(), -2)); + this.addAbility(new LoyaltyAbility(new KothoftheHammerThirdEffect(), -5)); + } + + public KothoftheHammer (final KothoftheHammer card) { + super(card); + } + + @Override + public KothoftheHammer copy() { + return new KothoftheHammer(this); + } +} + +class KothoftheHammerFirstEffect extends ContinuousEffectImpl { + + public KothoftheHammerFirstEffect() { + super(Duration.EndOfTurn, Constants.Outcome.BecomeCreature); + } + + public KothoftheHammerFirstEffect(final KothoftheHammerFirstEffect effect) { + super(effect); + } + + @Override + public boolean apply(Constants.Layer layer, Constants.SubLayer sublayer, Ability source, Game game) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent != null) { + switch (layer) { + case TypeChangingEffects_4: + if (sublayer == Constants.SubLayer.NA) { + permanent.getCardType().add(CardType.CREATURE); + permanent.getSubtype().add("Elemental"); + } + break; + case ColorChangingEffects_5: + if (sublayer == Constants.SubLayer.NA) { + permanent.getColor().setRed(true); + } + break; + case PTChangingEffects_7: + if (sublayer == Constants.SubLayer.SetPT_7b) { + permanent.getPower().setValue(4); + permanent.getToughness().setValue(4); + } + } + return true; + } + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public KothoftheHammerFirstEffect copy() { + return new KothoftheHammerFirstEffect(this); + } + + @Override + public boolean hasLayer(Constants.Layer layer) { + return layer == Constants.Layer.PTChangingEffects_7 || layer == Constants.Layer.ColorChangingEffects_5 || layer == layer.TypeChangingEffects_4; + } + + @Override + public String getText(Ability source) { + return "It becomes a 4/4 red Elemental creature until end of turn. It's still a land"; + } +} + +class KothoftheHammerSecondEffect extends OneShotEffect { + public KothoftheHammerSecondEffect() { + super(Constants.Outcome.PutManaInPool); + } + + public KothoftheHammerSecondEffect(final KothoftheHammerSecondEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + int count = game.getBattlefield().count(KothoftheHammer.filter, source.getControllerId(), game); + int current = game.getPlayer(source.getControllerId()).getManaPool().getRed(); + game.getPlayer(source.getControllerId()).getManaPool().setRed(count + current); + return true; + } + + @Override + public KothoftheHammerSecondEffect copy() { + return new KothoftheHammerSecondEffect(this); + } + + @Override + public String getText(Ability source) { + return "Add {R} to your mana pool for each Mountain you control"; + } +} + +class KothoftheHammerThirdEffect extends ContinuousEffectImpl { + public KothoftheHammerThirdEffect() { + super(Duration.EndOfGame, Constants.Outcome.AddAbility); + } + + public KothoftheHammerThirdEffect(final KothoftheHammerThirdEffect effect) { + super(effect); + } + + @Override + public boolean apply(Constants.Layer layer, Constants.SubLayer sublayer, Ability source, Game game) { + switch (layer) { + case AbilityAddingRemovingEffects_6: + if (sublayer == Constants.SubLayer.NA) { + for (Permanent p : game.getBattlefield().getActivePermanents(KothoftheHammer.filter, source.getControllerId(), game)) { + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new TapSourceCost()); + ability.addTarget(new TargetCreatureOrPlayer()); + p.addAbility(ability); + } + } + break; + } + return true; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public KothoftheHammerThirdEffect copy() { + return new KothoftheHammerThirdEffect(this); + } + + @Override + public boolean hasLayer(Constants.Layer layer) { + return layer == Constants.Layer.AbilityAddingRemovingEffects_6; + } + + @Override + public String getText(Ability source) { + return "You get an emblem with \"Mountains you control have '{T}: This land deals 1 damage to target creature or player.'\""; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/LuxCannon.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/LuxCannon.java index 78f1095b1d7..dba7f75735a 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/LuxCannon.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/LuxCannon.java @@ -38,6 +38,7 @@ import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.common.AddCountersSourceEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; +import mage.counters.CounterType; import mage.target.TargetPermanent; import java.util.UUID; @@ -51,9 +52,9 @@ public class LuxCannon extends CardImpl { public LuxCannon (UUID ownerId) { super(ownerId, 173, "Lux Cannon", Rarity.MYTHIC, new CardType[]{CardType.ARTIFACT}, "{4}"); this.expansionSetCode = "SOM"; - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersSourceEffect("charge", 1), new TapSourceCost())); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.CHARGE.getName(), 1), new TapSourceCost())); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), new TapSourceCost()); - ability.addCost(new RemoveCountersSourceCost("charge", 3)); + ability.addCost(new RemoveCountersSourceCost(CounterType.CHARGE.getName(), 3)); ability.addTarget(new TargetPermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/PlagueStinger.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/PlagueStinger.java new file mode 100644 index 00000000000..e95bea1e8b3 --- /dev/null +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/PlagueStinger.java @@ -0,0 +1,71 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.sets.scarsofmirrodin; + +import java.util.UUID; +import mage.Constants.CardType; +import mage.Constants.Duration; +import mage.Constants.Rarity; +import mage.Constants.Zone; +import mage.MageInt; +import mage.abilities.common.OnEventTriggeredAbility; +import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.InfectAbility; +import mage.cards.CardImpl; +import mage.game.events.GameEvent; + +/** + * + * @author Loki + */ +public class PlagueStinger extends CardImpl { + + public PlagueStinger (UUID ownerId) { + super(ownerId, 75, "Plague Stinger", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{B}"); + this.expansionSetCode = "SOM"; + this.subtype.add("Insect"); + this.subtype.add("Horror"); + this.color.setBlack(true); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + this.addAbility(FlyingAbility.getInstance()); + this.addAbility(InfectAbility.getInstance()); + } + + public PlagueStinger (final PlagueStinger card) { + super(card); + } + + @Override + public PlagueStinger copy() { + return new PlagueStinger(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/Putrefax.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/Putrefax.java new file mode 100644 index 00000000000..96d89943265 --- /dev/null +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/Putrefax.java @@ -0,0 +1,69 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.sets.scarsofmirrodin; + +import java.util.UUID; +import mage.Constants.CardType; +import mage.Constants.Rarity; +import mage.MageInt; +import mage.abilities.common.OnEventTriggeredAbility; +import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.abilities.keyword.InfectAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.game.events.GameEvent; + +/** + * + * @author Loki + */ +public class Putrefax extends CardImpl { + + public Putrefax (UUID ownerId) { + super(ownerId, 126, "Putrefax", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{3}{G}{G}"); + this.expansionSetCode = "SOM"; + this.subtype.add("Horror"); + this.color.setGreen(true); + this.power = new MageInt(5); + this.toughness = new MageInt(3); + this.addAbility(TrampleAbility.getInstance()); + this.addAbility(InfectAbility.getInstance()); + this.addAbility(new OnEventTriggeredAbility(GameEvent.EventType.END_TURN_STEP_PRE, "beginning of the end step", new SacrificeSourceEffect())); + } + + public Putrefax (final Putrefax card) { + super(card); + } + + @Override + public Putrefax copy() { + return new Putrefax(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/SkithiryxtheBlightDragon.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/SkithiryxtheBlightDragon.java new file mode 100644 index 00000000000..89c004f98ca --- /dev/null +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/SkithiryxtheBlightDragon.java @@ -0,0 +1,76 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.sets.scarsofmirrodin; + +import java.util.UUID; +import mage.Constants.CardType; +import mage.Constants.Duration; +import mage.Constants.Rarity; +import mage.Constants.Zone; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.GainAbilitySourceEffect; +import mage.abilities.effects.common.RegenerateSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.InfectAbility; +import mage.cards.CardImpl; + +/** + * + * @author Loki + */ +public class SkithiryxtheBlightDragon extends CardImpl { + + public SkithiryxtheBlightDragon (UUID ownerId) { + super(ownerId, 79, "Skithiryx, the Blight Dragon", Rarity.MYTHIC, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); + this.expansionSetCode = "SOM"; + this.supertype.add("Legendary"); + this.subtype.add("Dragon"); + this.subtype.add("Skeleton"); + this.color.setBlack(true); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + this.addAbility(FlyingAbility.getInstance()); + this.addAbility(InfectAbility.getInstance()); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainAbilitySourceEffect(HasteAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl("{B}"))); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new ManaCostsImpl("{B}{B}"))); + } + + public SkithiryxtheBlightDragon (final SkithiryxtheBlightDragon card) { + super(card); + } + + @Override + public SkithiryxtheBlightDragon copy() { + return new SkithiryxtheBlightDragon(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/TaintedStrike.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/TaintedStrike.java new file mode 100644 index 00000000000..7129b69ebb6 --- /dev/null +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/TaintedStrike.java @@ -0,0 +1,66 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.sets.scarsofmirrodin; + +import java.util.UUID; +import mage.Constants.CardType; +import mage.Constants.Duration; +import mage.Constants.Rarity; +import mage.Constants.Zone; +import mage.abilities.effects.common.BoostTargetEffect; +import mage.abilities.effects.common.GainAbilityTargetEffect; +import mage.abilities.keyword.InfectAbility; +import mage.cards.CardImpl; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author Loki + */ +public class TaintedStrike extends CardImpl { + + public TaintedStrike (UUID ownerId) { + super(ownerId, 80, "Tainted Strike", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{B}"); + this.expansionSetCode = "SOM"; + this.color.setBlack(true); + this.getSpellAbility().addEffect(new BoostTargetEffect(1, 0, Duration.EndOfTurn)); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect(InfectAbility.getInstance(), Duration.EndOfTurn)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + public TaintedStrike (final TaintedStrike card) { + super(card); + } + + @Override + public TaintedStrike copy() { + return new TaintedStrike(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/VulshokHeartstoker.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/VulshokHeartstoker.java new file mode 100644 index 00000000000..009f3d08209 --- /dev/null +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/VulshokHeartstoker.java @@ -0,0 +1,71 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.sets.scarsofmirrodin; + +import java.util.UUID; +import mage.Constants.CardType; +import mage.Constants.Duration; +import mage.Constants.Rarity; +import mage.Constants.Zone; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author Loki + */ +public class VulshokHeartstoker extends CardImpl { + + public VulshokHeartstoker (UUID ownerId) { + super(ownerId, 107, "Vulshok Heartstoker", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{R}"); + this.expansionSetCode = "SOM"; + this.subtype.add("Human"); + this.subtype.add("Shaman"); + this.color.setRed(true); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + Ability ability = new EntersBattlefieldTriggeredAbility(new BoostTargetEffect(2, 0, Duration.EndOfTurn)); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public VulshokHeartstoker (final VulshokHeartstoker card) { + super(card); + } + + @Override + public VulshokHeartstoker copy() { + return new VulshokHeartstoker(this); + } + +} diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/WurmcoilEngine.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/WurmcoilEngine.java new file mode 100644 index 00000000000..b755693d3c9 --- /dev/null +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/WurmcoilEngine.java @@ -0,0 +1,96 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.sets.scarsofmirrodin; + +import java.util.UUID; +import mage.Constants.CardType; +import mage.Constants.Duration; +import mage.Constants.Rarity; +import mage.Constants.Zone; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.PutIntoGraveFromBattlefieldTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.keyword.LifelinkAbility; +import mage.cards.CardImpl; +import mage.game.permanent.token.Token; + +/** + * + * @author Loki + */ +public class WurmcoilEngine extends CardImpl { + + public WurmcoilEngine (UUID ownerId) { + super(ownerId, 223, "Wurmcoil Engine", Rarity.MYTHIC, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{6}"); + this.expansionSetCode = "SOM"; + this.subtype.add("Wurm"); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + this.addAbility(DeathtouchAbility.getInstance()); + this.addAbility(LifelinkAbility.getInstance()); + Ability ability = new PutIntoGraveFromBattlefieldTriggeredAbility(new CreateTokenEffect(new Wurm1Token()), false); + ability.addEffect(new CreateTokenEffect(new Wurm2Token())); + this.addAbility(ability); + } + + public WurmcoilEngine (final WurmcoilEngine card) { + super(card); + } + + @Override + public WurmcoilEngine copy() { + return new WurmcoilEngine(this); + } + +} + +class Wurm1Token extends Token { + public Wurm1Token() { + super("Wurm", "a 3/3 colorless Wurm artifact creature token with deathtouch"); + cardType.add(CardType.CREATURE); + subtype.add("Wurm"); + power = new MageInt(3); + toughness = new MageInt(3); + this.addAbility(DeathtouchAbility.getInstance()); + } +} + +class Wurm2Token extends Token { + public Wurm2Token() { + super("Wurm", "a 3/3 colorless Wurm artifact creature token with lifelink"); + cardType.add(CardType.CREATURE); + subtype.add("Wurm"); + power = new MageInt(3); + toughness = new MageInt(3); + this.addAbility(LifelinkAbility.getInstance()); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/worldwake/EverflowingChalice.java b/Mage.Sets/src/mage/sets/worldwake/EverflowingChalice.java index 91b15082017..e8234e93f43 100644 --- a/Mage.Sets/src/mage/sets/worldwake/EverflowingChalice.java +++ b/Mage.Sets/src/mage/sets/worldwake/EverflowingChalice.java @@ -44,6 +44,7 @@ import mage.abilities.effects.common.ManaEffect; import mage.abilities.keyword.MultikickerAbility; import mage.abilities.mana.ManaAbility; import mage.cards.CardImpl; +import mage.counters.CounterType; import mage.game.Game; /** @@ -55,7 +56,7 @@ public class EverflowingChalice extends CardImpl { public EverflowingChalice(UUID ownerId) { super(ownerId, 123, "Everflowing Chalice", Rarity.UNCOMMON, new CardType[]{CardType.ARTIFACT}, "{0}"); this.expansionSetCode = "WWK"; - Ability ability1 = new EntersBattlefieldTriggeredAbility(new AddCountersSourceEffect("charge", 1)); + Ability ability1 = new EntersBattlefieldTriggeredAbility(new AddCountersSourceEffect(CounterType.CHARGE.getName(), 1)); MultikickerAbility ability = new MultikickerAbility(new GainAbilitySourceEffect(ability1, Duration.WhileOnBattlefield), false); ability.addManaCost(new GenericManaCost(2)); this.addAbility(ability); @@ -120,7 +121,7 @@ class EverflowingChaliceEffect extends ManaEffect { @Override public boolean apply(Game game, Ability source) { this.mana.clear(); - this.mana.setColorless(game.getPermanent(source.getSourceId()).getCounters().getCount("charge")); + this.mana.setColorless(game.getPermanent(source.getSourceId()).getCounters().getCount(CounterType.CHARGE)); return super.apply(game, source); } diff --git a/Mage.Sets/src/mage/sets/zendikar/OranRiefTheVastwood.java b/Mage.Sets/src/mage/sets/zendikar/OranRiefTheVastwood.java index 640a2a21b9c..2aed5cfeb64 100644 --- a/Mage.Sets/src/mage/sets/zendikar/OranRiefTheVastwood.java +++ b/Mage.Sets/src/mage/sets/zendikar/OranRiefTheVastwood.java @@ -40,7 +40,7 @@ import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.mana.GreenManaAbility; import mage.cards.CardImpl; -import mage.counters.PlusOneCounter; +import mage.counters.common.PlusOneCounter; import mage.filter.FilterPermanent; import mage.game.Game; import mage.game.permanent.Permanent; diff --git a/Mage.Tests/src/test/java/org/mage/test/base/MageBase.java b/Mage.Tests/src/test/java/org/mage/test/base/MageBase.java index b174d9bbf19..6bda8ab0fc9 100644 --- a/Mage.Tests/src/test/java/org/mage/test/base/MageBase.java +++ b/Mage.Tests/src/test/java/org/mage/test/base/MageBase.java @@ -21,6 +21,9 @@ import java.util.List; import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; +import mage.Constants.MultiplayerAttackOption; +import mage.Constants.RangeOfInfluence; +import mage.game.match.MatchOptions; /** * Base for starting Mage server. @@ -64,14 +67,18 @@ public class MageBase { connect("player", "localhost", 17171); UUID roomId = server.getMainRoomId(); - List playerTypes = new ArrayList(); - playerTypes.add("Human"); - playerTypes.add("Computer - default"); - TableView table = server.createTable(sessionId, roomId, "Two Player Duel", "Limited", playerTypes, null, null); + MatchOptions options = new MatchOptions("1", "Two Player Duel"); + options.getPlayerTypes().add("Human"); + options.getPlayerTypes().add("Computer - default"); + options.setDeckType("Limited"); + options.setAttackOption(MultiplayerAttackOption.LEFT); + options.setRange(RangeOfInfluence.ALL); + options.setWinsNeeded(1); + TableView table = server.createTable(sessionId, roomId, options); System.out.println("Cards in the deck: " + Sets.loadDeck("UW Control.dck").getCards().size()); server.joinTable(sessionId, roomId, table.getTableId(), "Human", Sets.loadDeck("UW Control.dck")); server.joinTable(sessionId, roomId, table.getTableId(), "Computer", Sets.loadDeck("UW Control.dck")); - server.startGame(sessionId, roomId, table.getTableId()); + server.startMatch(sessionId, roomId, table.getTableId()); synchronized (syncStart) { int waitTime = 7000; diff --git a/Mage/src/mage/abilities/Abilities.java b/Mage/src/mage/abilities/Abilities.java index 84fa54f9061..373446b4554 100644 --- a/Mage/src/mage/abilities/Abilities.java +++ b/Mage/src/mage/abilities/Abilities.java @@ -39,7 +39,7 @@ import mage.filter.FilterAbility; public interface Abilities extends List, Serializable { - public List getRules(); + public List getRules(String source); public Abilities getActivatedAbilities(Zone zone); public Abilities getActivatedAbilities(Zone zone, FilterAbility filter); public Abilities getManaAbilities(Zone zone); diff --git a/Mage/src/mage/abilities/AbilitiesImpl.java b/Mage/src/mage/abilities/AbilitiesImpl.java index ae40e84139e..e63ac8d181f 100644 --- a/Mage/src/mage/abilities/AbilitiesImpl.java +++ b/Mage/src/mage/abilities/AbilitiesImpl.java @@ -58,7 +58,7 @@ public class AbilitiesImpl extends ArrayList implements Ab } @Override - public List getRules() { + public List getRules(String source) { List rules = new ArrayList(); for (T ability:this) { diff --git a/Mage/src/mage/abilities/Ability.java b/Mage/src/mage/abilities/Ability.java index ab37daa5358..54c9cc73b22 100644 --- a/Mage/src/mage/abilities/Ability.java +++ b/Mage/src/mage/abilities/Ability.java @@ -73,6 +73,7 @@ public interface Ability extends Serializable { public Zone getZone(); public boolean isUsesStack(); public String getRule(); + public String getRule(String source); public boolean activate(Game game, boolean noMana); public boolean resolve(Game game); public void reset(Game game); diff --git a/Mage/src/mage/abilities/AbilityImpl.java b/Mage/src/mage/abilities/AbilityImpl.java index b8149c48050..fdfe229c7a9 100644 --- a/Mage/src/mage/abilities/AbilityImpl.java +++ b/Mage/src/mage/abilities/AbilityImpl.java @@ -302,6 +302,17 @@ public abstract class AbilityImpl> implements Ability { return sbRule.toString(); } + @Override + public String getRule(String source) { + return formatRule(getRule(), source); + } + + protected String formatRule(String rule, String source) { + String replace = rule.replace("{this}", source); + replace = replace.replace("{source}", source); + return replace; + } + @Override public void addCost(Cost cost) { if (cost != null) { diff --git a/Mage/src/mage/abilities/TriggeredAbilityImpl.java b/Mage/src/mage/abilities/TriggeredAbilityImpl.java index df530369a21..4aa8a015647 100644 --- a/Mage/src/mage/abilities/TriggeredAbilityImpl.java +++ b/Mage/src/mage/abilities/TriggeredAbilityImpl.java @@ -81,10 +81,13 @@ public abstract class TriggeredAbilityImpl> ex Player player = game.getPlayer(this.getControllerId()); MageObject object = game.getObject(sourceId); StringBuilder sb = new StringBuilder(); - sb.append("Use ").append(this.getRule()).append("ability"); if (object != null) { + sb.append("Use ").append(this.getRule(object.getName())).append("ability"); sb.append(" from ").append(object.getName()); } + else { + sb.append("Use ").append(this.getRule()).append("ability"); + } sb.append("?"); if (!player.chooseUse(this.effects.get(0).getOutcome(), sb.toString(), game)) { return false; diff --git a/Mage/src/mage/abilities/condition/common/ControlsPermanent.java b/Mage/src/mage/abilities/condition/common/ControlsPermanent.java new file mode 100644 index 00000000000..7c35d6af7ed --- /dev/null +++ b/Mage/src/mage/abilities/condition/common/ControlsPermanent.java @@ -0,0 +1,19 @@ +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.filter.FilterPermanent; +import mage.game.Game; + +public class ControlsPermanent implements Condition { + private FilterPermanent filter; + + public ControlsPermanent(FilterPermanent filter) { + this.filter = filter; + } + + @Override + public boolean apply(Game game, Ability source) { + return game.getBattlefield().countAll(filter, source.getControllerId()) > 0; + } +} diff --git a/Mage/src/mage/abilities/effects/WhileConditionContiniousEffect.java b/Mage/src/mage/abilities/effects/WhileConditionContiniousEffect.java new file mode 100644 index 00000000000..f5b8e997406 --- /dev/null +++ b/Mage/src/mage/abilities/effects/WhileConditionContiniousEffect.java @@ -0,0 +1,32 @@ +package mage.abilities.effects; + +import mage.Constants; +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.game.Game; + +public abstract class WhileConditionContiniousEffect> extends ContinuousEffectImpl { + protected Condition condition; + + public WhileConditionContiniousEffect(Constants.Duration duration, Constants.Layer layer, Constants.SubLayer sublayer, Condition condition, Constants.Outcome outcome) { + super(duration, outcome); + this.condition = condition; + this.layer = layer; + this.sublayer = sublayer; + } + + public WhileConditionContiniousEffect(final WhileConditionContiniousEffect effect) { + super(effect); + this.condition = effect.condition; + } + + @Override + public boolean apply(Game game, Ability source) { + if (condition.apply(game, source)) { + return applyEffect(game, source); + } + return false; + } + + protected abstract boolean applyEffect(Game game, Ability source); +} diff --git a/Mage/src/mage/abilities/effects/common/AddPlusOneCountersAttachedEffect.java b/Mage/src/mage/abilities/effects/common/AddPlusOneCountersAttachedEffect.java index e8d55b02577..2b17b1b4c07 100644 --- a/Mage/src/mage/abilities/effects/common/AddPlusOneCountersAttachedEffect.java +++ b/Mage/src/mage/abilities/effects/common/AddPlusOneCountersAttachedEffect.java @@ -31,7 +31,7 @@ package mage.abilities.effects.common; import mage.Constants.Outcome; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.counters.PlusOneCounter; +import mage.counters.common.PlusOneCounter; import mage.game.Game; import mage.game.permanent.Permanent; diff --git a/Mage/src/mage/abilities/effects/common/AddPlusOneCountersControlledEffect.java b/Mage/src/mage/abilities/effects/common/AddPlusOneCountersControlledEffect.java index 4d0a4e24ac6..b427b6cad14 100644 --- a/Mage/src/mage/abilities/effects/common/AddPlusOneCountersControlledEffect.java +++ b/Mage/src/mage/abilities/effects/common/AddPlusOneCountersControlledEffect.java @@ -31,7 +31,7 @@ package mage.abilities.effects.common; import mage.Constants.Outcome; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.counters.PlusOneCounter; +import mage.counters.common.PlusOneCounter; import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; diff --git a/Mage/src/mage/abilities/effects/common/AddPlusOneCountersSourceEffect.java b/Mage/src/mage/abilities/effects/common/AddPlusOneCountersSourceEffect.java index 27d80dc0d32..2a8c8586f4c 100644 --- a/Mage/src/mage/abilities/effects/common/AddPlusOneCountersSourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/AddPlusOneCountersSourceEffect.java @@ -31,7 +31,7 @@ package mage.abilities.effects.common; import mage.Constants.Outcome; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.counters.PlusOneCounter; +import mage.counters.common.PlusOneCounter; import mage.game.Game; import mage.game.permanent.Permanent; diff --git a/Mage/src/mage/abilities/effects/common/BoostSourceWhileControlsEffect.java b/Mage/src/mage/abilities/effects/common/BoostSourceWhileControlsEffect.java index 845be8d499b..1abdc1905c0 100644 --- a/Mage/src/mage/abilities/effects/common/BoostSourceWhileControlsEffect.java +++ b/Mage/src/mage/abilities/effects/common/BoostSourceWhileControlsEffect.java @@ -28,7 +28,8 @@ package mage.abilities.effects.common; -import mage.abilities.effects.WhileControlsContinuousEffect; +import mage.abilities.condition.common.ControlsPermanent; +import mage.abilities.effects.WhileConditionContiniousEffect; import mage.Constants.Duration; import mage.Constants.Layer; import mage.Constants.Outcome; @@ -38,25 +39,32 @@ import mage.filter.FilterPermanent; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.ArrayList; +import java.util.List; + /** * * @author BetaSteward_at_googlemail.com */ -public class BoostSourceWhileControlsEffect extends WhileControlsContinuousEffect { +public class BoostSourceWhileControlsEffect extends WhileConditionContiniousEffect { private int power; private int toughness; + private List filterDescription; public BoostSourceWhileControlsEffect(FilterPermanent filter, int power, int toughness) { - super(Duration.WhileOnBattlefield, Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, filter, Outcome.BoostCreature); + super(Duration.WhileOnBattlefield, Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, new ControlsPermanent(filter), Outcome.BoostCreature); this.power = power; this.toughness = toughness; + this.filterDescription = filter.getName(); } public BoostSourceWhileControlsEffect(final BoostSourceWhileControlsEffect effect) { super(effect); this.power = effect.power; this.toughness = effect.toughness; + this.filterDescription = new ArrayList(); + this.filterDescription.addAll(effect.filterDescription); } @Override @@ -76,6 +84,6 @@ public class BoostSourceWhileControlsEffect extends WhileControlsContinuousEffec @Override public String getText(Ability source) { - return "{this} gets " + String.format("%1$+d/%2$+d", power, toughness) + " as long as you control a " + filter.getName(); + return "{this} gets " + String.format("%1$+d/%2$+d", power, toughness) + " as long as you control a " + filterDescription; } } diff --git a/Mage/src/mage/abilities/effects/common/SacrificeSourceUnlessPaysEffect.java b/Mage/src/mage/abilities/effects/common/SacrificeSourceUnlessPaysEffect.java index b8b48c9a84a..c95b298dd67 100644 --- a/Mage/src/mage/abilities/effects/common/SacrificeSourceUnlessPaysEffect.java +++ b/Mage/src/mage/abilities/effects/common/SacrificeSourceUnlessPaysEffect.java @@ -30,15 +30,17 @@ public class SacrificeSourceUnlessPaysEffect extends OneShotEffect { + + private static final InfectAbility fINSTANCE = new InfectAbility(); + + private Object readResolve() throws ObjectStreamException { + return fINSTANCE; + } + + public static InfectAbility getInstance() { + return fINSTANCE; + } + + private InfectAbility() { + super(Zone.ALL, null); + } + + @Override + public String getRule() { + return "Infect"; + } + + @Override + public InfectAbility copy() { + return fINSTANCE; + } + +} diff --git a/Mage/src/mage/abilities/keyword/LevelAbility.java b/Mage/src/mage/abilities/keyword/LevelAbility.java index ec1df74a835..84438ddd4e4 100644 --- a/Mage/src/mage/abilities/keyword/LevelAbility.java +++ b/Mage/src/mage/abilities/keyword/LevelAbility.java @@ -93,7 +93,7 @@ public class LevelAbility extends StaticAbility { else sb.append("-").append(level2); sb.append(": ").append(power).append("/").append(toughness).append(" "); - for (String rule: abilities.getRules()) { + for (String rule: abilities.getRules("{this}")) { sb.append(rule).append(" "); } return sb.toString(); diff --git a/Mage/src/mage/abilities/keyword/WitherAbility.java b/Mage/src/mage/abilities/keyword/WitherAbility.java new file mode 100644 index 00000000000..53d05434cf0 --- /dev/null +++ b/Mage/src/mage/abilities/keyword/WitherAbility.java @@ -0,0 +1,75 @@ +/* +* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are +* permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, this list +* of conditions and the following disclaimer in the documentation and/or other materials +* provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR +* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +* The views and conclusions contained in the software and documentation are those of the +* authors and should not be interpreted as representing official policies, either expressed +* or implied, of BetaSteward_at_googlemail.com. +*/ + +package mage.abilities.keyword; + +import mage.Constants.Zone; +import mage.abilities.StaticAbility; + +import java.io.ObjectStreamException; + +/** + * 702.77. Wither + * + * 702.77a. Wither is a static ability. Damage dealt to a creature by a source with wither isn't marked on that creature. Rather, it causes that many -1/-1 counters to be put on that creature. See rule 119.3. + * + * 702.77b. If a permanent leaves the battlefield before an effect causes it to deal damage, its last known information is used to determine whether it had wither. + * + * 702.77c. The wither rules function no matter what zone an object with wither deals damage from. + * + * 702.77d. Multiple instances of wither on the same object are redundant. + * + * @author nantuko + */ +public class WitherAbility extends StaticAbility { + + private static final WitherAbility fINSTANCE = new WitherAbility(); + + private Object readResolve() throws ObjectStreamException { + return fINSTANCE; + } + + public static WitherAbility getInstance() { + return fINSTANCE; + } + + private WitherAbility() { + super(Zone.ALL, null); + } + + @Override + public String getRule() { + return "Wither"; + } + + @Override + public WitherAbility copy() { + return fINSTANCE; + } + +} diff --git a/Mage/src/mage/cards/CardImpl.java b/Mage/src/mage/cards/CardImpl.java index be6684ac7bc..499e9161711 100644 --- a/Mage/src/mage/cards/CardImpl.java +++ b/Mage/src/mage/cards/CardImpl.java @@ -130,9 +130,9 @@ public abstract class CardImpl> extends MageObjectImpl @Override public List getRules() { - List rules = abilities.getRules(); + List rules = abilities.getRules(this.name); if (cardType.contains(CardType.INSTANT) || cardType.contains(CardType.SORCERY)) { - rules.add(0, getSpellAbility().getRule()); + rules.add(0, getSpellAbility().getRule(this.name)); } return rules; } diff --git a/Mage/src/mage/cards/ExpansionSet.java b/Mage/src/mage/cards/ExpansionSet.java index e4870d6bd1e..6ef19623954 100644 --- a/Mage/src/mage/cards/ExpansionSet.java +++ b/Mage/src/mage/cards/ExpansionSet.java @@ -143,6 +143,19 @@ public abstract class ExpansionSet implements Serializable { return null; } + public String findCard(String name, boolean random) { + List cards = new ArrayList(); + for (Card card: createCards()) { + if (name.equals(card.getName())) { + cards.add(card.getClass().getCanonicalName()); + } + } + if (cards.size() > 0) { + return cards.get(rnd.nextInt(cards.size())); + } + return null; + } + public String findCard(int cardNum) { for (Card card: createCards()) { if (card.getCardNumber() == cardNum) diff --git a/Mage/src/mage/counters/CounterType.java b/Mage/src/mage/counters/CounterType.java new file mode 100644 index 00000000000..418c1b4a186 --- /dev/null +++ b/Mage/src/mage/counters/CounterType.java @@ -0,0 +1,108 @@ +/* +* 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.counters; + +import mage.counters.common.*; + +/** + * Enum for counters, names and instances. + * + * @author nantuko + */ +public enum CounterType { + P1P1(new PlusOneCounter().name), + M1M1(new MinusOneCounter().name), + POISON(new PoisonCounter().name), + CHARGE(new ChargeCounter().name), + LEVEL(new LevelCounter().name), + TIME(new TimeCounter().name), + FADE(new FadeCounter().name), + FEATHER(new FeatherCounter().name), + QUEST(new QuestCounter().name), + ARROWHEAD(new ArrowheadCounter().name), + EON(new EonCounter().name); + + private String name; + + private CounterType(String name) { + this.name = name; + } + + /** + * Get counter string name. + * + * @return + */ + public String getName() { + return this.name; + } + + /** + * Get instance of counter type with amount equal to 1. + * + * @return + */ + public Counter getInstance() { + return getInstance(1); + } + + /** + * Get instance of counter type with defined amount of counters of the given type. + * + * @param amount amount of counters of the given type. + * @return + */ + public Counter getInstance(int amount) { + switch(this) { + case P1P1: + return new PlusOneCounter(amount); + case M1M1: + return new MinusOneCounter(amount); + case POISON: + return new PoisonCounter(amount); + case CHARGE: + return new ChargeCounter(amount); + case LEVEL: + return new LevelCounter(amount); + case TIME: + return new TimeCounter(amount); + case FADE: + return new FadeCounter(amount); + case FEATHER: + return new FeatherCounter(amount); + case QUEST: + return new QuestCounter(amount); + case ARROWHEAD: + return new ArrowheadCounter(amount); + case EON: + return new EonCounter(amount); + } + return null; + } +} diff --git a/Mage/src/mage/counters/Counters.java b/Mage/src/mage/counters/Counters.java index 625db5a855a..3b142957427 100644 --- a/Mage/src/mage/counters/Counters.java +++ b/Mage/src/mage/counters/Counters.java @@ -86,6 +86,12 @@ public class Counters extends HashMap implements Serializable { return 0; } + public int getCount(CounterType type) { + if (this.containsKey(type.getName())) + return this.get(type.getName()).getCount(); + return 0; + } + public List getBoostCounters() { List boosters = new ArrayList(); for (Counter counter: this.values()) { diff --git a/Mage/src/mage/abilities/effects/WhileControlsContinuousEffect.java b/Mage/src/mage/counters/common/ArrowheadCounter.java similarity index 59% rename from Mage/src/mage/abilities/effects/WhileControlsContinuousEffect.java rename to Mage/src/mage/counters/common/ArrowheadCounter.java index 07a24ffe5ef..c6972f11832 100644 --- a/Mage/src/mage/abilities/effects/WhileControlsContinuousEffect.java +++ b/Mage/src/mage/counters/common/ArrowheadCounter.java @@ -1,69 +1,49 @@ -/* -* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, are -* permitted provided that the following conditions are met: -* -* 1. Redistributions of source code must retain the above copyright notice, this list of -* conditions and the following disclaimer. -* -* 2. Redistributions in binary form must reproduce the above copyright notice, this list -* of conditions and the following disclaimer in the documentation and/or other materials -* provided with the distribution. -* -* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR -* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -* -* The views and conclusions contained in the software and documentation are those of the -* authors and should not be interpreted as representing official policies, either expressed -* or implied, of BetaSteward_at_googlemail.com. -*/ - -package mage.abilities.effects; - -import mage.Constants.Duration; -import mage.Constants.Layer; -import mage.Constants.Outcome; -import mage.Constants.SubLayer; -import mage.abilities.Ability; -import mage.filter.FilterPermanent; -import mage.game.Game; - -/** - * - * @author BetaSteward_at_googlemail.com - */ -public abstract class WhileControlsContinuousEffect> extends ContinuousEffectImpl { - - protected FilterPermanent filter; - - public WhileControlsContinuousEffect(Duration duration, Layer layer, SubLayer sublayer, FilterPermanent filter, Outcome outcome) { - super(duration, outcome); - this.filter = filter; - this.layer = layer; - this.sublayer = sublayer; - } - - public WhileControlsContinuousEffect(WhileControlsContinuousEffect effect) { - super(effect); - this.filter = effect.filter.copy(); - } - - @Override - public boolean apply(Game game, Ability source) { - if (game.getBattlefield().countAll(filter, source.getControllerId()) > 0) { - return applyEffect(game, source); - } - return false; - } - - protected abstract boolean applyEffect(Game game, Ability source); - -} +/* +* 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.counters.common; + +import mage.counters.Counter; + +/** + * Arrowhead counter. + * + * @author nantuko + */ +public class ArrowheadCounter extends Counter { + + public ArrowheadCounter() { + super("Arrowhead"); + this.count = 1; + } + + public ArrowheadCounter(int amount) { + super("Arrowhead"); + this.count = amount; + } +} diff --git a/Mage/src/mage/counters/common/ChargeCounter.java b/Mage/src/mage/counters/common/ChargeCounter.java new file mode 100644 index 00000000000..474355e52a2 --- /dev/null +++ b/Mage/src/mage/counters/common/ChargeCounter.java @@ -0,0 +1,49 @@ +/* +* 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.counters.common; + +import mage.counters.Counter; + +/** + * Charge counter. + * + * @author nantuko + */ +public class ChargeCounter extends Counter { + + public ChargeCounter() { + super("Charge"); + this.count = 1; + } + + public ChargeCounter(int amount) { + super("Charge"); + this.count = amount; + } +} \ No newline at end of file diff --git a/Mage/src/mage/counters/common/EonCounter.java b/Mage/src/mage/counters/common/EonCounter.java new file mode 100644 index 00000000000..fb3df296712 --- /dev/null +++ b/Mage/src/mage/counters/common/EonCounter.java @@ -0,0 +1,49 @@ +/* +* 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.counters.common; + +import mage.counters.Counter; + +/** + * Eon counter. + * + * @author nantuko + */ +public class EonCounter extends Counter { + + public EonCounter() { + super("Eon"); + this.count = 1; + } + + public EonCounter(int amount) { + super("Eon"); + this.count = amount; + } +} diff --git a/Mage/src/mage/counters/common/FadeCounter.java b/Mage/src/mage/counters/common/FadeCounter.java new file mode 100644 index 00000000000..5684054fb05 --- /dev/null +++ b/Mage/src/mage/counters/common/FadeCounter.java @@ -0,0 +1,49 @@ +/* +* 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.counters.common; + +import mage.counters.Counter; + +/** + * Fade counter. + * + * @author nantuko + */ +public class FadeCounter extends Counter { + + public FadeCounter() { + super("Fade"); + this.count = 1; + } + + public FadeCounter(int amount) { + super("Fade"); + this.count = amount; + } +} diff --git a/Mage/src/mage/counters/common/FeatherCounter.java b/Mage/src/mage/counters/common/FeatherCounter.java new file mode 100644 index 00000000000..3face1d12e3 --- /dev/null +++ b/Mage/src/mage/counters/common/FeatherCounter.java @@ -0,0 +1,49 @@ +/* +* 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.counters.common; + +import mage.counters.Counter; + +/** + * Feather counter. + * + * @author nantuko + */ +public class FeatherCounter extends Counter { + + public FeatherCounter() { + super("Feather"); + this.count = 1; + } + + public FeatherCounter(int amount) { + super("Feather"); + this.count = amount; + } +} diff --git a/Mage/src/mage/counters/common/LevelCounter.java b/Mage/src/mage/counters/common/LevelCounter.java new file mode 100644 index 00000000000..16282b063c7 --- /dev/null +++ b/Mage/src/mage/counters/common/LevelCounter.java @@ -0,0 +1,49 @@ +/* +* 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.counters.common; + +import mage.counters.Counter; + +/** + * Level counter. + * + * @author nantuko + */ +public class LevelCounter extends Counter { + + public LevelCounter() { + super("Level"); + this.count = 1; + } + + public LevelCounter(int amount) { + super("Level"); + this.count = amount; + } +} diff --git a/Mage/src/mage/counters/MinusOneCounter.java b/Mage/src/mage/counters/common/MinusOneCounter.java similarity index 96% rename from Mage/src/mage/counters/MinusOneCounter.java rename to Mage/src/mage/counters/common/MinusOneCounter.java index ccaaef28055..0e8e4a842bc 100644 --- a/Mage/src/mage/counters/MinusOneCounter.java +++ b/Mage/src/mage/counters/common/MinusOneCounter.java @@ -26,7 +26,9 @@ * or implied, of BetaSteward_at_googlemail.com. */ -package mage.counters; +package mage.counters.common; + +import mage.counters.BoostCounter; /** * diff --git a/Mage/src/mage/counters/PlusOneCounter.java b/Mage/src/mage/counters/common/PlusOneCounter.java similarity index 96% rename from Mage/src/mage/counters/PlusOneCounter.java rename to Mage/src/mage/counters/common/PlusOneCounter.java index 1e1844c7c79..6fb6c72c358 100644 --- a/Mage/src/mage/counters/PlusOneCounter.java +++ b/Mage/src/mage/counters/common/PlusOneCounter.java @@ -26,7 +26,9 @@ * or implied, of BetaSteward_at_googlemail.com. */ -package mage.counters; +package mage.counters.common; + +import mage.counters.BoostCounter; /** * diff --git a/Mage/src/mage/counters/common/PoisonCounter.java b/Mage/src/mage/counters/common/PoisonCounter.java new file mode 100644 index 00000000000..70e3a22740a --- /dev/null +++ b/Mage/src/mage/counters/common/PoisonCounter.java @@ -0,0 +1,49 @@ +/* +* 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.counters.common; + +import mage.counters.Counter; + +/** + * Poison counter. + * + * @author nantuko + */ +public class PoisonCounter extends Counter { + + public PoisonCounter() { + super("Poison"); + this.count = 1; + } + + public PoisonCounter(int amount) { + super("Poison"); + this.count = amount; + } +} diff --git a/Mage/src/mage/counters/common/QuestCounter.java b/Mage/src/mage/counters/common/QuestCounter.java new file mode 100644 index 00000000000..18c3dc0dd95 --- /dev/null +++ b/Mage/src/mage/counters/common/QuestCounter.java @@ -0,0 +1,49 @@ +/* +* 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.counters.common; + +import mage.counters.Counter; + +/** + * Quest counter. + * + * @author nantuko + */ +public class QuestCounter extends Counter { + + public QuestCounter() { + super("Quest"); + this.count = 1; + } + + public QuestCounter(int amount) { + super("Quest"); + this.count = amount; + } +} diff --git a/Mage/src/mage/counters/common/TimeCounter.java b/Mage/src/mage/counters/common/TimeCounter.java new file mode 100644 index 00000000000..040294a7522 --- /dev/null +++ b/Mage/src/mage/counters/common/TimeCounter.java @@ -0,0 +1,49 @@ +/* +* 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.counters.common; + +import mage.counters.Counter; + +/** + * Time counter. + * + * @author nantuko + */ +public class TimeCounter extends Counter { + + public TimeCounter() { + super("Time"); + this.count = 1; + } + + public TimeCounter(int amount) { + super("Time"); + this.count = amount; + } +} \ No newline at end of file diff --git a/Mage/src/mage/game/Game.java b/Mage/src/mage/game/Game.java index 952c43e4cca..71fadddf838 100644 --- a/Mage/src/mage/game/Game.java +++ b/Mage/src/mage/game/Game.java @@ -28,6 +28,7 @@ package mage.game; +import mage.game.match.MatchType; import mage.cards.Card; import mage.game.stack.SpellStack; import mage.MageObject; @@ -64,7 +65,7 @@ import mage.players.Players; public interface Game extends MageItem, Serializable { - public GameType getGameType(); + public MatchType getGameType(); public int getNumPlayers(); public int getLife(); public RangeOfInfluence getRangeOfInfluence(); @@ -130,8 +131,8 @@ public interface Game extends MageItem, Serializable { public boolean replaceEvent(GameEvent event); //game play methods - public void init(); - public void start(); +// public void init(UUID choosingPlayerId); + public void start(UUID choosingPlayerId); public void end(); public void mulligan(UUID playerId); public void quit(UUID playerId); diff --git a/Mage/src/mage/game/GameImpl.java b/Mage/src/mage/game/GameImpl.java index 280324324a2..f34f000181f 100644 --- a/Mage/src/mage/game/GameImpl.java +++ b/Mage/src/mage/game/GameImpl.java @@ -28,6 +28,8 @@ package mage.game; +import mage.counters.CounterType; +import mage.game.match.MatchType; import java.io.IOException; import mage.game.stack.SpellStack; import java.io.Serializable; @@ -108,8 +110,9 @@ public abstract class GameImpl> implements Game, Serializa protected Map gameCards = new HashMap(); protected GameState state; protected UUID startingPlayerId; - protected UUID choosingPlayerId; +// protected UUID choosingPlayerId; protected UUID winnerId; + protected transient GameStates gameStates = new GameStates(); protected RangeOfInfluence range; protected MultiplayerAttackOption attackOption; @@ -128,7 +131,7 @@ public abstract class GameImpl> implements Game, Serializa this.id = game.id; this.ready = game.ready; this.startingPlayerId = game.startingPlayerId; - this.choosingPlayerId = game.choosingPlayerId; +// this.choosingPlayerId = game.choosingPlayerId; this.winnerId = game.winnerId; this.range = game.range; this.attackOption = game.attackOption; @@ -298,8 +301,8 @@ public abstract class GameImpl> implements Game, Serializa } @Override - public void start() { - init(); + public void start(UUID choosingPlayerId) { + init(choosingPlayerId); PlayerList players = state.getPlayerList(startingPlayerId); Player player = getPlayer(players.get()); while (!isGameOver()) { @@ -315,13 +318,12 @@ public abstract class GameImpl> implements Game, Serializa player = players.getNext(this); } - winnerId = findWinner(); + winnerId = findWinnersAndLosers(); saveState(); } - @Override - public void init() { + protected void init(UUID choosingPlayerId) { for (Player player: state.getPlayers().values()) { player.init(this); } @@ -334,19 +336,24 @@ public abstract class GameImpl> implements Game, Serializa } //20091005 - 103.2 - if (startingPlayerId == null) { - TargetPlayer targetPlayer = new TargetPlayer(); - targetPlayer.setRequired(true); - targetPlayer.setTargetName("starting player"); - Player choosingPlayer = getPlayer(pickChoosingPlayer()); - if (choosingPlayer.chooseTarget(Outcome.Benefit, targetPlayer, null, this)) { - startingPlayerId = ((List)targetPlayer.getTargets()).get(0); - fireInformEvent(state.getPlayer(startingPlayerId).getName() + " will start"); - } - else { - return; - } + TargetPlayer targetPlayer = new TargetPlayer(); + targetPlayer.setRequired(true); + targetPlayer.setTargetName("starting player"); + Player choosingPlayer; + if (choosingPlayerId == null) { + choosingPlayer = getPlayer(pickChoosingPlayer()); } + else { + choosingPlayer = this.getPlayer(choosingPlayerId); + } + if (choosingPlayer.chooseTarget(Outcome.Benefit, targetPlayer, null, this)) { + startingPlayerId = ((List)targetPlayer.getTargets()).get(0); + fireInformEvent(state.getPlayer(startingPlayerId).getName() + " will start"); + } + else { + return; + } + saveState(); //20091005 - 103.3 @@ -380,13 +387,21 @@ public abstract class GameImpl> implements Game, Serializa } } - protected UUID findWinner() { + protected UUID findWinnersAndLosers() { + UUID winner = null; for (Player player: state.getPlayers().values()) { if (player.hasWon() || (!player.hasLost() && !player.hasLeft())) { - return player.getId(); + player.won(this); + winner = player.getId(); + break; } } - return null; + for (Player player: state.getPlayers().values()) { + if (winner != null && !player.getId().equals(winner)) { + player.lost(this); + } + } + return winner; } protected void endOfTurn() { @@ -568,7 +583,7 @@ public abstract class GameImpl> implements Game, Serializa //20091005 - 704.5a/704.5b/704.5c for (Player player: state.getPlayers().values()) { - if (!player.hasLost() && (player.getLife() <= 0 || player.isEmptyDraw() || player.getCounters().getCount("Poison") >= 10)) { + if (!player.hasLost() && (player.getLife() <= 0 || player.isEmptyDraw() || player.getCounters().getCount(CounterType.POISON) >= 10)) { player.lost(this); } } diff --git a/Mage/src/mage/game/Table.java b/Mage/src/mage/game/Table.java index 464bb5f355e..0cfe414008d 100644 --- a/Mage/src/mage/game/Table.java +++ b/Mage/src/mage/game/Table.java @@ -32,7 +32,12 @@ import java.io.Serializable; import java.util.List; import java.util.UUID; import mage.Constants.TableState; +import mage.cards.decks.Deck; import mage.cards.decks.DeckValidator; +import mage.game.events.Listener; +import mage.game.events.TableEvent; +import mage.game.events.TableEvent.EventType; +import mage.game.events.TableEventSource; import mage.players.Player; /** @@ -49,10 +54,13 @@ public class Table implements Serializable { private DeckValidator validator; private TableState state = TableState.WAITING; - public Table(String gameType, DeckValidator validator, List playerTypes) { + protected TableEventSource tableEventSource = new TableEventSource(); + + public Table(String gameType, String name, DeckValidator validator, List playerTypes) { tableId = UUID.randomUUID(); this.numSeats = playerTypes.size(); this.gameType = gameType; + this.name = name; createSeats(playerTypes); this.validator = validator; } @@ -70,10 +78,7 @@ public class Table implements Serializable { return tableId; } - public void initGame(Game game) throws GameException { - for (int i = 0; i < numSeats; i++ ) { - game.addPlayer(seats[i].getPlayer()); - } + public void initGame() { state = TableState.DUELING; } @@ -134,4 +139,23 @@ public class Table implements Serializable { return this.validator; } + public void sideboard() { + state = TableState.SIDEBOARDING; + } + + public String getName() { + return this.name; + } + + public void fireSideboardEvent(UUID playerId) { + tableEventSource.fireTableEvent(EventType.SIDEBOARD, playerId, null); + } + + public void fireSubmitDeckEvent(UUID playerId, Deck deck) { + tableEventSource.fireTableEvent(EventType.SUBMIT_DECK, playerId, deck); + } + + public void addTableEventListener(Listener listener) { + tableEventSource.addListener(listener); + } } diff --git a/Mage/src/mage/game/events/TableEvent.java b/Mage/src/mage/game/events/TableEvent.java index c9b915c4aa6..a7f52d8d650 100644 --- a/Mage/src/mage/game/events/TableEvent.java +++ b/Mage/src/mage/game/events/TableEvent.java @@ -30,7 +30,9 @@ package mage.game.events; import java.io.Serializable; import java.util.EventObject; +import java.util.UUID; import mage.cards.Cards; +import mage.cards.decks.Deck; import mage.game.Game; /** @@ -40,13 +42,15 @@ import mage.game.Game; public class TableEvent extends EventObject implements ExternalEvent, Serializable { public enum EventType { - UPDATE, INFO, REVEAL, LOOK + UPDATE, INFO, REVEAL, LOOK, SIDEBOARD, SUBMIT_DECK } private Game game; private EventType eventType; private String message; private Cards cards; + private UUID playerId; + private Deck deck; public TableEvent(EventType eventType, String message, Cards cards, Game game) { super(game); @@ -56,6 +60,13 @@ public class TableEvent extends EventObject implements ExternalEvent, Serializab this.eventType = eventType; } + public TableEvent(EventType eventType, UUID playerId, Deck deck) { + super(playerId); + this.playerId = playerId; + this.deck = deck; + this.eventType = eventType; + } + public Game getGame() { return game; } @@ -72,4 +83,11 @@ public class TableEvent extends EventObject implements ExternalEvent, Serializab return cards; } + public UUID getPlayerId() { + return playerId; + } + + public Deck getDeck() { + return deck; + } } diff --git a/Mage/src/mage/game/events/TableEventSource.java b/Mage/src/mage/game/events/TableEventSource.java index 410df526ca6..4b46273a35d 100644 --- a/Mage/src/mage/game/events/TableEventSource.java +++ b/Mage/src/mage/game/events/TableEventSource.java @@ -29,8 +29,11 @@ package mage.game.events; import java.io.Serializable; +import java.util.UUID; import mage.cards.Cards; +import mage.cards.decks.Deck; import mage.game.Game; +import mage.game.events.TableEvent.EventType; /** * @@ -45,11 +48,15 @@ public class TableEventSource implements EventSource, Serializable { dispatcher.addListener(listener); } - public void fireTableEvent(TableEvent.EventType eventType, String message, Game game) { + public void fireTableEvent(EventType eventType, String message, Game game) { dispatcher.fireEvent(new TableEvent(eventType, message, null, game)); } - public void fireTableEvent(TableEvent.EventType eventType, String message, Cards cards, Game game) { + public void fireTableEvent(EventType eventType, String message, Cards cards, Game game) { dispatcher.fireEvent(new TableEvent(eventType, message, cards, game)); } + + public void fireTableEvent(EventType eventType, UUID playerId, Deck deck) { + dispatcher.fireEvent(new TableEvent(eventType, playerId, deck)); + } } diff --git a/Mage/src/mage/game/Match.java b/Mage/src/mage/game/match/Match.java similarity index 82% rename from Mage/src/mage/game/Match.java rename to Mage/src/mage/game/match/Match.java index ad58ddd6508..7364ab57637 100644 --- a/Mage/src/mage/game/Match.java +++ b/Mage/src/mage/game/match/Match.java @@ -26,10 +26,13 @@ * or implied, of BetaSteward_at_googlemail.com. */ -package mage.game; +package mage.game.match; import java.util.List; +import java.util.UUID; import mage.cards.decks.Deck; +import mage.game.Game; +import mage.game.GameException; import mage.players.Player; /** @@ -38,11 +41,17 @@ import mage.players.Player; */ public interface Match { + public UUID getId(); public boolean isMatchOver(); public List getPlayers(); + public MatchPlayer getPlayer(UUID playerId); public void addPlayer(Player player, Deck deck); - public int getMaxPlayers(); - public int getMinPlayers(); - public void startMatch(); - + public void startMatch() throws GameException; + public void startGame() throws GameException; + public void endGame(); + public Game getGame(); + public int getNumGames(); + public boolean isDoneSideboarding(); + public UUID getChooser(); + } diff --git a/Mage/src/mage/game/match/MatchImpl.java b/Mage/src/mage/game/match/MatchImpl.java new file mode 100644 index 00000000000..2ce1488afb7 --- /dev/null +++ b/Mage/src/mage/game/match/MatchImpl.java @@ -0,0 +1,149 @@ +/* + * 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.game.match; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import mage.cards.decks.Deck; +import mage.game.Game; +import mage.game.GameException; +import mage.players.Player; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public abstract class MatchImpl implements Match { + + protected UUID id = UUID.randomUUID(); + protected List players = new ArrayList(); + protected List games = new ArrayList(); + protected MatchOptions options; + + public MatchImpl(MatchOptions options) { + this.options = options; + } + + @Override + public List getPlayers() { + return players; + } + + @Override + public MatchPlayer getPlayer(UUID playerId) { + for (MatchPlayer player: players) { + if (player.getPlayer().getId().equals(playerId)) + return player; + } + return null; + } + + @Override + public void addPlayer(Player player, Deck deck) { + MatchPlayer mPlayer = new MatchPlayer(player, deck); + players.add(mPlayer); + } + + @Override + public void startMatch() throws GameException { + + } + + @Override + public UUID getId() { + return id; + } + + @Override + public boolean isMatchOver() { + for (MatchPlayer player: players) { + if (player.getWins() >= options.getWinsNeeded()) { + return true; + } + } + return false; + } + + @Override + public T getGame() { + return games.get(games.size() -1); + } + + @Override + public int getNumGames() { + return games.size(); + } + + protected void initGame(Game game) throws GameException { + for (MatchPlayer matchPlayer: this.players) { + game.addPlayer(matchPlayer.getPlayer()); + game.loadCards(matchPlayer.getDeck().getCards(), matchPlayer.getPlayer().getId()); + game.loadCards(matchPlayer.getDeck().getSideboard(), matchPlayer.getPlayer().getId()); + } + } + + @Override + public void endGame() { + Game game = getGame(); + for (MatchPlayer player: this.players) { + Player p = game.getPlayer(player.getPlayer().getId()); + if (p != null) { + if (p.hasWon()) + player.addWin(); + if (p.hasLost()) + player.addLose(); + } + } + } + + @Override + public UUID getChooser() { + UUID loserId = null; + Game game = getGame(); + for (MatchPlayer player: this.players) { + Player p = game.getPlayer(player.getPlayer().getId()); + if (p != null) { + if (p.hasLost()) + loserId = p.getId(); + } + } + return loserId; + } + + @Override + public boolean isDoneSideboarding() { + for (MatchPlayer player: this.players) { + if (!player.isDoneSideboarding()) + return false; + } + return true; + } + +} diff --git a/Mage/src/mage/game/match/MatchOptions.java b/Mage/src/mage/game/match/MatchOptions.java new file mode 100644 index 00000000000..5301c55e5bc --- /dev/null +++ b/Mage/src/mage/game/match/MatchOptions.java @@ -0,0 +1,104 @@ +/* + * 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.game.match; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import mage.Constants.MultiplayerAttackOption; +import mage.Constants.RangeOfInfluence; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class MatchOptions implements Serializable { + + protected String name; + protected MultiplayerAttackOption attackOption; + protected RangeOfInfluence range; + protected int winsNeeded; + protected String gameType; + protected String deckType; + protected List playerTypes = new ArrayList(); + + public MatchOptions(String name, String gameType) { + this.name = name; + this.gameType = gameType; + } + + public String getName() { + return name; + } + + public MultiplayerAttackOption getAttackOption() { + return attackOption; + } + + public void setAttackOption(MultiplayerAttackOption attackOption) { + this.attackOption = attackOption; + } + + public RangeOfInfluence getRange() { + return range; + } + + public void setRange(RangeOfInfluence range) { + this.range = range; + } + + public int getWinsNeeded() { + return winsNeeded; + } + + public void setWinsNeeded(int winsNeeded) { + this.winsNeeded = winsNeeded; + } + + public String getGameType() { + return gameType; + } + + public void setGameType(String gameType) { + this.gameType = gameType; + } + + public String getDeckType() { + return deckType; + } + + public void setDeckType(String deckType) { + this.deckType = deckType; + } + + public List getPlayerTypes() { + return playerTypes; + } + +} diff --git a/Mage/src/mage/game/MatchPlayer.java b/Mage/src/mage/game/match/MatchPlayer.java similarity index 87% rename from Mage/src/mage/game/MatchPlayer.java rename to Mage/src/mage/game/match/MatchPlayer.java index 4402b85c500..6408ad00758 100644 --- a/Mage/src/mage/game/MatchPlayer.java +++ b/Mage/src/mage/game/match/MatchPlayer.java @@ -26,7 +26,7 @@ * or implied, of BetaSteward_at_googlemail.com. */ -package mage.game; +package mage.game.match; import mage.cards.decks.Deck; import mage.players.Player; @@ -40,12 +40,14 @@ public class MatchPlayer { private int loses; private Deck deck; private Player player; + private boolean doneSideboarding; public MatchPlayer(Player player, Deck deck) { this.player = player; this.deck = deck; this.wins = 0; this.loses = 0; + this.doneSideboarding = true; } public int getWins() { @@ -68,8 +70,21 @@ public class MatchPlayer { return deck; } + public void submitDeck(Deck deck) { + this.deck = deck; + this.doneSideboarding = true; + } + public Player getPlayer() { return player; } + public void setSideboarding() { + this.doneSideboarding = false; + } + + public boolean isDoneSideboarding() { + return this.doneSideboarding; + } + } diff --git a/Mage/src/mage/game/GameType.java b/Mage/src/mage/game/match/MatchType.java similarity index 80% rename from Mage/src/mage/game/GameType.java rename to Mage/src/mage/game/match/MatchType.java index 4670e3da2e3..d3c58fece03 100644 --- a/Mage/src/mage/game/GameType.java +++ b/Mage/src/mage/game/match/MatchType.java @@ -26,15 +26,17 @@ * or implied, of BetaSteward_at_googlemail.com. */ -package mage.game; +package mage.game.match; import java.io.Serializable; +import mage.Constants.MultiplayerAttackOption; +import mage.Constants.RangeOfInfluence; /** * * @author BetaSteward_at_googlemail.com */ -public abstract class GameType implements Serializable { +public abstract class MatchType> implements Serializable { protected String name; protected int minPlayers; @@ -44,6 +46,20 @@ public abstract class GameType implements Serializable { protected boolean useRange; protected boolean useAttackOption; + protected MatchType() {} + + protected MatchType(final MatchType matchType) { + this.name = matchType.name; + this.maxPlayers = matchType.maxPlayers; + this.minPlayers = matchType.minPlayers; + this.numTeams = matchType.numTeams; + this.playersPerTeam = matchType.playersPerTeam; + this.useRange = matchType.useRange; + this.useAttackOption = matchType.useAttackOption; + } + + public abstract T copy(); + @Override public String toString() { return name; diff --git a/Mage/src/mage/game/permanent/PermanentImpl.java b/Mage/src/mage/game/permanent/PermanentImpl.java index a6c501f9fca..722ad28129f 100644 --- a/Mage/src/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/mage/game/permanent/PermanentImpl.java @@ -35,19 +35,13 @@ import mage.Constants.CardType; import mage.Constants.Zone; import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.EvasionAbility; import mage.abilities.TriggeredAbility; import mage.abilities.effects.RestrictionEffect; -import mage.abilities.keyword.DeathtouchAbility; -import mage.abilities.keyword.DefenderAbility; -import mage.abilities.keyword.HasteAbility; -import mage.abilities.keyword.IndestructibleAbility; -import mage.abilities.keyword.LifelinkAbility; -import mage.abilities.keyword.ProtectionAbility; -import mage.abilities.keyword.ShroudAbility; +import mage.abilities.keyword.*; import mage.cards.CardImpl; import mage.counters.Counter; import mage.counters.Counters; +import mage.counters.common.MinusOneCounter; import mage.game.Game; import mage.game.events.DamageCreatureEvent; import mage.game.events.DamagePlaneswalkerEvent; @@ -467,7 +461,13 @@ public abstract class PermanentImpl> extends CardImpl if (this.damage + event.getAmount() > this.toughness.getValue()) { actualDamage = this.toughness.getValue() - this.damage; } - this.damage += actualDamage; + Permanent source = game.getPermanent(sourceId); + if (source != null && (source.getAbilities().containsKey(InfectAbility.getInstance().getId()) + || source.getAbilities().containsKey(WitherAbility.getInstance().getId()))) { + addCounters(new MinusOneCounter(actualDamage)); + } else { + this.damage += actualDamage; + } game.fireEvent(new DamagedCreatureEvent(objectId, sourceId, controllerId, actualDamage, combat)); return actualDamage; } diff --git a/Mage/src/mage/game/stack/StackAbility.java b/Mage/src/mage/game/stack/StackAbility.java index 2228a4e878d..54ddb3d24be 100644 --- a/Mage/src/mage/game/stack/StackAbility.java +++ b/Mage/src/mage/game/stack/StackAbility.java @@ -192,6 +192,11 @@ public class StackAbility implements StackObject, Ability { return ability.getRule(); } + @Override + public String getRule(String source) { + return ability.getRule(source); + } + @Override public void setControllerId(UUID controllerId) { this.controllerId = controllerId; diff --git a/Mage/src/mage/players/Player.java b/Mage/src/mage/players/Player.java index 74f434d3f49..16bc4ecdf35 100644 --- a/Mage/src/mage/players/Player.java +++ b/Mage/src/mage/players/Player.java @@ -46,11 +46,13 @@ import mage.abilities.effects.ReplacementEffect; import mage.abilities.mana.ManaOptions; import mage.cards.Card; import mage.cards.Cards; +import mage.cards.decks.Deck; import mage.choices.Choice; import mage.counters.Counters; import mage.filter.FilterAbility; import mage.game.events.GameEvent; import mage.game.Game; +import mage.game.Table; import mage.game.permanent.Permanent; import mage.target.Target; import mage.target.TargetAmount; @@ -144,6 +146,7 @@ public interface Player extends MageItem, Copyable { public abstract void selectBlockers(Game game); public abstract void assignDamage(int damage, List targets, UUID sourceId, Game game); public abstract int getAmount(int min, int max, String message, Game game); + public abstract void sideboard(Table table); public void declareAttacker(UUID attackerId, UUID defenderId, Game game); public void declareBlocker(UUID blockerId, UUID attackerId, Game game); diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index 40dd4e3f137..bd381ef8bf9 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -52,16 +52,14 @@ import mage.abilities.SpecialAction; import mage.abilities.SpellAbility; import mage.abilities.TriggeredAbility; import mage.abilities.common.PassAbility; -import mage.abilities.keyword.KickerAbility; -import mage.abilities.keyword.LifelinkAbility; -import mage.abilities.keyword.ProtectionAbility; -import mage.abilities.keyword.ShroudAbility; +import mage.abilities.keyword.*; import mage.abilities.mana.ManaAbility; import mage.abilities.mana.ManaOptions; import mage.cards.Card; import mage.cards.Cards; import mage.cards.CardsImpl; import mage.cards.decks.Deck; +import mage.counters.CounterType; import mage.counters.Counters; import mage.filter.FilterAbility; import mage.filter.common.FilterCreatureForAttack; @@ -79,6 +77,7 @@ import mage.target.common.TargetDiscard; public abstract class PlayerImpl> implements Player, Serializable { + protected boolean abort; protected final UUID playerId; protected String name; protected boolean human; @@ -122,6 +121,7 @@ public abstract class PlayerImpl> implements Player, Ser } public PlayerImpl(final PlayerImpl player) { + this.abort = player.abort; this.playerId = player.playerId; this.name = player.name; this.human = player.human; @@ -148,6 +148,7 @@ public abstract class PlayerImpl> implements Player, Ser @Override public void init(Game game) { + this.abort = false; library.addAll(deck.getCards(), game); this.hand.clear(); this.graveyard.clear(); @@ -623,8 +624,12 @@ public abstract class PlayerImpl> implements Player, Ser if (!game.replaceEvent(event)) { int actualDamage = event.getAmount(); if (actualDamage > 0) { - actualDamage = this.loseLife(actualDamage, game); Permanent source = game.getPermanent(sourceId); + if (source != null && (source.getAbilities().containsKey(InfectAbility.getInstance().getId()))) { + getCounters().addCounter(CounterType.POISON.getInstance(actualDamage)); + } else { + actualDamage = this.loseLife(actualDamage, game); + } if (source != null && source.getAbilities().containsKey(LifelinkAbility.getInstance().getId())) { Player player = game.getPlayer(source.getControllerId()); player.gainLife(actualDamage, game);