diff --git a/Mage.Client/src/main/java/mage/client/chat/ChatPanel.java b/Mage.Client/src/main/java/mage/client/chat/ChatPanel.java index 12b95847501..bc8d98adc5c 100644 --- a/Mage.Client/src/main/java/mage/client/chat/ChatPanel.java +++ b/Mage.Client/src/main/java/mage/client/chat/ChatPanel.java @@ -63,7 +63,7 @@ import org.mage.card.arcane.ManaSymbols; * @author BetaSteward_at_googlemail.com, nantuko */ public class ChatPanel extends javax.swing.JPanel { - + private UUID chatId; private Session session; private final List players = new ArrayList<>(); @@ -71,7 +71,7 @@ public class ChatPanel extends javax.swing.JPanel { /** * Chat message color for opponents. */ - private static final String OPPONENT_COLOR = "#FF7F50"; + private static final String OPPONENT_COLOR = "#FF7F50"; /** * Chat message color for client player. */ @@ -123,7 +123,7 @@ public class ChatPanel extends javax.swing.JPanel { private ChatType chatType = ChatType.DEFAULT; private static final int[] defaultColumnsWidth = {20, 100, 100, 80}; - + public enum ChatType { DEFAULT, GAME, TABLES, TOURNAMENT @@ -142,6 +142,7 @@ public class ChatPanel extends javax.swing.JPanel { */ /** * Creates new form ChatPanel + * * @param addPlayersTab */ public ChatPanel(boolean addPlayersTab) { @@ -151,10 +152,10 @@ public class ChatPanel extends javax.swing.JPanel { jTablePlayers.setBackground(new Color(0, 0, 0, ALPHA)); jTablePlayers.setForeground(Color.white); jTablePlayers.setRowSorter(new MageTableRowSorter(userTableModel)); - + TableUtil.setColumnWidthAndOrder(jTablePlayers, defaultColumnsWidth, KEY_USERS_COLUMNS_WIDTH, KEY_USERS_COLUMNS_ORDER); jTablePlayers.setDefaultRenderer(Icon.class, new CountryCellRenderer()); - + if (jScrollPaneTxt != null) { jScrollPaneTxt.setBackground(new Color(0, 0, 0, ALPHA)); jScrollPaneTxt.getViewport().setBackground(new Color(0, 0, 0, ALPHA)); @@ -169,7 +170,7 @@ public class ChatPanel extends javax.swing.JPanel { } public void cleanUp() { - TableUtil.saveColumnWidthAndOrderToPrefs(jTablePlayers, KEY_USERS_COLUMNS_WIDTH, KEY_USERS_COLUMNS_ORDER); + TableUtil.saveColumnWidthAndOrderToPrefs(jTablePlayers, KEY_USERS_COLUMNS_WIDTH, KEY_USERS_COLUMNS_ORDER); } public ChatType getChatType() { @@ -248,7 +249,7 @@ public class ChatPanel extends javax.swing.JPanel { } if (username != null && !username.isEmpty()) { text.append(getColoredText(userColor, username + userSeparator)); - } + } text.append(getColoredText(textColor, ManaSymbols.replaceSymbolsWithHTML(message, ManaSymbols.Type.PAY))); this.txtConversation.append(text.toString()); } @@ -262,6 +263,7 @@ public class ChatPanel extends javax.swing.JPanel { sb.append(""); return sb.toString(); } + public String getText() { return txtConversation.getText(); } @@ -325,8 +327,8 @@ public class ChatPanel extends javax.swing.JPanel { } class UserTableModel extends AbstractTableModel { - - private final String[] columnNames = new String[]{" ","Players", "Info", "Games", "Connection"}; + + private final String[] columnNames = new String[]{"Loc", "Players", "Info", "Games", "Connection"}; private UsersView[] players = new UsersView[0]; public void loadData(Collection roomUserInfoList) throws MageRemoteException { @@ -334,12 +336,12 @@ public class ChatPanel extends javax.swing.JPanel { this.players = roomUserInfo.getUsersView().toArray(new UsersView[0]); JTableHeader th = jTablePlayers.getTableHeader(); TableColumnModel tcm = th.getColumnModel(); - + tcm.getColumn(jTablePlayers.convertColumnIndexToView(1)).setHeaderValue("Players (" + this.players.length + ")"); tcm.getColumn(jTablePlayers.convertColumnIndexToView(3)).setHeaderValue( - "Games " + roomUserInfo.getNumberActiveGames() + - (roomUserInfo.getNumberActiveGames() != roomUserInfo.getNumberGameThreads() ? " (T:" + roomUserInfo.getNumberGameThreads():" (") + - " limit: " + roomUserInfo.getNumberMaxGames() + ")"); + "Games " + roomUserInfo.getNumberActiveGames() + + (roomUserInfo.getNumberActiveGames() != roomUserInfo.getNumberGameThreads() ? " (T:" + roomUserInfo.getNumberGameThreads() : " (") + + " limit: " + roomUserInfo.getNumberMaxGames() + ")"); th.repaint(); this.fireTableDataChanged(); } @@ -358,7 +360,7 @@ public class ChatPanel extends javax.swing.JPanel { public Object getValueAt(int arg0, int arg1) { switch (arg1) { case 0: - return players[arg0].getFlagName(); + return players[arg0].getFlagName(); case 1: return players[arg0].getUserName(); case 2: @@ -389,16 +391,14 @@ public class ChatPanel extends javax.swing.JPanel { return Icon.class; default: return String.class; - } + } } @Override public boolean isCellEditable(int rowIndex, int columnIndex) { return false; } - - } public void clear() { @@ -486,9 +486,9 @@ public class ChatPanel extends javax.swing.JPanel { layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(jScrollPaneTxt, javax.swing.GroupLayout.DEFAULT_SIZE, 294, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(txtMessage, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE))); + .addComponent(jScrollPaneTxt, javax.swing.GroupLayout.DEFAULT_SIZE, 294, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtMessage, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE))); jTablePlayers = null; jScrollPanePlayers = null; } diff --git a/Mage.Client/src/main/java/mage/client/components/HoverButton.java b/Mage.Client/src/main/java/mage/client/components/HoverButton.java index f7eca203f09..d7998fe5041 100644 --- a/Mage.Client/src/main/java/mage/client/components/HoverButton.java +++ b/Mage.Client/src/main/java/mage/client/components/HoverButton.java @@ -1,12 +1,17 @@ package mage.client.components; -import mage.client.util.Command; - -import javax.swing.*; -import java.awt.*; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Rectangle; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.font.FontRenderContext; +import javax.swing.JPanel; +import mage.client.util.Command; /** * Image button with hover. @@ -48,6 +53,8 @@ public class HoverButton extends JPanel implements MouseListener { static final Font textSetFontBold = new Font("Arial", Font.BOLD, 14); private boolean useMiniFont = false; + private boolean alignTextLeft = false; + public HoverButton(String text, Image image, Rectangle size) { this(text, image, image, null, image, size); if (image == null) { @@ -113,7 +120,7 @@ public class HoverButton extends JPanel implements MouseListener { } topTextOffsetX = calculateOffsetForTop(g2d, topText); g2d.setColor(textBGColor); - g2d.drawString(topText, topTextOffsetX+1, 13); + g2d.drawString(topText, topTextOffsetX + 1, 13); g2d.setColor(textColor); g2d.drawString(topText, topTextOffsetX, 12); } @@ -148,7 +155,11 @@ public class HoverButton extends JPanel implements MouseListener { frc = g2d.getFontRenderContext(); textWidth = (int) textFontMini.getStringBounds(text, frc).getWidth(); } - textOffsetX = (imageSize.width - textWidth) / 2; + if (alignTextLeft) { + textOffsetX = 0; + } else { + textOffsetX = (imageSize.width - textWidth) / 2; + } } return textOffsetX; } @@ -277,4 +288,8 @@ public class HoverButton extends JPanel implements MouseListener { this.textAlwaysVisible = textAlwaysVisible; } + public void setAlignTextLeft(boolean alignTextLeft) { + this.alignTextLeft = alignTextLeft; + } + } diff --git a/Mage.Client/src/main/java/mage/client/components/MageTextArea.java b/Mage.Client/src/main/java/mage/client/components/MageTextArea.java index 47c68ce1410..159e437a0f5 100644 --- a/Mage.Client/src/main/java/mage/client/components/MageTextArea.java +++ b/Mage.Client/src/main/java/mage/client/components/MageTextArea.java @@ -1,19 +1,16 @@ package mage.client.components; +import java.awt.Color; +import javax.swing.JEditorPane; +import javax.swing.SwingUtilities; import org.mage.card.arcane.ManaSymbols; import org.mage.card.arcane.UI; -import javax.swing.*; -import java.awt.*; -import javax.swing.text.JTextComponent; - /** - * Component for displaying text in mage. - * Supports drawing mana symbols. + * Component for displaying text in mage. Supports drawing mana symbols. * * @author nantuko */ - public class MageTextArea extends JEditorPane { public MageTextArea() { @@ -27,10 +24,10 @@ public class MageTextArea extends JEditorPane { @Override public void setText(String text) { - setText(text, 16); + setText(text, 0); } - public void setText(String text, int fontSize) { + public void setText(String text, final int panelWidth) { if (text == null) { return; } @@ -38,23 +35,36 @@ public class MageTextArea extends JEditorPane { final StringBuilder buffer = new StringBuilder(512); // Dialog is a java logical font family, so it should work on all systems buffer.append("
"); - text = text.replaceAll("#([^#]+)#", "$1"); + // Don't know what it does (easy italc?) but it bugs with multiple #HTML color codes (LevelX2) + //text = text.replaceAll("#([^#]+)#", "$1"); //text = text.replaceAll("\\s*//\\s*", "
"); text = text.replace("\r\n", "
"); + final String basicText = ManaSymbols.replaceSymbolsWithHTML(text, ManaSymbols.Type.PAY); if (text.length() > 0) { - buffer.append(ManaSymbols.replaceSymbolsWithHTML(text, ManaSymbols.Type.PAY)); + buffer.append(basicText); } buffer.append("
"); SwingUtilities.invokeLater(new Runnable() { + @Override public void run() { - MageTextArea.super.setText(buffer.toString()); - //System.out.println(buffer.toString()); + String promptText = buffer.toString(); + MageTextArea.super.setText(promptText); + // in case the text don't fit in the panel a tooltip with the text is added + if (panelWidth > 0 && MageTextArea.this.getPreferredSize().getWidth() > panelWidth) { +// String tooltip = promptText +// .replace("color: #FFFFFF'>", "color: #111111'>

") +// .replace("", "

"); + String tooltip = "

" + basicText + "

"; + MageTextArea.super.setToolTipText(tooltip); + } else { + MageTextArea.super.setToolTipText(null); + } setCaretPosition(0); } }); diff --git a/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.java b/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.java index 4210bf4ffb8..f198e866d29 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.java @@ -1,30 +1,30 @@ /* -* Copyright 2011 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. -*/ + * Copyright 2011 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.client.dialog; import java.util.HashSet; @@ -46,6 +46,7 @@ import mage.cards.repository.ExpansionRepository; import mage.client.MageFrame; import mage.client.constants.Constants.DeckEditorMode; import mage.constants.Rarity; +import org.apache.log4j.Logger; /** * @@ -53,12 +54,16 @@ import mage.constants.Rarity; */ public class AddLandDialog extends MageDialog { + private static final Logger logger = Logger.getLogger(MageDialog.class); + private Deck deck; private final Set setCodesland = new HashSet<>(); - + private static final int DEFAULT_SEALED_DECK_CARD_NUMBER = 40; - /** Creates new form AddLandDialog */ + /** + * Creates new form AddLandDialog + */ public AddLandDialog() { initComponents(); this.setModal(true); @@ -69,7 +74,7 @@ public class AddLandDialog extends MageDialog { SortedSet landSets = new TreeSet<>(); if (!mode.equals(DeckEditorMode.FREE_BUILDING)) { // decide from which sets basic lands are taken from - for (String setCode :deck.getExpansionSetCodes()) { + for (String setCode : deck.getExpansionSetCodes()) { ExpansionInfo expansionInfo = ExpansionRepository.instance.getSetByCode(setCode); if (expansionInfo != null && expansionInfo.hasBasicLands()) { this.setCodesland.add(expansionInfo.getCode()); @@ -79,11 +84,11 @@ public class AddLandDialog extends MageDialog { // if sets have no basic land, take land from block if (this.setCodesland.isEmpty()) { - for (String setCode :deck.getExpansionSetCodes()) { + for (String setCode : deck.getExpansionSetCodes()) { ExpansionInfo expansionInfo = ExpansionRepository.instance.getSetByCode(setCode); if (expansionInfo != null) { List blockSets = ExpansionRepository.instance.getSetsFromBlock(expansionInfo.getBlockName()); - for (ExpansionInfo blockSet: blockSets) { + for (ExpansionInfo blockSet : blockSets) { if (blockSet.hasBasicLands()) { this.setCodesland.add(blockSet.getCode()); landSets.add(blockSet.getName()); @@ -92,22 +97,22 @@ public class AddLandDialog extends MageDialog { } } } - } + } // if still no set with lands found, add list of all available if (this.setCodesland.isEmpty()) { List basicLandSets = ExpansionRepository.instance.getSetsWithBasicLandsByReleaseDate(); - for (ExpansionInfo expansionInfo: basicLandSets) { + for (ExpansionInfo expansionInfo : basicLandSets) { landSets.add(expansionInfo.getName()); } - } + } if (landSets.isEmpty()) { throw new IllegalArgumentException("No set with basic land was found"); } - if(landSets.size() > 1) { + if (landSets.size() > 1) { landSets.add(""); } cbLandSet.setModel(new DefaultComboBoxModel(landSets.toArray())); - + MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER); this.setVisible(true); } @@ -115,7 +120,7 @@ public class AddLandDialog extends MageDialog { private void addLands(String landName, int number) { Random random = new Random(); String landSetName = (String) cbLandSet.getSelectedItem(); - + CardCriteria criteria = new CardCriteria(); if (landSetName.equals("")) { criteria.setCodes(setCodesland.toArray(new String[setCodesland.size()])); @@ -123,13 +128,17 @@ public class AddLandDialog extends MageDialog { ExpansionInfo expansionInfo = ExpansionRepository.instance.getSetByName(landSetName); if (expansionInfo == null) { throw new IllegalArgumentException("Code of Set " + landSetName + " not found"); - } - criteria.setCodes(expansionInfo.getCode()); - } + } + criteria.setCodes(expansionInfo.getCode()); + } criteria.rarities(Rarity.LAND).name(landName); List cards = CardRepository.instance.findCards(criteria); if (cards.isEmpty()) { - throw new IllegalArgumentException("No basic lands found in Set: " + landSetName); + logger.error("No basic lands found in Set: " + landSetName); + criteria = new CardCriteria(); + criteria.rarities(Rarity.LAND).name(landName); + criteria.setCodes("M15"); + cards = CardRepository.instance.findCards(criteria); } for (int i = 0; i < number; i++) { @@ -138,10 +147,10 @@ public class AddLandDialog extends MageDialog { } } - /** This method is called from within the constructor to - * initialize the form. - * WARNING: Do NOT modify this code. The content of this method is - * always regenerated by the Form Editor. + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents @@ -298,11 +307,11 @@ public class AddLandDialog extends MageDialog { }//GEN-LAST:event_btnCancelActionPerformed private void btnAddActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnAddActionPerformed - int nForest = ((Number)spnForest.getValue()).intValue(); - int nIsland = ((Number)spnIsland.getValue()).intValue(); - int nMountain = ((Number)spnMountain.getValue()).intValue(); - int nPlains = ((Number)spnPlains.getValue()).intValue(); - int nSwamp = ((Number)spnSwamp.getValue()).intValue(); + int nForest = ((Number) spnForest.getValue()).intValue(); + int nIsland = ((Number) spnIsland.getValue()).intValue(); + int nMountain = ((Number) spnMountain.getValue()).intValue(); + int nPlains = ((Number) spnPlains.getValue()).intValue(); + int nSwamp = ((Number) spnSwamp.getValue()).intValue(); addLands("Forest", nForest); addLands("Island", nIsland); @@ -316,7 +325,7 @@ public class AddLandDialog extends MageDialog { autoAddLands(); }//GEN-LAST:event_btnAutoAddActionPerformed - private void autoAddLands(){ + private void autoAddLands() { int red = 0; int green = 0; int black = 0; @@ -324,7 +333,9 @@ public class AddLandDialog extends MageDialog { int white = 0; Set cards = deck.getCards(); int land_number = DEFAULT_SEALED_DECK_CARD_NUMBER - cards.size(); - if(land_number < 0) land_number = 0; + if (land_number < 0) { + land_number = 0; + } for (Card cd : cards) { Mana m = cd.getManaCost().getMana(); red += m.getRed(); @@ -334,14 +345,18 @@ public class AddLandDialog extends MageDialog { white += m.getWhite(); } int total = red + green + black + blue + white; - int redcards = Math.round(land_number*((float)red/(float)total)); - total -= red; land_number -= redcards; - int greencards = Math.round(land_number*((float)green/(float)total)); - total -= green; land_number -= greencards; - int blackcards = Math.round(land_number*((float)black/(float)total)); - total -= black; land_number -= blackcards; - int bluecards = Math.round(land_number*((float)blue/(float)total)); - total -= blue; land_number -= bluecards; + int redcards = Math.round(land_number * ((float) red / (float) total)); + total -= red; + land_number -= redcards; + int greencards = Math.round(land_number * ((float) green / (float) total)); + total -= green; + land_number -= greencards; + int blackcards = Math.round(land_number * ((float) black / (float) total)); + total -= black; + land_number -= blackcards; + int bluecards = Math.round(land_number * ((float) blue / (float) total)); + total -= blue; + land_number -= bluecards; int whitecards = land_number; spnMountain.setValue(redcards); spnForest.setValue(greencards); @@ -349,7 +364,7 @@ public class AddLandDialog extends MageDialog { spnIsland.setValue(bluecards); spnPlains.setValue(whitecards); } - + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton btnAdd; private javax.swing.JButton btnAutoAdd; diff --git a/Mage.Client/src/main/java/mage/client/dialog/CardInfoWindowDialog.java b/Mage.Client/src/main/java/mage/client/dialog/CardInfoWindowDialog.java index a0abd01fbf6..284852f6c0b 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/CardInfoWindowDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/CardInfoWindowDialog.java @@ -112,6 +112,25 @@ public class CardInfoWindowDialog extends MageDialog { cards.cleanUp(); } + public void loadCards(ExileView exile, BigCard bigCard, UUID gameId) { + boolean changed = cards.loadCards(exile, bigCard, gameId, null); + String titel = name + " (" + exile.size() + ")"; + setTitle(titel); + this.setTitelBarToolTip(titel); + if (exile.size() > 0) { + show(); + if (changed) { + try { + this.setIcon(false); + } catch (PropertyVetoException ex) { + Logger.getLogger(CardInfoWindowDialog.class.getName()).log(Level.SEVERE, null, ex); + } + } + } else { + this.hideDialog(); + } + } + public void loadCards(SimpleCardsView showCards, BigCard bigCard, UUID gameId) { cards.loadCards(showCards, bigCard, gameId); showAndPositionWindow(); @@ -120,8 +139,9 @@ public class CardInfoWindowDialog extends MageDialog { public void loadCards(CardsView showCards, BigCard bigCard, UUID gameId) { cards.loadCards(showCards, bigCard, gameId, null); if (showType.equals(ShowType.GRAVEYARD)) { - setTitle(name + "'s Graveyard (" + showCards.size() + ")"); - this.setTitelBarToolTip(name); + String titel = name + "'s Graveyard (" + showCards.size() + ")"; + setTitle(titel); + this.setTitelBarToolTip(titel); } showAndPositionWindow(); } @@ -160,22 +180,6 @@ public class CardInfoWindowDialog extends MageDialog { }); } - public void loadCards(ExileView exile, BigCard bigCard, UUID gameId) { - boolean changed = cards.loadCards(exile, bigCard, gameId, null); - if (exile.size() > 0) { - show(); - if (changed) { - try { - this.setIcon(false); - } catch (PropertyVetoException ex) { - Logger.getLogger(CardInfoWindowDialog.class.getName()).log(Level.SEVERE, null, ex); - } - } - } else { - this.hideDialog(); - } - } - /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always diff --git a/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.java b/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.java index 6f11993a746..59eacfaa88b 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.java @@ -35,17 +35,15 @@ package mage.client.dialog; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.UUID; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; -import javax.swing.DefaultListModel; -import javax.swing.DefaultListSelectionModel; +import javax.swing.JButton; import javax.swing.JComboBox; -import javax.swing.JList; import javax.swing.JOptionPane; -import javax.swing.JScrollPane; -import static javax.swing.ListSelectionModel.SINGLE_SELECTION; +import javax.swing.JTextArea; import javax.swing.SpinnerNumberModel; import mage.cards.decks.importer.DeckImporterUtil; import mage.cards.repository.ExpansionInfo; @@ -80,12 +78,12 @@ public class NewTournamentDialog extends MageDialog { private UUID roomId; private final Session session; private String lastSessionId; - private JList randomList = new JList(); + private RandomPacksSelectorDialog randomPackSelector; + private JTextArea txtRandomPacks; private final List players = new ArrayList<>(); private final List packs = new ArrayList<>(); private final int CONSTRUCTION_TIME_MIN = 6; private final int CONSTRUCTION_TIME_MAX = 30; - private final String randomDraftDescription = ("The selected packs will be randomly distributed to players. Each player may open different packs. Duplicates will be avoided."); private boolean automaticChange = false; @@ -534,15 +532,8 @@ public class NewTournamentDialog extends MageDialog { if (tournamentType.isCubeBooster()) { tOptions.getLimitedOptions().setDraftCubeName(this.cbDraftCube.getSelectedItem().toString()); } else if (tournamentType.isRandom()) { - for (Object pack : randomList.getSelectedValuesList()) { - String packStr = (String) pack; - String code = packStr.substring(0, 3); - tOptions.getLimitedOptions().getSetCodes().add(code); - } - if (tOptions.getLimitedOptions().getSetCodes().size() < 2) { - // At least two sets must be chosen. - return; - } + tOptions.getLimitedOptions().getSetCodes().clear(); + tOptions.getLimitedOptions().getSetCodes().addAll(randomPackSelector.getSelectedPacks()); } else { for (JComboBox pack: packs) { tOptions.getLimitedOptions().getSetCodes().add(((ExpansionInfo) pack.getSelectedItem()).getCode()); @@ -724,60 +715,54 @@ public class NewTournamentDialog extends MageDialog { private void createRandomPacks() { if (pnlRandomPacks.getComponentCount() == 0) { - - DefaultListModel randomListModel = new DefaultListModel(); - randomList = new JList(randomListModel); - randomList.setToolTipText(randomDraftDescription); - ExpansionInfo[] allExpansions = ExpansionRepository.instance.getWithBoostersSortedByReleaseDate(); - for (ExpansionInfo expansion : allExpansions) { - String exp = expansion.getCode() + " - " + expansion.getName(); - randomListModel.addElement(exp); + if (randomPackSelector == null) { + randomPackSelector = new RandomPacksSelectorDialog(); } - randomList.setSelectionModel(new DefaultListSelectionModel() { - private boolean mGestureStarted; - - @Override - public void setSelectionInterval(int index0, int index1) { - // Toggle only one element while the user is dragging the mouse - if (!mGestureStarted) { - if (isSelectedIndex(index0)) { - super.removeSelectionInterval(index0, index1); - } else { - if (getSelectionMode() == SINGLE_SELECTION) { - super.setSelectionInterval(index0, index1); - } else { - super.addSelectionInterval(index0, index1); - } - } - } - // Disable toggling till the adjusting is over, or keep it - // enabled in case setSelectionInterval was called directly. - mGestureStarted = getValueIsAdjusting(); - } - - @Override - public void setValueIsAdjusting(boolean isAdjusting) { - super.setValueIsAdjusting(isAdjusting); - - if (isAdjusting == false) { - // Enable toggling - mGestureStarted = false; - } - } - }); - + txtRandomPacks = new JTextArea(); + txtRandomPacks.setEnabled(false); + txtRandomPacks.setLineWrap(true); String randomPrefs = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_PACKS_RANDOM_DRAFT, ""); if (randomPrefs.length() > 0) { - for (String exp : randomPrefs.split(";")) { - randomList.setSelectedValue(exp, false); - } + txtRandomPacks.setText(randomPrefs); + ArrayList theList = new ArrayList<>(); + theList.addAll(Arrays.asList(randomPrefs.split(";"))); + randomPackSelector.setSelectedPacks(theList); } else { - randomList.setSelectionInterval(0, randomListModel.size() - 1); + ExpansionInfo[] allExpansions = ExpansionRepository.instance.getWithBoostersSortedByReleaseDate(); + StringBuilder packList = new StringBuilder(); + for (ExpansionInfo exp : allExpansions) { + packList.append(exp.getCode()); + packList.append(";"); + } + txtRandomPacks.setText(packList.toString()); } - JScrollPane list1scr = new JScrollPane(randomList); - randomList.setVisibleRowCount(4); - pnlRandomPacks.add(list1scr); + + pnlRandomPacks.add(txtRandomPacks); + JButton btnSelectRandomPacks = new JButton(); + btnSelectRandomPacks.setText("Select packs to be included in the pool"); + btnSelectRandomPacks.setToolTipText(RandomPacksSelectorDialog.randomDraftDescription); + btnSelectRandomPacks.addActionListener(new java.awt.event.ActionListener() { + @Override + public void actionPerformed(java.awt.event.ActionEvent evt) { + showRandomPackSelectorDialog(); + + } + }); + pnlRandomPacks.add(btnSelectRandomPacks); + } + this.pack(); + this.revalidate(); + this.repaint(); + } + + private void showRandomPackSelectorDialog() { + randomPackSelector.showDialog(); + StringBuilder packList = new StringBuilder(); + for (String str : randomPackSelector.getSelectedPacks()) { + packList.append(str); + packList.append(";"); } + this.txtRandomPacks.setText(packList.toString()); this.pack(); this.revalidate(); this.repaint(); @@ -1006,8 +991,8 @@ public class NewTournamentDialog extends MageDialog { if (tOptions.getLimitedOptions().getIsRandom()){ // save random boosters to prefs StringBuilder packlist = new StringBuilder(); - for (Object pack: randomList.getSelectedValuesList()){ - packlist.append((String)pack); + for (String pack : this.randomPackSelector.getSelectedPacks()){ + packlist.append(pack); packlist.append(";"); } PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TOURNAMENT_PACKS_RANDOM_DRAFT, packlist.toString()); diff --git a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form index cfc3e9c0364..74699d86535 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form +++ b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form @@ -1150,21 +1150,21 @@ - + - + - + - + @@ -1256,6 +1256,14 @@ + + + + + + + + @@ -1328,14 +1336,6 @@ - - - - - - - - diff --git a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java index 27390bedf11..8ae68984ae6 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java @@ -1,30 +1,30 @@ /* -* Copyright 2011 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. -*/ + * Copyright 2011 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. + */ /* * PreferencesDialog.java @@ -63,10 +63,11 @@ import mage.client.MageFrame; import mage.client.util.Config; import mage.client.util.ImageHelper; import mage.client.util.gui.BufferedImageBuilder; +import mage.players.net.UserData; +import mage.players.net.UserGroup; import mage.players.net.UserSkipPrioritySteps; import mage.remote.Connection; import mage.remote.Connection.ProxyType; -import mage.view.UserDataView; import org.apache.log4j.Logger; /** @@ -77,7 +78,7 @@ import org.apache.log4j.Logger; public class PreferencesDialog extends javax.swing.JDialog { private static final transient Logger log = Logger.getLogger(PreferencesDialog.class); - + public static final String KEY_HAND_USE_BIG_CARDS = "handUseBigCards"; public static final String KEY_SHOW_TOOLTIPS_ANY_ZONE = "showTooltipsInAnyZone"; public static final String KEY_SHOW_CARD_NAMES = "showCardNames"; @@ -88,7 +89,7 @@ public class PreferencesDialog extends javax.swing.JDialog { public static final String KEY_GAME_SHOW_STORM_COUNTER = "gameShowStormCounter"; public static final String KEY_GAME_CONFIRM_EMPTY_MANA_POOL = "gameConfirmEmptyManaPool"; public static final String KEY_GAME_ASK_MOVE_TO_GRAVE_ORDER = "gameAskMoveToGraveORder"; - + public static final String KEY_GAME_LOG_AUTO_SAVE = "gameLogAutoSave"; public static final String KEY_CARD_IMAGES_USE_DEFAULT = "cardImagesUseDefault"; @@ -96,12 +97,12 @@ public class PreferencesDialog extends javax.swing.JDialog { public static final String KEY_CARD_IMAGES_CHECK = "cardImagesCheck"; public static final String KEY_CARD_IMAGES_SAVE_TO_ZIP = "cardImagesSaveToZip"; public static final String KEY_CARD_IMAGES_PREF_LANGUAGE = "cardImagesPreferedImageLaguage"; - + public static final String KEY_BACKGROUND_IMAGE = "backgroundImage"; public static final String KEY_BATTLEFIELD_IMAGE = "battlefieldImage"; public static final String KEY_BACKGROUND_IMAGE_DEFAULT = "backgroundImagedDefault"; public static final String KEY_BATTLEFIELD_IMAGE_RANDOM = "battlefieldImagerandom"; - public static final String KEY_BATTLEFIELD_IMAGE_DEFAULT = "battlefieldImageDefault"; + public static final String KEY_BATTLEFIELD_IMAGE_DEFAULT = "battlefieldImageDefault"; public static final String KEY_SOUNDS_GAME_ON = "soundsOn"; public static final String KEY_SOUNDS_DRAFT_ON = "soundsDraftOn"; @@ -112,7 +113,6 @@ public class PreferencesDialog extends javax.swing.JDialog { public static final String KEY_BIG_CARD_TOGGLED = "bigCardToggled"; - // Phases public static final String UPKEEP_YOU = "upkeepYou"; public static final String DRAW_YOU = "drawYou"; @@ -138,15 +138,15 @@ public class PreferencesDialog extends javax.swing.JDialog { // mana auto payment public static final String KEY_GAME_MANA_AUTOPAYMENT = "gameManaAutopayment"; public static final String KEY_GAME_MANA_AUTOPAYMENT_ONLY_ONE = "gameManaAutopaymentOnlyOne"; - + // Size of frame to check if divider locations should be used public static final String KEY_MAGE_PANEL_LAST_SIZE = "gamepanelLastSize"; - + // pref settings of table settings and filtering public static final String KEY_TABLES_FILTER_SETTINGS = "tablePanelFilterSettings"; public static final String KEY_TABLES_COLUMNS_WIDTH = "tablePanelColumnWidth"; public static final String KEY_TABLES_COLUMNS_ORDER = "tablePanelColumnSort"; - + // positions of divider bars public static final String KEY_TABLES_DIVIDER_LOCATION_1 = "tablePanelDividerLocation1"; public static final String KEY_TABLES_DIVIDER_LOCATION_2 = "tablePanelDividerLocation2"; @@ -155,11 +155,20 @@ public class PreferencesDialog extends javax.swing.JDialog { // user list public static final String KEY_USERS_COLUMNS_WIDTH = "userPanelColumnWidth"; public static final String KEY_USERS_COLUMNS_ORDER = "userPanelColumnSort"; - + // table waiting dialog + public static final String KEY_TABLE_WAITING_WIDTH = "tableWaitingPanelWidth"; + public static final String KEY_TABLE_WAITING_HEIGHT = "tableWaitingPanelHeight"; + public static final String KEY_TABLE_WAITING_COLUMNS_WIDTH = "tableWaitingPanelColumnWidth"; + public static final String KEY_TABLE_WAITING_COLUMNS_ORDER = "tableWaitingPanelColumnSort"; + public static final String KEY_GAMEPANEL_DIVIDER_LOCATION_0 = "gamepanelDividerLocation0"; public static final String KEY_GAMEPANEL_DIVIDER_LOCATION_1 = "gamepanelDividerLocation1"; public static final String KEY_GAMEPANEL_DIVIDER_LOCATION_2 = "gamepanelDividerLocation2"; + public static final String KEY_TOURNAMENT_PLAYER_COLUMNS_WIDTH = "tournamentPlayerPanelColumnWidth"; + public static final String KEY_TOURNAMENT_PLAYER_COLUMNS_ORDER = "tournamentPlayerPanelColumnSort"; + public static final String KEY_TOURNAMENT_MATCH_COLUMNS_WIDTH = "tournamentMatchPanelColumnWidth"; + public static final String KEY_TOURNAMENT_MATCH_COLUMNS_ORDER = "tournamentMatchPanelColumnSort"; public static final String KEY_TOURNAMENT_DIVIDER_LOCATION_1 = "tournamentPanelDividerLocation1"; public static final String KEY_TOURNAMENT_DIVIDER_LOCATION_2 = "tournamentPanelDividerLocation2"; @@ -204,7 +213,7 @@ public class PreferencesDialog extends javax.swing.JDialog { // used to save and restore the settings for the cardArea (draft, sideboarding, deck builder) public static final String KEY_DRAFT_VIEW = "draftView"; - + public static final String KEY_DRAFT_SORT_BY = "draftSortBy"; public static final String KEY_DRAFT_SORT_INDEX = "draftSortIndex"; public static final String KEY_DRAFT_SORT_ASCENDING = "draftSortAscending"; @@ -234,10 +243,9 @@ public class PreferencesDialog extends javax.swing.JDialog { public static final String KEY_CONNECTION_URL_SERVER_LIST = "connectionURLServerList"; public static final String KEY_AVATAR = "selectedId"; - + public static final String KEY_CONNECT_AUTO_CONNECT = "autoConnect"; public static final String KEY_CONNECT_FLAG = "connectFlag"; - private static final Map cache = new HashMap<>(); @@ -278,38 +286,37 @@ public class PreferencesDialog extends javax.swing.JDialog { { fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); } - + private final JFileChooser fc_i = new JFileChooser(); + { fc_i.setAcceptAllFileFilterUsed(false); fc_i.addChoosableFileFilter(new ImageFileFilter()); } - private static class ImageFileFilter extends FileFilter{ - + private static class ImageFileFilter extends FileFilter { + @Override public boolean accept(File f) { String filename = f.getName(); - if(f.isDirectory()){ + if (f.isDirectory()) { return true; } - if(filename != null){ - if(filename.endsWith(".jpg") || filename.endsWith(".jpeg") || - filename.endsWith(".png") || filename.endsWith(".bmp")){ - return true; + if (filename != null) { + if (filename.endsWith(".jpg") || filename.endsWith(".jpeg") + || filename.endsWith(".png") || filename.endsWith(".bmp")) { + return true; } } return false; } - + @Override public String getDescription() { - return "*.png | *.bmp |*.jpg | *.jpeg"; - } + return "*.png | *.bmp |*.jpg | *.jpeg"; + } } - - - + /** * Creates new form PreferencesDialog * @@ -322,15 +329,15 @@ public class PreferencesDialog extends javax.swing.JDialog { txtImageFolderPath.setEditable(false); cbProxyType.setModel(new DefaultComboBoxModel<>(Connection.ProxyType.values())); addAvatars(); - - cbPreferedImageLanguage.setModel(new DefaultComboBoxModel<>(new String[] {"en","de","fr","it","es","pt","jp","cn","ru","tw","ko"})); - + + cbPreferedImageLanguage.setModel(new DefaultComboBoxModel<>(new String[]{"en", "de", "fr", "it", "es", "pt", "jp", "cn", "ru", "tw", "ko"})); + } - /** This method is called from within the constructor to - * initialize the form. - * WARNING: Do NOT modify this code. The content of this method is - * always regenerated by the Form Editor. + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents @@ -413,12 +420,12 @@ public class PreferencesDialog extends javax.swing.JDialog { txtBattlefieldIBGMPath = new javax.swing.JTextField(); btnBattlefieldBGMBrowse = new javax.swing.JButton(); tabAvatars = new javax.swing.JPanel(); - jScrollPane1 = new javax.swing.JScrollPane(); - jPanel9 = new javax.swing.JPanel(); + avatarPane = new javax.swing.JScrollPane(); + avatarPanel = new javax.swing.JPanel(); + jLabel12 = new javax.swing.JLabel(); jPanel10 = new javax.swing.JPanel(); jPanel13 = new javax.swing.JPanel(); jPanel11 = new javax.swing.JPanel(); - jLabel12 = new javax.swing.JLabel(); jPanel12 = new javax.swing.JPanel(); jPanel14 = new javax.swing.JPanel(); jPanel15 = new javax.swing.JPanel(); @@ -1183,6 +1190,9 @@ public class PreferencesDialog extends javax.swing.JDialog { tabsPanel.addTab("Sounds", tabSounds); + jLabel12.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N + jLabel12.setText("Choose your avatar:"); + jPanel10.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(204, 204, 204), 1, true)); javax.swing.GroupLayout jPanel10Layout = new javax.swing.GroupLayout(jPanel10); @@ -1222,9 +1232,6 @@ public class PreferencesDialog extends javax.swing.JDialog { .addGap(0, 100, Short.MAX_VALUE) ); - jLabel12.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N - jLabel12.setText("Choose your avatar:"); - jPanel12.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(204, 204, 204), 1, true)); javax.swing.GroupLayout jPanel12Layout = new javax.swing.GroupLayout(jPanel12); @@ -1345,68 +1352,68 @@ public class PreferencesDialog extends javax.swing.JDialog { .addGap(0, 100, Short.MAX_VALUE) ); - javax.swing.GroupLayout jPanel9Layout = new javax.swing.GroupLayout(jPanel9); - jPanel9.setLayout(jPanel9Layout); - jPanel9Layout.setHorizontalGroup( - jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel9Layout.createSequentialGroup() - .addGroup(jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel9Layout.createSequentialGroup() + javax.swing.GroupLayout avatarPanelLayout = new javax.swing.GroupLayout(avatarPanel); + avatarPanel.setLayout(avatarPanelLayout); + avatarPanelLayout.setHorizontalGroup( + avatarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(avatarPanelLayout.createSequentialGroup() + .addGroup(avatarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(avatarPanelLayout.createSequentialGroup() .addContainerGap() .addComponent(jLabel12)) - .addGroup(jPanel9Layout.createSequentialGroup() - .addGroup(jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel9Layout.createSequentialGroup() + .addGroup(avatarPanelLayout.createSequentialGroup() + .addGroup(avatarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(avatarPanelLayout.createSequentialGroup() .addGap(30, 30, 30) - .addGroup(jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(avatarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addComponent(jPanel12, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jPanel10, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jPanel19, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGap(33, 33, 33) - .addGroup(jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(avatarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jPanel13, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jPanel14, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jPanel20, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addGroup(jPanel9Layout.createSequentialGroup() + .addGroup(avatarPanelLayout.createSequentialGroup() .addContainerGap() - .addGroup(jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel9Layout.createSequentialGroup() + .addGroup(avatarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(avatarPanelLayout.createSequentialGroup() .addGap(20, 20, 20) .addComponent(jPanel16, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(33, 33, 33) .addComponent(jPanel17, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(jLabel13)))) .addGap(32, 32, 32) - .addGroup(jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(avatarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jPanel18, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jPanel21, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jPanel15, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jPanel11, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); - jPanel9Layout.setVerticalGroup( - jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel9Layout.createSequentialGroup() + avatarPanelLayout.setVerticalGroup( + avatarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(avatarPanelLayout.createSequentialGroup() .addContainerGap() .addComponent(jLabel12) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(avatarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jPanel11, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jPanel13, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jPanel10, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGap(26, 26, 26) - .addGroup(jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(avatarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jPanel15, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jPanel12, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jPanel14, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGap(23, 23, 23) - .addGroup(jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(avatarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addComponent(jPanel19, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jPanel20, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jPanel21, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGap(18, 18, 18) - .addGroup(jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(jPanel9Layout.createSequentialGroup() + .addGroup(avatarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(avatarPanelLayout.createSequentialGroup() .addComponent(jLabel13) .addGap(18, 18, 18) .addComponent(jPanel16, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) @@ -1415,17 +1422,17 @@ public class PreferencesDialog extends javax.swing.JDialog { .addGap(25, 25, 25)) ); - jScrollPane1.setViewportView(jPanel9); + avatarPane.setViewportView(avatarPanel); javax.swing.GroupLayout tabAvatarsLayout = new javax.swing.GroupLayout(tabAvatars); tabAvatars.setLayout(tabAvatarsLayout); tabAvatarsLayout.setHorizontalGroup( tabAvatarsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 590, Short.MAX_VALUE) + .addComponent(avatarPane, javax.swing.GroupLayout.DEFAULT_SIZE, 590, Short.MAX_VALUE) ); tabAvatarsLayout.setVerticalGroup( tabAvatarsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 359, Short.MAX_VALUE) + .addComponent(avatarPane, javax.swing.GroupLayout.DEFAULT_SIZE, 359, Short.MAX_VALUE) ); tabsPanel.addTab("Avatars", tabAvatars); @@ -1698,9 +1705,9 @@ public class PreferencesDialog extends javax.swing.JDialog { save(prefs, dialog.cbUseDefaultImageFolder, KEY_CARD_IMAGES_USE_DEFAULT, "true", "false", UPDATE_CACHE_POLICY); saveImagesPath(prefs); save(prefs, dialog.cbCheckForNewImages, KEY_CARD_IMAGES_CHECK, "true", "false", UPDATE_CACHE_POLICY); - save(prefs, dialog.cbSaveToZipFiles, KEY_CARD_IMAGES_SAVE_TO_ZIP, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.cbSaveToZipFiles, KEY_CARD_IMAGES_SAVE_TO_ZIP, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.cbPreferedImageLanguage, KEY_CARD_IMAGES_PREF_LANGUAGE); - + save(prefs, dialog.cbUseDefaultBackground, KEY_BACKGROUND_IMAGE_DEFAULT, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.cbUseDefaultBattleImage, KEY_BATTLEFIELD_IMAGE_DEFAULT, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.cbUseRandomBattleImage, KEY_BATTLEFIELD_IMAGE_RANDOM, "true", "false", UPDATE_CACHE_POLICY); @@ -1712,7 +1719,7 @@ public class PreferencesDialog extends javax.swing.JDialog { save(prefs, dialog.cbEnableOtherSounds, KEY_SOUNDS_OTHER_ON, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.cbEnableBattlefieldBGM, KEY_SOUNDS_MATCH_MUSIC_ON, "true", "false", UPDATE_CACHE_POLICY); saveSoundPath(prefs); - + // connection save(prefs, dialog.cbProxyType, KEY_PROXY_TYPE); save(prefs, dialog.txtProxyServer, KEY_PROXY_ADDRESS); @@ -1770,7 +1777,7 @@ public class PreferencesDialog extends javax.swing.JDialog { private void btnBrowseImageLocationActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnBrowseImageLocationActionPerformed int returnVal = fc.showOpenDialog(PreferencesDialog.this); - + if (returnVal == JFileChooser.APPROVE_OPTION) { File file = fc.getSelectedFile(); txtImageFolderPath.setText(file.getAbsolutePath()); @@ -1803,101 +1810,101 @@ public class PreferencesDialog extends javax.swing.JDialog { }//GEN-LAST:event_cbEnableGameSoundsActionPerformed private void cbEnableBattlefieldBGMActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbEnableBattlefieldBGMActionPerformed - if(cbEnableBattlefieldBGM.isSelected()){ + if (cbEnableBattlefieldBGM.isSelected()) { txtBattlefieldIBGMPath.setEnabled(true); btnBattlefieldBGMBrowse.setEnabled(true); - }else{ + } else { txtBattlefieldIBGMPath.setEnabled(false); btnBattlefieldBGMBrowse.setEnabled(false); } }//GEN-LAST:event_cbEnableBattlefieldBGMActionPerformed - + private void cbUseDefaultBackgroundActionPerformed(java.awt.event.ActionEvent evt) { - if(cbUseDefaultBackground.isSelected()){ + if (cbUseDefaultBackground.isSelected()) { useDefaultBackgroundImage(); - }else{ + } else { useSelectBackgroundImage(); } - } + } - private void useDefaultBackgroundImage(){ + private void useDefaultBackgroundImage() { txtBackgroundImagePath.setEnabled(false); btnBrowseBackgroundImage.setEnabled(false); txtBackgroundImagePath.setText(""); } - - private void useSelectBackgroundImage(){ + + private void useSelectBackgroundImage() { String path = cache.get(KEY_BACKGROUND_IMAGE); dialog.txtBackgroundImagePath.setText(path); txtBackgroundImagePath.setEnabled(true); btnBrowseBackgroundImage.setEnabled(true); } - + private void cbUseDefaultBattleImageActionPerformed(java.awt.event.ActionEvent evt) { - if(cbUseDefaultBattleImage.isSelected()){ + if (cbUseDefaultBattleImage.isSelected()) { useDefaultBattlefield(); - }else{ + } else { useSelectedOrRandom(); } - } - - private void useDefaultBattlefield(){ + } + + private void useDefaultBattlefield() { cbUseRandomBattleImage.setEnabled(false); txtBattlefieldImagePath.setEnabled(false); btnBrowseBattlefieldImage.setEnabled(false); } - - private void useSelectedOrRandom(){ + + private void useSelectedOrRandom() { cbUseRandomBattleImage.setEnabled(true); String temp = cache.get(KEY_BATTLEFIELD_IMAGE_RANDOM); - if(temp != null){ - if(temp.equals("true")){ + if (temp != null) { + if (temp.equals("true")) { useRandomBattleField(); cbUseRandomBattleImage.setSelected(true); - }else{ + } else { useSelectedBattleField(); cbUseRandomBattleImage.setSelected(false); } - }else{ - useSelectedBattleField(); - cbUseRandomBattleImage.setSelected(false); + } else { + useSelectedBattleField(); + cbUseRandomBattleImage.setSelected(false); } } - + private void cbUseRandomBattleImageActionPerformed(java.awt.event.ActionEvent evt) { - if(cbUseRandomBattleImage.isSelected()){ + if (cbUseRandomBattleImage.isSelected()) { useRandomBattleField(); - }else{ + } else { useSelectedBattleField(); } - } + } - private void useRandomBattleField(){ + private void useRandomBattleField() { txtBattlefieldImagePath.setEnabled(false); btnBrowseBattlefieldImage.setEnabled(false); } - - private void useSelectedBattleField(){ + + private void useSelectedBattleField() { txtBattlefieldImagePath.setEnabled(true); btnBrowseBattlefieldImage.setEnabled(true); } - + private void btnBrowseBackgroundImageActionPerformed(java.awt.event.ActionEvent evt) { - int returnVal = fc_i.showOpenDialog(PreferencesDialog.this); + int returnVal = fc_i.showOpenDialog(PreferencesDialog.this); if (returnVal == JFileChooser.APPROVE_OPTION) { File file = fc_i.getSelectedFile(); txtBackgroundImagePath.setText(file.getAbsolutePath()); } - } + } private void btnBrowseBattlefieldImageActionPerformed(java.awt.event.ActionEvent evt) { - int returnVal = fc_i.showOpenDialog(PreferencesDialog.this); + int returnVal = fc_i.showOpenDialog(PreferencesDialog.this); if (returnVal == JFileChooser.APPROVE_OPTION) { File file = fc_i.getSelectedFile(); txtBattlefieldImagePath.setText(file.getAbsolutePath()); } - } - + } + private void txtBackgroundImagePathActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtBackgroundImagePathActionPerformed // TODO add your handling code here: }//GEN-LAST:event_txtBackgroundImagePathActionPerformed @@ -1995,12 +2002,10 @@ public class PreferencesDialog extends javax.swing.JDialog { if (cbProxyType.getSelectedItem() == Connection.ProxyType.SOCKS) { this.pnlProxy.setVisible(true); this.pnlProxySettings.setVisible(true); - } - else if (cbProxyType.getSelectedItem() == Connection.ProxyType.HTTP) { + } else if (cbProxyType.getSelectedItem() == Connection.ProxyType.HTTP) { this.pnlProxy.setVisible(true); this.pnlProxySettings.setVisible(true); - } - else if (cbProxyType.getSelectedItem() == Connection.ProxyType.NONE) { + } else if (cbProxyType.getSelectedItem() == Connection.ProxyType.NONE) { this.pnlProxy.setVisible(false); this.pnlProxySettings.setVisible(false); } @@ -2059,7 +2064,7 @@ public class PreferencesDialog extends javax.swing.JDialog { } private static void loadPhases(Preferences prefs) { - load(prefs, dialog.displayBigCardsInHand, KEY_HAND_USE_BIG_CARDS, "true","true"); + load(prefs, dialog.displayBigCardsInHand, KEY_HAND_USE_BIG_CARDS, "true", "true"); load(prefs, dialog.showToolTipsInAnyZone, KEY_SHOW_TOOLTIPS_ANY_ZONE, "true"); load(prefs, dialog.showCardName, KEY_SHOW_CARD_NAMES, "true"); load(prefs, dialog.nonLandPermanentsInOnePile, KEY_PERMANENTS_IN_ONE_PILE, "true"); @@ -2072,21 +2077,21 @@ public class PreferencesDialog extends javax.swing.JDialog { load(prefs, dialog.cbGameLogAutoSave, KEY_GAME_LOG_AUTO_SAVE, "true"); - load(prefs, dialog.checkBoxUpkeepYou, UPKEEP_YOU, "on","on"); - load(prefs, dialog.checkBoxDrawYou, DRAW_YOU, "on","on"); - load(prefs, dialog.checkBoxMainYou, MAIN_YOU, "on","on"); - load(prefs, dialog.checkBoxBeforeCYou, BEFORE_COMBAT_YOU, "on","on"); - load(prefs, dialog.checkBoxEndOfCYou, END_OF_COMBAT_YOU, "on","on"); - load(prefs, dialog.checkBoxMain2You, MAIN_2_YOU, "on","on"); - load(prefs, dialog.checkBoxEndTurnYou, END_OF_TURN_YOU, "on","on"); + load(prefs, dialog.checkBoxUpkeepYou, UPKEEP_YOU, "on", "on"); + load(prefs, dialog.checkBoxDrawYou, DRAW_YOU, "on", "on"); + load(prefs, dialog.checkBoxMainYou, MAIN_YOU, "on", "on"); + load(prefs, dialog.checkBoxBeforeCYou, BEFORE_COMBAT_YOU, "on", "on"); + load(prefs, dialog.checkBoxEndOfCYou, END_OF_COMBAT_YOU, "on", "on"); + load(prefs, dialog.checkBoxMain2You, MAIN_2_YOU, "on", "on"); + load(prefs, dialog.checkBoxEndTurnYou, END_OF_TURN_YOU, "on", "on"); - load(prefs, dialog.checkBoxUpkeepOthers, UPKEEP_OTHERS, "on","on"); - load(prefs, dialog.checkBoxDrawOthers, DRAW_OTHERS, "on","on"); - load(prefs, dialog.checkBoxMainOthers, MAIN_OTHERS, "on","on"); - load(prefs, dialog.checkBoxBeforeCOthers, BEFORE_COMBAT_OTHERS, "on","on"); - load(prefs, dialog.checkBoxEndOfCOthers, END_OF_COMBAT_OTHERS, "on","on"); - load(prefs, dialog.checkBoxMain2Others, MAIN_2_OTHERS, "on","on"); - load(prefs, dialog.checkBoxEndTurnOthers, END_OF_TURN_OTHERS, "on","on"); + load(prefs, dialog.checkBoxUpkeepOthers, UPKEEP_OTHERS, "on", "on"); + load(prefs, dialog.checkBoxDrawOthers, DRAW_OTHERS, "on", "on"); + load(prefs, dialog.checkBoxMainOthers, MAIN_OTHERS, "on", "on"); + load(prefs, dialog.checkBoxBeforeCOthers, BEFORE_COMBAT_OTHERS, "on", "on"); + load(prefs, dialog.checkBoxEndOfCOthers, END_OF_COMBAT_OTHERS, "on", "on"); + load(prefs, dialog.checkBoxMain2Others, MAIN_2_OTHERS, "on", "on"); + load(prefs, dialog.checkBoxEndTurnOthers, END_OF_TURN_OTHERS, "on", "on"); load(prefs, dialog.cbStopAttack, KEY_STOP_ATTACK, "true", "true"); load(prefs, dialog.cbStopBlock, KEY_STOP_BLOCK, "true", "true"); @@ -2110,13 +2115,13 @@ public class PreferencesDialog extends javax.swing.JDialog { load(prefs, dialog.cbCheckForNewImages, KEY_CARD_IMAGES_CHECK, "true"); load(prefs, dialog.cbSaveToZipFiles, KEY_CARD_IMAGES_SAVE_TO_ZIP, "true"); dialog.cbPreferedImageLanguage.setSelectedItem(MageFrame.getPreferences().get(KEY_CARD_IMAGES_PREF_LANGUAGE, "en")); - - //add background load precedure + + //add background load precedure prop = prefs.get(KEY_BACKGROUND_IMAGE_DEFAULT, "true"); - if(prop.equals("true")){ + if (prop.equals("true")) { dialog.cbUseDefaultBackground.setSelected(true); dialog.useDefaultBackgroundImage(); - }else{ + } else { dialog.cbUseDefaultBackground.setSelected(false); dialog.useSelectBackgroundImage(); String path = prefs.get(KEY_BACKGROUND_IMAGE, ""); @@ -2124,27 +2129,27 @@ public class PreferencesDialog extends javax.swing.JDialog { updateCache(KEY_BACKGROUND_IMAGE, path); } prop = prefs.get(KEY_BATTLEFIELD_IMAGE_DEFAULT, "true"); - if(prop.equals("true")){ + if (prop.equals("true")) { dialog.cbUseDefaultBattleImage.setSelected(true); - dialog.useDefaultBattlefield(); - }else{ + dialog.useDefaultBattlefield(); + } else { dialog.cbUseDefaultBattleImage.setSelected(false); dialog.useSelectedOrRandom(); } prop = prefs.get(KEY_BATTLEFIELD_IMAGE_RANDOM, "true"); - - if(dialog.cbUseRandomBattleImage.isEnabled()) { - if(prop.equals("true")){ + + if (dialog.cbUseRandomBattleImage.isEnabled()) { + if (prop.equals("true")) { dialog.cbUseRandomBattleImage.setSelected(true); dialog.useRandomBattleField(); - }else{ + } else { dialog.cbUseRandomBattleImage.setSelected(false); dialog.useSelectedBattleField(); String path = prefs.get(KEY_BATTLEFIELD_IMAGE, ""); dialog.txtBattlefieldImagePath.setText(path); updateCache(KEY_BATTLEFIELD_IMAGE, path); } - } + } } private static void loadSoundSettings(Preferences prefs) { @@ -2200,7 +2205,7 @@ public class PreferencesDialog extends javax.swing.JDialog { loadPhases(MageFrame.getPreferences()); } UserSkipPrioritySteps userSkipPrioritySteps = new UserSkipPrioritySteps(); - + userSkipPrioritySteps.getYourTurn().setUpkeep(dialog.checkBoxUpkeepYou.isSelected()); userSkipPrioritySteps.getYourTurn().setDraw(dialog.checkBoxDrawYou.isSelected()); userSkipPrioritySteps.getYourTurn().setMain1(dialog.checkBoxMainYou.isSelected()); @@ -2216,7 +2221,7 @@ public class PreferencesDialog extends javax.swing.JDialog { userSkipPrioritySteps.getOpponentTurn().setEndOfCombat(dialog.checkBoxEndOfCOthers.isSelected()); userSkipPrioritySteps.getOpponentTurn().setMain2(dialog.checkBoxMain2Others.isSelected()); userSkipPrioritySteps.getOpponentTurn().setEndOfTurn(dialog.checkBoxEndTurnOthers.isSelected()); - + userSkipPrioritySteps.setStopOnDeclareAttackersDuringSkipActions(dialog.cbStopAttack.isSelected()); userSkipPrioritySteps.setStopOnDeclareBlockerIfNoneAvailable(dialog.cbStopBlock.isSelected()); userSkipPrioritySteps.setStopOnAllEndPhases(dialog.cbStopOnAllEnd.isSelected()); @@ -2235,7 +2240,6 @@ public class PreferencesDialog extends javax.swing.JDialog { } } - private static void saveImagesPath(Preferences prefs) { if (!dialog.cbUseDefaultImageFolder.isSelected()) { String path = dialog.txtImageFolderPath.getText(); @@ -2243,19 +2247,19 @@ public class PreferencesDialog extends javax.swing.JDialog { updateCache(KEY_CARD_IMAGES_PATH, path); } // background path save precedure - if(!dialog.cbUseDefaultBackground.isSelected()){ + if (!dialog.cbUseDefaultBackground.isSelected()) { String path = dialog.txtBackgroundImagePath.getText(); prefs.put(KEY_BACKGROUND_IMAGE, path); updateCache(KEY_BACKGROUND_IMAGE, path); } - if(!dialog.cbUseDefaultBattleImage.isSelected() && !dialog.cbUseRandomBattleImage.isSelected()){ + if (!dialog.cbUseDefaultBattleImage.isSelected() && !dialog.cbUseRandomBattleImage.isSelected()) { String path = dialog.txtBattlefieldImagePath.getText(); prefs.put(KEY_BATTLEFIELD_IMAGE, path); updateCache(KEY_BATTLEFIELD_IMAGE, path); } } - - private static void saveSoundPath(Preferences prefs){ + + private static void saveSoundPath(Preferences prefs) { String path = dialog.txtBattlefieldIBGMPath.getText(); prefs.put(KEY_SOUNDS_MATCH_MUSIC_PATH, path); updateCache(KEY_SOUNDS_MATCH_MUSIC_PATH, path); @@ -2294,13 +2298,14 @@ public class PreferencesDialog extends javax.swing.JDialog { } public static void setPrefValue(String key, boolean value) { - switch(key) { + switch (key) { case KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS: dialog.cbAllowRequestToShowHandCards.setSelected(value); save(MageFrame.getPreferences(), dialog.cbAllowRequestToShowHandCards, KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS, "true", "false", UPDATE_CACHE_POLICY); break; - } + } } + private static void save(Preferences prefs, JCheckBox checkBox, String propName, String yesValue, String noValue, boolean updateCache) { prefs.put(propName, checkBox.isSelected() ? yesValue : noValue); if (updateCache) { @@ -2356,7 +2361,7 @@ public class PreferencesDialog extends javax.swing.JDialog { try { addAvatar(jPanel10, 51, true, false); addAvatar(jPanel13, 13, false, false); - addAvatar(jPanel11, 9, false, false); + addAvatar(jPanel11, 9, false, false); addAvatar(jPanel12, 53, false, false); addAvatar(jPanel14, 10, false, false); addAvatar(jPanel15, 39, false, false); @@ -2409,26 +2414,28 @@ public class PreferencesDialog extends javax.swing.JDialog { public void mousePressed(MouseEvent e) { if (selectedAvatarId != id) { setSelectedId(id); - MageFrame.getSession().updatePreferencesForServer(getUserData()); + MageFrame.getSession().updatePreferencesForServer(getUserData()); } } }); } } - public static UserDataView getUserData(){ - return new UserDataView( - getSelectedAvatar(), - PreferencesDialog.getCachedValue(PreferencesDialog.KEY_SHOW_TOOLTIPS_ANY_ZONE, "true").equals("true"), - PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS, "true").equals("true"), - PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAME_CONFIRM_EMPTY_MANA_POOL, "true").equals("true"), - getUserSkipPrioritySteps(), - MageFrame.getPreferences().get(KEY_CONNECT_FLAG, "world"), - PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAME_ASK_MOVE_TO_GRAVE_ORDER, "true").equals("true") + public static UserData getUserData() { + return new UserData(UserGroup.PLAYER, + PreferencesDialog.selectedAvatarId, + PreferencesDialog.getCachedValue(PreferencesDialog.KEY_SHOW_TOOLTIPS_ANY_ZONE, "true").equals("true"), + PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS, "true").equals("true"), + PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAME_CONFIRM_EMPTY_MANA_POOL, "true").equals("true"), + getUserSkipPrioritySteps(), + MageFrame.getPreferences().get(KEY_CONNECT_FLAG, "world"), + PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAME_ASK_MOVE_TO_GRAVE_ORDER, "true").equals("true") ); } - + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JScrollPane avatarPane; + private javax.swing.JPanel avatarPanel; private javax.swing.JButton btnBattlefieldBGMBrowse; private javax.swing.JButton btnBrowseBackgroundImage; private javax.swing.JButton btnBrowseBattlefieldImage; @@ -2501,8 +2508,6 @@ public class PreferencesDialog extends javax.swing.JDialog { private javax.swing.JPanel jPanel19; private javax.swing.JPanel jPanel20; private javax.swing.JPanel jPanel21; - private javax.swing.JPanel jPanel9; - private javax.swing.JScrollPane jScrollPane1; private javax.swing.JLabel labelPreferedImageLanguage; private javax.swing.JLabel lblProxyPassword; private javax.swing.JLabel lblProxyPort; diff --git a/Mage.Client/src/main/java/mage/client/dialog/RandomPacksSelectorDialog.form b/Mage.Client/src/main/java/mage/client/dialog/RandomPacksSelectorDialog.form new file mode 100644 index 00000000000..d486cab0471 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/dialog/RandomPacksSelectorDialog.form @@ -0,0 +1,106 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Mage.Client/src/main/java/mage/client/dialog/RandomPacksSelectorDialog.java b/Mage.Client/src/main/java/mage/client/dialog/RandomPacksSelectorDialog.java new file mode 100644 index 00000000000..5b9b3cc0d09 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/dialog/RandomPacksSelectorDialog.java @@ -0,0 +1,199 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.client.dialog; + +import java.awt.Component; +import java.util.ArrayList; +import javax.swing.JCheckBox; +import mage.cards.repository.ExpansionInfo; +import mage.cards.repository.ExpansionRepository; + +/** + * + * @author BrodyL + */ +public class RandomPacksSelectorDialog extends javax.swing.JDialog { + + /** + * Creates new form RandomPacksSelectorDialog + */ + private boolean boxesCreated; + public final static String randomDraftDescription = ("The selected packs will be randomly distributed to players. Each player may open different packs. Duplicates will be avoided."); + + public RandomPacksSelectorDialog() { + initComponents(); + this.pnlApply.setToolTipText(randomDraftDescription); + this.pnlSelect.setToolTipText(randomDraftDescription); + boxesCreated = false; + } + + public void showDialog() { + createCheckboxes(); + pnlPacks.setVisible(true); + pnlPacks.revalidate(); + pnlPacks.repaint(); + this.pack(); + this.revalidate(); + this.repaint(); + this.setVisible(true); + this.setModal(true); + } + + public void setSelectedPacks(ArrayList packs){ + if (!boxesCreated){ + createCheckboxes(); + } + for (Component pack : pnlPacks.getComponents()) { + JCheckBox thePack = (JCheckBox) pack; + if (packs.contains(thePack.getText())) { + thePack.setSelected(true); + } else{ + thePack.setSelected(false); + } + } + } + + public ArrayList getSelectedPacks() { + ArrayList returnVal = new ArrayList<>(); + for (Component pack: pnlPacks.getComponents()){ + JCheckBox thePack = (JCheckBox) pack; + if (thePack.isSelected()){ + returnVal.add(thePack.getText()); + } + } + return returnVal; + } + + private void createCheckboxes() { + if (!boxesCreated) { + ExpansionInfo[] allExpansions = ExpansionRepository.instance.getWithBoostersSortedByReleaseDate(); + for (ExpansionInfo exp : allExpansions) { + JCheckBox pack = new JCheckBox(); + pack.setSelected(true); + pack.setText(exp.getCode()); + pack.setToolTipText(exp.getName()); + pnlPacks.add(pack); + } + pnlPacks.setVisible(true); + this.pack(); + boxesCreated = true; + pnlPacks.validate(); + } + } + + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + pnlPacks = new java.awt.Panel(); + pnlSelect = new javax.swing.JPanel(); + btnNone = new javax.swing.JButton(); + btnAll = new javax.swing.JButton(); + pnlApply = new javax.swing.JPanel(); + btnApply = new javax.swing.JButton(); + + setTitle("Random Booster Draft Packs Selector"); + setModal(true); + setModalExclusionType(java.awt.Dialog.ModalExclusionType.APPLICATION_EXCLUDE); + setPreferredSize(new java.awt.Dimension(600, 450)); + setResizable(false); + + pnlPacks.setLayout(new java.awt.GridLayout(11, 12)); + + pnlSelect.setLayout(new javax.swing.BoxLayout(pnlSelect, javax.swing.BoxLayout.LINE_AXIS)); + + btnNone.setText("Select none"); + btnNone.setActionCommand("none"); + btnNone.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnNoneActionPerformed(evt); + } + }); + pnlSelect.add(btnNone); + + btnAll.setText("Select all"); + btnAll.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnAllActionPerformed(evt); + } + }); + pnlSelect.add(btnAll); + + pnlApply.setLayout(new javax.swing.BoxLayout(pnlApply, javax.swing.BoxLayout.LINE_AXIS)); + + btnApply.setText("Apply"); + btnApply.setToolTipText("At least two packs must be selected"); + btnApply.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnApplyActionPerformed(evt); + } + }); + pnlApply.add(btnApply); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(pnlSelect, javax.swing.GroupLayout.PREFERRED_SIZE, 241, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 300, Short.MAX_VALUE) + .addComponent(pnlApply, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(pnlPacks, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(pnlPacks, javax.swing.GroupLayout.PREFERRED_SIZE, 372, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(pnlApply, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(pnlSelect, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + + pack(); + }// //GEN-END:initComponents + + private void btnAllActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnAllActionPerformed + setAllCheckBoxes(true); + }//GEN-LAST:event_btnAllActionPerformed + + private void btnNoneActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnNoneActionPerformed + setAllCheckBoxes(false); + }//GEN-LAST:event_btnNoneActionPerformed + + private void btnApplyActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnApplyActionPerformed + if (getSelectedPacks().size() < 2) { + // at least 2 packs must be selected. + } else { + this.setVisible(false); + } + }//GEN-LAST:event_btnApplyActionPerformed + + private void setAllCheckBoxes(boolean value) { + for (Component pack : pnlPacks.getComponents()) { + JCheckBox thePack = (JCheckBox) pack; + thePack.setSelected(value); + } + } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton btnAll; + private javax.swing.JButton btnApply; + private javax.swing.JButton btnNone; + private javax.swing.JPanel pnlApply; + private java.awt.Panel pnlPacks; + private javax.swing.JPanel pnlSelect; + // End of variables declaration//GEN-END:variables +} diff --git a/Mage.Client/src/main/java/mage/client/dialog/TableWaitingDialog.java b/Mage.Client/src/main/java/mage/client/dialog/TableWaitingDialog.java index c2166b34d4b..156ea32b0a1 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/TableWaitingDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/TableWaitingDialog.java @@ -1,50 +1,54 @@ /* -* 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. -*/ + * 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. + */ /* * TableWaitingDialog.java * * Created on Dec 16, 2009, 10:27:44 AM */ - package mage.client.dialog; import java.util.List; import java.util.UUID; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; +import javax.swing.Icon; import javax.swing.SwingWorker; import javax.swing.table.AbstractTableModel; import mage.client.MageFrame; import mage.client.chat.ChatPanel; import mage.client.components.MageComponents; import mage.client.components.tray.MageTray; +import static mage.client.dialog.PreferencesDialog.KEY_TABLE_WAITING_COLUMNS_ORDER; +import static mage.client.dialog.PreferencesDialog.KEY_TABLE_WAITING_COLUMNS_WIDTH; import mage.client.util.audio.AudioManager; +import mage.client.util.gui.TableUtil; +import mage.client.util.gui.countryBox.CountryCellRenderer; import mage.remote.Session; import mage.view.SeatView; import mage.view.TableView; @@ -64,8 +68,11 @@ public class TableWaitingDialog extends MageDialog { private Session session; private final TableWaitModel tableWaitModel; private UpdateSeatsTask updateTask; + private static final int[] defaultColumnsWidth = {20, 50, 100, 100}; - /** Creates new form TableWaitingDialog */ + /** + * Creates new form TableWaitingDialog + */ public TableWaitingDialog() { session = MageFrame.getSession(); @@ -73,8 +80,17 @@ public class TableWaitingDialog extends MageDialog { initComponents(); + int prefWidth = Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_TABLE_WAITING_WIDTH, "500")); + int prefHeight = Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_TABLE_WAITING_HEIGHT, "400")); + if (prefWidth > 40 && prefHeight > 40) { + this.setSize(prefWidth, prefHeight); + } + chatPanel.useExtendedView(ChatPanel.VIEW_MODE.NONE); tableSeats.createDefaultColumnsFromModel(); + TableUtil.setColumnWidthAndOrder(tableSeats, defaultColumnsWidth, KEY_TABLE_WAITING_COLUMNS_WIDTH, KEY_TABLE_WAITING_COLUMNS_ORDER); + tableSeats.setDefaultRenderer(Icon.class, new CountryCellRenderer()); + MageFrame.getUI().addButton(MageComponents.TABLE_WAITING_START_BUTTON, btnStart); } @@ -97,11 +113,14 @@ public class TableWaitingDialog extends MageDialog { return; } int row = this.tableSeats.getSelectedRow(); + if (getTitle().equals("Waiting for players")) { + this.title = getTitle() + " - " + table.getDeckType() + " / " + table.getGameType(); + this.repaint(); + } tableWaitModel.loadData(table); this.tableSeats.repaint(); this.tableSeats.getSelectionModel().setSelectionInterval(row, row); - } - else { + } else { closeDialog(); } } catch (Exception ex) { @@ -131,8 +150,7 @@ public class TableWaitingDialog extends MageDialog { this.setModal(false); this.setLocation(100, 100); this.setVisible(true); - } - else { + } else { closeDialog(); } } @@ -144,14 +162,15 @@ public class TableWaitingDialog extends MageDialog { this.chatPanel.disconnect(); MageFrame.getUI().removeButton(MageComponents.TABLE_WAITING_START_BUTTON); this.removeDialog(); + TableUtil.saveColumnWidthAndOrderToPrefs(tableSeats, KEY_TABLE_WAITING_COLUMNS_WIDTH, KEY_TABLE_WAITING_COLUMNS_ORDER); + PreferencesDialog.saveValue(PreferencesDialog.KEY_TABLE_WAITING_WIDTH, Integer.toString(getWidth())); + PreferencesDialog.saveValue(PreferencesDialog.KEY_TABLE_WAITING_HEIGHT, Integer.toString(getHeight())); } - - - /** This method is called from within the constructor to - * initialize the form. - * WARNING: Do NOT modify this code. The content of this method is - * always regenerated by the Form Editor. + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents @@ -248,12 +267,11 @@ public class TableWaitingDialog extends MageDialog { if (session.startMatch(roomId, tableId)) { closeDialog(); } - } - else { + } else { if (session.startTournament(roomId, tableId)) { closeDialog(); } - } + } }//GEN-LAST:event_btnStartActionPerformed private void btnCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCancelActionPerformed @@ -285,7 +303,6 @@ public class TableWaitingDialog extends MageDialog { } }//GEN-LAST:event_btnMoveUpActionPerformed - // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton btnCancel; private javax.swing.JButton btnMoveDown; @@ -300,7 +317,8 @@ public class TableWaitingDialog extends MageDialog { } class TableWaitModel extends AbstractTableModel { - private final String[] columnNames = new String[]{"Seat Num", "Player Name", "Player Type"}; + + private final String[] columnNames = new String[]{"Seat", "Loc", "Player Name", "Player Type"}; private SeatView[] seats = new SeatView[0]; public void loadData(TableView table) { @@ -324,14 +342,15 @@ class TableWaitModel extends AbstractTableModel { if (arg1 == 0) { return Integer.toString(arg0 + 1); } - } - else { + } else { switch (arg1) { case 0: return Integer.toString(arg0 + 1); case 1: - return seats[arg0].getPlayerName(); + return seats[arg0].getFlagName(); case 2: + return seats[arg0].getPlayerName(); + case 3: return seats[arg0].getPlayerType(); } } @@ -350,8 +369,13 @@ class TableWaitModel extends AbstractTableModel { } @Override - public Class getColumnClass(int columnIndex){ - return String.class; + public Class getColumnClass(int columnIndex) { + switch (columnIndex) { + case 1: + return Icon.class; + default: + return String.class; + } } @Override @@ -413,7 +437,7 @@ class UpdateSeatsTask extends SwingWorker { private int getPlayersCount(TableView tableView) { int playerCount = 0; if (tableView != null) { - for (SeatView seatView: tableView.getSeats()) { + for (SeatView seatView : tableView.getSeats()) { if (seatView.getPlayerId() != null && seatView.getPlayerType().equals("Human")) { playerCount++; } @@ -422,7 +446,6 @@ class UpdateSeatsTask extends SwingWorker { return playerCount; } - @Override protected void done() { try { @@ -431,7 +454,8 @@ class UpdateSeatsTask extends SwingWorker { logger.fatal("Update Seats Task error", ex); } catch (ExecutionException ex) { logger.fatal("Update Seats Task error", ex); - } catch (CancellationException ex) {} + } catch (CancellationException ex) { + } } -} \ No newline at end of file +} diff --git a/Mage.Client/src/main/java/mage/client/game/FeedbackPanel.java b/Mage.Client/src/main/java/mage/client/game/FeedbackPanel.java index fdd97d9b35c..f246336bd62 100644 --- a/Mage.Client/src/main/java/mage/client/game/FeedbackPanel.java +++ b/Mage.Client/src/main/java/mage/client/game/FeedbackPanel.java @@ -1,37 +1,36 @@ /* -* 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. -*/ + * 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. + */ /* * FeedbackPanel.java * * Created on 23-Dec-2009, 9:54:01 PM */ - package mage.client.game; import java.awt.Component; @@ -61,6 +60,7 @@ public class FeedbackPanel extends javax.swing.JPanel { private static final Logger logger = Logger.getLogger(FeedbackPanel.class); public enum FeedbackMode { + INFORM, QUESTION, CONFIRM, CANCEL, SELECT, END } @@ -73,7 +73,9 @@ public class FeedbackPanel extends javax.swing.JPanel { private static final ScheduledExecutorService worker = Executors.newSingleThreadScheduledExecutor(); - /** Creates new form FeedbackPanel */ + /** + * Creates new form FeedbackPanel + */ public FeedbackPanel() { //initComponents(); customInitComponents(); @@ -170,7 +172,7 @@ public class FeedbackPanel extends javax.swing.JPanel { while (c != null && !(c instanceof GamePane)) { c = c.getParent(); } - if (c != null && ((GamePane)c).isVisible()) { // check if GamePanel still visible + if (c != null && ((GamePane) c).isVisible()) { // check if GamePanel still visible FeedbackPanel.this.btnRight.doClick(); } } @@ -181,8 +183,8 @@ public class FeedbackPanel extends javax.swing.JPanel { private void handleOptions(Map options) { if (options != null) { if (options.containsKey("UI.right.btn.text")) { - this.btnRight.setText((String)options.get("UI.right.btn.text")); - this.helper.setRight((String)options.get("UI.right.btn.text"), true); + this.btnRight.setText((String) options.get("UI.right.btn.text")); + this.helper.setRight((String) options.get("UI.right.btn.text"), true); } if (options.containsKey("dialog")) { connectedDialog = (MageDialog) options.get("dialog"); @@ -224,7 +226,7 @@ public class FeedbackPanel extends javax.swing.JPanel { btnUndo = new javax.swing.JButton(); btnUndo.setVisible(true); - setBackground(new java.awt.Color(0,0,0,80)); + setBackground(new java.awt.Color(0, 0, 0, 80)); btnRight.setText("Cancel"); btnRight.addActionListener(new java.awt.event.ActionListener() { @@ -294,7 +296,7 @@ public class FeedbackPanel extends javax.swing.JPanel { session.sendPlayerString(gameId, "special"); }//GEN-LAST:event_btnSpecialActionPerformed - private void btnUndoActionPerformed(java.awt.event.ActionEvent evt) { + private void btnUndoActionPerformed(java.awt.event.ActionEvent evt) { session.sendPlayerAction(PlayerAction.UNDO, gameId, null); } @@ -309,7 +311,7 @@ public class FeedbackPanel extends javax.swing.JPanel { public void setConnectedChatPanel(ChatPanel chatPanel) { this.connectedChatPanel = chatPanel; } - + public void pressOKYesOrDone() { if (btnLeft.getText().equals("OK") || btnLeft.getText().equals("Yes")) { btnLeft.doClick(); diff --git a/Mage.Client/src/main/java/mage/client/game/HelperPanel.java b/Mage.Client/src/main/java/mage/client/game/HelperPanel.java index 602e94b6b1a..f4f716f92b7 100644 --- a/Mage.Client/src/main/java/mage/client/game/HelperPanel.java +++ b/Mage.Client/src/main/java/mage/client/game/HelperPanel.java @@ -1,40 +1,43 @@ /* -* 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. -*/ - + * 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.client.game; import java.awt.Color; import java.awt.Dimension; import java.awt.GridBagLayout; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JPanel; import javax.swing.SwingUtilities; +import javax.swing.ToolTipManager; +import javax.swing.UIManager; import mage.client.components.MageTextArea; /** @@ -58,11 +61,15 @@ public class HelperPanel extends JPanel { private javax.swing.JButton linkSpecial; private javax.swing.JButton linkUndo; + private final int defaultDismissTimeout = ToolTipManager.sharedInstance().getDismissDelay(); + private final Object tooltipBackground = UIManager.get("info"); + public HelperPanel() { initComponents(); } private void initComponents() { + setBackground(new Color(0, 0, 0, 100)); //setLayout(new GridBagLayout()); setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); @@ -84,7 +91,7 @@ public class HelperPanel extends JPanel { add(jPanel); add(container); - + btnSpecial = new JButton("Special"); btnSpecial.setVisible(false); container.add(btnSpecial); @@ -101,22 +108,24 @@ public class HelperPanel extends JPanel { btnLeft.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { - if (linkLeft != null) {{ - Thread worker = new Thread(){ - @Override - public void run(){ - SwingUtilities.invokeLater(new Runnable(){ - @Override - public void run(){ - setState("",false,"",false); - setSpecial("", false); - linkLeft.doClick(); - } - }); - } - }; - worker.start(); - }} + if (linkLeft != null) { + { + Thread worker = new Thread() { + @Override + public void run() { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + setState("", false, "", false); + setSpecial("", false); + linkLeft.doClick(); + } + }); + } + }; + worker.start(); + } + } } }); @@ -124,13 +133,13 @@ public class HelperPanel extends JPanel { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { if (linkRight != null) { - Thread worker = new Thread(){ + Thread worker = new Thread() { @Override - public void run(){ - SwingUtilities.invokeLater(new Runnable(){ + public void run() { + SwingUtilities.invokeLater(new Runnable() { @Override - public void run(){ - setState("",false,"",false); + public void run() { + setState("", false, "", false); setSpecial("", false); linkRight.doClick(); } @@ -145,42 +154,61 @@ public class HelperPanel extends JPanel { btnSpecial.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { - if (linkSpecial != null) {{ - Thread worker = new Thread(){ - @Override - public void run(){ - SwingUtilities.invokeLater(new Runnable(){ - @Override - public void run(){ - setState("",false,"",false); - setSpecial("", false); - linkSpecial.doClick(); - } - }); - } - }; - worker.start(); - }} + if (linkSpecial != null) { + { + Thread worker = new Thread() { + @Override + public void run() { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + setState("", false, "", false); + setSpecial("", false); + linkSpecial.doClick(); + } + }); + } + }; + worker.start(); + } + } } }); btnUndo.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { - if (linkUndo != null) {{ - Thread worker = new Thread(){ - @Override - public void run(){ - SwingUtilities.invokeLater(new Runnable(){ - @Override - public void run(){ - linkUndo.doClick(); - } - }); - } - }; - worker.start(); - }} + if (linkUndo != null) { + { + Thread worker = new Thread() { + @Override + public void run() { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + linkUndo.doClick(); + } + }); + } + }; + worker.start(); + } + } + } + }); + + textArea.addMouseListener(new MouseAdapter() { + + @Override + public void mouseEntered(MouseEvent me) { + ToolTipManager.sharedInstance().setDismissDelay(100000); + UIManager.put("info", Color.DARK_GRAY); + } + + @Override + public void mouseExited(MouseEvent me) { + ToolTipManager.sharedInstance().setDismissDelay(defaultDismissTimeout); + UIManager.put("info", tooltipBackground); } }); } @@ -218,19 +246,20 @@ public class HelperPanel extends JPanel { this.linkSpecial = special; this.linkUndo = undo; } - + public void setMessage(String message) { - if (message.startsWith("Use alternative cost")) { - message = "Use alternative cost?"; - } else if (message.contains("Use ")) { - if (message.length() < this.getWidth() / 10) { - message = getSmallText(message); - } else { - message = "Use ability?" + getSmallText(message.substring(0, this.getWidth() / 10)); - } - } - textArea.setText(message); +// if (message.startsWith("Use alternative cost")) { +// message = "Use alternative cost?"; +// } else if (message.contains("Use ")) { +// if (message.length() < this.getWidth() / 10) { +// message = getSmallText(message); +// } else { +// message = "Use ability?" + getSmallText(message.substring(0, this.getWidth() / 10)); +// } +// } + textArea.setText(message, this.getWidth()); } + protected String getSmallText(String text) { return "
" + text + "
"; } diff --git a/Mage.Client/src/main/java/mage/client/game/PlayAreaPanel.java b/Mage.Client/src/main/java/mage/client/game/PlayAreaPanel.java index f82dda7b13b..c7be776f300 100644 --- a/Mage.Client/src/main/java/mage/client/game/PlayAreaPanel.java +++ b/Mage.Client/src/main/java/mage/client/game/PlayAreaPanel.java @@ -1,30 +1,30 @@ /* -* 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. -*/ + * 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.client.game; import java.awt.Color; @@ -37,7 +37,6 @@ import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.lang.reflect.Field; import java.util.UUID; - import javax.swing.BorderFactory; import javax.swing.GroupLayout; import javax.swing.GroupLayout.Alignment; @@ -72,21 +71,23 @@ public class PlayAreaPanel extends javax.swing.JPanel { private boolean playingMode = true; private final GamePanel gamePanel; private final PlayAreaPanelOptions options; - + private JCheckBoxMenuItem manaPoolMenuItem1; private JCheckBoxMenuItem manaPoolMenuItem2; private JCheckBoxMenuItem allowViewHandCardsMenuItem; - + public static final int PANEL_HEIGHT = 242; public static final int PANEL_HEIGHT_SMALL = 190; - /** Creates new form PlayAreaPanel + /** + * Creates new form PlayAreaPanel + * * @param player * @param bigCard * @param gameId * @param priorityTime * @param gamePanel - * @param options + * @param options */ public PlayAreaPanel(PlayerView player, BigCard bigCard, UUID gameId, int priorityTime, GamePanel gamePanel, PlayAreaPanelOptions options) { this.gamePanel = gamePanel; @@ -97,7 +98,7 @@ public class PlayAreaPanel extends javax.swing.JPanel { popupMenu = new JPopupMenu(); if (options.isPlayer) { - addPopupMenuPlayer(player.getUserData().allowRequestShowHandCards()); + addPopupMenuPlayer(player.getUserData().isAllowRequestShowHandCards()); } else { addPopupMenuWatcher(); } @@ -109,15 +110,14 @@ public class PlayAreaPanel extends javax.swing.JPanel { public void CleanUp() { battlefieldPanel.cleanUp(); playerPanel.cleanUp(); - - for (ActionListener al : btnCheat.getActionListeners() ) { + for (ActionListener al : btnCheat.getActionListeners()) { btnCheat.removeActionListener(al); } - + // Taken form : https://community.oracle.com/thread/2183145 // removed the internal focus of a popupMenu data to allow GC before another popup menu is selected - for(ChangeListener listener : MenuSelectionManager.defaultManager().getChangeListeners()) { + for (ChangeListener listener : MenuSelectionManager.defaultManager().getChangeListeners()) { if (listener.getClass().getName().contains("MenuKeyboardHelper")) { try { Field field = listener.getClass().getDeclaredField("menuInputMap"); @@ -130,7 +130,7 @@ public class PlayAreaPanel extends javax.swing.JPanel { } } - for (MouseListener ml :battlefieldPanel.getMainPanel().getMouseListeners()) { + for (MouseListener ml : battlefieldPanel.getMainPanel().getMouseListeners()) { battlefieldPanel.getMainPanel().removeMouseListener(ml); } popupMenu.getUI().uninstallUI(this); @@ -170,11 +170,11 @@ public class PlayAreaPanel extends javax.swing.JPanel { case "F9": { gamePanel.getSession().sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_MY_NEXT_TURN, gameId, null); break; - } + } } } }; - + menuItem = new JMenuItem("F2 - Confirm current request"); menuItem.setActionCommand("F2"); menuItem.setMnemonic(KeyEvent.VK_O); @@ -187,11 +187,10 @@ public class PlayAreaPanel extends javax.swing.JPanel { popupMenu.add(menuItem); menuItem.addActionListener(skipListener); - JMenu skipMenu = new JMenu("Skip"); skipMenu.setMnemonic(KeyEvent.VK_S); popupMenu.add(skipMenu); - + String tooltipText = "This skip actions stops if something goes to
stack and if attackers or blocker have to be declared."; menuItem = new JMenuItem("F4 - Phases until next turn"); menuItem.setActionCommand("F4"); @@ -213,7 +212,7 @@ public class PlayAreaPanel extends javax.swing.JPanel { menuItem.setMnemonic(KeyEvent.VK_M); skipMenu.add(menuItem); menuItem.addActionListener(skipListener); - + menuItem = new JMenuItem("F9 - Everything until your own next turn"); menuItem.setActionCommand("F9"); menuItem.setToolTipText(tooltipText); @@ -222,50 +221,50 @@ public class PlayAreaPanel extends javax.swing.JPanel { menuItem.addActionListener(skipListener); popupMenu.addSeparator(); - + JMenu manaPoolMenu = new JMenu("Mana payment"); - manaPoolMenu.setMnemonic(KeyEvent.VK_M); + manaPoolMenu.setMnemonic(KeyEvent.VK_M); popupMenu.add(manaPoolMenu); - + manaPoolMenuItem1 = new JCheckBoxMenuItem("Automatically", true); manaPoolMenuItem1.setMnemonic(KeyEvent.VK_A); manaPoolMenuItem1.setToolTipText("If not active, produced mana goes only to the mana pool
" - + "and you have to click the type of mana you want to use
" - + "in the player mana pool panel for payment."); + + "and you have to click the type of mana you want to use
" + + "in the player mana pool panel for payment."); manaPoolMenu.add(manaPoolMenuItem1); // Auto pay mana from mana pool manaPoolMenuItem1.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - boolean manaPoolAutomatic = ((JCheckBoxMenuItem)e.getSource()).getState(); - PreferencesDialog.saveValue(KEY_GAME_MANA_AUTOPAYMENT, manaPoolAutomatic ? "true": "false"); + boolean manaPoolAutomatic = ((JCheckBoxMenuItem) e.getSource()).getState(); + PreferencesDialog.saveValue(KEY_GAME_MANA_AUTOPAYMENT, manaPoolAutomatic ? "true" : "false"); gamePanel.setMenuStates(manaPoolAutomatic, manaPoolMenuItem2.getState()); - gamePanel.getSession().sendPlayerAction(manaPoolAutomatic ? PlayerAction.MANA_AUTO_PAYMENT_ON: PlayerAction.MANA_AUTO_PAYMENT_OFF, gameId, null); + gamePanel.getSession().sendPlayerAction(manaPoolAutomatic ? PlayerAction.MANA_AUTO_PAYMENT_ON : PlayerAction.MANA_AUTO_PAYMENT_OFF, gameId, null); } }); manaPoolMenuItem2 = new JCheckBoxMenuItem("No automatic usage for mana already in the pool", true); manaPoolMenuItem2.setMnemonic(KeyEvent.VK_N); manaPoolMenuItem2.setToolTipText("Mana that is already in the mana pool as you start casting a spell or activating an ability
" - + " needs to be payed manually. So you use the mana in the pool only by clicking on the related
" - + " mana symbols of mana pool area."); + + " needs to be payed manually. So you use the mana in the pool only by clicking on the related
" + + " mana symbols of mana pool area."); manaPoolMenu.add(manaPoolMenuItem2); // Auto pay mana from mana pool manaPoolMenuItem2.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - boolean manaPoolAutomaticRestricted = ((JCheckBoxMenuItem)e.getSource()).getState(); - PreferencesDialog.saveValue(KEY_GAME_MANA_AUTOPAYMENT_ONLY_ONE, manaPoolAutomaticRestricted ? "true": "false"); + boolean manaPoolAutomaticRestricted = ((JCheckBoxMenuItem) e.getSource()).getState(); + PreferencesDialog.saveValue(KEY_GAME_MANA_AUTOPAYMENT_ONLY_ONE, manaPoolAutomaticRestricted ? "true" : "false"); gamePanel.setMenuStates(manaPoolMenuItem1.getState(), manaPoolAutomaticRestricted); - gamePanel.getSession().sendPlayerAction(manaPoolAutomaticRestricted ? PlayerAction.MANA_AUTO_PAYMENT_RESTRICTED_ON: PlayerAction.MANA_AUTO_PAYMENT_RESTRICTED_OFF, gameId, null); + gamePanel.getSession().sendPlayerAction(manaPoolAutomaticRestricted ? PlayerAction.MANA_AUTO_PAYMENT_RESTRICTED_ON : PlayerAction.MANA_AUTO_PAYMENT_RESTRICTED_OFF, gameId, null); } }); JMenu automaticConfirmsMenu = new JMenu("Automatic confirms"); automaticConfirmsMenu.setMnemonic(KeyEvent.VK_U); popupMenu.add(automaticConfirmsMenu); - + menuItem = new JMenuItem("Replacement effects - reset auto select"); menuItem.setMnemonic(KeyEvent.VK_R); menuItem.setToolTipText("Reset all effects that were added to the list of auto select replacement effects this game."); @@ -281,7 +280,7 @@ public class PlayAreaPanel extends javax.swing.JPanel { JMenu handCardsMenu = new JMenu("Cards on hand"); handCardsMenu.setMnemonic(KeyEvent.VK_H); popupMenu.add(handCardsMenu); - + if (!options.playerItself) { menuItem = new JMenuItem("Request permission to see the hand cards"); menuItem.setMnemonic(KeyEvent.VK_P); @@ -304,9 +303,9 @@ public class PlayAreaPanel extends javax.swing.JPanel { allowViewHandCardsMenuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - boolean requestsAllowed = ((JCheckBoxMenuItem)e.getSource()).getState(); + boolean requestsAllowed = ((JCheckBoxMenuItem) e.getSource()).getState(); PreferencesDialog.setPrefValue(KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS, requestsAllowed); - gamePanel.getSession().sendPlayerAction(requestsAllowed ? PlayerAction.PERMISSION_REQUESTS_ALLOWED_ON: PlayerAction.PERMISSION_REQUESTS_ALLOWED_OFF, gameId, null); + gamePanel.getSession().sendPlayerAction(requestsAllowed ? PlayerAction.PERMISSION_REQUESTS_ALLOWED_ON : PlayerAction.PERMISSION_REQUESTS_ALLOWED_OFF, gameId, null); } }); @@ -323,7 +322,7 @@ public class PlayAreaPanel extends javax.swing.JPanel { } }); } - + if (options.rollbackTurnsAllowed) { ActionListener rollBackActionListener = new ActionListener() { @Override @@ -332,44 +331,42 @@ public class PlayAreaPanel extends javax.swing.JPanel { gamePanel.getSession().sendPlayerAction(PlayerAction.ROLLBACK_TURNS, gameId, turnsToRollBack); } }; - + JMenu rollbackMainItem = new JMenu("Roll back"); rollbackMainItem.setMnemonic(KeyEvent.VK_R); rollbackMainItem.setToolTipText("The game will be rolled back to the start of the requested turn if all players agree."); popupMenu.add(rollbackMainItem); - + menuItem = new JMenuItem("To the start of the current turn"); menuItem.setMnemonic(KeyEvent.VK_C); menuItem.setActionCommand("0"); - menuItem.addActionListener(rollBackActionListener); + menuItem.addActionListener(rollBackActionListener); rollbackMainItem.add(menuItem); - + menuItem = new JMenuItem("To the start of the previous turn"); menuItem.setMnemonic(KeyEvent.VK_P); menuItem.setActionCommand("1"); - menuItem.addActionListener(rollBackActionListener); + menuItem.addActionListener(rollBackActionListener); rollbackMainItem.add(menuItem); menuItem = new JMenuItem("The current turn and the 2 turns before"); menuItem.setMnemonic(KeyEvent.VK_2); menuItem.setActionCommand("2"); - menuItem.addActionListener(rollBackActionListener); + menuItem.addActionListener(rollBackActionListener); rollbackMainItem.add(menuItem); menuItem = new JMenuItem("The current turn and the 3 turns before"); menuItem.setMnemonic(KeyEvent.VK_3); menuItem.setActionCommand("3"); - menuItem.addActionListener(rollBackActionListener); + menuItem.addActionListener(rollBackActionListener); rollbackMainItem.add(menuItem); - - } - - + + } JMenu concedeMenu = new JMenu("Concede"); concedeMenu.setMnemonic(KeyEvent.VK_C); popupMenu.add(concedeMenu); - + ActionListener concedeListener = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -377,19 +374,19 @@ public class PlayAreaPanel extends javax.swing.JPanel { case "Game": { if (JOptionPane.showConfirmDialog(PlayAreaPanel.this, "Are you sure you want to concede the game?", "Confirm concede game", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { MageFrame.getSession().sendPlayerAction(PlayerAction.CONCEDE, gameId, null); - } + } break; } case "Match": { if (JOptionPane.showConfirmDialog(PlayAreaPanel.this, "Are you sure you want to concede the complete match?", "Confirm concede match", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { MageFrame.getSession().quitMatch(gameId); - } + } break; } } } }; - + // Concede Game menuItem = new JMenuItem("Game"); menuItem.setMnemonic(KeyEvent.VK_G); @@ -397,7 +394,7 @@ public class PlayAreaPanel extends javax.swing.JPanel { menuItem.setToolTipText("Concedes only the current game and after that the next game of the match is started if there is another game needed."); concedeMenu.add(menuItem); menuItem.addActionListener(concedeListener); - + // Concede Match menuItem = new JMenuItem("Match"); menuItem.setMnemonic(KeyEvent.VK_M); @@ -406,20 +403,19 @@ public class PlayAreaPanel extends javax.swing.JPanel { concedeMenu.add(menuItem); menuItem.addActionListener(concedeListener); - battlefieldPanel.getMainPanel().addMouseListener(new MouseAdapter() { @Override public void mouseReleased(MouseEvent Me) { this.checkMenu(Me); } - + // neccessary for linux and mac systems @Override public void mousePressed(MouseEvent Me) { this.checkMenu(Me); } - private void checkMenu(MouseEvent Me){ + private void checkMenu(MouseEvent Me) { if (Me.isPopupTrigger() && playingMode) { popupMenu.show(Me.getComponent(), Me.getX(), Me.getY()); } @@ -461,13 +457,14 @@ public class PlayAreaPanel extends javax.swing.JPanel { public void mouseReleased(MouseEvent Me) { this.checkMenu(Me); } + // neccessary for linux and mac systems @Override public void mousePressed(MouseEvent Me) { this.checkMenu(Me); } - private void checkMenu(MouseEvent Me){ + private void checkMenu(MouseEvent Me) { if (Me.isPopupTrigger() && playingMode) { popupMenu.show(Me.getComponent(), Me.getX(), Me.getY()); } @@ -483,8 +480,7 @@ public class PlayAreaPanel extends javax.swing.JPanel { if (MageFrame.getSession().isTestMode()) { this.playerId = player.getPlayerId(); this.btnCheat.setVisible(true); - } - else { + } else { this.btnCheat.setVisible(false); } } @@ -493,7 +489,7 @@ public class PlayAreaPanel extends javax.swing.JPanel { this.playerPanel.update(player); this.battlefieldPanel.update(player.getBattlefield()); if (this.allowViewHandCardsMenuItem != null) { - this.allowViewHandCardsMenuItem.setSelected(player.getUserData().allowRequestShowHandCards()); + this.allowViewHandCardsMenuItem.setSelected(player.getUserData().isAllowRequestShowHandCards()); } } @@ -506,7 +502,7 @@ public class PlayAreaPanel extends javax.swing.JPanel { } private void initComponents() { - setBorder(BorderFactory.createLineBorder(new Color(0,0,0,0))); + setBorder(BorderFactory.createLineBorder(new Color(0, 0, 0, 0))); playerPanel = new PlayerPanelExt(); btnCheat = new javax.swing.JButton(); //jScrollPane1 = new javax.swing.JScrollPane(); @@ -525,16 +521,15 @@ public class PlayAreaPanel extends javax.swing.JPanel { //Border empty = new EmptyBorder(0,0,0,0); //jScrollPane1.setBorder(empty); //jScrollPane1.setViewportBorder(empty); - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); layout.setHorizontalGroup( - layout.createSequentialGroup() + layout.createSequentialGroup() .addComponent(playerPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addPreferredGap(ComponentPlacement.RELATED) .addComponent(battlefieldPanel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); layout.setVerticalGroup( - layout.createParallelGroup(Alignment.LEADING) + layout.createParallelGroup(Alignment.LEADING) .addComponent(playerPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(battlefieldPanel, GroupLayout.DEFAULT_SIZE, 160, Short.MAX_VALUE) ); @@ -548,8 +543,7 @@ public class PlayAreaPanel extends javax.swing.JPanel { this.playerPanel.setPreferredSize(new Dimension(92, PANEL_HEIGHT_SMALL)); //this.jScrollPane1.setPreferredSize(new Dimension(160, 160)); this.battlefieldPanel.setPreferredSize(new Dimension(160, PANEL_HEIGHT_SMALL)); - } - else { + } else { this.playerPanel.setPreferredSize(new Dimension(92, PANEL_HEIGHT)); //this.jScrollPane1.setPreferredSize(new Dimension(160, 212)); this.battlefieldPanel.setPreferredSize(new Dimension(160, PANEL_HEIGHT)); @@ -576,7 +570,7 @@ public class PlayAreaPanel extends javax.swing.JPanel { manaPoolMenuItem2.setSelected(manaPoolAutomaticRestricted); } } - + private mage.client.game.BattlefieldPanel battlefieldPanel; private javax.swing.JButton btnCheat; //private javax.swing.JScrollPane jScrollPane1; diff --git a/Mage.Client/src/main/java/mage/client/game/PlayerPanelExt.java b/Mage.Client/src/main/java/mage/client/game/PlayerPanelExt.java index bf8a5721825..5b8de71db4a 100644 --- a/Mage.Client/src/main/java/mage/client/game/PlayerPanelExt.java +++ b/Mage.Client/src/main/java/mage/client/game/PlayerPanelExt.java @@ -36,6 +36,7 @@ package mage.client.game; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; +import java.awt.GridLayout; import java.awt.Image; import java.awt.Rectangle; import java.awt.event.ActionEvent; @@ -67,6 +68,7 @@ import mage.client.util.CardsViewUtil; import mage.client.util.Command; import mage.client.util.ImageHelper; import mage.client.util.gui.BufferedImageBuilder; +import mage.client.util.gui.countryBox.CountryUtil; import mage.components.ImagePanel; import mage.constants.ManaType; import mage.remote.Session; @@ -103,6 +105,7 @@ public class PlayerPanelExt extends javax.swing.JPanel { private static final Border emptyBorder = BorderFactory.createEmptyBorder(0, 0, 0, 0); private int avatarId = -1; + private String flagName = ""; private PriorityTimer timer; @@ -234,6 +237,11 @@ public class PlayerPanelExt extends javax.swing.JPanel { BufferedImage resized = ImageHelper.getResizedImage(BufferedImageBuilder.bufferImage(image, BufferedImage.TYPE_INT_ARGB), r); this.avatar.update("player", resized, resized, resized, resized, r); } + if (!player.getUserData().getFlagName().equals(flagName)) { + flagName = player.getUserData().getFlagName(); + this.avatarFlag.setIcon(CountryUtil.getCountryFlagIcon(flagName)); + avatar.repaint(); + } } this.avatar.setText(player.getName()); if (this.timer != null) { @@ -298,6 +306,7 @@ public class PlayerPanelExt extends javax.swing.JPanel { panelBackground = new MageRoundPane(); panelBackground.setPreferredSize(new Dimension(PANEL_WIDTH - 2, PANEL_HEIGHT)); Rectangle r = new Rectangle(80, 80); + avatarFlag = new JLabel(); timerLabel = new JLabel(); lifeLabel = new JLabel(); handLabel = new JLabel(); @@ -315,6 +324,14 @@ public class PlayerPanelExt extends javax.swing.JPanel { BufferedImage resized = ImageHelper.getResizedImage(BufferedImageBuilder.bufferImage(image, BufferedImage.TYPE_INT_ARGB), r); avatar = new HoverButton("player", resized, resized, resized, r); + avatar.setLayout(new GridLayout(4, 1, 0, 0)); + avatar.add(new JLabel()); + avatar.add(new JLabel()); + avatar.add(avatarFlag); + avatar.setAlignTextLeft(true); + avatarFlag.setHorizontalAlignment(JLabel.LEFT); + avatarFlag.setVerticalAlignment(JLabel.BOTTOM); + avatar.add(new JLabel()); String showPlayerNamePermanently = MageFrame.getPreferences().get(PreferencesDialog.KEY_SHOW_PLAYER_NAMES_PERMANENTLY, "true"); if (showPlayerNamePermanently.equals("true")) { avatar.setTextAlwaysVisible(true); @@ -326,6 +343,7 @@ public class PlayerPanelExt extends javax.swing.JPanel { session.sendPlayerUUID(gameId, playerId); } }); + // timer area /small layout) timerLabel.setToolTipText("Time left"); timerLabel.setSize(80, 12); @@ -637,6 +655,8 @@ public class PlayerPanelExt extends javax.swing.JPanel { .addComponent(btnPlayer, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(timerLabel, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(avatar, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 80, Short.MAX_VALUE)) + // .addGroup(gl_panelBackground.createSequentialGroup() + // .addComponent(avatarFlag, GroupLayout.PREFERRED_SIZE, 16, GroupLayout.PREFERRED_SIZE)) .addGap(14)) .addGroup(gl_panelBackground.createSequentialGroup() .addGap(6) @@ -748,12 +768,14 @@ public class PlayerPanelExt extends javax.swing.JPanel { protected void sizePlayerPanel(boolean smallMode) { if (smallMode) { avatar.setVisible(false); + avatarFlag.setVisible(false); btnPlayer.setVisible(true); timerLabel.setVisible(true); panelBackground.setPreferredSize(new Dimension(PANEL_WIDTH - 2, PANEL_HEIGHT_SMALL)); panelBackground.setBounds(0, 0, PANEL_WIDTH - 2, PANEL_HEIGHT_SMALL); } else { avatar.setVisible(true); + avatarFlag.setVisible(true); btnPlayer.setVisible(false); timerLabel.setVisible(false); panelBackground.setPreferredSize(new Dimension(PANEL_WIDTH - 2, PANEL_HEIGHT)); @@ -791,6 +813,7 @@ public class PlayerPanelExt extends javax.swing.JPanel { } private HoverButton avatar; + private JLabel avatarFlag; private JButton btnPlayer; private ImagePanel life; private ImagePanel poison; diff --git a/Mage.Client/src/main/java/mage/client/tournament/TournamentPanel.java b/Mage.Client/src/main/java/mage/client/tournament/TournamentPanel.java index 6b681fc17d3..1d76e09ae52 100644 --- a/Mage.Client/src/main/java/mage/client/tournament/TournamentPanel.java +++ b/Mage.Client/src/main/java/mage/client/tournament/TournamentPanel.java @@ -31,7 +31,6 @@ * * Created on 20-Jan-2011, 9:18:30 PM */ - package mage.client.tournament; import java.awt.Component; @@ -45,14 +44,21 @@ import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import javax.swing.AbstractAction; import javax.swing.Action; +import javax.swing.Icon; import javax.swing.JOptionPane; import javax.swing.SwingWorker; import javax.swing.table.AbstractTableModel; import mage.client.MageFrame; import mage.client.chat.ChatPanel; import mage.client.dialog.PreferencesDialog; +import static mage.client.dialog.PreferencesDialog.KEY_TOURNAMENT_MATCH_COLUMNS_ORDER; +import static mage.client.dialog.PreferencesDialog.KEY_TOURNAMENT_MATCH_COLUMNS_WIDTH; +import static mage.client.dialog.PreferencesDialog.KEY_TOURNAMENT_PLAYER_COLUMNS_ORDER; +import static mage.client.dialog.PreferencesDialog.KEY_TOURNAMENT_PLAYER_COLUMNS_WIDTH; import mage.client.util.ButtonColumn; import mage.client.util.Format; +import mage.client.util.gui.TableUtil; +import mage.client.util.gui.countryBox.CountryCellRenderer; import mage.remote.Session; import mage.view.RoundView; import mage.view.TournamentGameView; @@ -76,7 +82,12 @@ public class TournamentPanel extends javax.swing.JPanel { private UpdateTournamentTask updateTask; private final DateFormat df; - /** Creates new form TournamentPanel */ + private static final int[] defaultColumnsWidthPlayers = {30, 150, 150, 60, 400}; + private static final int[] defaultColumnsWidthMatches = {60, 140, 140, 400, 80}; + + /** + * Creates new form TournamentPanel + */ public TournamentPanel() { playersModel = new TournamentPlayersTableModel(); matchesModel = new TournamentMatchesTableModel(); @@ -84,28 +95,29 @@ public class TournamentPanel extends javax.swing.JPanel { initComponents(); this.restoreDividerLocations(); btnQuitTournament.setVisible(false); - + df = DateFormat.getDateTimeInstance(); tablePlayers.createDefaultColumnsFromModel(); + TableUtil.setColumnWidthAndOrder(tablePlayers, defaultColumnsWidthPlayers, KEY_TOURNAMENT_PLAYER_COLUMNS_WIDTH, KEY_TOURNAMENT_PLAYER_COLUMNS_ORDER); + tablePlayers.setDefaultRenderer(Icon.class, new CountryCellRenderer()); + tableMatches.createDefaultColumnsFromModel(); + TableUtil.setColumnWidthAndOrder(tableMatches, defaultColumnsWidthMatches, KEY_TOURNAMENT_MATCH_COLUMNS_WIDTH, KEY_TOURNAMENT_MATCH_COLUMNS_ORDER); chatPanel1.useExtendedView(ChatPanel.VIEW_MODE.NONE); chatPanel1.setChatType(ChatPanel.ChatType.TOURNAMENT); - Action action = new AbstractAction() - { + Action action = new AbstractAction() { @Override - public void actionPerformed(ActionEvent e) - { - int modelRow = Integer.valueOf( e.getActionCommand() ); - - String state = (String)tableMatches.getValueAt(modelRow, 2); - String actionText = (String)tableMatches.getValueAt(modelRow, TournamentMatchesTableModel.ACTION_COLUMN); - UUID tableId = UUID.fromString((String)matchesModel.getValueAt(modelRow, TournamentMatchesTableModel.ACTION_COLUMN +1)); - UUID gameId = UUID.fromString((String)matchesModel.getValueAt(modelRow, TournamentMatchesTableModel.ACTION_COLUMN +3)); + public void actionPerformed(ActionEvent e) { + int modelRow = Integer.valueOf(e.getActionCommand()); + + String state = (String) tableMatches.getValueAt(modelRow, 2); + String actionText = (String) tableMatches.getValueAt(modelRow, TournamentMatchesTableModel.ACTION_COLUMN); + UUID tableId = UUID.fromString((String) matchesModel.getValueAt(modelRow, TournamentMatchesTableModel.ACTION_COLUMN + 1)); + UUID gameId = UUID.fromString((String) matchesModel.getValueAt(modelRow, TournamentMatchesTableModel.ACTION_COLUMN + 3)); - // if (state.equals("Finished") && action.equals("Replay")) { // logger.info("Replaying game " + gameId); // session.replayGame(gameId); @@ -127,6 +139,7 @@ public class TournamentPanel extends javax.swing.JPanel { if (this.chatPanel1 != null) { this.chatPanel1.disconnect(); } + } private void saveDividerLocations() { @@ -167,8 +180,7 @@ public class TournamentPanel extends javax.swing.JPanel { startTasks(); this.setVisible(true); this.repaint(); - } - else { + } else { hideTournament(); } @@ -182,12 +194,15 @@ public class TournamentPanel extends javax.swing.JPanel { stopTasks(); this.chatPanel1.disconnect(); this.saveDividerLocations(); + TableUtil.saveColumnWidthAndOrderToPrefs(tablePlayers, KEY_TOURNAMENT_PLAYER_COLUMNS_WIDTH, KEY_TOURNAMENT_PLAYER_COLUMNS_ORDER); + TableUtil.saveColumnWidthAndOrderToPrefs(tableMatches, KEY_TOURNAMENT_MATCH_COLUMNS_WIDTH, KEY_TOURNAMENT_MATCH_COLUMNS_ORDER); + Component c = this.getParent(); while (c != null && !(c instanceof TournamentPane)) { c = c.getParent(); } if (c != null) { - ((TournamentPane)c).removeTournament(); + ((TournamentPane) c).removeTournament(); } } @@ -201,21 +216,21 @@ public class TournamentPanel extends javax.swing.JPanel { c = c.getParent(); } if (c != null) { - ((TournamentPane)c).setTitle("Tournament [" + tournament.getTournamentName() +"]"); + ((TournamentPane) c).setTitle("Tournament [" + tournament.getTournamentName() + "]"); } txtName.setText(tournament.getTournamentName()); txtType.setText(tournament.getTournamentType()); txtStartTime.setText(df.format(tournament.getStartTime())); txtEndTime.setText("running..."); - + firstInitDone = true; } switch (tournament.getTournamentState()) { case "Constructing": String timeLeft = ""; if (tournament.getStepStartTime() != null) { - timeLeft = Format.getDuration(tournament.getConstructionTime() - (tournament.getServerTime().getTime() - tournament.getStepStartTime().getTime())/1000); + timeLeft = Format.getDuration(tournament.getConstructionTime() - (tournament.getServerTime().getTime() - tournament.getStepStartTime().getTime()) / 1000); } txtTournamentState.setText(new StringBuilder(tournament.getTournamentState()).append(" (").append(timeLeft).append(")").toString()); break; @@ -223,7 +238,7 @@ public class TournamentPanel extends javax.swing.JPanel { case "Drafting": String usedTime = ""; if (tournament.getStepStartTime() != null) { - usedTime = Format.getDuration((tournament.getServerTime().getTime() - tournament.getStepStartTime().getTime())/1000); + usedTime = Format.getDuration((tournament.getServerTime().getTime() - tournament.getStepStartTime().getTime()) / 1000); } txtTournamentState.setText(tournament.getTournamentState() + " (" + usedTime + ") " + tournament.getRunningInfo()); break; @@ -238,7 +253,7 @@ public class TournamentPanel extends javax.swing.JPanel { if (txtEndTime.getText().equals("running...") && tournament.getEndTime() != null) { txtEndTime.setText(df.format(tournament.getEndTime())); } - + playersModel.loadData(tournament); matchesModel.loadData(tournament); this.tablePlayers.repaint(); @@ -274,10 +289,10 @@ public class TournamentPanel extends javax.swing.JPanel { } } - /** This method is called from within the constructor to - * initialize the form. - * WARNING: Do NOT modify this code. The content of this method is - * always regenerated by the Form Editor. + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents @@ -505,7 +520,6 @@ public class TournamentPanel extends javax.swing.JPanel { // TODO add your handling code here: }//GEN-LAST:event_txtNameActionPerformed - // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JPanel actionPanel; private javax.swing.JButton btnCloseWindow; @@ -532,7 +546,8 @@ public class TournamentPanel extends javax.swing.JPanel { } class TournamentPlayersTableModel extends AbstractTableModel { - private final String[] columnNames = new String[]{"Player Name", "State", "Points", "Results"}; + + private final String[] columnNames = new String[]{"Loc", "Player Name", "State", "Points", "Results"}; private TournamentPlayerView[] players = new TournamentPlayerView[0]; public void loadData(TournamentView tournament) { @@ -554,12 +569,14 @@ class TournamentPlayersTableModel extends AbstractTableModel { public Object getValueAt(int arg0, int arg1) { switch (arg1) { case 0: - return players[arg0].getName(); + return players[arg0].getFlagName(); case 1: - return players[arg0].getState(); + return players[arg0].getName(); case 2: - return Integer.toString(players[arg0].getPoints()); + return players[arg0].getState(); case 3: + return Integer.toString(players[arg0].getPoints()); + case 4: return players[arg0].getResults(); } return ""; @@ -577,8 +594,13 @@ class TournamentPlayersTableModel extends AbstractTableModel { } @Override - public Class getColumnClass(int columnIndex){ - return String.class; + public Class getColumnClass(int columnIndex) { + switch (columnIndex) { + case 0: + return Icon.class; + default: + return String.class; + } } @Override @@ -599,8 +621,8 @@ class TournamentMatchesTableModel extends AbstractTableModel { public void loadData(TournamentView tournament) { List views = new ArrayList<>(); watchingAllowed = tournament.isWatchingAllowed(); - for (RoundView round: tournament.getRounds()) { - for (TournamentGameView game: round.getGames()) { + for (RoundView round : tournament.getRounds()) { + for (TournamentGameView game : round.getGames()) { views.add(game); } } @@ -660,7 +682,7 @@ class TournamentMatchesTableModel extends AbstractTableModel { } @Override - public Class getColumnClass(int columnIndex){ + public Class getColumnClass(int columnIndex) { return String.class; } @@ -688,7 +710,7 @@ class UpdateTournamentTask extends SwingWorker { @Override protected Void doInBackground() throws Exception { while (!isCancelled()) { - this.publish(session.getTournament(tournamentId)); + this.publish(session.getTournament(tournamentId)); Thread.sleep(2000); } return null; @@ -709,7 +731,8 @@ class UpdateTournamentTask extends SwingWorker { logger.fatal("Update Tournament Task error", ex); } catch (ExecutionException ex) { logger.fatal("Update Tournament Task error", ex); - } catch (CancellationException ex) {} + } catch (CancellationException ex) { + } } } diff --git a/Mage.Client/src/main/java/mage/client/util/gui/TableUtil.java b/Mage.Client/src/main/java/mage/client/util/gui/TableUtil.java index 187453aa5e1..3667d86d40a 100644 --- a/Mage.Client/src/main/java/mage/client/util/gui/TableUtil.java +++ b/Mage.Client/src/main/java/mage/client/util/gui/TableUtil.java @@ -8,7 +8,6 @@ package mage.client.util.gui; import javax.swing.JTable; import javax.swing.table.TableColumn; import mage.client.dialog.PreferencesDialog; -import org.mage.card.arcane.Util; /** * @@ -17,25 +16,29 @@ import org.mage.card.arcane.Util; public class TableUtil { /** - * + * * @param table - * @param defaultColumnsWidth - * @param widthPrefKey - * @param orderPrefKey + * @param defaultColumnsWidth + * @param widthPrefKey + * @param orderPrefKey */ static public void setColumnWidthAndOrder(JTable table, int[] defaultColumnsWidth, String widthPrefKey, String orderPrefKey) { table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); - // set the column width from saved value or defaults + // set the column width from saved value or defaults int[] widths = getIntArrayFromString(PreferencesDialog.getCachedValue(widthPrefKey, null)); int i = 0; for (int width : defaultColumnsWidth) { if (widths != null && widths.length > i) { width = widths[i]; } - TableColumn column = table.getColumnModel().getColumn(i++); - column.setWidth(width); - column.setPreferredWidth(width); + if (table.getColumnModel().getColumnCount() >= i) { + TableColumn column = table.getColumnModel().getColumn(i++); + column.setWidth(width); + column.setPreferredWidth(width); + } else { + break; + } } // set the column order @@ -47,7 +50,7 @@ public class TableUtil { } } - + static public void saveColumnWidthAndOrderToPrefs(JTable table, String widthPrefKey, String orderPrefKey) { // Column width StringBuilder columnWidthSettings = new StringBuilder(); @@ -68,8 +71,7 @@ public class TableUtil { PreferencesDialog.saveValue(orderPrefKey, columnOrderSettings.toString()); } - - + public static int[] getIntArrayFromString(String stringData) { int[] intArray = null; if (stringData != null && !stringData.isEmpty()) { @@ -79,9 +81,10 @@ public class TableUtil { for (int i = 0; i < lengthW; i++) { try { intArray[i] = Integer.parseInt(items[i]); - } catch (NumberFormatException nfe) {} + } catch (NumberFormatException nfe) { + } } - } + } return intArray; - } + } } diff --git a/Mage.Client/src/main/java/mage/client/util/gui/countryBox/CountryCellRenderer.java b/Mage.Client/src/main/java/mage/client/util/gui/countryBox/CountryCellRenderer.java index 2ee392fe9ea..bd0d0d223a9 100644 --- a/Mage.Client/src/main/java/mage/client/util/gui/countryBox/CountryCellRenderer.java +++ b/Mage.Client/src/main/java/mage/client/util/gui/countryBox/CountryCellRenderer.java @@ -25,56 +25,28 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.client.util.gui.countryBox; import java.awt.Component; -import java.util.HashMap; -import java.util.Map; -import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JTable; import javax.swing.table.DefaultTableCellRenderer; -import org.apache.log4j.Logger; /** * * @author LevelX2 */ public class CountryCellRenderer extends DefaultTableCellRenderer { - - private static final Logger logger = Logger.getLogger(CountryCellRenderer.class); - private final Map flagIconCache = new HashMap<>(); - - private final Map countryMap = new HashMap<>(); - - public CountryCellRenderer() { - for( int i = 0; i <= CountryComboBox.countryList.length - 1; i++) { - countryMap.put(CountryComboBox.countryList[i][1],CountryComboBox.countryList[i][0]); - } - } @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { - JLabel label = (JLabel)super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); - if(table.convertColumnIndexToView(0) == column) { - label.setToolTipText(countryMap.get((String)value)); - label.setIcon(getCountryFlagIcon((String)value)); - label.setText(""); - } - return label; - } - - private ImageIcon getCountryFlagIcon(String countryCode) { - ImageIcon flagIcon = flagIconCache.get(countryCode); - if (flagIcon == null) { - flagIcon = new javax.swing.ImageIcon(getClass().getResource("/flags/" + countryCode + (countryCode.endsWith(".png") ? "" :".png"))); - if (flagIcon.getImage() == null) { - logger.warn("Country flag resource not found: " + countryCode); - } else { - flagIconCache.put(countryCode, flagIcon); - } + JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + if (value == null || ((String) value).isEmpty()) { + value = (String) "world"; } - return flagIcon; - } + label.setToolTipText(CountryUtil.getCountryName((String) value)); + label.setIcon(CountryUtil.getCountryFlagIcon((String) value)); + label.setText(""); + return label; + } } diff --git a/Mage.Client/src/main/java/mage/client/util/gui/countryBox/CountryUtil.java b/Mage.Client/src/main/java/mage/client/util/gui/countryBox/CountryUtil.java new file mode 100644 index 00000000000..17f8386defa --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/util/gui/countryBox/CountryUtil.java @@ -0,0 +1,49 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.client.util.gui.countryBox; + +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import javax.swing.ImageIcon; +import org.apache.log4j.Logger; + +/** + * + * @author LevelX2 + */ +public class CountryUtil { + + private static final Logger logger = Logger.getLogger(CountryUtil.class); + private static final Map flagIconCache = new HashMap<>(); + private static final Map countryMap = new HashMap<>(); + + public static ImageIcon getCountryFlagIcon(String countryCode) { + ImageIcon flagIcon = flagIconCache.get(countryCode); + if (flagIcon == null) { + URL url = CountryUtil.class.getResource("/flags/" + countryCode + (countryCode.endsWith(".png") ? "" : ".png")); + if (url != null) { + flagIcon = new javax.swing.ImageIcon(url); + } + if (flagIcon == null || flagIcon.getImage() == null) { + logger.warn("Country flag resource not found: " + countryCode); + flagIconCache.put(countryCode, flagIcon); + } else { + flagIconCache.put(countryCode, flagIcon); + } + } + return flagIcon; + } + + public static String getCountryName(String countryCode) { + if (countryMap.isEmpty()) { + for (int i = 0; i <= CountryComboBox.countryList.length - 1; i++) { + countryMap.put(CountryComboBox.countryList[i][1], CountryComboBox.countryList[i][0]); + } + } + return countryMap.get(countryCode); + } +} diff --git a/Mage.Client/src/main/resources/flags/computer.png b/Mage.Client/src/main/resources/flags/computer.png new file mode 100644 index 00000000000..1c5fd6e3272 Binary files /dev/null and b/Mage.Client/src/main/resources/flags/computer.png differ diff --git a/Mage.Common/src/mage/interfaces/MageServer.java b/Mage.Common/src/mage/interfaces/MageServer.java index fd86ee26645..4d30942a1e5 100644 --- a/Mage.Common/src/mage/interfaces/MageServer.java +++ b/Mage.Common/src/mage/interfaces/MageServer.java @@ -1,31 +1,30 @@ /* -* 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. -*/ - + * 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.interfaces; import java.util.List; @@ -40,14 +39,14 @@ import mage.constants.PlayerAction; import mage.game.GameException; import mage.game.match.MatchOptions; import mage.game.tournament.TournamentOptions; +import mage.players.net.UserData; import mage.utils.MageVersion; import mage.view.DraftPickView; import mage.view.GameView; import mage.view.MatchView; +import mage.view.RoomUsersView; import mage.view.TableView; import mage.view.TournamentView; -import mage.view.UserDataView; -import mage.view.RoomUsersView; import mage.view.UserView; /** @@ -58,22 +57,28 @@ public interface MageServer { // connection methods boolean registerClient(String userName, String sessionId, MageVersion version) throws MageException; + boolean registerAdmin(String password, String sessionId, MageVersion version) throws MageException; // Not used // void deregisterClient(String sessionId) throws MageException; // update methods List getMissingExpansionData(List codes); + List getMissingCardsData(List classNames); // user methods - boolean setUserData(String userName, String sessionId, UserDataView userDataView) throws MageException; + boolean setUserData(String userName, String sessionId, UserData userData) throws MageException; + void sendFeedbackMessage(String sessionId, String username, String title, String type, String message, String email) throws MageException; // server state methods ServerState getServerState() throws MageException; + List getRoomUsers(UUID roomId) throws MageException; + List getFinishedMatches(UUID roomId) throws MageException; + Object getServerMessagesCompressed(String sessionId) throws MageException; // messages of the day // ping - extends session @@ -81,27 +86,46 @@ public interface MageServer { //table methods TableView createTable(String sessionId, UUID roomId, MatchOptions matchOptions) throws MageException; + TableView createTournamentTable(String sessionId, UUID roomId, TournamentOptions tournamentOptions) throws MageException; + boolean joinTable(String sessionId, UUID roomId, UUID tableId, String name, String playerType, int skill, DeckCardLists deckList, String password) throws MageException, GameException; + boolean joinTournamentTable(String sessionId, UUID roomId, UUID tableId, String name, String playerType, int skill, DeckCardLists deckList, String password) throws MageException, GameException; + boolean submitDeck(String sessionId, UUID tableId, DeckCardLists deckList) throws MageException, GameException; + void updateDeck(String sessionId, UUID tableId, DeckCardLists deckList) throws MageException, GameException; + boolean watchTable(String sessionId, UUID roomId, UUID tableId) throws MageException; + boolean watchTournamentTable(String sessionId, UUID tableId) throws MageException; + boolean leaveTable(String sessionId, UUID roomId, UUID tableId) throws MageException; + void swapSeats(String sessionId, UUID roomId, UUID tableId, int seatNum1, int seatNum2) throws MageException; + void removeTable(String sessionId, UUID roomId, UUID tableId) throws MageException; + boolean isTableOwner(String sessionId, UUID roomId, UUID tableId) throws MageException; + TableView getTable(UUID roomId, UUID tableId) throws MageException; + List getTables(UUID roomId) throws MageException; //chat methods void sendChatMessage(UUID chatId, String userName, String message) throws MageException; + void joinChat(UUID chatId, String sessionId, String userName) throws MageException; + void leaveChat(UUID chatId, String sessionId) throws MageException; + UUID getTableChatId(UUID tableId) throws MageException; + UUID getGameChatId(UUID gameId) throws MageException; + UUID getRoomChatId(UUID roomId) throws MageException; + UUID getTournamentChatId(UUID tournamentId) throws MageException; //room methods @@ -109,50 +133,77 @@ public interface MageServer { //game methods boolean startMatch(String sessionId, UUID roomId, UUID tableId) throws MageException; + void joinGame(UUID gameId, String sessionId) throws MageException; + void watchGame(UUID gameId, String sessionId) throws MageException; + void stopWatching(UUID gameId, String sessionId) throws MageException; + void sendPlayerUUID(UUID gameId, String sessionId, UUID data) throws MageException; + void sendPlayerString(UUID gameId, String sessionId, String data) throws MageException; + void sendPlayerBoolean(UUID gameId, String sessionId, Boolean data) throws MageException; + void sendPlayerInteger(UUID gameId, String sessionId, Integer data) throws MageException; + void sendPlayerManaType(UUID gameId, UUID playerId, String sessionId, ManaType data) throws MageException; + void quitMatch(UUID gameId, String sessionId) throws MageException; + GameView getGameView(UUID gameId, String sessionId, UUID playerId) throws MageException; + // priority, undo, concede, mana pool + void sendPlayerAction(PlayerAction playerAction, UUID gameId, String sessionId, Object data) throws MageException; //tournament methods boolean startTournament(String sessionId, UUID roomId, UUID tableId) throws MageException; + void joinTournament(UUID draftId, String sessionId) throws MageException; + void quitTournament(UUID tournamentId, String sessionId) throws MageException; + TournamentView getTournament(UUID tournamentId) throws MageException; //draft methods void joinDraft(UUID draftId, String sessionId) throws MageException; + void quitDraft(UUID draftId, String sessionId) throws MageException; + DraftPickView sendCardPick(UUID draftId, String sessionId, UUID cardId, Set hiddenCards) throws MageException; + void sendCardMark(UUID draftId, String sessionId, UUID cardId) throws MageException; //challenge methods // void startChallenge(String sessionId, UUID roomId, UUID tableId, UUID challengeId) throws MageException; - //replay methods void replayGame(UUID gameId, String sessionId) throws MageException; + void startReplay(UUID gameId, String sessionId) throws MageException; + void stopReplay(UUID gameId, String sessionId) throws MageException; + void nextPlay(UUID gameId, String sessionId) throws MageException; + void previousPlay(UUID gameId, String sessionId) throws MageException; + void skipForward(UUID gameId, String sessionId, int moves) throws MageException; //test methods void cheat(UUID gameId, String sessionId, UUID playerId, DeckCardLists deckList) throws MageException; + boolean cheat(UUID gameId, String sessionId, UUID playerId, String cardName) throws MageException; //admin methods List getUsers(String sessionId) throws MageException; + void disconnectUser(String sessionId, String userSessionId) throws MageException; + void endUserSession(String sessionId, String userSessionId) throws MageException; + void removeTable(String sessionId, UUID tableId) throws MageException; + void sendBroadcastMessage(String sessionId, String message) throws MageException; } diff --git a/Mage.Common/src/mage/remote/Connection.java b/Mage.Common/src/mage/remote/Connection.java index e8337feacde..0c4e86c827f 100644 --- a/Mage.Common/src/mage/remote/Connection.java +++ b/Mage.Common/src/mage/remote/Connection.java @@ -1,31 +1,30 @@ /* -* Copyright 2011 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. -*/ - + * Copyright 2011 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.remote; import java.net.Inet4Address; @@ -34,8 +33,7 @@ import java.net.InterfaceAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.util.Enumeration; -import mage.players.net.UserSkipPrioritySteps; -import mage.view.UserDataView; +import mage.players.net.UserData; /** * @@ -55,37 +53,36 @@ public class Connection { private int clientCardDatabaseVersion; private boolean forceDBComparison; - private UserDataView userData; - + private UserData userData; + // private int avatarId; // private boolean showAbilityPickerForced; // private boolean allowRequestShowHandCards; // private boolean confirmEmptyManaPool; // private String flagName; // private UserSkipPrioritySteps userSkipPrioritySteps; - - private static final String serialization = "?serializationtype=jboss"; + private static final String serialization = "?serializationtype=jboss"; private static final String transport = "bisocket"; - private final String parameter; - + private final String parameter; + public Connection() { this(""); } - + public Connection(String parameter) { this.parameter = parameter; } - + @Override public int hashCode() { - return (transport + host + Integer.toString(port) + proxyType.toString()).hashCode(); + return (transport + host + Integer.toString(port) + proxyType.toString()).hashCode(); } @Override public boolean equals(Object object) { - if (! (object instanceof Connection)) { - return false; + if (!(object instanceof Connection)) { + return false; } Connection otherConnection = (Connection) object; return hashCode() == otherConnection.hashCode(); @@ -119,6 +116,7 @@ public class Connection { } public enum ProxyType { + SOCKS("Socks"), HTTP("HTTP"), NONE("None"); private final String text; @@ -207,12 +205,12 @@ public class Connection { } public static InetAddress getLocalAddress() throws SocketException { - for (Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); interfaces.hasMoreElements(); ) { - NetworkInterface iface = interfaces.nextElement( ); + for (Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); interfaces.hasMoreElements();) { + NetworkInterface iface = interfaces.nextElement(); if (iface.isLoopback()) { continue; } - for (InterfaceAddress addr: iface.getInterfaceAddresses()) { + for (InterfaceAddress addr : iface.getInterfaceAddresses()) { if (addr != null) { InetAddress iaddr = addr.getAddress(); if (iaddr != null && iaddr instanceof Inet4Address) { @@ -224,11 +222,11 @@ public class Connection { return null; } - public void setUserData(UserDataView userData) { - this.userData= userData; + public void setUserData(UserData userData) { + this.userData = userData; } - - public UserDataView getUserData() { + + public UserData getUserData() { return userData; } diff --git a/Mage.Common/src/mage/remote/SessionImpl.java b/Mage.Common/src/mage/remote/SessionImpl.java index a5bf686b3bc..8017868ba74 100644 --- a/Mage.Common/src/mage/remote/SessionImpl.java +++ b/Mage.Common/src/mage/remote/SessionImpl.java @@ -1,31 +1,30 @@ /* -* 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. -*/ - + * 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.remote; import java.io.IOException; @@ -61,8 +60,8 @@ import mage.interfaces.MageClient; import mage.interfaces.MageServer; import mage.interfaces.ServerState; import mage.interfaces.callback.ClientCallback; +import mage.players.net.UserData; import mage.utils.CompressUtil; -import mage.players.net.UserSkipPrioritySteps; import mage.view.DraftPickView; import mage.view.GameTypeView; import mage.view.MatchView; @@ -70,7 +69,6 @@ import mage.view.RoomUsersView; import mage.view.TableView; import mage.view.TournamentTypeView; import mage.view.TournamentView; -import mage.view.UserDataView; import mage.view.UserView; import org.apache.log4j.Logger; import org.jboss.remoting.CannotConnectException; @@ -106,7 +104,7 @@ public class SessionImpl implements Session { private Connection connection; private final static int PING_CYCLES = 10; private final LinkedList pingTime = new LinkedList<>(); - private String pingInfo = ""; + private String pingInfo = ""; private static boolean debugMode = false; private boolean canceled = false; @@ -123,7 +121,7 @@ public class SessionImpl implements Session { public String getSessionId() { return sessionId; } - + @Override public synchronized boolean connect(Connection connection) { if (isConnected()) { @@ -165,82 +163,88 @@ public class SessionImpl implements Session { break; } InvokerLocator clientLocator = new InvokerLocator(connection.getURI()); - + Map metadata = new HashMap<>(); /* - 5.8.3.1.1. Write timeouts - The socket timeout facility offered by the JDK applies only to read operations on the socket. As of release 2.5.2, - the socket and bisocket (and also sslsocket and sslbisocket) transports offer a write timeout facility. When a client - or server is configured, in any of the usual ways, with the parameter org.jboss.remoting.transport.socket.SocketWrapper.WRITE_TIMEOUT - (actual value "writeTimeout") set to a positive value (in milliseconds), all write operations will time out if they do - not complete within the configured period. When a write operation times out, the socket upon which the write was invoked - will be closed, which is likely to result in a java.net.SocketException. - Note. A SocketException is considered to be a "retriable" exception, so, if the parameter "numberOfCallRetries" is set - to a value greater than 1, an invocation interrupted by a write timeout can be retried. - Note. The write timeout facility applies to writing of both invocations and responses. It applies to push callbacks as well. - */ + 5.8.3.1.1. Write timeouts + The socket timeout facility offered by the JDK applies only to read operations on the socket. As of release 2.5.2, + the socket and bisocket (and also sslsocket and sslbisocket) transports offer a write timeout facility. When a client + or server is configured, in any of the usual ways, with the parameter org.jboss.remoting.transport.socket.SocketWrapper.WRITE_TIMEOUT + (actual value "writeTimeout") set to a positive value (in milliseconds), all write operations will time out if they do + not complete within the configured period. When a write operation times out, the socket upon which the write was invoked + will be closed, which is likely to result in a java.net.SocketException. + Note. A SocketException is considered to be a "retriable" exception, so, if the parameter "numberOfCallRetries" is set + to a value greater than 1, an invocation interrupted by a write timeout can be retried. + Note. The write timeout facility applies to writing of both invocations and responses. It applies to push callbacks as well. + */ metadata.put(SocketWrapper.WRITE_TIMEOUT, "2000"); metadata.put("generalizeSocketException", "true"); server = (MageServer) TransporterClient.createTransporterClient(clientLocator.getLocatorURI(), MageServer.class, metadata); // http://docs.jboss.org/jbossremoting/docs/guide/2.5/html_single/#d0e1057 Map clientMetadata = new HashMap<>(); - + clientMetadata.put(SocketWrapper.WRITE_TIMEOUT, "2000"); - /* generalizeSocketException - * If set to false, a failed invocation will be retried in the case of - * SocketExceptions. If set to true, a failed invocation will be retried in the case of - * SocketExceptions and also any IOException - * whose message matches the regular expression - * ^.*(?:connection.*reset|connection.*closed|broken.*pipe).*$. - * See also the "numberOfCallRetries" parameter, above. The default value is false.*/ + /* generalizeSocketException + * If set to false, a failed invocation will be retried in the case of + * SocketExceptions. If set to true, a failed invocation will be retried in the case of + * SocketExceptions and also any IOException + * whose message matches the regular expression + * ^.*(?:connection.*reset|connection.*closed|broken.*pipe).*$. + * See also the "numberOfCallRetries" parameter, above. The default value is false.*/ clientMetadata.put("generalizeSocketException", "true"); - - /* A remoting server also has the capability to detect when a client is no longer available. - * This is done by estabilishing a lease with the remoting clients that connect to a server. - * On the client side, an org.jboss.remoting.LeasePinger periodically sends PING messages to - * the server, and on the server side an org.jboss.remoting.Lease informs registered listeners - * if the PING doesn't arrive withing the specified timeout period. */ + + /* A remoting server also has the capability to detect when a client is no longer available. + * This is done by estabilishing a lease with the remoting clients that connect to a server. + * On the client side, an org.jboss.remoting.LeasePinger periodically sends PING messages to + * the server, and on the server side an org.jboss.remoting.Lease informs registered listeners + * if the PING doesn't arrive withing the specified timeout period. */ clientMetadata.put(Client.ENABLE_LEASE, "true"); /* - When the socket client invoker makes its first invocation, it will check to see if there is an available - socket connection in its pool. Since is the first invocation, there will not be and will create a new socket - connection and use it for making the invocation. Then when finished making invocation, will return the still - active socket connection to the pool. As more client invocations are made, is possible for the number of - socket connections to reach the maximum allowed (which is controlled by 'clientMaxPoolSize' property). At this - point, when the next client invocation is made, it will wait up to some configured number of milliseconds, at - which point it will throw an org.jboss.remoting.CannotConnectException. The number of milliseconds is given by - the parameter MicroSocketClientInvoker.CONNECTION_WAIT (actual value "connectionWait"), with a default of - 30000 milliseconds. Note that if more than one call retry is configured (see next paragraph), - the CannotConnectException will be swallowed. - Once the socket client invoker get an available socket connection from the pool, are not out of the woods yet. - For example, a network problem could cause a java.net.SocketException. There is also a possibility that the socket - connection, while still appearing to be valid, has "gone stale" while sitting in the pool. For example, a ServerThread - on the other side of the connection could time out and close its socket. If the attempt to complete an invocation - fails, then MicroSocketClientInvoker will make a number of attempts, according to the parameter "numberOfCallRetries", - with a default value of 3. Once the configured number of retries has been exhausted, - an org.jboss.remoting.InvocationFailureException will be thrown. - */ + When the socket client invoker makes its first invocation, it will check to see if there is an available + socket connection in its pool. Since is the first invocation, there will not be and will create a new socket + connection and use it for making the invocation. Then when finished making invocation, will return the still + active socket connection to the pool. As more client invocations are made, is possible for the number of + socket connections to reach the maximum allowed (which is controlled by 'clientMaxPoolSize' property). At this + point, when the next client invocation is made, it will wait up to some configured number of milliseconds, at + which point it will throw an org.jboss.remoting.CannotConnectException. The number of milliseconds is given by + the parameter MicroSocketClientInvoker.CONNECTION_WAIT (actual value "connectionWait"), with a default of + 30000 milliseconds. Note that if more than one call retry is configured (see next paragraph), + the CannotConnectException will be swallowed. + Once the socket client invoker get an available socket connection from the pool, are not out of the woods yet. + For example, a network problem could cause a java.net.SocketException. There is also a possibility that the socket + connection, while still appearing to be valid, has "gone stale" while sitting in the pool. For example, a ServerThread + on the other side of the connection could time out and close its socket. If the attempt to complete an invocation + fails, then MicroSocketClientInvoker will make a number of attempts, according to the parameter "numberOfCallRetries", + with a default value of 3. Once the configured number of retries has been exhausted, + an org.jboss.remoting.InvocationFailureException will be thrown. + */ clientMetadata.put("numberOfCallRetries", "1"); - /** - * I'll explain the meaning of "secondaryBindPort" and "secondaryConnectPort", and maybe that will help. - * The Remoting bisocket transport creates two ServerSockets on the server. The "primary" ServerSocket is used to create - * connections used for ordinary invocations, e.g., a request to create a JMS consumer, and the "secondary" ServerSocket - * is used to create "control" connections for internal Remoting messages. The port for the primary ServerSocket is configured - * by the "serverBindPort" parameter, and the port for the secondary ServerSocket is, by default, chosen randomly. - * The "secondaryBindPort" parameter can be used to assign a specific port to the secondary ServerSocket. Now, if there is a - * translating firewall between the client and server, the client should be given the value of the port that is translated - * to the actual binding port of the secondary ServerSocket. - * For example, your configuration will tell the secondary ServerSocket to bind to port 14000, and it will tell the client to - * connect to port 14001. It assumes that there is a firewall which will translate 14001 to 14000. Apparently, that's not happening. + * I'll explain the meaning of "secondaryBindPort" and + * "secondaryConnectPort", and maybe that will help. The Remoting + * bisocket transport creates two ServerSockets on the server. The + * "primary" ServerSocket is used to create connections used for + * ordinary invocations, e.g., a request to create a JMS consumer, + * and the "secondary" ServerSocket is used to create "control" + * connections for internal Remoting messages. The port for the + * primary ServerSocket is configured by the "serverBindPort" + * parameter, and the port for the secondary ServerSocket is, by + * default, chosen randomly. The "secondaryBindPort" parameter can + * be used to assign a specific port to the secondary ServerSocket. + * Now, if there is a translating firewall between the client and + * server, the client should be given the value of the port that is + * translated to the actual binding port of the secondary + * ServerSocket. For example, your configuration will tell the + * secondary ServerSocket to bind to port 14000, and it will tell + * the client to connect to port 14001. It assumes that there is a + * firewall which will translate 14001 to 14000. Apparently, that's + * not happening. */ // secondaryBindPort - the port to which the secondary server socket is to be bound. By default, an arbitrary port is selected. - // secondaryConnectPort - the port clients are to use to connect to the secondary server socket. - // By default, the value of secondaryBindPort is used. secondaryConnectPort is useful if the server is behind a translating firewall. - + // By default, the value of secondaryBindPort is used. secondaryConnectPort is useful if the server is behind a translating firewall. // Indicated the max number of threads used within oneway thread pool. clientMetadata.put(Client.MAX_NUM_ONEWAY_THREADS, "10"); clientMetadata.put(Remoting.USE_CLIENT_CONNECTION_IDENTITY, "true"); @@ -269,7 +273,7 @@ public class SessionImpl implements Session { logger.warn("There should be one callback Connector (number existing = " + callbackConnectors.size() + ")"); } - logger.info("Trying to connect as " + (this.getUserName() == null ? "":this.getUserName()) + " to XMAGE server at " + connection.getHost() + ":" + connection.getPort()); + logger.info("Trying to connect as " + (this.getUserName() == null ? "" : this.getUserName()) + " to XMAGE server at " + connection.getHost() + ":" + connection.getPort()); callbackClient.invoke(null); this.sessionId = callbackClient.getSessionId(); @@ -289,15 +293,15 @@ public class SessionImpl implements Session { if (!connection.getUsername().equals("Admin")) { updateDatabase(connection.isForceDBComparison(), serverState); } - logger.info("Connected as " + (this.getUserName() == null ? "":this.getUserName()) + " to MAGE server at " + connection.getHost() + ":" + connection.getPort()); - client.connected(this.getUserName() == null ? "":this.getUserName() +"@" + connection.getHost() + ":" + connection.getPort() +" "); + logger.info("Connected as " + (this.getUserName() == null ? "" : this.getUserName()) + " to MAGE server at " + connection.getHost() + ":" + connection.getPort()); + client.connected(this.getUserName() == null ? "" : this.getUserName() + "@" + connection.getHost() + ":" + connection.getPort() + " "); return true; } disconnect(false); // client.showMessage("Unable to connect to server."); } catch (MalformedURLException ex) { logger.fatal("", ex); - client.showMessage("Unable to connect to server. " + ex.getMessage()); + client.showMessage("Unable to connect to server. " + ex.getMessage()); } catch (UndeclaredThrowableException ex) { String addMessage = ""; if (ex.getCause() instanceof InvocationFailureException) { @@ -311,17 +315,17 @@ public class SessionImpl implements Session { if (addMessage.isEmpty()) { logger.fatal("", ex); } - client.showMessage("Unable to connect to server. " + addMessage + (ex.getMessage() != null ? ex.getMessage():"")); + client.showMessage("Unable to connect to server. " + addMessage + (ex.getMessage() != null ? ex.getMessage() : "")); } catch (IOException ex) { logger.fatal("", ex); String addMessage = ""; if (ex.getMessage() != null && ex.getMessage().startsWith("Unable to perform invocation")) { addMessage = "Maybe the server version is not compatible. "; } - client.showMessage("Unable to connect to server. " + addMessage + ex.getMessage() != null ? ex.getMessage():""); + client.showMessage("Unable to connect to server. " + addMessage + ex.getMessage() != null ? ex.getMessage() : ""); } catch (MageVersionException ex) { if (!canceled) { - client.showMessage("Unable to connect to server. " + ex.getMessage()); + client.showMessage("Unable to connect to server. " + ex.getMessage()); } disconnect(false); } catch (CannotConnectException ex) { @@ -334,12 +338,12 @@ public class SessionImpl implements Session { disconnect(false); StringBuilder sb = new StringBuilder(); sb.append("Unable to connect to server.\n"); - for (StackTraceElement element :t.getStackTrace()) { + for (StackTraceElement element : t.getStackTrace()) { sb.append(element.toString()).append("\n"); } client.showMessage(sb.toString()); } - } + } return false; } @@ -350,8 +354,8 @@ public class SessionImpl implements Session { List cards = server.getMissingCardsData(classNames); CardRepository.instance.addCards(cards); CardRepository.instance.setContentVersion(serverState.getCardsContentVersion()); - logger.info("Updating client cards DB - existing cards: " + classNames.size() + " new cards: " + cards.size() + - " content versions - server: " + serverState.getCardsContentVersion() + " client: " + cardDBVersion); + logger.info("Updating client cards DB - existing cards: " + classNames.size() + " new cards: " + cards.size() + + " content versions - server: " + serverState.getCardsContentVersion() + " client: " + cardDBVersion); } long expansionDBVersion = ExpansionRepository.instance.getContentVersionFromDB(); @@ -362,8 +366,8 @@ public class SessionImpl implements Session { ExpansionRepository.instance.add(expansion); } ExpansionRepository.instance.setContentVersion(serverState.getExpansionsContentVersion()); - logger.info("Updating client expansions DB - existing sets: " + setCodes.size() + " new sets: " + expansions.size()+ - " content versions - server: " + serverState.getExpansionsContentVersion() + " client: " + expansionDBVersion); + logger.info("Updating client expansions DB - existing sets: " + setCodes.size() + " new sets: " + expansions.size() + + " content versions - server: " + serverState.getExpansionsContentVersion() + " client: " + expansionDBVersion); } } @@ -399,7 +403,8 @@ public class SessionImpl implements Session { /** * - * @param askForReconnect - true = connection was lost because of error and ask the user if he want to try to reconnect + * @param askForReconnect - true = connection was lost because of error and + * ask the user if he want to try to reconnect */ @Override public synchronized void disconnect(boolean askForReconnect) { @@ -410,7 +415,7 @@ public class SessionImpl implements Session { if (connection == null || sessionState == SessionState.DISCONNECTED) { return; } - + try { callbackClient.removeListener(callbackHandler); callbackClient.disconnect(); @@ -450,10 +455,11 @@ public class SessionImpl implements Session { } class CallbackHandler implements InvokerCallbackHandler { + @Override public void handleCallback(Callback callback) throws HandleCallbackException { //logger.info("callback handler"); - client.processCallback((ClientCallback)callback.getCallbackObject()); + client.processCallback((ClientCallback) callback.getCallbackObject()); } } @@ -502,7 +508,6 @@ public class SessionImpl implements Session { return serverState.getDraftCubes(); } - @Override public List getTournamentTypes() { return serverState.getTournamentTypes(); @@ -561,7 +566,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return null; } @@ -588,7 +593,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return false; } @@ -621,7 +626,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return false; } @@ -637,7 +642,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return false; } @@ -652,7 +657,7 @@ public class SessionImpl implements Session { handleMageException(ex); throw new MageRemoteException(); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return null; } @@ -667,7 +672,7 @@ public class SessionImpl implements Session { handleMageException(ex); throw new MageRemoteException(); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return null; } @@ -697,7 +702,7 @@ public class SessionImpl implements Session { handleMageException(ex); throw new MageRemoteException(); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return null; } @@ -711,7 +716,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return null; } @@ -726,7 +731,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return false; } @@ -741,7 +746,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return false; } @@ -756,7 +761,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return false; } @@ -771,7 +776,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return false; } @@ -800,7 +805,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return null; } @@ -829,7 +834,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return false; } @@ -845,7 +850,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); // } finally { // lock.readLock().unlock(); } @@ -863,7 +868,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); // } finally { // lock.readLock().unlock(); } @@ -895,7 +900,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return false; } @@ -910,7 +915,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return false; } @@ -925,7 +930,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return false; } @@ -940,7 +945,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return false; } @@ -955,7 +960,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return false; } @@ -969,7 +974,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return null; } @@ -983,7 +988,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return null; } @@ -997,7 +1002,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return false; } @@ -1013,13 +1018,14 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return false; } /** * Remove table - called from admin console + * * @param tableId * @return */ @@ -1033,7 +1039,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return false; } @@ -1048,7 +1054,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return false; } @@ -1062,7 +1068,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return false; } @@ -1088,7 +1094,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return false; } @@ -1107,7 +1113,6 @@ public class SessionImpl implements Session { // } // return false; // } - @Override public boolean submitDeck(UUID tableId, DeckCardLists deck) { try { @@ -1119,7 +1124,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return false; } @@ -1136,7 +1141,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return false; } @@ -1198,7 +1203,7 @@ public class SessionImpl implements Session { } return false; } - + @Override public boolean stopWatching(UUID gameId) { try { @@ -1209,7 +1214,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return false; } @@ -1224,7 +1229,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return false; } @@ -1239,7 +1244,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return false; } @@ -1254,7 +1259,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return false; } @@ -1269,7 +1274,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return false; } @@ -1284,7 +1289,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return false; } @@ -1299,7 +1304,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return false; } @@ -1313,7 +1318,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return null; } @@ -1342,7 +1347,7 @@ public class SessionImpl implements Session { } catch (MageException ex) { handleMageException(ex); } catch (Throwable t) { - handleThrowable(t); + handleThrowable(t); } return false; } @@ -1384,14 +1389,13 @@ public class SessionImpl implements Session { client.showError(ex.getMessage()); } - @Override public String getUserName() { return connection.getUsername(); } @Override - public boolean updatePreferencesForServer(UserDataView userData) { + public boolean updatePreferencesForServer(UserData userData) { try { if (isConnected()) { server.setUserData(connection.getUsername(), sessionId, userData); @@ -1411,26 +1415,26 @@ public class SessionImpl implements Session { if (isConnected()) { long startTime = System.nanoTime(); if (!server.ping(sessionId, pingInfo)) { - logger.error("Ping failed: " + this.getUserName() + " Session: " + sessionId + " to MAGE server at " + connection.getHost() +":" + connection.getPort()); + logger.error("Ping failed: " + this.getUserName() + " Session: " + sessionId + " to MAGE server at " + connection.getHost() + ":" + connection.getPort()); throw new MageException("Ping failed"); } pingTime.add(System.nanoTime() - startTime); long milliSeconds = TimeUnit.MILLISECONDS.convert(pingTime.getLast(), TimeUnit.NANOSECONDS); - String lastPing = milliSeconds > 0 ? milliSeconds+"ms" : "<1ms"; + String lastPing = milliSeconds > 0 ? milliSeconds + "ms" : "<1ms"; if (pingTime.size() > PING_CYCLES) { pingTime.poll(); } long sum = 0; - for (Long time :pingTime) { + for (Long time : pingTime) { sum += time; } milliSeconds = TimeUnit.MILLISECONDS.convert(sum / pingTime.size(), TimeUnit.NANOSECONDS); - pingInfo = lastPing + " (Av: " + (milliSeconds > 0 ? milliSeconds + "ms":"<1ms")+")"; + pingInfo = lastPing + " (Av: " + (milliSeconds > 0 ? milliSeconds + "ms" : "<1ms") + ")"; } return true; } catch (MageException ex) { - handleMageException(ex); - disconnect(true); + handleMageException(ex); + disconnect(true); } catch (Throwable t) { handleThrowable(t); } @@ -1448,7 +1452,6 @@ public class SessionImpl implements Session { } - class MageAuthenticator extends Authenticator { private final String username; @@ -1460,7 +1463,7 @@ class MageAuthenticator extends Authenticator { } @Override - public PasswordAuthentication getPasswordAuthentication () { - return new PasswordAuthentication (username, password.toCharArray()); + public PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password.toCharArray()); } } diff --git a/Mage.Common/src/mage/remote/interfaces/ClientData.java b/Mage.Common/src/mage/remote/interfaces/ClientData.java index 7b4f248d934..741b69b1b54 100644 --- a/Mage.Common/src/mage/remote/interfaces/ClientData.java +++ b/Mage.Common/src/mage/remote/interfaces/ClientData.java @@ -1,33 +1,33 @@ /* -* 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. -*/ + * 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.remote.interfaces; -import mage.view.UserDataView; +import mage.players.net.UserData; /** * @author noxx @@ -36,5 +36,5 @@ public interface ClientData { String getUserName(); - boolean updatePreferencesForServer(UserDataView userData); + boolean updatePreferencesForServer(UserData userData); } diff --git a/Mage.Common/src/mage/view/PlayerView.java b/Mage.Common/src/mage/view/PlayerView.java index 487e84afd26..14c3990eb38 100644 --- a/Mage.Common/src/mage/view/PlayerView.java +++ b/Mage.Common/src/mage/view/PlayerView.java @@ -1,31 +1,30 @@ /* -* 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. -*/ - + * 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.view; import java.io.Serializable; @@ -44,12 +43,14 @@ import mage.game.command.Commander; import mage.game.command.Emblem; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.players.net.UserData; /** * * @author BetaSteward_at_googlemail.com */ public class PlayerView implements Serializable { + private static final long serialVersionUID = 1L; private final UUID playerId; @@ -67,7 +68,7 @@ public class PlayerView implements Serializable { private final CardsView exile = new CardsView(); private final Map battlefield = new LinkedHashMap<>(); private final CardView topCard; - private final UserDataView userDataView; + private final UserData userData; private final List commandList = new ArrayList<>(); private final List attachments = new ArrayList<>(); private final int statesSavedSize; @@ -89,50 +90,49 @@ public class PlayerView implements Serializable { this.isActive = (player.getId().equals(state.getActivePlayerId())); this.hasPriority = player.getId().equals(state.getPriorityPlayerId()); this.priorityTimeLeft = player.getPriorityTimeLeft(); - this.timerActive = (this.hasPriority && player.isGameUnderControl()) || - (player.getPlayersUnderYourControl().contains(state.getPriorityPlayerId())) || - player.getId().equals(game.getState().getChoosingPlayerId()); + this.timerActive = (this.hasPriority && player.isGameUnderControl()) + || (player.getPlayersUnderYourControl().contains(state.getPriorityPlayerId())) + || player.getId().equals(game.getState().getChoosingPlayerId()); this.hasLeft = player.hasLeft(); - for (Card card: player.getGraveyard().getCards(game)) { + for (Card card : player.getGraveyard().getCards(game)) { graveyard.put(card.getId(), new CardView(card, game, false)); } for (ExileZone exileZone : game.getExile().getExileZones()) { for (Card card : exileZone.getCards(game)) { if (player.getId().equals(card.getOwnerId())) { exile.put(card.getId(), new CardView(card, game, false)); // unnown if it's allowed to look under a face down card - } + } } } - for (Permanent permanent: state.getBattlefield().getAllPermanents()) { + for (Permanent permanent : state.getBattlefield().getAllPermanents()) { if (showInBattlefield(permanent, state)) { PermanentView view = new PermanentView(permanent, game.getCard(permanent.getId()), createdForPlayerId, game); battlefield.put(view.getId(), view); } } - this.topCard = player.isTopCardRevealed() && player.getLibrary().size() > 0 ? - new CardView(player.getLibrary().getFromTop(game)) : null; + this.topCard = player.isTopCardRevealed() && player.getLibrary().size() > 0 + ? new CardView(player.getLibrary().getFromTop(game)) : null; if (player.getUserData() != null) { - this.userDataView = new UserDataView(player.getUserData()); + this.userData = player.getUserData(); } else { - this.userDataView = UserDataView.getDefaultUserDataView(); + this.userData = UserData.getDefaultUserDataView(); } - + for (CommandObject commandObject : game.getState().getCommand()) { if (commandObject instanceof Emblem) { Emblem emblem = (Emblem) commandObject; if (emblem.getControllerId().equals(this.playerId)) { - Card sourceCard = game.getCard(((CommandObject)emblem).getSourceId()); + Card sourceCard = game.getCard(((CommandObject) emblem).getSourceId()); if (sourceCard != null) { commandList.add(new EmblemView(emblem, sourceCard)); } } - } - else if(commandObject instanceof Commander){ - Commander commander = (Commander)commandObject; - if(commander.getControllerId().equals(this.playerId)){ + } else if (commandObject instanceof Commander) { + Commander commander = (Commander) commandObject; + if (commander.getControllerId().equals(this.playerId)) { Card sourceCard = game.getCard(commander.getSourceId()); - if(sourceCard != null){ + if (sourceCard != null) { commandList.add(new CommanderView(commander, sourceCard, game)); } } @@ -157,13 +157,11 @@ public class PlayerView implements Serializable { //show permanents controlled by player or attachments to permanents controlled by player if (permanent.getAttachedTo() == null) { return permanent.getControllerId().equals(playerId); - } - else { + } else { Permanent attachedTo = state.getPermanent(permanent.getAttachedTo()); if (attachedTo != null) { return attachedTo.getControllerId().equals(playerId); - } - else { + } else { return permanent.getControllerId().equals(playerId); } } @@ -221,8 +219,8 @@ public class PlayerView implements Serializable { return this.topCard; } - public UserDataView getUserData() { - return this.userDataView; + public UserData getUserData() { + return this.userData; } public List getCommadObjectList() { diff --git a/Mage.Common/src/mage/view/SeatView.java b/Mage.Common/src/mage/view/SeatView.java index 7a9f2badf12..f8f79a397e2 100644 --- a/Mage.Common/src/mage/view/SeatView.java +++ b/Mage.Common/src/mage/view/SeatView.java @@ -1,31 +1,30 @@ /* -* 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. -*/ - + * 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.view; import java.io.Serializable; @@ -37,16 +36,23 @@ import mage.game.Seat; * @author BetaSteward_at_googlemail.com */ public class SeatView implements Serializable { + private static final long serialVersionUID = 1L; + private final String flagName; private UUID playerId; - private String playerName; - private String playerType; + private final String playerName; + private final String playerType; public SeatView(Seat seat) { if (seat.getPlayer() != null) { this.playerId = seat.getPlayer().getId(); this.playerName = seat.getPlayer().getName(); + this.flagName = seat.getPlayer().getUserData().getFlagName(); + } else { + // Empty seat + this.playerName = ""; + this.flagName = ""; } this.playerType = seat.getPlayerType(); } @@ -63,4 +69,8 @@ public class SeatView implements Serializable { return playerType; } + public String getFlagName() { + return flagName; + } + } diff --git a/Mage.Common/src/mage/view/TournamentPlayerView.java b/Mage.Common/src/mage/view/TournamentPlayerView.java index 8a1bcc22954..2c488cd6921 100644 --- a/Mage.Common/src/mage/view/TournamentPlayerView.java +++ b/Mage.Common/src/mage/view/TournamentPlayerView.java @@ -1,16 +1,16 @@ /* * Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,12 +20,11 @@ * 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.view; import java.io.Serializable; @@ -35,9 +34,11 @@ import mage.game.tournament.TournamentPlayer; * * @author BetaSteward_at_googlemail.com */ -public class TournamentPlayerView implements Serializable, Comparable{ +public class TournamentPlayerView implements Serializable, Comparable { + private static final long serialVersionUID = 1L; + private final String flagName; private final String name; private final String state; private final String results; @@ -46,7 +47,7 @@ public class TournamentPlayerView implements Serializable, Comparable{ TournamentPlayerView(TournamentPlayer tournamentPlayer) { this.name = tournamentPlayer.getPlayer().getName(); - StringBuilder sb = new StringBuilder(tournamentPlayer.getState().toString()); + StringBuilder sb = new StringBuilder(tournamentPlayer.getState().toString()); String stateInfo = tournamentPlayer.getStateInfo(); if (!stateInfo.isEmpty()) { sb.append(" (").append(stateInfo).append(")"); @@ -56,6 +57,7 @@ public class TournamentPlayerView implements Serializable, Comparable{ this.points = tournamentPlayer.getPoints(); this.results = tournamentPlayer.getResults(); this.quit = !tournamentPlayer.isInTournament(); + this.flagName = tournamentPlayer.getPlayer().getUserData().getFlagName(); } public String getName() { @@ -83,4 +85,7 @@ public class TournamentPlayerView implements Serializable, Comparable{ return ((TournamentPlayerView) t).getPoints() - this.getPoints(); } + public String getFlagName() { + return flagName; + } } diff --git a/Mage.Common/src/mage/view/UserDataView.java b/Mage.Common/src/mage/view/UserDataView.java index 40171cbe315..cc313936a9e 100644 --- a/Mage.Common/src/mage/view/UserDataView.java +++ b/Mage.Common/src/mage/view/UserDataView.java @@ -2,6 +2,7 @@ package mage.view; import java.io.Serializable; import mage.players.net.UserData; +import mage.players.net.UserGroup; import mage.players.net.UserSkipPrioritySteps; /** @@ -20,11 +21,11 @@ public class UserDataView implements Serializable { String flagName; protected boolean askMoveToGraveOrder; - static UserDataView getDefaultUserDataView() { - return new UserDataView(0, false, false, true, null,"world.png", false); + static UserData getDefaultUserDataView() { + return new UserData(UserGroup.DEFAULT, 0, false, false, true, null, "world.png", false); } - - public UserDataView(int avatarId, boolean showAbilityPickerForced, boolean allowRequestShowHandCards, + + public UserDataView(int avatarId, boolean showAbilityPickerForced, boolean allowRequestShowHandCards, boolean confirmEmptyManaPool, UserSkipPrioritySteps userSkipPrioritySteps, String flagName, boolean askMoveToGraveOrder) { this.avatarId = avatarId; this.showAbilityPickerForced = showAbilityPickerForced; @@ -33,7 +34,7 @@ public class UserDataView implements Serializable { this.confirmEmptyManaPool = confirmEmptyManaPool; this.flagName = flagName; this.askMoveToGraveOrder = askMoveToGraveOrder; - + } public UserDataView(UserData userData) { @@ -74,5 +75,5 @@ public class UserDataView implements Serializable { public boolean askMoveToGraveOrder() { return askMoveToGraveOrder; } - + } diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java index 0f7fe7b3832..c6ba9cec919 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java @@ -1,31 +1,30 @@ /* -* 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. -*/ - + * 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.player.ai; import java.io.IOException; @@ -150,7 +149,6 @@ import mage.util.Copier; import mage.util.TreeNode; import org.apache.log4j.Logger; - /** * * suitable for two player games and some multiplayer games @@ -160,10 +158,10 @@ import org.apache.log4j.Logger; public class ComputerPlayer extends PlayerImpl implements Player { private transient final static Logger log = Logger.getLogger(ComputerPlayer.class); - + protected int PASSIVITY_PENALTY = 5; // Penalty value for doing nothing if some actions are availble - protected boolean ALLOW_INTERRUPT = true; // change this for test purposes to switch off interrupts while debugging - + protected boolean ALLOW_INTERRUPT = true; // change this for test purposes to switch off interrupts while debugging + private transient Map unplayable = new TreeMap<>(); private transient List playableNonInstant = new ArrayList<>(); private transient List playableInstant = new ArrayList<>(); @@ -172,8 +170,10 @@ public class ComputerPlayer extends PlayerImpl implements Player { private transient List chosenColors; private transient ManaCost currentUnpaidMana; + public ComputerPlayer(String name, RangeOfInfluence range) { super(name, range); + flagName = "computer"; human = false; userData = new UserData(UserGroup.COMPUTER, 64, false, true, false, null, "Computer.png", false); pickedCards = new ArrayList<>(); @@ -212,7 +212,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { UUID abilityControllerId = playerId; if (target.getTargetController() != null && target.getAbilityController() != null) { abilityControllerId = target.getAbilityController(); - } + } UUID opponentId = game.getOpponents(abilityControllerId).iterator().next(); if (target instanceof TargetPlayer) { if (outcome.isGood()) { @@ -293,7 +293,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { targets = threats(abilityControllerId, sourceId, ((TargetPermanent) target).getFilter(), game, target.getTargets()); } else { targets = threats(opponentId, sourceId, ((TargetPermanent) target).getFilter(), game, target.getTargets()); - } + } } } for (Permanent permanent : targets) { @@ -306,13 +306,13 @@ public class ComputerPlayer extends PlayerImpl implements Player { } if (target instanceof TargetCardInHand) { List cards = new ArrayList<>(); - for (UUID cardId: ((TargetCardInHand)target).possibleTargets(sourceId, this.getId(), game)) { + for (UUID cardId : ((TargetCardInHand) target).possibleTargets(sourceId, this.getId(), game)) { Card card = game.getCard(cardId); if (card != null) { cards.add(card); } - } - while((outcome.isGood() ? target.getTargets().size() < target.getMaxNumberOfTargets() : !target.isChosen()) + } + while ((outcome.isGood() ? target.getTargets().size() < target.getMaxNumberOfTargets() : !target.isChosen()) && !cards.isEmpty()) { Card pick = pickTarget(cards, outcome, target, null, game); if (pick != null) { @@ -391,7 +391,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { if (target.canTarget(opponentId, null, game)) { target.add(opponentId, game); return true; - } + } if (target.canTarget(abilityControllerId, null, game)) { target.add(abilityControllerId, game); return true; @@ -400,7 +400,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { targets = opponentTargets; } else { targets = ownedTargets; - } + } for (Permanent permanent : targets) { List alreadyTargetted = target.getTargets(); if (t.canTarget(permanent.getId(), game)) { @@ -409,19 +409,19 @@ public class ComputerPlayer extends PlayerImpl implements Player { return true; } } - } + } return false; } if (target instanceof TargetCardInGraveyard) { List cards = new ArrayList<>(); - for (Player player: game.getPlayers().values()) { - for (Card card: player.getGraveyard().getCards(game)) { + for (Player player : game.getPlayers().values()) { + for (Card card : player.getGraveyard().getCards(game)) { if (target.canTarget(card.getId(), game)) { cards.add(card); } } } - for (Card card: cards) { + for (Card card : cards) { target.add(card.getId(), game); if (target.isChosen()) { return true; @@ -433,7 +433,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { if (target instanceof TargetCardInYourGraveyard) { List alreadyTargetted = target.getTargets(); List cards = new ArrayList<>(game.getPlayer(abilityControllerId).getGraveyard().getCards(game)); - while(!cards.isEmpty()) { + while (!cards.isEmpty()) { Card card = pickTarget(cards, outcome, target, null, game); if (card != null && alreadyTargetted != null && !alreadyTargetted.contains(card.getId())) { target.add(card.getId(), game); @@ -476,7 +476,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { UUID abilityControllerId = playerId; if (target.getAbilityController() != null) { abilityControllerId = target.getAbilityController(); - } + } UUID opponentId = game.getOpponents(abilityControllerId).iterator().next(); if (target instanceof TargetPlayer) { if (outcome.isGood()) { @@ -490,8 +490,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { return true; } } - } - else { + } else { if (target.canTarget(abilityControllerId, opponentId, source, game)) { target.addTarget(opponentId, source, game); return true; @@ -520,8 +519,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } } } - } - else { + } else { findPlayables(game); if (unplayable.size() > 0) { for (int i = unplayable.size() - 1; i >= 0; i--) { @@ -548,12 +546,12 @@ public class ComputerPlayer extends PlayerImpl implements Player { } if (target instanceof TargetControlledPermanent) { List targets; - targets = threats(abilityControllerId, source.getSourceId(), ((TargetControlledPermanent)target).getFilter(), game, target.getTargets()); + targets = threats(abilityControllerId, source.getSourceId(), ((TargetControlledPermanent) target).getFilter(), game, target.getTargets()); if (!outcome.isGood()) { Collections.reverse(targets); } - for (Permanent permanent: targets) { - if (((TargetControlledPermanent)target).canTarget(abilityControllerId, permanent.getId(), source, game)) { + for (Permanent permanent : targets) { + if (((TargetControlledPermanent) target).canTarget(abilityControllerId, permanent.getId(), source, game)) { target.addTarget(permanent.getId(), source, game); if (target.getNumberOfTargets() <= target.getTargets().size() && (!outcome.isGood() || target.getMaxNumberOfTargets() <= target.getTargets().size())) { return true; @@ -567,19 +565,18 @@ public class ComputerPlayer extends PlayerImpl implements Player { List targets; boolean outcomeTargets = true; if (outcome.isGood()) { - targets = threats(abilityControllerId, source == null?null:source.getSourceId(), ((TargetPermanent)target).getFilter(), game, target.getTargets()); + targets = threats(abilityControllerId, source == null ? null : source.getSourceId(), ((TargetPermanent) target).getFilter(), game, target.getTargets()); + } else { + targets = threats(opponentId, source == null ? null : source.getSourceId(), ((TargetPermanent) target).getFilter(), game, target.getTargets()); } - else { - targets = threats(opponentId, source == null?null:source.getSourceId(), ((TargetPermanent)target).getFilter(), game, target.getTargets()); - } if (targets.isEmpty() && target.isRequired(source)) { - targets = threats(null, source == null?null:source.getSourceId(), ((TargetPermanent)target).getFilter(), game, target.getTargets()); + targets = threats(null, source == null ? null : source.getSourceId(), ((TargetPermanent) target).getFilter(), game, target.getTargets()); Collections.reverse(targets); outcomeTargets = false; //targets = game.getBattlefield().getActivePermanents(((TargetPermanent)target).getFilter(), playerId, game); } - for (Permanent permanent: targets) { - if (((TargetPermanent)target).canTarget(abilityControllerId, permanent.getId(), source, game)) { + for (Permanent permanent : targets) { + if (((TargetPermanent) target).canTarget(abilityControllerId, permanent.getId(), source, game)) { target.addTarget(permanent.getId(), source, game); if (!outcomeTargets || target.getMaxNumberOfTargets() <= target.getTargets().size()) { return true; @@ -590,12 +587,11 @@ public class ComputerPlayer extends PlayerImpl implements Player { } if (target instanceof TargetCreatureOrPlayer) { List targets; - TargetCreatureOrPlayer t = ((TargetCreatureOrPlayer)target); + TargetCreatureOrPlayer t = ((TargetCreatureOrPlayer) target); if (outcome.isGood()) { - targets = threats(abilityControllerId, source.getSourceId(), ((FilterCreatureOrPlayer)t.getFilter()).getCreatureFilter(), game, target.getTargets()); - } - else { - targets = threats(opponentId, source.getSourceId(), ((FilterCreatureOrPlayer)t.getFilter()).getCreatureFilter(), game, target.getTargets()); + targets = threats(abilityControllerId, source.getSourceId(), ((FilterCreatureOrPlayer) t.getFilter()).getCreatureFilter(), game, target.getTargets()); + } else { + targets = threats(opponentId, source.getSourceId(), ((FilterCreatureOrPlayer) t.getFilter()).getCreatureFilter(), game, target.getTargets()); } if (targets.isEmpty()) { @@ -604,8 +600,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { target.addTarget(abilityControllerId, source, game); return true; } - } - else { + } else { if (target.canTarget(getId(), opponentId, source, game)) { target.addTarget(opponentId, source, game); return true; @@ -614,7 +609,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } if (targets.isEmpty() && target.isRequired(source)) { - targets = game.getBattlefield().getActivePermanents(((FilterCreatureOrPlayer)t.getFilter()).getCreatureFilter(), playerId, game); + targets = game.getBattlefield().getActivePermanents(((FilterCreatureOrPlayer) t.getFilter()).getCreatureFilter(), playerId, game); } for (Permanent permanent : targets) { List alreadyTargetted = target.getTargets(); @@ -627,24 +622,23 @@ public class ComputerPlayer extends PlayerImpl implements Player { } if (outcome.isGood()) { - if (target.canTarget(getId(),abilityControllerId, source, game)) { + if (target.canTarget(getId(), abilityControllerId, source, game)) { target.addTarget(abilityControllerId, source, game); return true; } - } - else { - if (target.canTarget(getId(),opponentId, source, game)) { + } else { + if (target.canTarget(getId(), opponentId, source, game)) { target.addTarget(opponentId, source, game); return true; } } //if (!target.isRequired()) - return false; + return false; } if (target instanceof TargetCardInGraveyard) { List cards = new ArrayList<>(); - for (Player player: game.getPlayers().values()) { + for (Player player : game.getPlayers().values()) { cards.addAll(player.getGraveyard().getCards(game)); } Card card = pickTarget(cards, outcome, target, source, game); @@ -653,7 +647,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { return true; } //if (!target.isRequired()) - return false; + return false; } if (target instanceof TargetCardInLibrary) { List cards = new ArrayList<>(game.getPlayer(abilityControllerId).getLibrary().getCards(game)); @@ -666,7 +660,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } if (target instanceof TargetCardInYourGraveyard) { List cards = new ArrayList<>(game.getPlayer(abilityControllerId).getGraveyard().getCards(game)); - while(!target.isChosen() && !cards.isEmpty()) { + while (!target.isChosen() && !cards.isEmpty()) { Card card = pickTarget(cards, outcome, target, source, game); if (card != null) { target.addTarget(card.getId(), source, game); @@ -677,7 +671,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { if (target instanceof TargetCardInHand) { List cards = new ArrayList<>(); cards.addAll(this.hand.getCards(game)); - while(!target.isChosen() && !cards.isEmpty()) { + while (!target.isChosen() && !cards.isEmpty()) { Card pick = pickTarget(cards, outcome, target, source, game); if (pick != null) { target.addTarget(pick.getId(), source, game); @@ -697,36 +691,35 @@ public class ComputerPlayer extends PlayerImpl implements Player { } } return false; - } + } if (target instanceof TargetSpellOrPermanent) { List targets; boolean outcomeTargets = true; if (outcome.isGood()) { - targets = threats(abilityControllerId, source == null?null:source.getSourceId(), ((TargetSpellOrPermanent)target).getPermanentFilter(), game, target.getTargets()); + targets = threats(abilityControllerId, source == null ? null : source.getSourceId(), ((TargetSpellOrPermanent) target).getPermanentFilter(), game, target.getTargets()); + } else { + targets = threats(opponentId, source == null ? null : source.getSourceId(), ((TargetSpellOrPermanent) target).getPermanentFilter(), game, target.getTargets()); } - else { - targets = threats(opponentId, source == null?null:source.getSourceId(), ((TargetSpellOrPermanent)target).getPermanentFilter(), game, target.getTargets()); - } if (targets.isEmpty() && target.isRequired(source)) { - targets = threats(null, source == null?null:source.getSourceId(), ((TargetSpellOrPermanent)target).getPermanentFilter(), game, target.getTargets()); + targets = threats(null, source == null ? null : source.getSourceId(), ((TargetSpellOrPermanent) target).getPermanentFilter(), game, target.getTargets()); Collections.reverse(targets); outcomeTargets = false; //targets = game.getBattlefield().getActivePermanents(((TargetPermanent)target).getFilter(), playerId, game); } - for (Permanent permanent: targets) { - if (((TargetPermanent)target).canTarget(abilityControllerId, permanent.getId(), source, game)) { + for (Permanent permanent : targets) { + if (((TargetPermanent) target).canTarget(abilityControllerId, permanent.getId(), source, game)) { target.addTarget(permanent.getId(), source, game); if (!outcomeTargets || target.getMaxNumberOfTargets() <= target.getTargets().size()) { return true; } } - } + } if (game.getStack().size() > 0) { Iterator it = game.getStack().iterator(); while (it.hasNext()) { StackObject stackObject = it.next(); if (stackObject instanceof Spell && source != null && !source.getId().equals(stackObject.getStackAbility().getId())) { - if (((TargetSpellOrPermanent)target).getFilter().match(stackObject, game)) { + if (((TargetSpellOrPermanent) target).getFilter().match(stackObject, game)) { target.addTarget(stackObject.getId(), source, game); return true; } @@ -737,7 +730,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } if (target instanceof TargetCardInOpponentsGraveyard) { List cards = new ArrayList<>(); - for (UUID uuid: game.getOpponents(abilityControllerId)) { + for (UUID uuid : game.getOpponents(abilityControllerId)) { Player player = game.getPlayer(uuid); if (player != null) { cards.addAll(player.getGraveyard().getCards(game)); @@ -749,15 +742,15 @@ public class ComputerPlayer extends PlayerImpl implements Player { return true; } //if (!target.isRequired()) - return false; + return false; } if (target instanceof TargetDefender) { // TODO: Improve, now planeswalker is always chosen if it exits - List targets ; + List targets; targets = game.getBattlefield().getActivePermanents(new FilterPlaneswalkerPermanent(), opponentId, game); if (targets != null && !targets.isEmpty()) { - for (Permanent planeswalker: targets) { - if (target.canTarget(getId(),planeswalker.getId(), source, game)) { + for (Permanent planeswalker : targets) { + if (target.canTarget(getId(), planeswalker.getId(), source, game)) { target.addTarget(planeswalker.getId(), source, game); } if (target.isChosen()) { @@ -766,7 +759,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } } if (!target.isChosen()) { - if (target.canTarget(getId() ,opponentId, source, game)) { + if (target.canTarget(getId(), opponentId, source, game)) { target.addTarget(opponentId, source, game); } } @@ -775,10 +768,10 @@ public class ComputerPlayer extends PlayerImpl implements Player { if (target instanceof TargetCardInASingleGraveyard) { List cards = new ArrayList<>(); - for (Player player: game.getPlayers().values()) { + for (Player player : game.getPlayers().values()) { cards.addAll(player.getGraveyard().getCards(game)); } - while(!target.isChosen() && !cards.isEmpty()) { + while (!target.isChosen() && !cards.isEmpty()) { Card pick = pickTarget(cards, outcome, target, source, game); if (pick != null) { target.addTarget(pick.getId(), source, game); @@ -789,13 +782,13 @@ public class ComputerPlayer extends PlayerImpl implements Player { if (target instanceof TargetCardInExile) { List cards = new ArrayList<>(); - for (UUID uuid: ((TargetCardInExile) target).possibleTargets(source.getSourceId(), source.getControllerId(), game)) { + for (UUID uuid : ((TargetCardInExile) target).possibleTargets(source.getSourceId(), source.getControllerId(), game)) { Card card = game.getCard(uuid); if (card != null) { cards.add(card); } } - while(!target.isChosen() && !cards.isEmpty()) { + while (!target.isChosen() && !cards.isEmpty()) { Card pick = pickTarget(cards, outcome, target, source, game); if (pick != null) { target.addTarget(pick.getId(), source, game); @@ -804,7 +797,6 @@ public class ComputerPlayer extends PlayerImpl implements Player { return target.isChosen(); } - throw new IllegalStateException("Target wasn't handled. class:" + target.getClass().toString()); } @@ -813,16 +805,14 @@ public class ComputerPlayer extends PlayerImpl implements Player { while (!cards.isEmpty()) { if (outcome.isGood()) { card = pickBestCard(cards, null, target, source, game); - } - else { + } else { card = pickWorstCard(cards, null, target, source, game); } if (source != null) { if (target.canTarget(getId(), card.getId(), source, game)) { return card; } - } - else { + } else { return card; } cards.remove(card); @@ -844,12 +834,11 @@ public class ComputerPlayer extends PlayerImpl implements Player { List targets; if (outcome.isGood()) { targets = threats(playerId, source.getSourceId(), new FilterCreaturePermanent(), game, target.getTargets()); - } - else { + } else { targets = threats(opponentId, source.getSourceId(), new FilterCreaturePermanent(), game, target.getTargets()); } - for (Permanent permanent: targets) { - if (target.canTarget(getId() ,permanent.getId(), source, game)) { + for (Permanent permanent : targets) { + if (target.canTarget(getId(), permanent.getId(), source, game)) { if (permanent.getToughness().getValue() <= target.getAmountRemaining()) { target.addTarget(permanent.getId(), permanent.getToughness().getValue(), source, game); return true; @@ -859,7 +848,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { if (outcome.isGood() && target.canTarget(getId(), getId(), source, game)) { target.addTarget(opponentId, target.getAmountRemaining(), source, game); return true; - } else if (target.canTarget(getId(), opponentId, source, game)){ + } else if (target.canTarget(getId(), opponentId, source, game)) { // no permanent target so take opponent target.addTarget(opponentId, target.getAmountRemaining(), source, game); return true; @@ -896,7 +885,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { case PRECOMBAT_MAIN: findPlayables(game); if (playableAbilities.size() > 0) { - for (ActivatedAbility ability: playableAbilities) { + for (ActivatedAbility ability : playableAbilities) { if (ability.canActivate(playerId, game)) { if (ability.getEffects().hasOutcome(Outcome.PutLandInPlay)) { if (this.activateAbility(ability, game)) { @@ -927,7 +916,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { findPlayables(game); if (game.getStack().isEmpty()) { if (playableNonInstant.size() > 0) { - for (Card card: playableNonInstant) { + for (Card card : playableNonInstant) { if (card.getSpellAbility().canActivate(playerId, game)) { if (this.activateAbility(card.getSpellAbility(), game)) { return true; @@ -936,7 +925,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } } if (playableAbilities.size() > 0) { - for (ActivatedAbility ability: playableAbilities) { + for (ActivatedAbility ability : playableAbilities) { if (ability.canActivate(playerId, game)) { if (!(ability.getEffects().get(0) instanceof BecomesCreatureSourceEffect)) { if (this.activateAbility(ability, game)) { @@ -949,8 +938,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } break; } - } - else { + } else { //respond to opponent events switch (game.getTurn().getStepType()) { case UPKEEP: @@ -967,15 +955,15 @@ public class ComputerPlayer extends PlayerImpl implements Player { break; } } - pass(game); + pass(game); return true; } @Override public boolean activateAbility(ActivatedAbility ability, Game game) { if (!isTestMode()) { // Test player already sends target event as he selects the target - for (Target target: ability.getModes().getMode().getTargets()) { - for (UUID targetId: target.getTargets()) { + for (Target target : ability.getModes().getMode().getTargets()) { + for (UUID targetId : target.getTargets()) { game.fireEvent(GameEvent.getEvent(EventType.TARGETED, targetId, ability.getId(), ability.getControllerId())); } } @@ -986,7 +974,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { protected void playLand(Game game) { log.debug("playLand"); Set lands = new LinkedHashSet<>(); - for (Card landCard: hand.getCards(new FilterLandCard(), game)) { + for (Card landCard : hand.getCards(new FilterLandCard(), game)) { // remove lands that can not be played if (game.getContinuousEffects().preventedByRuleModification(GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, landCard.getId(), landCard.getId(), playerId), null, game, true)) { break; @@ -996,8 +984,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { while (lands.size() > 0 && this.canPlayLand()) { if (lands.size() == 1) { this.playLand(lands.iterator().next(), game); - } - else { + } else { playALand(lands, game); } } @@ -1006,10 +993,10 @@ public class ComputerPlayer extends PlayerImpl implements Player { protected void playALand(Set lands, Game game) { log.debug("playALand"); //play a land that will allow us to play an unplayable - for (Mana mana: unplayable.keySet()) { - for (Card card: lands) { - for (ManaAbility ability: card.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) { - for (Mana netMana: ability.getNetMana(game)) { + for (Mana mana : unplayable.keySet()) { + for (Card card : lands) { + for (ManaAbility ability : card.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) { + for (Mana netMana : ability.getNetMana(game)) { if (netMana.enough(mana)) { this.playLand(card, game); lands.remove(card); @@ -1020,10 +1007,10 @@ public class ComputerPlayer extends PlayerImpl implements Player { } } //play a land that will get us closer to playing an unplayable - for (Mana mana: unplayable.keySet()) { - for (Card card: lands) { - for (ManaAbility ability: card.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) { - for (Mana netMana: ability.getNetMana(game)) { + for (Mana mana : unplayable.keySet()) { + for (Card card : lands) { + for (ManaAbility ability : card.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) { + for (Mana netMana : ability.getNetMana(game)) { if (mana.contains(netMana)) { this.playLand(card, game); lands.remove(card); @@ -1047,30 +1034,28 @@ public class ComputerPlayer extends PlayerImpl implements Player { ManaOptions available = getManaAvailable(game); available.addMana(manaPool.getMana()); - for (Card card: nonLands) { + for (Card card : nonLands) { ManaOptions options = card.getManaCost().getOptions(); if (card.getManaCost().getVariableCosts().size() > 0) { //don't use variable mana costs unless there is at least 3 extra mana for X - for (Mana option: options) { + for (Mana option : options) { option.add(Mana.ColorlessMana(3)); } } - for (Mana mana: options) { - for (Mana avail: available) { + for (Mana mana : options) { + for (Mana avail : available) { if (mana.enough(avail)) { SpellAbility ability = card.getSpellAbility(); - if (ability != null && ability.canActivate(playerId, game) && - game.getContinuousEffects().preventedByRuleModification(GameEvent.getEvent(GameEvent.EventType.CAST_SPELL, ability.getSourceId(), ability.getSourceId(), playerId), ability, game, true)) { + if (ability != null && ability.canActivate(playerId, game) + && game.getContinuousEffects().preventedByRuleModification(GameEvent.getEvent(GameEvent.EventType.CAST_SPELL, ability.getSourceId(), ability.getSourceId(), playerId), ability, game, true)) { if (card.getCardType().contains(CardType.INSTANT) || card.hasAbility(FlashAbility.getInstance().getId(), game)) { playableInstant.add(card); - } - else { + } else { playableNonInstant.add(card); } } - } - else { + } else { if (!playableInstant.contains(card) && !playableNonInstant.contains(card)) { unplayable.put(mana.needed(avail), card); } @@ -1078,8 +1063,8 @@ public class ComputerPlayer extends PlayerImpl implements Player { } } } - for (Permanent permanent: game.getBattlefield().getAllActivePermanents(playerId)) { - for (ActivatedAbility ability: permanent.getAbilities().getActivatedAbilities(Zone.BATTLEFIELD)) { + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(playerId)) { + for (ActivatedAbility ability : permanent.getAbilities().getActivatedAbilities(Zone.BATTLEFIELD)) { if (!(ability instanceof ManaAbility) && ability.canActivate(playerId, game)) { if (ability instanceof EquipAbility && permanent.getAttachedTo() != null) { continue; @@ -1087,16 +1072,15 @@ public class ComputerPlayer extends PlayerImpl implements Player { ManaOptions abilityOptions = ability.getManaCosts().getOptions(); if (ability.getManaCosts().getVariableCosts().size() > 0) { //don't use variable mana costs unless there is at least 3 extra mana for X - for (Mana option: abilityOptions) { + for (Mana option : abilityOptions) { option.add(Mana.ColorlessMana(3)); } } if (abilityOptions.size() == 0) { playableAbilities.add(ability); - } - else { - for (Mana mana: abilityOptions) { - for (Mana avail: available) { + } else { + for (Mana mana : abilityOptions) { + for (Mana avail : available) { if (mana.enough(avail)) { playableAbilities.add(ability); } @@ -1106,16 +1090,15 @@ public class ComputerPlayer extends PlayerImpl implements Player { } } } - for (Card card: graveyard.getCards(game)) { - for (ActivatedAbility ability: card.getAbilities().getActivatedAbilities(Zone.GRAVEYARD)) { + for (Card card : graveyard.getCards(game)) { + for (ActivatedAbility ability : card.getAbilities().getActivatedAbilities(Zone.GRAVEYARD)) { if (ability.canActivate(playerId, game)) { ManaOptions abilityOptions = ability.getManaCosts().getOptions(); if (abilityOptions.size() == 0) { playableAbilities.add(ability); - } - else { - for (Mana mana: abilityOptions) { - for (Mana avail: available) { + } else { + for (Mana mana : abilityOptions) { + for (Mana avail : available) { if (mana.enough(avail)) { playableAbilities.add(ability); } @@ -1126,16 +1109,16 @@ public class ComputerPlayer extends PlayerImpl implements Player { } } if (log.isDebugEnabled()) { - log.debug("findPlayables: " + playableInstant.toString() + "---" + playableNonInstant.toString() + "---" + playableAbilities.toString() ); + log.debug("findPlayables: " + playableInstant.toString() + "---" + playableNonInstant.toString() + "---" + playableAbilities.toString()); } } - + @Override public boolean playMana(ManaCost unpaid, String promptText, Game game) { payManaMode = true; - currentUnpaidMana = unpaid; + currentUnpaidMana = unpaid; boolean result = playManaHandling(unpaid, game); - currentUnpaidMana = null; + currentUnpaidMana = null; payManaMode = false; return result; } @@ -1145,19 +1128,18 @@ public class ComputerPlayer extends PlayerImpl implements Player { ManaCost cost; List producers; if (unpaid instanceof ManaCosts) { - cost = ((ManaCosts)unpaid).get(0); - producers = getSortedProducers((ManaCosts)unpaid, game); - } - else { + cost = ((ManaCosts) unpaid).get(0); + producers = getSortedProducers((ManaCosts) unpaid, game); + } else { cost = unpaid; producers = this.getAvailableManaProducers(game); producers.addAll(this.getAvailableManaProducersWithCost(game)); } - for (Permanent perm: producers) { + for (Permanent perm : producers) { // pay all colored costs first - for (ManaAbility ability: perm.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game)) { + for (ManaAbility ability : perm.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game)) { if (cost instanceof ColoredManaCost) { - for (Mana netMana: ability.getNetMana(game)) { + for (Mana netMana : ability.getNetMana(game)) { if (cost.testPay(netMana)) { if (activateAbility(ability, game)) { return true; @@ -1167,9 +1149,9 @@ public class ComputerPlayer extends PlayerImpl implements Player { } } // then pay hybrid - for (ManaAbility ability: perm.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game)) { + for (ManaAbility ability : perm.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game)) { if (cost instanceof HybridManaCost) { - for (Mana netMana: ability.getNetMana(game)) { + for (Mana netMana : ability.getNetMana(game)) { if (cost.testPay(netMana)) { if (activateAbility(ability, game)) { return true; @@ -1179,9 +1161,9 @@ public class ComputerPlayer extends PlayerImpl implements Player { } } // then pay mono hybrid - for (ManaAbility ability: perm.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game)) { + for (ManaAbility ability : perm.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game)) { if (cost instanceof MonoHybridManaCost) { - for (Mana netMana: ability.getNetMana(game)) { + for (Mana netMana : ability.getNetMana(game)) { if (cost.testPay(netMana)) { if (activateAbility(ability, game)) { return true; @@ -1191,9 +1173,9 @@ public class ComputerPlayer extends PlayerImpl implements Player { } } // finally pay generic - for (ManaAbility ability: perm.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game)) { + for (ManaAbility ability : perm.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game)) { if (cost instanceof GenericManaCost) { - for (Mana netMana: ability.getNetMana(game)) { + for (Mana netMana : ability.getNetMana(game)) { if (cost.testPay(netMana)) { if (activateAbility(ability, game)) { return true; @@ -1214,11 +1196,13 @@ public class ComputerPlayer extends PlayerImpl implements Player { /** * - * returns a list of Permanents that produce mana sorted by the number of mana the Permanent produces - * that match the unpaid costs in ascending order + * returns a list of Permanents that produce mana sorted by the number of + * mana the Permanent produces that match the unpaid costs in ascending + * order * - * the idea is that we should pay costs first from mana producers that produce only one type of mana - * and save the multi-mana producers for those costs that can't be paid by any other producers + * the idea is that we should pay costs first from mana producers that + * produce only one type of mana and save the multi-mana producers for those + * costs that can't be paid by any other producers * * @param unpaid - the amount of unpaid mana costs * @param game @@ -1228,12 +1212,12 @@ public class ComputerPlayer extends PlayerImpl implements Player { List unsorted = this.getAvailableManaProducers(game); unsorted.addAll(this.getAvailableManaProducersWithCost(game)); Map scored = new HashMap<>(); - for (Permanent permanent: unsorted) { + for (Permanent permanent : unsorted) { int score = 0; - for (ManaCost cost: unpaid) { + for (ManaCost cost : unpaid) { Abilities: - for (ManaAbility ability: permanent.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game)) { - for (Mana netMana: ability.getNetMana(game)) { + for (ManaAbility ability : permanent.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game)) { + for (Mana netMana : ability.getNetMana(game)) { if (cost.testPay(netMana)) { score++; break Abilities; @@ -1245,10 +1229,9 @@ public class ComputerPlayer extends PlayerImpl implements Player { score += permanent.getAbilities().getAvailableManaAbilities(Zone.BATTLEFIELD, game).size(); score += permanent.getAbilities().getActivatedAbilities(Zone.BATTLEFIELD).size(); if (!permanent.getCardType().contains(CardType.LAND)) { - score+=2; - } - else if(permanent.getCardType().contains(CardType.CREATURE)) { - score+=2; + score += 2; + } else if (permanent.getCardType().contains(CardType.CREATURE)) { + score += 2; } } scored.put(permanent, score); @@ -1286,14 +1269,13 @@ public class ComputerPlayer extends PlayerImpl implements Player { public int announceXCost(int min, int max, String message, Game game, Ability ability, VariableCost variablCost) { log.debug("announceXMana"); //TODO: improve this - int value = new Random().nextInt(max+1); + int value = new Random().nextInt(max + 1); if (value < max) { value++; } return value; } - @Override public void abort() { abort = true; @@ -1304,7 +1286,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } @Override - public boolean chooseUse(Outcome outcome, String message, Game game) { + public boolean chooseUse(Outcome outcome, String message, Ability source, Game game) { log.debug("chooseUse: " + outcome.isGood()); // Be proactive! Always use abilities, the evaluation function will decide if it's good or not // Otherwise some abilities won't be used by AI like LoseTargetEffect that has "bad" outcome @@ -1320,7 +1302,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { chooseCreatureType(outcome, choice, game); } // choose the correct color to pay a spell - if(outcome.equals(Outcome.PutManaInPool) && choice instanceof ChoiceColor && currentUnpaidMana != null) { + if (outcome.equals(Outcome.PutManaInPool) && choice instanceof ChoiceColor && currentUnpaidMana != null) { if (currentUnpaidMana.containsColor(ColoredManaSymbol.W) && choice.getChoices().contains("White")) { choice.setChoice("White"); return true; @@ -1344,7 +1326,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } // choose by random if (!choice.isChosen()) { - int choiceIdx = (int) (Math.random()*choice.getChoices().size()+1); + int choiceIdx = (int) (Math.random() * choice.getChoices().size() + 1); for (String next : choice.getChoices()) { if (--choiceIdx > 0) { continue; @@ -1361,8 +1343,8 @@ public class ComputerPlayer extends PlayerImpl implements Player { protected boolean chooseCreatureType(Outcome outcome, Choice choice, Game game) { if (outcome.equals(Outcome.Detriment)) { // choose a creature type of opponent on battlefield or graveyard - for (Permanent permanent :game.getBattlefield().getActivePermanents(this.getId(), game)) { - if(game.getOpponents(this.getId()).contains(permanent.getControllerId()) + for (Permanent permanent : game.getBattlefield().getActivePermanents(this.getId(), game)) { + if (game.getOpponents(this.getId()).contains(permanent.getControllerId()) && permanent.getCardType().contains(CardType.CREATURE) && permanent.getSubtype().size() > 0) { if (choice.getChoices().contains(permanent.getSubtype().get(0))) { @@ -1373,7 +1355,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } // or in opponent graveyard if (!choice.isChosen()) { - for (UUID opponentId :game.getOpponents(this.getId())) { + for (UUID opponentId : game.getOpponents(this.getId())) { Player opponent = game.getPlayer(opponentId); for (Card card : opponent.getGraveyard().getCards(game)) { if (card != null && card.getCardType().contains(CardType.CREATURE) && card.getSubtype().size() > 0) { @@ -1390,7 +1372,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } } else { // choose a creature type of hand or library - for (UUID cardId :this.getHand()) { + for (UUID cardId : this.getHand()) { Card card = game.getCard(cardId); if (card != null && card.getCardType().contains(CardType.CREATURE) && card.getSubtype().size() > 0) { if (choice.getChoices().contains(card.getSubtype().get(0))) { @@ -1413,8 +1395,9 @@ public class ComputerPlayer extends PlayerImpl implements Player { } return choice.isChosen(); } + @Override - public boolean chooseTarget(Outcome outcome, Cards cards, TargetCard target, Ability source, Game game) { + public boolean chooseTarget(Outcome outcome, Cards cards, TargetCard target, Ability source, Game game) { log.debug("chooseTarget"); if (cards == null || cards.isEmpty()) { return target.isRequired(source); @@ -1438,7 +1421,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } @Override - public boolean choose(Outcome outcome, Cards cards, TargetCard target, Game game) { + public boolean choose(Outcome outcome, Cards cards, TargetCard target, Game game) { log.debug("choose 2"); if (cards == null || cards.isEmpty()) { return true; @@ -1476,19 +1459,17 @@ public class ComputerPlayer extends PlayerImpl implements Player { List actualAttackers = new ArrayList<>(); if (blockers.isEmpty()) { actualAttackers = attackers.getAttackers(); - } - else if (attackers.size() - blockers.size() >= game.getPlayer(opponentId).getLife()) { + } else if (attackers.size() - blockers.size() >= game.getPlayer(opponentId).getLife()) { actualAttackers = attackers.getAttackers(); - } - else { + } else { CombatSimulator combat = simulateAttack(attackers, blockers, opponentId, game); if (combat.rating > 2) { - for (CombatGroupSimulator group: combat.groups) { + for (CombatGroupSimulator group : combat.groups) { this.declareAttacker(group.attackers.get(0).id, group.defenderId, game, false); } } } - for (Permanent attacker: actualAttackers) { + for (Permanent attacker : actualAttackers) { this.declareAttacker(attacker.getId(), opponentId, game, false); } } @@ -1502,8 +1483,8 @@ public class ComputerPlayer extends PlayerImpl implements Player { CombatSimulator sim = simulateBlock(CombatSimulator.load(game), blockers, game); List groups = game.getCombat().getGroups(); - for (int i = 0; i< groups.size(); i++) { - for (CreatureSimulator creature: sim.groups.get(i).blockers) { + for (int i = 0; i < groups.size(); i++) { + for (CreatureSimulator creature : sim.groups.get(i).blockers) { groups.get(i).addBlocker(creature.id, playerId, game); } } @@ -1518,7 +1499,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { @Override public SpellAbility chooseSpellAbilityForCast(SpellAbility ability, Game game, boolean noMana) { - switch(ability.getSpellAbilityType()) { + switch (ability.getSpellAbilityType()) { case SPLIT: case SPLIT_FUSED: MageObject object = game.getObject(ability.getSourceId()); @@ -1544,7 +1525,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { return modes.getMode(); } //TODO: improve this; - for (Mode mode: modes.values()) { + for (Mode mode : modes.values()) { if (!modes.getSelectedModes().contains(mode.getId()) // select only modes not already selected && mode.getTargets().canChoose(source.getSourceId(), source.getControllerId(), game)) { // and where targets are available return mode; @@ -1578,7 +1559,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } //TODO: improve this if (min < max && min == 0) { - return new Random().nextInt(max+1); + return new Random().nextInt(max + 1); } return min; } @@ -1590,7 +1571,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } @Override - public UUID chooseBlockerOrder(List blockers, CombatGroup combatGroup, List blockerOrder, Game game) { + public UUID chooseBlockerOrder(List blockers, CombatGroup combatGroup, List blockerOrder, Game game) { //TODO: improve this return blockers.iterator().next().getId(); } @@ -1608,10 +1589,10 @@ public class ComputerPlayer extends PlayerImpl implements Player { private static void addBasicLands(Deck deck, String landName, int number) { Random random = new Random(); - Set landSets = new HashSet<>(); + Set landSets = new HashSet<>(); // decide from which sets basic lands are taken from - for (String setCode :deck.getExpansionSetCodes()) { + for (String setCode : deck.getExpansionSetCodes()) { ExpansionInfo expansionInfo = ExpansionRepository.instance.getSetByCode(setCode); if (expansionInfo.hasBasicLands()) { landSets.add(expansionInfo.getCode()); @@ -1620,10 +1601,10 @@ public class ComputerPlayer extends PlayerImpl implements Player { // if sets have no basic land, take land from block if (landSets.isEmpty()) { - for (String setCode :deck.getExpansionSetCodes()) { + for (String setCode : deck.getExpansionSetCodes()) { ExpansionInfo expansionInfo = ExpansionRepository.instance.getSetByCode(setCode); List blockSets = ExpansionRepository.instance.getSetsFromBlock(expansionInfo.getBlockName()); - for (ExpansionInfo blockSet: blockSets) { + for (ExpansionInfo blockSet : blockSets) { if (blockSet.hasBasicLands()) { landSets.add(blockSet.getCode()); } @@ -1653,7 +1634,10 @@ public class ComputerPlayer extends PlayerImpl implements Player { List cards = CardRepository.instance.findCards(criteria); if (cards.isEmpty()) { - return; + criteria = new CardCriteria(); + criteria.rarities(Rarity.LAND).name(landName); + criteria.setCodes("M15"); + cards = CardRepository.instance.findCards(criteria); } for (int i = 0; i < number; i++) { @@ -1685,7 +1669,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { // add basic lands // TODO: compensate for non basic lands Mana mana = new Mana(); - for (Card card: deck.getCards()) { + for (Card card : deck.getCards()) { mana.add(card.getManaCost().getMana()); } double total = mana.getBlack() + mana.getBlue() + mana.getGreen() + mana.getRed() + mana.getWhite(); @@ -1735,10 +1719,10 @@ public class ComputerPlayer extends PlayerImpl implements Player { @Override public void construct(Tournament tournament, Deck deck) { - if (deck != null && deck.getCards().size() < 40 && deck.getSideboard().size() > 0 ) { + if (deck != null && deck.getCards().size() < 40 && deck.getSideboard().size() > 0) { //pick the top 23 cards if (chosenColors == null) { - for (Card card: deck.getSideboard()) { + for (Card card : deck.getSideboard()) { rememberPick(card, RateCard.rateCard(card, null)); } chosenColors = chooseDeckColorsIfPossible(); @@ -1857,11 +1841,10 @@ public class ComputerPlayer extends PlayerImpl implements Player { // take it! if (counterPickScore >= 8) { bestCard = counterPick; - maxScore = RateCard.rateCard(bestCard, chosenColors); + maxScore = RateCard.rateCard(bestCard, chosenColors); } } - String colors = "not chosen yet"; // remember card if colors are not chosen yet if (chosenColors == null) { @@ -1877,7 +1860,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { log.debug("[DEBUG] AI picked: " + bestCard.getName() + ", score=" + maxScore + ", deck colors=" + colors); draft.addPick(playerId, bestCard.getId(), null); } catch (Exception e) { - log.debug("Exception during AI pick card for draft playerId= " +getId()); + log.debug("Exception during AI pick card for draft playerId= " + getId()); draft.addPick(playerId, cards.get(0).getId(), null); } } @@ -1893,11 +1876,11 @@ public class ComputerPlayer extends PlayerImpl implements Player { } /** - * Choose 2 deck colors for draft: - * 1. there should be at least 3 cards in card pool - * 2. at least 2 cards should have different colors - * 3. get card colors as chosen starting from most rated card - * @return + * Choose 2 deck colors for draft: 1. there should be at least 3 cards in + * card pool 2. at least 2 cards should have different colors 3. get card + * colors as chosen starting from most rated card + * + * @return */ protected List chooseDeckColorsIfPossible() { if (pickedCards.size() > 2) { @@ -1929,7 +1912,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } } // only two or three color decks are allowed - if (chosenSymbols.size() > 1 && chosenSymbols.size() < 4) { + if (chosenSymbols.size() > 1 && chosenSymbols.size() < 4) { List colorsChosen = new ArrayList<>(); for (String symbol : chosenSymbols) { ColoredManaSymbol manaSymbol = ColoredManaSymbol.lookup(symbol.charAt(0)); @@ -1949,10 +1932,13 @@ public class ComputerPlayer extends PlayerImpl implements Player { } private class PickedCard { + public Card card; public Integer score; + public PickedCard(Card card, int score) { - this.card = card; this.score = score; + this.card = card; + this.score = score; } } @@ -1960,7 +1946,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { log.debug("getAvailableAttackers"); Attackers attackers = new Attackers(); List creatures = super.getAvailableAttackers(game); - for (Permanent creature: creatures) { + for (Permanent creature : creatures) { int potential = combatPotential(creature, game); if (potential > 0 && creature.getPower().getValue() > 0) { List l = attackers.get(potential); @@ -1969,7 +1955,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } l.add(creature); } - } + } return attackers; } @@ -1981,9 +1967,9 @@ public class ComputerPlayer extends PlayerImpl implements Player { int potential = creature.getPower().getValue(); potential += creature.getAbilities().getEvasionAbilities().size(); potential += creature.getAbilities().getProtectionAbilities().size(); - potential += creature.getAbilities().containsKey(FirstStrikeAbility.getInstance().getId())?1:0; - potential += creature.getAbilities().containsKey(DoubleStrikeAbility.getInstance().getId())?2:0; - potential += creature.getAbilities().containsKey(TrampleAbility.getInstance().getId())?1:0; + potential += creature.getAbilities().containsKey(FirstStrikeAbility.getInstance().getId()) ? 1 : 0; + potential += creature.getAbilities().containsKey(DoubleStrikeAbility.getInstance().getId()) ? 2 : 0; + potential += creature.getAbilities().containsKey(TrampleAbility.getInstance().getId()) ? 1 : 0; return potential; } @@ -2002,7 +1988,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { int powerElements = (int) Math.pow(2, attackersList.size()); for (int i = 1; i < powerElements; i++) { String binary = Integer.toBinaryString(i); - while(binary.length() < attackersList.size()) { + while (binary.length() < attackersList.size()) { binary = "0" + binary; } List trialAttackers = new ArrayList<>(); @@ -2012,7 +1998,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } } CombatSimulator combat = new CombatSimulator(); - for (Permanent permanent: trialAttackers) { + for (Permanent permanent : trialAttackers) { combat.groups.add(new CombatGroupSimulator(opponentId, Arrays.asList(permanent.getId()), new ArrayList(), game)); } CombatSimulator test = simulateBlock(combat, blockers, game); @@ -2041,7 +2027,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { protected void addBlockSimulations(List blockers, TreeNode node, Game game) { int numGroups = node.getData().groups.size(); Copier copier = new Copier<>(); - for (Permanent blocker: blockers) { + for (Permanent blocker : blockers) { List subList = remove(blockers, blocker); for (int i = 0; i < numGroups; i++) { if (node.getData().groups.get(i).canBlock(blocker, game)) { @@ -2058,7 +2044,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { protected List remove(List source, Permanent element) { List newList = new ArrayList<>(); - for (Permanent permanent: source) { + for (Permanent permanent : source) { if (!permanent.equals(element)) { newList.add(permanent); } @@ -2069,7 +2055,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { protected CombatSimulator getBestSimulation(TreeNode simulations) { CombatSimulator best = simulations.getData(); int bestResult = best.evaluate(); - for (TreeNode node: simulations.getChildren()) { + for (TreeNode node : simulations.getChildren()) { CombatSimulator bestSub = getBestSimulation(node); if (bestSub.evaluate() > bestResult) { best = node.getData(); @@ -2082,7 +2068,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { protected CombatSimulator getWorstSimulation(TreeNode simulations) { CombatSimulator worst = simulations.getData(); int worstResult = worst.evaluate(); - for (TreeNode node: simulations.getChildren()) { + for (TreeNode node : simulations.getChildren()) { CombatSimulator worstSub = getWorstSimulation(node); if (worstSub.evaluate() < worstResult) { worst = node.getData(); @@ -2100,7 +2086,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { FilterPermanent filterCopy = filter.copy(); filterCopy.add(new ControllerIdPredicate(playerId)); threats = game.getBattlefield().getActivePermanents(filter, this.getId(), sourceId, game); - } + } Iterator it = threats.iterator(); while (it.hasNext()) { // remove permanents already targeted Permanent test = it.next(); @@ -2122,7 +2108,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { protected void logList(String message, List list) { StringBuilder sb = new StringBuilder(); sb.append(message).append(": "); - for (MageObject object: list) { + for (MageObject object : list) { sb.append(object.getName()).append(","); } log.info(sb.toString()); @@ -2131,17 +2117,17 @@ public class ComputerPlayer extends PlayerImpl implements Player { protected void logAbilityList(String message, List list) { StringBuilder sb = new StringBuilder(); sb.append(message).append(": "); - for (Ability ability: list) { + for (Ability ability : list) { sb.append(ability.getRule()).append(","); } log.debug(sb.toString()); } private void playRemoval(List creatures, Game game) { - for (UUID creatureId: creatures) { - for (Card card: this.playableInstant) { + for (UUID creatureId : creatures) { + for (Card card : this.playableInstant) { if (card.getSpellAbility().canActivate(playerId, game)) { - for (Effect effect: card.getSpellAbility().getEffects()) { + for (Effect effect : card.getSpellAbility().getEffects()) { if (effect.getOutcome().equals(Outcome.DestroyPermanent) || effect.getOutcome().equals(Outcome.ReturnToHand)) { if (card.getSpellAbility().getTargets().get(0).canTarget(creatureId, card.getSpellAbility(), game)) { if (this.activateAbility(card.getSpellAbility(), game)) { @@ -2156,14 +2142,14 @@ public class ComputerPlayer extends PlayerImpl implements Player { } private void playDamage(List creatures, Game game) { - for (UUID creatureId: creatures) { + for (UUID creatureId : creatures) { Permanent creature = game.getPermanent(creatureId); - for (Card card: this.playableInstant) { + for (Card card : this.playableInstant) { if (card.getSpellAbility().canActivate(playerId, game)) { - for (Effect effect: card.getSpellAbility().getEffects()) { + for (Effect effect : card.getSpellAbility().getEffects()) { if (effect instanceof DamageTargetEffect) { if (card.getSpellAbility().getTargets().get(0).canTarget(creatureId, card.getSpellAbility(), game)) { - if (((DamageTargetEffect)effect).getAmount() > (creature.getPower().getValue() - creature.getDamage())) { + if (((DamageTargetEffect) effect).getAmount() > (creature.getPower().getValue() - creature.getDamage())) { if (this.activateAbility(card.getSpellAbility(), game)) { return; } @@ -2189,8 +2175,6 @@ public class ComputerPlayer extends PlayerImpl implements Player { super.cleanUpOnMatchEnd(); //To change body of generated methods, choose Tools | Templates. } - - @Override public ComputerPlayer copy() { return new ComputerPlayer(this); diff --git a/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/SimulatedPlayerMCTS.java b/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/SimulatedPlayerMCTS.java index c64f365fd43..f43fc6dc022 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/SimulatedPlayerMCTS.java +++ b/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/SimulatedPlayerMCTS.java @@ -1,16 +1,16 @@ /* * Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,20 +20,31 @@ * 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.player.ai; -import mage.constants.Outcome; -import mage.abilities.*; +import java.io.Serializable; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Set; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.ActivatedAbility; +import mage.abilities.Mode; +import mage.abilities.Modes; +import mage.abilities.TriggeredAbility; import mage.abilities.common.PassAbility; import mage.abilities.costs.mana.GenericManaCost; import mage.cards.Card; import mage.cards.Cards; import mage.choices.Choice; +import mage.constants.Outcome; import mage.game.Game; import mage.game.combat.CombatGroup; import mage.game.permanent.Permanent; @@ -44,13 +55,10 @@ import mage.target.TargetAmount; import mage.target.TargetCard; import org.apache.log4j.Logger; -import java.io.Serializable; -import java.util.*; - /** * * plays randomly - * + * * @author BetaSteward_at_googlemail.com */ public class SimulatedPlayerMCTS extends MCTSPlayer { @@ -58,7 +66,7 @@ public class SimulatedPlayerMCTS extends MCTSPlayer { private boolean isSimulatedPlayer; private static Random rnd = new Random(); private int actionCount = 0; - private static final transient Logger logger = Logger.getLogger(SimulatedPlayerMCTS.class); + private static final transient Logger logger = Logger.getLogger(SimulatedPlayerMCTS.class); public SimulatedPlayerMCTS(UUID id, boolean isSimulatedPlayer) { super(id); @@ -83,14 +91,15 @@ public class SimulatedPlayerMCTS extends MCTSPlayer { return actionCount; } - @Override + @Override public boolean priority(Game game) { // logger.info("priority"); boolean didSomething = false; Ability ability = getAction(game); // logger.info("simulate " + ability.toString()); - if (!(ability instanceof PassAbility)) + if (!(ability instanceof PassAbility)) { didSomething = true; + } activateAbility((ActivatedAbility) ability, game); @@ -102,16 +111,18 @@ public class SimulatedPlayerMCTS extends MCTSPlayer { List playables = getPlayableAbilities(game); Ability ability; while (true) { - if (playables.size() == 1) + if (playables.size() == 1) { ability = playables.get(0); - else + } else { ability = playables.get(rnd.nextInt(playables.size())); + } List options = getPlayableOptions(ability, game); if (!options.isEmpty()) { - if (options.size() == 1) + if (options.size() == 1) { ability = options.get(0); - else + } else { ability = options.get(rnd.nextInt(options.size())); + } } if (ability.getManaCosts().getVariableCosts().size() > 0) { int amount = getAvailableManaProducers(game).size() - ability.getManaCosts().convertedManaCost(); @@ -133,7 +144,7 @@ public class SimulatedPlayerMCTS extends MCTSPlayer { // } // } // else { - break; + break; // } } return ability; @@ -147,12 +158,12 @@ public class SimulatedPlayerMCTS extends MCTSPlayer { List options = getPlayableOptions(source, game); if (options.isEmpty()) { ability = source; - } - else { - if (options.size() == 1) + } else { + if (options.size() == 1) { ability = options.get(0); - else + } else { ability = options.get(rnd.nextInt(options.size())); + } } if (ability.isUsesStack()) { game.getStack().push(new StackAbility(ability, playerId)); @@ -205,7 +216,7 @@ public class SimulatedPlayerMCTS extends MCTSPlayer { } List blockers = getAvailableBlockers(game); - for (Permanent blocker: blockers) { + for (Permanent blocker : blockers) { int check = rnd.nextInt(numGroups + 1); if (check < numGroups) { CombatGroup group = game.getCombat().getGroups().get(check); @@ -242,9 +253,10 @@ public class SimulatedPlayerMCTS extends MCTSPlayer { } protected boolean chooseRandomTarget(Target target, Ability source, Game game) { - Set possibleTargets = target.possibleTargets(source==null?null:source.getSourceId(), playerId, game); - if (possibleTargets.isEmpty()) + Set possibleTargets = target.possibleTargets(source == null ? null : source.getSourceId(), playerId, game); + if (possibleTargets.isEmpty()) { return false; + } if (!target.isRequired(source)) { if (rnd.nextInt(possibleTargets.size() + 1) == 0) { return false; @@ -266,8 +278,9 @@ public class SimulatedPlayerMCTS extends MCTSPlayer { @Override public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game) { - if (this.isHuman()) + if (this.isHuman()) { return chooseRandom(target, game); + } return super.choose(outcome, target, sourceId, game); } @@ -318,7 +331,7 @@ public class SimulatedPlayerMCTS extends MCTSPlayer { @Override public boolean chooseTargetAmount(Outcome outcome, TargetAmount target, Ability source, Game game) { - Set possibleTargets = target.possibleTargets(source==null?null:source.getSourceId(), playerId, game); + Set possibleTargets = target.possibleTargets(source == null ? null : source.getSourceId(), playerId, game); if (possibleTargets.isEmpty()) { return !target.isRequired(source); } @@ -347,11 +360,11 @@ public class SimulatedPlayerMCTS extends MCTSPlayer { } @Override - public boolean chooseUse(Outcome outcome, String message, Game game) { + public boolean chooseUse(Outcome outcome, String message, Ability source, Game game) { if (this.isHuman()) { return rnd.nextBoolean(); } - return super.chooseUse(outcome, message, game); + return super.chooseUse(outcome, message, source, game); } @Override @@ -436,8 +449,7 @@ public class SimulatedPlayerMCTS extends MCTSPlayer { if (targets.size() == 1) { targetId = targets.get(0); amount = remainingDamage; - } - else { + } else { targetId = targets.get(rnd.nextInt(targets.size())); amount = rnd.nextInt(damage + 1); } @@ -445,8 +457,7 @@ public class SimulatedPlayerMCTS extends MCTSPlayer { if (permanent != null) { permanent.damage(amount, sourceId, game, false, true); remainingDamage -= amount; - } - else { + } else { Player player = game.getPlayer(targetId); if (player != null) { player.damage(amount, sourceId, game, false, true); @@ -455,8 +466,7 @@ public class SimulatedPlayerMCTS extends MCTSPlayer { } targets.remove(targetId); } - } - else { + } else { super.assignDamage(damage, targets, singleTargetName, sourceId, game); } } 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 77bb838f1de..3d0370d9e7d 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 @@ -1,35 +1,50 @@ /* -* 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. -*/ - + * 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.player.human; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; import mage.MageObject; -import mage.abilities.*; +import mage.abilities.Ability; +import mage.abilities.ActivatedAbility; +import mage.abilities.Mode; +import mage.abilities.Modes; +import mage.abilities.PlayLandAbility; +import mage.abilities.SpecialAction; +import mage.abilities.SpellAbility; +import mage.abilities.TriggeredAbility; import mage.abilities.costs.VariableCost; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.mana.ManaCost; @@ -42,7 +57,13 @@ import mage.cards.Cards; import mage.cards.decks.Deck; import mage.choices.Choice; import mage.choices.ChoiceImpl; -import mage.constants.*; +import mage.constants.Constants; +import mage.constants.ManaType; +import mage.constants.Outcome; +import mage.constants.PhaseStep; +import mage.constants.PlayerAction; +import mage.constants.RangeOfInfluence; +import mage.constants.Zone; import mage.filter.common.FilterAttackingCreature; import mage.filter.common.FilterBlockingCreature; import mage.filter.common.FilterCreatureForCombat; @@ -63,13 +84,10 @@ import mage.target.TargetPermanent; import mage.target.common.TargetAttackingCreature; import mage.target.common.TargetCreatureOrPlayer; import mage.target.common.TargetDefender; +import mage.util.GameLog; import mage.util.ManaUtil; import org.apache.log4j.Logger; -import java.io.Serializable; -import java.util.*; -import mage.util.GameLog; - /** * * @author BetaSteward_at_googlemail.com @@ -85,6 +103,7 @@ public class HumanPlayer extends PlayerImpl { protected static final Choice replacementEffectChoice = new ChoiceImpl(true); private static final Logger log = Logger.getLogger(HumanPlayer.class); + static { replacementEffectChoice.setMessage("Choose replacement effect to resolve first"); } @@ -104,7 +123,7 @@ public class HumanPlayer extends PlayerImpl { response.clear(); log.debug("Waiting response from player: " + getId()); game.resumeTimer(getTurnControlledBy()); - synchronized(response) { + synchronized (response) { try { response.wait(); log.debug("Got response from player: " + getId()); @@ -145,9 +164,9 @@ public class HumanPlayer extends PlayerImpl { updateGameStatePriority("chooseMulligan", game); int nextHandSize = game.mulliganDownTo(playerId); game.fireAskPlayerEvent(playerId, new StringBuilder("Mulligan ") - .append(getHand().size() > nextHandSize?"down to ":"for free, draw ") + .append(getHand().size() > nextHandSize ? "down to " : "for free, draw ") .append(nextHandSize) - .append(nextHandSize == 1?" card?":" cards?").toString()); + .append(nextHandSize == 1 ? " card?" : " cards?").toString()); waitForBooleanResponse(game); if (!abort) { return response.getBoolean(); @@ -156,9 +175,9 @@ public class HumanPlayer extends PlayerImpl { } @Override - public boolean chooseUse(Outcome outcome, String message, Game game) { + public boolean chooseUse(Outcome outcome, String message, Ability source, Game game) { updateGameStatePriority("chooseUse", game); - game.fireAskPlayerEvent(playerId, message); + game.fireAskPlayerEvent(playerId, addSecondLineWithObjectName(message, source == null ? null : source.getSourceId(), game)); waitForBooleanResponse(game); if (!abort) { return response.getBoolean(); @@ -166,6 +185,19 @@ public class HumanPlayer extends PlayerImpl { return false; } + private String addSecondLineWithObjectName(String message, UUID sourceId, Game game) { + if (sourceId != null) { + MageObject mageObject = game.getPermanent(sourceId); + if (mageObject == null) { + mageObject = game.getCard(sourceId); + } + if (mageObject != null) { + message += "
" + mageObject.getLogName() + "
"; + } + } + return message; + } + @Override public int chooseReplacementEffect(Map rEffects, Game game) { updateGameStatePriority("chooseEffect", game); @@ -173,7 +205,7 @@ public class HumanPlayer extends PlayerImpl { return 0; } if (!autoSelectReplacementEffects.isEmpty()) { - for (String autoKey :autoSelectReplacementEffects) { + for (String autoKey : autoSelectReplacementEffects) { int count = 0; for (String effectKey : rEffects.keySet()) { if (effectKey.equals(autoKey)) { @@ -230,22 +262,22 @@ public class HumanPlayer extends PlayerImpl { @Override public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game) { - return choose(outcome, target, sourceId, game, null); + return choose(outcome, target, sourceId, game, null); } @Override public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game, Map options) { - updateGameStatePriority("choose(5)", game); + updateGameStatePriority("choose(5)", game); UUID abilityControllerId = playerId; if (target.getTargetController() != null && target.getAbilityController() != null) { abilityControllerId = target.getAbilityController(); - } + } if (options == null) { options = new HashMap<>(); } while (!abort) { Set targetIds = target.possibleTargets(sourceId, abilityControllerId, game); - if (targetIds == null || targetIds.isEmpty()) { + if (targetIds == null || targetIds.isEmpty()) { return target.getTargets().size() >= target.getNumberOfTargets(); } boolean required = target.isRequired(sourceId, game); @@ -254,18 +286,18 @@ public class HumanPlayer extends PlayerImpl { } List chosen = target.getTargets(); - options.put("chosen", (Serializable)chosen); + options.put("chosen", (Serializable) chosen); - game.fireSelectTargetEvent(getId(), target.getMessage(), targetIds, required, getOptions(target, options)); + game.fireSelectTargetEvent(getId(), addSecondLineWithObjectName(target.getMessage(), sourceId, game), targetIds, required, getOptions(target, options)); waitForResponse(game); if (response.getUUID() != null) { if (!targetIds.contains(response.getUUID())) { continue; } if (target instanceof TargetPermanent) { - if (((TargetPermanent)target).canTarget(abilityControllerId, response.getUUID(), sourceId, game, false)) { + if (((TargetPermanent) target).canTarget(abilityControllerId, response.getUUID(), sourceId, game, false)) { target.add(response.getUUID(), game); - if(target.doneChosing()){ + if (target.doneChosing()) { return true; } } @@ -276,8 +308,8 @@ public class HumanPlayer extends PlayerImpl { if (target.getTargets().contains(response.getUUID())) { // if already included remove it with target.remove(response.getUUID()); } else { - target.addTarget(response.getUUID(), (Ability)object, game); - if(target.doneChosing()){ + target.addTarget(response.getUUID(), (Ability) object, game); + if (target.doneChosing()) { return true; } } @@ -288,7 +320,7 @@ public class HumanPlayer extends PlayerImpl { target.remove(response.getUUID()); } else { target.addTarget(response.getUUID(), null, game); - if(target.doneChosing()){ + if (target.doneChosing()) { return true; } } @@ -316,12 +348,13 @@ public class HumanPlayer extends PlayerImpl { abilityControllerId = target.getAbilityController(); } while (!abort) { - Set possibleTargets = target.possibleTargets(source==null?null:source.getSourceId(), abilityControllerId, game); + Set possibleTargets = target.possibleTargets(source == null ? null : source.getSourceId(), abilityControllerId, game); boolean required = target.isRequired(source); if (possibleTargets.isEmpty() || target.getTargets().size() >= target.getNumberOfTargets()) { required = false; } - game.fireSelectTargetEvent(getId(), target.getMessage(), possibleTargets, required, getOptions(target, null)); + + game.fireSelectTargetEvent(getId(), addSecondLineWithObjectName(target.getMessage(), source == null ? null : source.getSourceId(), game), possibleTargets, required, getOptions(target, null)); waitForResponse(game); if (response.getUUID() != null) { if (target.getTargets().contains(response.getUUID())) { @@ -331,11 +364,11 @@ public class HumanPlayer extends PlayerImpl { if (possibleTargets.contains(response.getUUID())) { if (target.canTarget(abilityControllerId, response.getUUID(), source, game)) { target.addTarget(response.getUUID(), source, game); - if(target.doneChosing()){ + if (target.doneChosing()) { return true; } } - } + } } else { if (target.getTargets().size() >= target.getNumberOfTargets()) { return true; @@ -348,7 +381,7 @@ public class HumanPlayer extends PlayerImpl { return false; } - private Map getOptions(Target target, Map options ) { + private Map getOptions(Target target, Map options) { if (options == null) { options = new HashMap<>(); } @@ -356,7 +389,7 @@ public class HumanPlayer extends PlayerImpl { options.put("UI.right.btn.text", "Done"); } options.put("targetZone", target.getZone()); - return options; + return options; } @Override @@ -378,7 +411,7 @@ public class HumanPlayer extends PlayerImpl { } Map options = getOptions(target, null); List chosen = target.getTargets(); - options.put("chosen", (Serializable)chosen); + options.put("chosen", (Serializable) chosen); List choosable = new ArrayList<>(); for (UUID cardId : cards) { if (target.canTarget(cardId, cards, game)) { @@ -392,7 +425,7 @@ public class HumanPlayer extends PlayerImpl { waitForResponse(game); if (response.getUUID() != null) { if (target.canTarget(response.getUUID(), cards, game)) { - if (target.getTargets().contains(response.getUUID())) { // if already included remove it with + if (target.getTargets().contains(response.getUUID())) { // if already included remove it with target.remove(response.getUUID()); } else { target.add(response.getUUID(), game); @@ -432,7 +465,7 @@ public class HumanPlayer extends PlayerImpl { } Map options = getOptions(target, null); List chosen = target.getTargets(); - options.put("chosen", (Serializable)chosen); + options.put("chosen", (Serializable) chosen); List choosable = new ArrayList<>(); for (UUID cardId : cards) { if (target.canTarget(cardId, cards, game)) { @@ -442,10 +475,10 @@ public class HumanPlayer extends PlayerImpl { if (!choosable.isEmpty()) { options.put("choosable", (Serializable) choosable); } - game.fireSelectTargetEvent(playerId, target.getMessage(), cards, required, options); + game.fireSelectTargetEvent(playerId, addSecondLineWithObjectName(target.getMessage(), source == null ? null : source.getSourceId(), game), cards, required, options); waitForResponse(game); if (response.getUUID() != null) { - if (target.getTargets().contains(response.getUUID())) { // if already included remove it + if (target.getTargets().contains(response.getUUID())) { // if already included remove it target.remove(response.getUUID()); } else { if (target.canTarget(response.getUUID(), cards, game)) { @@ -471,8 +504,8 @@ public class HumanPlayer extends PlayerImpl { public boolean chooseTargetAmount(Outcome outcome, TargetAmount target, Ability source, Game game) { updateGameStatePriority("chooseTargetAmount", game); while (!abort) { - game.fireSelectTargetEvent(playerId, target.getMessage() + "\n Amount remaining:" + target.getAmountRemaining(), - target.possibleTargets(source==null?null:source.getSourceId(), playerId, game), + game.fireSelectTargetEvent(playerId, addSecondLineWithObjectName(target.getMessage() + "\n Amount remaining:" + target.getAmountRemaining(), source.getSourceId(), game), + target.possibleTargets(source == null ? null : source.getSourceId(), playerId, game), target.isRequired(source), getOptions(target, null)); waitForResponse(game); @@ -495,7 +528,7 @@ public class HumanPlayer extends PlayerImpl { passed = false; if (!abort) { if (passedAllTurns) { - if(passWithManaPoolCheck(game)) { + if (passWithManaPoolCheck(game)) { return false; } } @@ -503,7 +536,7 @@ public class HumanPlayer extends PlayerImpl { passedUntilStackResolved = false; boolean dontCheckPassStep = false; if (passedTurn) { - if(passWithManaPoolCheck(game)) { + if (passWithManaPoolCheck(game)) { return false; } } @@ -512,7 +545,7 @@ public class HumanPlayer extends PlayerImpl { // it's a main phase if (!skippedAtLeastOnce || (!playerId.equals(game.getActivePlayerId()) && !this.getUserData().getUserSkipPrioritySteps().isStopOnAllMainPhases())) { skippedAtLeastOnce = true; - if(passWithManaPoolCheck(game)) { + if (passWithManaPoolCheck(game)) { return false; } } else { @@ -521,7 +554,7 @@ public class HumanPlayer extends PlayerImpl { } } else { skippedAtLeastOnce = true; - if(passWithManaPoolCheck(game)) { + if (passWithManaPoolCheck(game)) { return false; } } @@ -531,7 +564,7 @@ public class HumanPlayer extends PlayerImpl { // It's end of turn phase if (!skippedAtLeastOnce || (playerId.equals(game.getActivePlayerId()) && !this.getUserData().getUserSkipPrioritySteps().isStopOnAllEndPhases())) { skippedAtLeastOnce = true; - if(passWithManaPoolCheck(game)) { + if (passWithManaPoolCheck(game)) { return false; } } else { @@ -540,20 +573,20 @@ public class HumanPlayer extends PlayerImpl { } } else { skippedAtLeastOnce = true; - if(passWithManaPoolCheck(game)) { + if (passWithManaPoolCheck(game)) { return false; } } } if (!dontCheckPassStep && checkPassStep(game)) { - if(passWithManaPoolCheck(game)) { + if (passWithManaPoolCheck(game)) { return false; } - } + } } else if (passedUntilStackResolved) { if (dateLastAddedToStack == game.getStack().getDateLastAdded()) { dateLastAddedToStack = game.getStack().getDateLastAdded(); - if(passWithManaPoolCheck(game)) { + if (passWithManaPoolCheck(game)) { return false; } } else { @@ -564,7 +597,7 @@ public class HumanPlayer extends PlayerImpl { updateGameStatePriority("priority", game); game.firePriorityEvent(playerId); waitForResponse(game); - if(game.executingRollback()) { + if (game.executingRollback()) { return true; } if (response.getBoolean() != null || response.getInteger() != null) { @@ -573,10 +606,10 @@ public class HumanPlayer extends PlayerImpl { } else { continue; } - } + } break; } - + if (response.getString() != null && response.getString().equals("special")) { specialAction(game); } else if (response.getUUID() != null) { @@ -593,7 +626,7 @@ public class HumanPlayer extends PlayerImpl { if (game.getPriorityPlayerId().equals(playerId)) { actingPlayer = this; } else if (getPlayersUnderYourControl().contains(game.getPriorityPlayerId())) { - actingPlayer = game.getPlayer(game.getPriorityPlayerId()); + actingPlayer = game.getPlayer(game.getPriorityPlayerId()); } if (actingPlayer != null) { LinkedHashMap useableAbilities = actingPlayer.getUseableActivatedAbilities(object, zone, game); @@ -628,7 +661,7 @@ public class HumanPlayer extends PlayerImpl { game.fireSelectTargetEvent(playerId, "Pick triggered ability (goes to the stack first)", abilities); waitForResponse(game); if (response.getUUID() != null) { - for (TriggeredAbility ability: abilities) { + for (TriggeredAbility ability : abilities) { if (ability.getId().equals(response.getUUID())) { return ability; } @@ -638,7 +671,6 @@ public class HumanPlayer extends PlayerImpl { return null; } - @Override public boolean playMana(ManaCost unpaid, String promptText, Game game) { payManaMode = true; @@ -647,7 +679,6 @@ public class HumanPlayer extends PlayerImpl { return result; } - protected boolean playManaHandling(ManaCost unpaid, String promptText, Game game) { updateGameStatePriority("playMana", game); game.firePlayManaEvent(playerId, "Pay " + promptText); @@ -666,9 +697,9 @@ public class HumanPlayer extends PlayerImpl { ManaCostsImpl costs = (ManaCostsImpl) unpaid; for (ManaCost cost : costs.getUnpaid()) { if (cost instanceof PhyrexianManaCost) { - PhyrexianManaCost ph = (PhyrexianManaCost)cost; + PhyrexianManaCost ph = (PhyrexianManaCost) cost; if (ph.canPay(null, null, playerId, game)) { - ((PhyrexianManaCost)cost).pay(null, game, null, playerId, false); + ((PhyrexianManaCost) cost).pay(null, game, null, playerId, false); } break; } @@ -679,13 +710,14 @@ public class HumanPlayer extends PlayerImpl { if (response.getResponseManaTypePlayerId().equals(this.getId())) { this.getManaPool().unlockManaType(response.getManaType()); } - // TODO: Handle if mana pool + // TODO: Handle if mana pool } return true; } /** * Gets the amount of mana the player want to spent for a x spell + * * @param min * @param max * @param message @@ -700,7 +732,7 @@ public class HumanPlayer extends PlayerImpl { game.fireGetAmountEvent(playerId, message, min, max); waitForIntegerResponse(game); if (response != null && response.getInteger() != null) { - xValue = response.getInteger(); + xValue = response.getInteger(); } return xValue; } @@ -712,7 +744,7 @@ public class HumanPlayer extends PlayerImpl { game.fireGetAmountEvent(playerId, message, min, max); waitForIntegerResponse(game); if (response != null && response.getInteger() != null) { - xValue = response.getInteger(); + xValue = response.getInteger(); } return xValue; } @@ -722,7 +754,7 @@ public class HumanPlayer extends PlayerImpl { MageObject object = game.getObject(response.getUUID()); if (object == null) { return; - } + } Zone zone = game.getState().getZone(object.getId()); if (zone != null) { LinkedHashMap useableAbilities = getUseableManaAbilities(object, zone, game); @@ -739,8 +771,8 @@ public class HumanPlayer extends PlayerImpl { FilterCreatureForCombat filter = filterCreatureForCombat.copy(); filter.add(new ControllerIdPredicate(attackingPlayerId)); while (!abort) { - if (passedAllTurns || - (!getUserData().getUserSkipPrioritySteps().isStopOnDeclareAttackersDuringSkipAction() && (passedTurn || passedUntilEndOfTurn || passedUntilNextMain) )) { + if (passedAllTurns + || (!getUserData().getUserSkipPrioritySteps().isStopOnDeclareAttackersDuringSkipAction() && (passedTurn || passedUntilEndOfTurn || passedUntilNextMain))) { return; } Map options = new HashMap<>(); @@ -751,7 +783,7 @@ public class HumanPlayer extends PlayerImpl { possibleAttackers.add(possibleAttacker.getId()); } } - options.put(Constants.Option.POSSIBLE_ATTACKERS, (Serializable)possibleAttackers); + options.put(Constants.Option.POSSIBLE_ATTACKERS, (Serializable) possibleAttackers); game.fireSelectEvent(playerId, "Select attackers", options); waitForResponse(game); @@ -761,7 +793,7 @@ public class HumanPlayer extends PlayerImpl { if (!game.getCombat().getAttackers().containsAll(game.getCombat().getCreaturesForcedToAttack().keySet())) { int forcedAttackers = 0; StringBuilder sb = new StringBuilder(); - for (UUID creatureId :game.getCombat().getCreaturesForcedToAttack().keySet()) { + for (UUID creatureId : game.getCombat().getCreaturesForcedToAttack().keySet()) { boolean validForcedAttacker = false; if (game.getCombat().getAttackers().contains(creatureId)) { Set possibleDefender = game.getCombat().getCreaturesForcedToAttack().get(creatureId); @@ -777,10 +809,10 @@ public class HumanPlayer extends PlayerImpl { sb.append(creature.getName()).append(" "); } } - + } if (game.getCombat().getMaxAttackers() > forcedAttackers) { - game.informPlayer(this, sb.insert(0," more attacker(s) that are forced to attack.\nCreatures forced to attack: ") + game.informPlayer(this, sb.insert(0, " more attacker(s) that are forced to attack.\nCreatures forced to attack: ") .insert(0, Math.min(game.getCombat().getMaxAttackers() - forcedAttackers, game.getCombat().getCreaturesForcedToAttack().size() - forcedAttackers)) .insert(0, "You have to attack with ").toString()); continue; @@ -799,18 +831,17 @@ public class HumanPlayer extends PlayerImpl { if (attacker != null) { if (filterCreatureForCombat.match(attacker, null, playerId, game)) { selectDefender(game.getCombat().getDefenders(), attacker.getId(), game); - } - else if (filterAttack.match(attacker, null, playerId, game) && game.getStack().isEmpty()) { + } else if (filterAttack.match(attacker, null, playerId, game) && game.getStack().isEmpty()) { removeAttackerIfPossible(game, attacker); } } - } + } } } private void removeAttackerIfPossible(Game game, Permanent attacker) { for (Map.Entry entry : game.getContinuousEffects().getApplicableRequirementEffects(attacker, game).entrySet()) { - RequirementEffect effect = (RequirementEffect)entry.getKey(); + RequirementEffect effect = (RequirementEffect) entry.getKey(); if (effect.mustAttack(game)) { if (game.getCombat().getMaxAttackers() >= game.getCombat().getCreaturesForcedToAttack().size() && game.getCombat().getDefenders().size() == 1) { return; // we can't change creatures forced to attack if only one possible defender exists and all forced creatures can attack @@ -840,8 +871,7 @@ public class HumanPlayer extends PlayerImpl { if (possibleDefender.size() == 1) { declareAttacker(attackerId, defenders.iterator().next(), game, true); return true; - } - else { + } else { TargetDefender target = new TargetDefender(possibleDefender, attackerId); target.setNotTarget(true); // player or planswalker hexproof does not prevent attacking a player if (forcedToAttack) { @@ -880,14 +910,14 @@ public class HumanPlayer extends PlayerImpl { if (blocker != null) { boolean removeBlocker = false; // does not block yet and can block or can block more attackers - if (filter.match(blocker, null, playerId, game)) { + if (filter.match(blocker, null, playerId, game)) { selectCombatGroup(defendingPlayerId, blocker.getId(), game); } else { if (filterBlock.match(blocker, null, playerId, game) && game.getStack().isEmpty()) { removeBlocker = true; - } + } } - + if (removeBlocker) { game.getCombat().removeBlocker(blocker.getId(), game); } @@ -903,7 +933,7 @@ public class HumanPlayer extends PlayerImpl { game.fireSelectTargetEvent(playerId, "Pick attacker", attackers, true); waitForResponse(game); if (response.getUUID() != null) { - for (Permanent perm: attackers) { + for (Permanent perm : attackers) { if (perm.getId().equals(response.getUUID())) { return perm.getId(); } @@ -913,7 +943,6 @@ public class HumanPlayer extends PlayerImpl { return null; } - @Override public UUID chooseBlockerOrder(List blockers, CombatGroup combatGroup, List blockerOrder, Game game) { updateGameStatePriority("chooseBlockerOrder", game); @@ -921,7 +950,7 @@ public class HumanPlayer extends PlayerImpl { game.fireSelectTargetEvent(playerId, "Pick blocker", blockers, true); waitForResponse(game); if (response.getUUID() != null) { - for (Permanent perm: blockers) { + for (Permanent perm : blockers) { if (perm.getId().equals(response.getUUID())) { return perm.getId(); } @@ -942,7 +971,7 @@ public class HumanPlayer extends PlayerImpl { CombatGroup group = game.getCombat().findGroup(response.getUUID()); if (group != null) { // check if already blocked, if not add - if (!group.getBlockers().contains(blockerId)) { + if (!group.getBlockers().contains(blockerId)) { declareBlocker(defenderId, blockerId, response.getUUID(), game); } else { // else remove from block game.getCombat().removeBlockerGromGroup(blockerId, group, game); @@ -967,8 +996,7 @@ public class HumanPlayer extends PlayerImpl { if (permanent != null) { permanent.damage(damageAmount, sourceId, game, false, true); remainingDamage -= damageAmount; - } - else { + } else { Player player = game.getPlayer(target.getFirstTarget()); if (player != null) { player.damage(damageAmount, sourceId, game, false, true); @@ -1006,7 +1034,7 @@ public class HumanPlayer extends PlayerImpl { draft.firePickCardEvent(playerId); } - protected void specialAction(Game game) { + protected void specialAction(Game game) { LinkedHashMap specialActions = game.getState().getSpecialActions().getControlledBy(playerId, false); if (!specialActions.isEmpty()) { updateGameStatePriority("specialAction", game); @@ -1041,7 +1069,7 @@ public class HumanPlayer extends PlayerImpl { @Override public boolean activateAbility(ActivatedAbility ability, Game game) { getManaPool().setStock(); // needed for the "mana already in the pool has to be used manually" option - return super.activateAbility(ability, game); + return super.activateAbility(ability, game); } protected void activateAbility(LinkedHashMap abilities, MageObject object, Game game) { @@ -1066,7 +1094,7 @@ public class HumanPlayer extends PlayerImpl { if (this.getUserData().isShowAbilityPickerForced()) { if (ability instanceof PlayLandAbility) { return true; - } + } if (!ability.getSourceId().equals(getCastSourceIdWithAlternateMana()) && ability.getManaCostsToPay().convertedManaCost() > 0) { return true; } @@ -1078,10 +1106,10 @@ public class HumanPlayer extends PlayerImpl { } return true; } - + @Override public SpellAbility chooseSpellAbilityForCast(SpellAbility ability, Game game, boolean noMana) { - switch(ability.getSpellAbilityType()) { + switch (ability.getSpellAbilityType()) { case SPLIT: case SPLIT_FUSED: MageObject object = game.getObject(ability.getSourceId()); @@ -1111,7 +1139,7 @@ public class HumanPlayer extends PlayerImpl { if (modes.size() > 1) { MageObject obj = game.getObject(source.getSourceId()); Map modeMap = new LinkedHashMap<>(); - for (Mode mode: modes.values()) { + for (Mode mode : modes.values()) { if (!modes.getSelectedModes().contains(mode.getId()) // show only modes not already selected && mode.getTargets().canChoose(source.getSourceId(), source.getControllerId(), game)) { // and where targets are available String modeText = mode.getEffects().getText(mode); @@ -1125,7 +1153,7 @@ public class HumanPlayer extends PlayerImpl { game.fireGetModeEvent(playerId, "Choose Mode", modeMap); waitForResponse(game); if (response.getUUID() != null) { - for (Mode mode: modes.values()) { + for (Mode mode : modes.values()) { if (mode.getId().equals(response.getUUID())) { return mode; } @@ -1150,7 +1178,7 @@ public class HumanPlayer extends PlayerImpl { @Override public void setResponseString(String responseString) { - synchronized(response) { + synchronized (response) { response.setString(responseString); response.notify(); log.debug("Got response string from player: " + getId()); @@ -1159,7 +1187,7 @@ public class HumanPlayer extends PlayerImpl { @Override public void setResponseManaType(UUID manaTypePlayerId, ManaType manaType) { - synchronized(response) { + synchronized (response) { response.setManaType(manaType); response.setResponseManaTypePlayerId(manaTypePlayerId); response.notify(); @@ -1169,7 +1197,7 @@ public class HumanPlayer extends PlayerImpl { @Override public void setResponseUUID(UUID responseUUID) { - synchronized(response) { + synchronized (response) { response.setUUID(responseUUID); response.notify(); log.debug("Got response UUID from player: " + getId()); @@ -1178,7 +1206,7 @@ public class HumanPlayer extends PlayerImpl { @Override public void setResponseBoolean(Boolean responseBoolean) { - synchronized(response) { + synchronized (response) { response.setBoolean(responseBoolean); response.notify(); log.debug("Got response boolean from player: " + getId()); @@ -1187,7 +1215,7 @@ public class HumanPlayer extends PlayerImpl { @Override public void setResponseInteger(Integer responseInteger) { - synchronized(response) { + synchronized (response) { response.setInteger(responseInteger); response.notify(); log.debug("Got response integer from player: " + getId()); @@ -1197,7 +1225,7 @@ public class HumanPlayer extends PlayerImpl { @Override public void abort() { abort = true; - synchronized(response) { + synchronized (response) { response.notify(); log.debug("Got cancel action from player: " + getId()); } @@ -1205,7 +1233,7 @@ public class HumanPlayer extends PlayerImpl { @Override public void skip() { - synchronized(response) { + synchronized (response) { response.setInteger(0); response.notify(); log.debug("Got skip action from player: " + getId()); @@ -1232,10 +1260,10 @@ public class HumanPlayer extends PlayerImpl { super.sendPlayerAction(playerAction, game); } } - + protected boolean passWithManaPoolCheck(Game game) { - if (userData.confirmEmptyManaPool() && - game.getStack().isEmpty() && getManaPool().count() > 0) { + if (userData.confirmEmptyManaPool() + && game.getStack().isEmpty() && getManaPool().count() > 0) { String activePlayerText; if (game.getActivePlayerId().equals(playerId)) { activePlayerText = "Your turn"; @@ -1245,14 +1273,14 @@ public class HumanPlayer extends PlayerImpl { String priorityPlayerText = ""; if (!isGameUnderControl()) { priorityPlayerText = " / priority " + game.getPlayer(game.getPriorityPlayerId()).getName(); - } + } if (!chooseUse(Outcome.Detriment, GameLog.getPlayerConfirmColoredText("You have still mana in your mana pool. Pass regardless?") - + GameLog.getSmallSecondLineText(activePlayerText + " / " + game.getStep().getType().toString() + priorityPlayerText), game)) { + + GameLog.getSmallSecondLineText(activePlayerText + " / " + game.getStep().getType().toString() + priorityPlayerText), null, game)) { sendPlayerAction(PlayerAction.PASS_PRIORITY_CANCEL_ALL_ACTIONS, game); return false; } } pass(game); return true; - } + } } diff --git a/Mage.Server/src/main/java/mage/server/MageServerImpl.java b/Mage.Server/src/main/java/mage/server/MageServerImpl.java index 7ddf83a1530..46c6ce0aadb 100644 --- a/Mage.Server/src/main/java/mage/server/MageServerImpl.java +++ b/Mage.Server/src/main/java/mage/server/MageServerImpl.java @@ -1,31 +1,30 @@ /* -* 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. -*/ - + * 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.server; import java.util.ArrayList; @@ -52,6 +51,7 @@ import mage.interfaces.ActionWithResult; import mage.interfaces.MageServer; import mage.interfaces.ServerState; import mage.interfaces.callback.ClientCallback; +import mage.players.net.UserData; import mage.remote.MageVersionException; import mage.server.draft.CubeFactory; import mage.server.draft.DraftManager; @@ -83,7 +83,6 @@ import mage.view.MatchView; import mage.view.RoomUsersView; import mage.view.TableView; import mage.view.TournamentView; -import mage.view.UserDataView; import mage.view.UserView; import org.apache.commons.lang3.StringEscapeUtils; import org.apache.log4j.Logger; @@ -117,7 +116,7 @@ public class MageServerImpl implements MageServer { return SessionManager.getInstance().registerUser(sessionId, userName); } catch (MageException ex) { if (ex instanceof MageVersionException) { - throw (MageVersionException)ex; + throw (MageVersionException) ex; } handleException(ex); } @@ -125,11 +124,11 @@ public class MageServerImpl implements MageServer { } @Override - public boolean setUserData(final String userName, final String sessionId, final UserDataView userDataView) throws MageException { + public boolean setUserData(final String userName, final String sessionId, final UserData userData) throws MageException { return executeWithResult("setUserData", sessionId, new ActionWithBooleanResult() { @Override public Boolean execute() throws MageException { - return SessionManager.getInstance().setUserData(userName, sessionId, userDataView); + return SessionManager.getInstance().setUserData(userName, sessionId, userData); } }); } @@ -162,7 +161,7 @@ public class MageServerImpl implements MageServer { if (user != null) { logger.debug("TABLE created - tableId: " + table.getTableId() + " " + table.getTableName()); logger.debug("- " + user.getName() + " userId: " + user.getId()); - logger.debug("- chatId: " + TableManager.getInstance().getChatId(table.getTableId())); + logger.debug("- chatId: " + TableManager.getInstance().getChatId(table.getTableId())); } } LogServiceImpl.instance.log(LogKeys.KEY_TABLE_CREATED, sessionId, userId.toString(), table.getTableId().toString()); @@ -229,7 +228,7 @@ public class MageServerImpl implements MageServer { if (userId == null) { logger.fatal("Got no userId from sessionId" + sessionId + " tableId" + tableId); return false; - } + } boolean ret = GamesRoomManager.getInstance().getRoom(roomId).joinTable(userId, tableId, name, playerType, skill, deckList, password); return ret; } @@ -247,11 +246,11 @@ public class MageServerImpl implements MageServer { if (user != null) { logger.trace("join tourn. tableId: " + tableId + " " + name); } - } + } if (userId == null) { logger.fatal("Got no userId from sessionId" + sessionId + " tableId" + tableId); return false; - } + } boolean ret = GamesRoomManager.getInstance().getRoom(roomId).joinTournamentTable(userId, tableId, name, playerType, skill, deckList, password); return ret; } @@ -293,8 +292,7 @@ public class MageServerImpl implements MageServer { } else { return null; } - } - catch (Exception ex) { + } catch (Exception ex) { handleException(ex); } return null; @@ -310,8 +308,7 @@ public class MageServerImpl implements MageServer { } else { return null; } - } - catch (Exception ex) { + } catch (Exception ex) { handleException(ex); } return null; @@ -326,8 +323,7 @@ public class MageServerImpl implements MageServer { } else { return null; } - } - catch (Exception ex) { + } catch (Exception ex) { handleException(ex); } return null; @@ -343,8 +339,7 @@ public class MageServerImpl implements MageServer { } else { return null; } - } - catch (Exception ex) { + } catch (Exception ex) { handleException(ex); } return null; @@ -365,7 +360,6 @@ public class MageServerImpl implements MageServer { // } // }); // } - @Override public boolean startMatch(final String sessionId, final UUID roomId, final UUID tableId) throws MageException { if (!TableManager.getInstance().getController(tableId).changeTableState(TableState.STARTING)) { @@ -391,7 +385,6 @@ public class MageServerImpl implements MageServer { // } // }); // } - @Override public boolean startTournament(final String sessionId, final UUID roomId, final UUID tableId) throws MageException { if (!TableManager.getInstance().getController(tableId).changeTableState(TableState.STARTING)) { @@ -412,8 +405,7 @@ public class MageServerImpl implements MageServer { public TournamentView getTournament(UUID tournamentId) throws MageException { try { return TournamentManager.getInstance().getTournamentView(tournamentId); - } - catch (Exception ex) { + } catch (Exception ex) { handleException(ex); } return null; @@ -424,15 +416,14 @@ public class MageServerImpl implements MageServer { public void sendChatMessage(final UUID chatId, final String userName, final String message) throws MageException { try { callExecutor.execute( - new Runnable() { - @Override - public void run() { - ChatManager.getInstance().broadcast(chatId, userName, StringEscapeUtils.escapeHtml4(message), MessageColor.BLUE); + new Runnable() { + @Override + public void run() { + ChatManager.getInstance().broadcast(chatId, userName, StringEscapeUtils.escapeHtml4(message), MessageColor.BLUE); + } } - } ); - } - catch (Exception ex) { + } catch (Exception ex) { handleException(ex); } } @@ -464,8 +455,7 @@ public class MageServerImpl implements MageServer { public UUID getMainRoomId() throws MageException { try { return GamesRoomManager.getInstance().getMainRoomId(); - } - catch (Exception ex) { + } catch (Exception ex) { handleException(ex); } return null; @@ -476,8 +466,7 @@ public class MageServerImpl implements MageServer { public UUID getRoomChatId(UUID roomId) throws MageException { try { return GamesRoomManager.getInstance().getRoom(roomId).getChatId(); - } - catch (Exception ex) { + } catch (Exception ex) { handleException(ex); } return null; @@ -527,8 +516,7 @@ public class MageServerImpl implements MageServer { public UUID getTableChatId(UUID tableId) throws MageException { try { return TableManager.getInstance().getChatId(tableId); - } - catch (Exception ex) { + } catch (Exception ex) { handleException(ex); } return null; @@ -572,8 +560,7 @@ public class MageServerImpl implements MageServer { public UUID getGameChatId(UUID gameId) throws MageException { try { return GameManager.getInstance().getChatId(gameId); - } - catch (Exception ex) { + } catch (Exception ex) { handleException(ex); } return null; @@ -584,8 +571,7 @@ public class MageServerImpl implements MageServer { public UUID getTournamentChatId(UUID tournamentId) throws MageException { try { return TournamentManager.getInstance().getChatId(tournamentId); - } - catch (Exception ex) { + } catch (Exception ex) { handleException(ex); } return null; @@ -602,7 +588,7 @@ public class MageServerImpl implements MageServer { user.sendPlayerUUID(gameId, data); } else { logger.warn("Your session expired: gameId=" + gameId + ", sessionId=" + sessionId); - } + } } }); } @@ -617,7 +603,7 @@ public class MageServerImpl implements MageServer { user.sendPlayerString(gameId, data); } else { logger.warn("Your session expired: gameId=" + gameId + ", sessionId=" + sessionId); - } + } } }); } @@ -647,7 +633,7 @@ public class MageServerImpl implements MageServer { user.sendPlayerBoolean(gameId, data); } else { logger.warn("Your session expired: gameId=" + gameId + ", sessionId=" + sessionId); - } + } } }); } @@ -675,8 +661,8 @@ public class MageServerImpl implements MageServer { Session session = SessionManager.getInstance().getSession(sessionId); if (session != null) { return DraftManager.getInstance().sendCardPick(draftId, session.getUserId(), cardPick, hiddenCards); - } else{ - logger.error("Session not found sessionId: "+ sessionId + " draftId:" + draftId); + } else { + logger.error("Session not found sessionId: " + sessionId + " draftId:" + draftId); } return null; } @@ -691,8 +677,8 @@ public class MageServerImpl implements MageServer { Session session = SessionManager.getInstance().getSession(sessionId); if (session != null) { DraftManager.getInstance().sendCardMark(draftId, session.getUserId(), cardPick); - } else{ - logger.error("Session not found sessionId: "+ sessionId + " draftId:" + draftId); + } else { + logger.error("Session not found sessionId: " + sessionId + " draftId:" + draftId); } } }); @@ -706,8 +692,8 @@ public class MageServerImpl implements MageServer { Session session = SessionManager.getInstance().getSession(sessionId); if (session != null) { GameManager.getInstance().quitMatch(gameId, session.getUserId()); - } else{ - logger.error("Session not found sessionId: "+ sessionId + " gameId:" +gameId); + } else { + logger.error("Session not found sessionId: " + sessionId + " gameId:" + gameId); } } }); @@ -721,8 +707,8 @@ public class MageServerImpl implements MageServer { Session session = SessionManager.getInstance().getSession(sessionId); if (session != null) { TournamentManager.getInstance().quit(tournamentId, session.getUserId()); - }else{ - logger.error("Session not found sessionId: "+ sessionId + " tournamentId:" + tournamentId); + } else { + logger.error("Session not found sessionId: " + sessionId + " tournamentId:" + tournamentId); } } }); @@ -735,7 +721,7 @@ public class MageServerImpl implements MageServer { public void execute() { Session session = SessionManager.getInstance().getSession(sessionId); if (session == null) { - logger.error("Session not found sessionId: "+ sessionId + " draftId:" + draftId); + logger.error("Session not found sessionId: " + sessionId + " draftId:" + draftId); return; } UUID tableId = DraftManager.getInstance().getControllerByDraftId(draftId).getTableId(); @@ -755,14 +741,14 @@ public class MageServerImpl implements MageServer { public void execute() { Session session = SessionManager.getInstance().getSession(sessionId); if (session == null) { - logger.error("Session not found sessionId: "+ sessionId + " gameId:" + gameId); + logger.error("Session not found sessionId: " + sessionId + " gameId:" + gameId); return; } GameManager.getInstance().sendPlayerAction(playerAction, gameId, session.getUserId(), data); } }); } - + @Override public boolean watchTable(final String sessionId, final UUID roomId, final UUID tableId) throws MageException { return executeWithResult("setUserData", sessionId, new ActionWithBooleanResult() { @@ -893,8 +879,7 @@ public class MageServerImpl implements MageServer { CardRepository.instance.getContentVersionConstant(), ExpansionRepository.instance.getContentVersionConstant() ); - } - catch (Exception ex) { + } catch (Exception ex) { handleException(ex); } return null; @@ -925,7 +910,7 @@ public class MageServerImpl implements MageServer { return false; } }); - } + } public void handleException(Exception ex) throws MageException { if (!ex.getMessage().equals("No message")) { @@ -936,12 +921,12 @@ public class MageServerImpl implements MageServer { @Override public GameView getGameView(final UUID gameId, final String sessionId, final UUID playerId) throws MageException { - return executeWithResult("getGameView", sessionId, new ActionWithNullNegativeResult() { - @Override - public GameView execute() throws MageException { - UUID userId = SessionManager.getInstance().getSession(sessionId).getUserId(); - return GameManager.getInstance().getGameView(gameId, userId, playerId); - } + return executeWithResult("getGameView", sessionId, new ActionWithNullNegativeResult() { + @Override + public GameView execute() throws MageException { + UUID userId = SessionManager.getInstance().getSession(sessionId).getUserId(); + return GameManager.getInstance().getGameView(gameId, userId, playerId); + } }); } @@ -988,11 +973,11 @@ public class MageServerImpl implements MageServer { } /** - * Admin console - Remove table - * + * Admin console - Remove table + * * @param sessionId * @param tableId - * @throws MageException + * @throws MageException */ @Override public void removeTable(final String sessionId, final UUID tableId) throws MageException { @@ -1009,9 +994,9 @@ public class MageServerImpl implements MageServer { public Object getServerMessagesCompressed(String sessionId) throws MageException { return executeWithResult("getGameView", sessionId, new ActionWithNullNegativeResult() { @Override - public Object execute() throws MageException { - return CompressUtil.compress(ServerMessagesUtil.getInstance().getMessages()); - } + public Object execute() throws MageException { + return CompressUtil.compress(ServerMessagesUtil.getInstance().getMessages()); + } }); } @@ -1028,7 +1013,7 @@ public class MageServerImpl implements MageServer { }); } } - + @Override public void sendBroadcastMessage(final String sessionId, final String message) throws MageException { if (message != null) { @@ -1061,23 +1046,22 @@ public class MageServerImpl implements MageServer { if (SessionManager.getInstance().isValidSession(sessionId)) { try { callExecutor.execute( - new Runnable() { - @Override - public void run() { - if (SessionManager.getInstance().isValidSession(sessionId)) { - try { - action.execute(); - } catch (MageException me) { - throw new RuntimeException(me); + new Runnable() { + @Override + public void run() { + if (SessionManager.getInstance().isValidSession(sessionId)) { + try { + action.execute(); + } catch (MageException me) { + throw new RuntimeException(me); + } + } else { + LogServiceImpl.instance.log(LogKeys.KEY_NOT_VALID_SESSION_INTERNAL, actionName, sessionId); } - } else { - LogServiceImpl.instance.log(LogKeys.KEY_NOT_VALID_SESSION_INTERNAL, actionName, sessionId); } } - } ); - } - catch (Exception ex) { + } catch (Exception ex) { handleException(ex); } } else { diff --git a/Mage.Server/src/main/java/mage/server/Session.java b/Mage.Server/src/main/java/mage/server/Session.java index 5bfe452d51c..d3d2bc5aa10 100644 --- a/Mage.Server/src/main/java/mage/server/Session.java +++ b/Mage.Server/src/main/java/mage/server/Session.java @@ -1,31 +1,30 @@ /* -* 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. -*/ - + * 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.server; import java.util.Date; @@ -42,7 +41,6 @@ import mage.players.net.UserData; import mage.players.net.UserGroup; import mage.server.game.GamesRoomManager; import mage.server.util.ConfigSettings; -import mage.view.UserDataView; import org.apache.log4j.Logger; import org.jboss.remoting.callback.AsynchInvokerCallbackHandler; import org.jboss.remoting.callback.Callback; @@ -124,7 +122,7 @@ public class Session { } if (!UserManager.getInstance().connectToSession(sessionId, user.getId())) { return new StringBuilder("Error connecting ").append(userName).toString(); - } + } this.userId = user.getId(); if (reconnect) { // must be connected to receive the message UUID chatId = GamesRoomManager.getInstance().getRoom(GamesRoomManager.getInstance().getMainRoomId()).getChatId(); @@ -132,7 +130,7 @@ public class Session { ChatManager.getInstance().joinChat(chatId, userId); } ChatManager.getInstance().sendReconnectMessage(userId); - } + } return null; } @@ -144,75 +142,45 @@ public class Session { } user.setUserData(new UserData(UserGroup.ADMIN, 0, false, false, false, null, "world.png", false)); if (!UserManager.getInstance().connectToSession(sessionId, user.getId())) { - logger.info("Error connecting Admin!"); - } + logger.info("Error connecting Admin!"); + } this.userId = user.getId(); } - public boolean setUserData(String userName, UserDataView userDataView) { + public boolean setUserData(String userName, UserData userData) { User user = UserManager.getInstance().findUser(userName); if (user != null) { - UserData userData = user.getUserData(); - if (userData == null) { - userData = new UserData(UserGroup.PLAYER, userDataView.getAvatarId(), - userDataView.isShowAbilityPickerForced(), userDataView.allowRequestShowHandCards(), - userDataView.confirmEmptyManaPool(), userDataView.getUserSkipPrioritySteps(), - userDataView.getFlagName(), userDataView.askMoveToGraveOrder()); + if (user.getUserData() == null || user.getUserData().getGroupId() == UserGroup.DEFAULT.getGroupId()) { user.setUserData(userData); } else { - if (userDataView.getAvatarId() == 51) { // Update special avatar if first avatar is selected - updateAvatar(userName, userData); - } - userData.setAvatarId(userDataView.getAvatarId()); - userData.setShowAbilityPickerForced(userDataView.isShowAbilityPickerForced()); - userData.setAllowRequestShowHandCards(userDataView.allowRequestShowHandCards()); - userData.setUserSkipPrioritySteps(userDataView.getUserSkipPrioritySteps()); - userData.setConfirmEmptyManaPool(userDataView.confirmEmptyManaPool()); - userData.setAskMoveToGraveOrder(userDataView.askMoveToGraveOrder()); + user.getUserData().update(userData); + } + if (user.getUserData().getAvatarId() == 51) { + user.getUserData().setAvatarId(updateAvatar(user.getName())); } return true; } return false; } - private void updateAvatar(String userName, UserData userData) { + private int updateAvatar(String userName) { //TODO: move to separate class //TODO: add for checking for private key switch (userName) { case "nantuko": - userData.setAvatarId(1000); - break; - case "i_no_k": - userData.setAvatarId(1002); - break; - case "Askael": - userData.setAvatarId(1004); - break; + return 1000; case "North": - userData.setAvatarId(1006); - break; + return 1006; case "BetaSteward": - userData.setAvatarId(1008); - break; - case "Arching": - userData.setAvatarId(1010); - break; + return 1008; case "loki": - userData.setAvatarId(1012); - break; - case "Alive": - userData.setAvatarId(1014); - break; - case "Rahan": - userData.setAvatarId(1016); - break; + return 1012; case "Ayrat": - userData.setAvatarId(1018); - break; + return 1018; case "Bandit": - userData.setAvatarId(1020); - break; + return 1020; } + return 51; } public String getId() { @@ -220,10 +188,10 @@ public class Session { } // because different threads can activate this - public void userLostConnection() { + public void userLostConnection() { boolean lockSet = false; try { - if(lock.tryLock(5000, TimeUnit.MILLISECONDS)) { + if (lock.tryLock(5000, TimeUnit.MILLISECONDS)) { lockSet = true; logger.debug("SESSION LOCK SET sessionId: " + sessionId); } else { @@ -243,9 +211,8 @@ public class Session { } catch (InterruptedException ex) { logger.error("SESSION LOCK lost connection - userId: " + userId, ex); - } - finally { - if (lockSet) { + } finally { + if (lockSet) { lock.unlock(); logger.trace("SESSION LOCK UNLOCK sessionId: " + sessionId); } @@ -256,18 +223,17 @@ public class Session { public void kill(DisconnectReason reason) { boolean lockSet = false; try { - if(lock.tryLock(5000, TimeUnit.MILLISECONDS)) { + if (lock.tryLock(5000, TimeUnit.MILLISECONDS)) { lockSet = true; - logger.debug("SESSION LOCK SET sessionId: " + sessionId); + logger.debug("SESSION LOCK SET sessionId: " + sessionId); } else { logger.error("SESSION LOCK - kill: userId " + userId); } UserManager.getInstance().removeUser(userId, reason); } catch (InterruptedException ex) { logger.error("SESSION LOCK - kill: userId " + userId, ex); - } - finally { - if (lockSet) { + } finally { + if (lockSet) { lock.unlock(); logger.debug("SESSION LOCK UNLOCK sessionId: " + sessionId); @@ -282,7 +248,7 @@ public class Session { callbackHandler.handleCallbackOneway(new Callback(call)); } catch (HandleCallbackException ex) { User user = UserManager.getInstance().getUser(userId); - logger.warn("SESSION CALLBACK EXCEPTION - " + (user != null ? user.getName():"") + " userId " + userId); + logger.warn("SESSION CALLBACK EXCEPTION - " + (user != null ? user.getName() : "") + " userId " + userId); logger.warn(" - method: " + call.getMethod()); logger.warn(" - cause: " + getBasicCause(ex).toString()); logger.trace("Stack trace:", ex); diff --git a/Mage.Server/src/main/java/mage/server/SessionManager.java b/Mage.Server/src/main/java/mage/server/SessionManager.java index 2bf3e9e4fc7..d7a6db388e2 100644 --- a/Mage.Server/src/main/java/mage/server/SessionManager.java +++ b/Mage.Server/src/main/java/mage/server/SessionManager.java @@ -31,9 +31,9 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import mage.MageException; +import mage.players.net.UserData; import mage.server.services.LogKeys; import mage.server.services.impl.LogServiceImpl; -import mage.view.UserDataView; import org.apache.log4j.Logger; import org.jboss.remoting.callback.InvokerCallbackHandler; @@ -73,7 +73,7 @@ public class SessionManager { public boolean registerUser(String sessionId, String userName) throws MageException { Session session = sessions.get(sessionId); if (session != null) { - String returnMessage = session.registerUser(userName); + String returnMessage = session.registerUser(userName); if (returnMessage == null) { LogServiceImpl.instance.log(LogKeys.KEY_USER_CONNECTED, userName, session.getHost(), sessionId); @@ -102,24 +102,24 @@ public class SessionManager { return false; } - public boolean setUserData(String userName, String sessionId, UserDataView userDataView) throws MageException { + public boolean setUserData(String userName, String sessionId, UserData userData) throws MageException { Session session = sessions.get(sessionId); if (session != null) { - session.setUserData(userName, userDataView); + session.setUserData(userName, userData); return true; } return false; } public void disconnect(String sessionId, DisconnectReason reason) { - Session session = sessions.get(sessionId); + Session session = sessions.get(sessionId); if (session != null) { if (!reason.equals(DisconnectReason.AdminDisconnect)) { if (!sessions.containsKey(sessionId)) { // session was removed meanwhile by another thread so we can return return; } - logger.debug("DISCONNECT " + reason.toString() + " - sessionId: "+ sessionId); + logger.debug("DISCONNECT " + reason.toString() + " - sessionId: " + sessionId); sessions.remove(sessionId); switch (reason) { case Disconnected: @@ -135,13 +135,13 @@ public class SessionManager { LogServiceImpl.instance.log(LogKeys.KEY_SESSION_DISCONNECTED, sessionId); break; default: - logger.error("endSession: unexpected reason " + reason.toString() + " - sessionId: "+ sessionId); + logger.error("endSession: unexpected reason " + reason.toString() + " - sessionId: " + sessionId); } } else { sessions.remove(sessionId); session.kill(reason); } - } + } } @@ -155,6 +155,7 @@ public class SessionManager { /** * Admin requested the disconnect of a user + * * @param sessionId * @param userSessionId */ @@ -163,12 +164,12 @@ public class SessionManager { User userAdmin, user; if ((userAdmin = getUserFromSession(sessionId)) != null) { if ((user = getUserFromSession(userSessionId)) != null) { - user.showUserMessage("Admin operation","Your session was disconnected by Admin."); + user.showUserMessage("Admin operation", "Your session was disconnected by Admin."); userAdmin.showUserMessage("Admin action", "User" + user.getName() + " was disconnected."); disconnect(userSessionId, DisconnectReason.AdminDisconnect); LogServiceImpl.instance.log(LogKeys.KEY_SESSION_DISCONNECTED_BY_ADMIN, sessionId, userSessionId); } else { - userAdmin.showUserMessage("Admin operation","User with sessionId " + userSessionId + " could not be found!"); + userAdmin.showUserMessage("Admin operation", "User with sessionId " + userSessionId + " could not be found!"); } } } @@ -203,7 +204,7 @@ public class SessionManager { public User getUser(String sessionId) { Session session = sessions.get(sessionId); - if (session != null) { + if (session != null) { return UserManager.getInstance().getUser(sessions.get(sessionId).getUserId()); } return null; diff --git a/Mage.Server/src/main/java/mage/server/TableController.java b/Mage.Server/src/main/java/mage/server/TableController.java index 4e5eceec45e..be401c7ffe8 100644 --- a/Mage.Server/src/main/java/mage/server/TableController.java +++ b/Mage.Server/src/main/java/mage/server/TableController.java @@ -1,31 +1,30 @@ /* -* 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. -*/ - + * 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.server; import java.util.Map; @@ -91,7 +90,7 @@ public class TableController { private Match match; private MatchOptions options; private Tournament tournament; - + private ScheduledFuture futureTimeout; protected static ScheduledExecutorService timeoutExecutor = ThreadExecutor.getInstance().getTimeoutExecutor(); @@ -103,12 +102,11 @@ public class TableController { User user = UserManager.getInstance().getUser(userId); // TODO: Handle if user == null controllerName = user.getName(); - } - else { + } else { controllerName = "System"; } table = new Table(roomId, options.getGameType(), options.getName(), controllerName, DeckValidatorFactory.getInstance().createDeckValidator(options.getDeckType()), options.getPlayerTypes(), match); - chatId = ChatManager.getInstance().createChatSession("Match Table " + table.getId()); + chatId = ChatManager.getInstance().createChatSession("Match Table " + table.getId()); init(); } @@ -123,30 +121,29 @@ public class TableController { } else { controllerName = user.getName(); } - } - else { + } else { controllerName = "System"; } table = new Table(roomId, options.getTournamentType(), options.getName(), controllerName, DeckValidatorFactory.getInstance().createDeckValidator(options.getMatchOptions().getDeckType()), options.getPlayerTypes(), tournament); - chatId = ChatManager.getInstance().createChatSession("Tourn. table " + table.getId()); + chatId = ChatManager.getInstance().createChatSession("Tourn. table " + table.getId()); } private void init() { match.addTableEventListener( - new Listener () { - @Override - public void event(TableEvent event) { - try { - switch (event.getEventType()) { - case SIDEBOARD: - sideboard(event.getPlayerId(), event.getDeck()); - break; + new Listener() { + @Override + public void event(TableEvent event) { + try { + switch (event.getEventType()) { + case SIDEBOARD: + sideboard(event.getPlayerId(), event.getDeck()); + break; + } + } catch (MageException ex) { + logger.fatal("Table event listener error", ex); } - } catch (MageException ex) { - logger.fatal("Table event listener error", ex); } } - } ); } @@ -171,13 +168,13 @@ public class TableController { return false; } } - if (userPlayerMap.containsKey(userId) && playerType.equals("Human")){ + if (userPlayerMap.containsKey(userId) && playerType.equals("Human")) { user.showUserMessage("Join Table", new StringBuilder("You can join a table only one time.").toString()); return false; } Deck deck = null; if (!table.getTournament().getTournamentType().isLimited()) { - if (deckList != null) { + if (deckList != null) { deck = Deck.load(deckList, false, false); } else { user.showUserMessage("Join Table", "No valid deck selected!"); @@ -208,9 +205,9 @@ public class TableController { TournamentPlayer tournamentPlayer = tournament.getPlayer(player.getId()); if (deck != null && tournamentPlayer != null) { tournamentPlayer.submitDeck(deck); - } - table.joinTable(player, seat); - logger.debug("Player " + player.getName() + " id: "+ player.getId() + " joined tableId: " + table.getId()); + } + table.joinTable(player, seat); + logger.debug("Player " + player.getName() + " id: " + player.getId() + " joined tableId: " + table.getId()); //only inform human players and add them to sessionPlayerMap if (seat.getPlayer().isHuman()) { seat.getPlayer().setUserData(user.getUserData()); @@ -235,12 +232,12 @@ public class TableController { return false; } TournamentPlayer oldTournamentPlayer = tournament.getPlayer(oldPlayer.getId()); - tournament.removePlayer(oldPlayer.getId()); + tournament.removePlayer(oldPlayer.getId()); tournament.addPlayer(newPlayer, playerType); - TournamentPlayer newTournamentPlayer = tournament.getPlayer(newPlayer.getId()); + TournamentPlayer newTournamentPlayer = tournament.getPlayer(newPlayer.getId()); newTournamentPlayer.setState(oldTournamentPlayer.getState()); - + DraftManager.getInstance().getController(table.getId()).replacePlayer(oldPlayer, newPlayer); return true; } @@ -250,7 +247,7 @@ public class TableController { if (user == null) { return false; } - if (userPlayerMap.containsKey(userId) && playerType.equals("Human")){ + if (userPlayerMap.containsKey(userId) && playerType.equals("Human")) { user.showUserMessage("Join Table", new StringBuilder("You can join a table only one time.").toString()); return false; } @@ -289,7 +286,7 @@ public class TableController { if (player == null) { String message = new StringBuilder("Could not create player ").append(name).append(" of type ").append(seat.getPlayerType()).toString(); logger.warn(new StringBuilder("User: ").append(user.getName()).append(" => ").append(message).toString()); - user.showUserMessage("Join Table",message); + user.showUserMessage("Join Table", message); return false; } logger.debug("DECK validated: " + table.getValidator().getName() + " " + player.getName() + " " + deck.getName()); @@ -312,7 +309,7 @@ public class TableController { return true; } - public void addPlayer(UUID userId, Player player, String playerType, Deck deck) throws GameException { + public void addPlayer(UUID userId, Player player, String playerType, Deck deck) throws GameException { if (table.getState() != TableState.WAITING) { return; } @@ -378,8 +375,7 @@ public class TableController { if (table.getState() == TableState.SIDEBOARDING) { match.submitDeck(playerId, deck); UserManager.getInstance().getUser(userId).removeSideboarding(table.getId()); - } - else { + } else { TournamentManager.getInstance().submitDeck(tournament.getId(), playerId, deck); UserManager.getInstance().getUser(userId).removeConstructing(playerId); } @@ -390,7 +386,7 @@ public class TableController { if (tournament != null) { TournamentManager.getInstance().updateDeck(tournament.getId(), playerId, deck); } else { - logger.fatal("Tournament == null table: " + table.getId() +" userId: " + userId); + logger.fatal("Tournament == null table: " + table.getId() + " userId: " + userId); } } else { if (TableState.SIDEBOARDING.equals(table.getState())) { @@ -427,13 +423,11 @@ public class TableController { // ReplayManager.getInstance().replayGame(table.getId(), userId); // return true; // } - private Player createPlayer(String name, String playerType, int skill) { Player player; if (options == null) { player = PlayerFactory.getInstance().createPlayer(playerType, name, RangeOfInfluence.ALL, skill); - } - else { + } else { player = PlayerFactory.getInstance().createPlayer(playerType, name, options.getRange(), skill); } if (player != null) { @@ -443,12 +437,12 @@ public class TableController { } public void leaveTableAll() { - for (UUID leavingUserId: userPlayerMap.keySet()) { + for (UUID leavingUserId : userPlayerMap.keySet()) { leaveTable(leavingUserId); } closeTable(); } - + public synchronized void leaveTable(UUID userId) { if (table == null) { logger.error("No table object - userId: " + userId); @@ -488,19 +482,19 @@ public class TableController { if (table.isTournament()) { logger.debug("Quit tournament sub tables for userId: " + userId); TableManager.getInstance().userQuitTournamentSubTables(tournament.getId(), userId); - logger.debug("Quit tournament Id: " + table.getTournament().getId() + "(" +table.getTournament().getTournamentState() + ")"); + logger.debug("Quit tournament Id: " + table.getTournament().getId() + "(" + table.getTournament().getTournamentState() + ")"); TournamentManager.getInstance().quit(tournament.getId(), userId); } else { MatchPlayer matchPlayer = match.getPlayer(playerId); if (matchPlayer != null && !match.hasEnded() && !matchPlayer.hasQuit()) { Game game = match.getGame(); - if (game != null && !game.hasEnded()){ + if (game != null && !game.hasEnded()) { Player player = match.getPlayer(playerId).getPlayer(); if (player != null && player.isInGame()) { GameManager.getInstance().quitMatch(game.getId(), userId); } match.quitMatch(playerId); - } else { + } else { if (table.getState().equals(TableState.SIDEBOARDING)) { if (!matchPlayer.isDoneSideboarding()) { // submit deck to finish sideboarding and trigger match start / end @@ -520,7 +514,7 @@ public class TableController { /** * Used from non tournament match to start - * + * * @param userId owner of the tabel */ public synchronized void startMatch(UUID userId) { @@ -536,7 +530,7 @@ public class TableController { logger.info("Tourn. match started id:" + match.getId() + " tournId: " + table.getTournament().getId()); } else { User user = UserManager.getInstance().getUser(userId); - logger.info("MATCH started [" + match.getName() + "] " + match.getId() + "(" + user.getName() +")"); + logger.info("MATCH started [" + match.getName() + "] " + match.getId() + "(" + user.getName() + ")"); logger.debug("- " + match.getOptions().getGameType() + " - " + match.getOptions().getDeckType()); } match.startMatch(); @@ -558,12 +552,12 @@ public class TableController { GameManager.getInstance().createGameSession(match.getGame(), userPlayerMap, table.getId(), choosingPlayerId, gameOptions); String creator = null; StringBuilder opponent = new StringBuilder(); - for (Entry entry: userPlayerMap.entrySet()) { // no AI players + for (Entry entry : userPlayerMap.entrySet()) { // no AI players if (!match.getPlayer(entry.getValue()).hasQuit()) { User user = UserManager.getInstance().getUser(entry.getKey()); if (user != null) { user.ccGameStarted(match.getGame().getId(), entry.getValue()); - + if (creator == null) { creator = user.getName(); } else { @@ -582,7 +576,7 @@ public class TableController { } } // Append AI opponents to the log file - for (MatchPlayer mPlayer :match.getPlayers()) { + for (MatchPlayer mPlayer : match.getPlayers()) { if (!mPlayer.getPlayer().isHuman()) { if (opponent.length() > 0) { opponent.append(" - "); @@ -592,9 +586,8 @@ public class TableController { } ServerMessagesUtil.getInstance().incGamesStarted(); - // log about game started - logger.info("GAME started " + match.getGame().getId() + " [" + match.getName() +"] "+ creator + " - " + opponent.toString()); + logger.info("GAME started " + match.getGame().getId() + " [" + match.getName() + "] " + creator + " - " + opponent.toString()); logger.debug("- matchId: " + match.getId() + " [" + match.getName() + "]"); if (match.getGame() != null) { logger.debug("- chatId: " + GameManager.getInstance().getChatId(match.getGame().getId())); @@ -602,8 +595,7 @@ public class TableController { logger.debug("- no valid game object"); } LogServiceImpl.instance.log(LogKeys.KEY_GAME_STARTED, String.valueOf(userPlayerMap.size()), creator, opponent.toString()); - } - catch (Exception ex) { + } catch (Exception ex) { logger.fatal("Error starting game", ex); if (table != null) { TableManager.getInstance().removeTable(table.getId()); @@ -618,11 +610,11 @@ public class TableController { } public synchronized void startTournament(UUID userId) { - try { + try { if (userId.equals(this.userId) && table.getState().equals(TableState.STARTING)) { tournament.setStartTime(); TournamentManager.getInstance().createTournamentSession(tournament, userPlayerMap, table.getId()); - for (Entry entry: userPlayerMap.entrySet()) { + for (Entry entry : userPlayerMap.entrySet()) { User user = UserManager.getInstance().getUser(entry.getKey()); if (user != null) { logger.info(new StringBuilder("User ").append(user.getName()).append(" tournament started: ").append(tournament.getId()).append(" userId: ").append(user.getId())); @@ -631,8 +623,7 @@ public class TableController { } ServerMessagesUtil.getInstance().incTournamentsStarted(); } - } - catch (Exception ex) { + } catch (Exception ex) { logger.fatal("Error starting tournament", ex); TableManager.getInstance().removeTable(table.getId()); TournamentManager.getInstance().quit(tournament.getId(), userId); @@ -642,7 +633,7 @@ public class TableController { public void startDraft(Draft draft) { table.initDraft(); DraftManager.getInstance().createDraftSession(draft, userPlayerMap, table.getId()); - for (Entry entry: userPlayerMap.entrySet()) { + for (Entry entry : userPlayerMap.entrySet()) { User user = UserManager.getInstance().getUser(entry.getKey()); if (user != null) { logger.info(new StringBuilder("User ").append(user.getName()).append(" draft started: ").append(draft.getId()).append(" userId: ").append(user.getId())); @@ -654,7 +645,7 @@ public class TableController { } private void sideboard(UUID playerId, Deck deck) throws MageException { - for (Entry entry: userPlayerMap.entrySet()) { + for (Entry entry : userPlayerMap.entrySet()) { if (entry.getValue().equals(playerId)) { User user = UserManager.getInstance().getUser(entry.getKey()); int remaining = (int) futureTimeout.getDelay(TimeUnit.SECONDS); @@ -668,7 +659,7 @@ public class TableController { public int getRemainingTime() { return (int) futureTimeout.getDelay(TimeUnit.SECONDS); - } + } public void construct() { table.construct(); @@ -715,8 +706,7 @@ public class TableController { } else { closeTable(); } - } - else { + } else { closeTable(); } } catch (GameException ex) { @@ -729,7 +719,7 @@ public class TableController { table.sideboard(); setupTimeout(Match.SIDEBOARD_TIME); if (table.isTournamentSubTable()) { - for (MatchPlayer matchPlayer :match.getPlayers()) { + for (MatchPlayer matchPlayer : match.getPlayers()) { if (!matchPlayer.hasQuit()) { TournamentPlayer tournamentPlayer = table.getTournament().getPlayer(matchPlayer.getPlayer().getId()); if (tournamentPlayer != null) { @@ -741,7 +731,7 @@ public class TableController { match.sideboard(); cancelTimeout(); if (table.isTournamentSubTable()) { - for (MatchPlayer matchPlayer :match.getPlayers()) { + for (MatchPlayer matchPlayer : match.getPlayers()) { TournamentPlayer tournamentPlayer = table.getTournament().getPlayer(matchPlayer.getPlayer().getId()); if (tournamentPlayer != null && tournamentPlayer.getStateInfo().equals("sideboarding")) { tournamentPlayer.setStateInfo(""); @@ -749,10 +739,11 @@ public class TableController { } } } + /** - * Tables of normal matches or tournament sub tables are no longer - * needed, if the match ends. - * + * Tables of normal matches or tournament sub tables are no longer needed, + * if the match ends. + * */ private void closeTable() { this.matchEnd(); @@ -761,11 +752,11 @@ public class TableController { private void matchEnd() { if (match != null) { - for (Entry entry: userPlayerMap.entrySet()) { + for (Entry entry : userPlayerMap.entrySet()) { MatchPlayer matchPlayer = match.getPlayer(entry.getValue()); // opponent(s) left during sideboarding if (matchPlayer != null) { - if(!matchPlayer.hasQuit()) { + if (!matchPlayer.hasQuit()) { User user = UserManager.getInstance().getUser(entry.getKey()); if (user != null) { if (table.getState().equals(TableState.SIDEBOARDING)) { @@ -801,13 +792,13 @@ public class TableController { cancelTimeout(); if (seconds > 0) { futureTimeout = timeoutExecutor.schedule( - new Runnable() { - @Override - public void run() { - autoSideboard(); - } - }, - seconds, TimeUnit.SECONDS + new Runnable() { + @Override + public void run() { + autoSideboard(); + } + }, + seconds, TimeUnit.SECONDS ); } } @@ -819,7 +810,7 @@ public class TableController { } private void autoSideboard() { - for (MatchPlayer player: match.getPlayers()) { + for (MatchPlayer player : match.getPlayers()) { if (!player.isDoneSideboarding()) { match.submitDeck(player.getPlayer().getId(), player.generateDeck()); } @@ -828,7 +819,7 @@ public class TableController { public void endDraft(Draft draft) { if (!draft.isAbort()) { - for (DraftPlayer player: draft.getPlayers()) { + for (DraftPlayer player : draft.getPlayers()) { player.prepareDeck(); tournament.getPlayer(player.getPlayer().getId()).setDeck(player.getDeck()); } @@ -871,7 +862,7 @@ public class TableController { public boolean isTournamentStillValid() { if (table.getTournament() != null) { - if (!table.getState().equals(TableState.WAITING) && !table.getState().equals(TableState.READY_TO_START) && !table.getState().equals(TableState.STARTING) ) { + if (!table.getState().equals(TableState.WAITING) && !table.getState().equals(TableState.READY_TO_START) && !table.getState().equals(TableState.STARTING)) { TournamentController tournamentController = TournamentManager.getInstance().getTournamentController(table.getTournament().getId()); if (tournamentController != null) { return tournamentController.isTournamentStillValid(table.getState()); @@ -888,7 +879,7 @@ public class TableController { } public UUID getUserId(UUID playerId) { - for (Map.Entry entry: userPlayerMap.entrySet()) { + for (Map.Entry entry : userPlayerMap.entrySet()) { if (entry.getValue().equals(playerId)) { return entry.getKey(); } @@ -900,7 +891,7 @@ public class TableController { // check only normal match table with state != Finished if (!table.isTournament()) { int humanPlayers = 0; - int aiPlayers = 0 ; + int aiPlayers = 0; int validHumanPlayers = 0; if (!(table.getState().equals(TableState.WAITING) || table.getState().equals(TableState.STARTING) || table.getState().equals(TableState.READY_TO_START))) { if (match == null) { @@ -917,7 +908,7 @@ public class TableController { } } // check for active players - for(Map.Entry userPlayerEntry: userPlayerMap.entrySet()) { + for (Map.Entry userPlayerEntry : userPlayerMap.entrySet()) { MatchPlayer matchPlayer = match.getPlayer(userPlayerEntry.getValue()); if (matchPlayer == null) { logger.debug("- Match player not found:"); @@ -927,12 +918,12 @@ public class TableController { continue; } if (matchPlayer.getPlayer().isHuman()) { - humanPlayers++; - if ((table.getState().equals(TableState.WAITING) || - table.getState().equals(TableState.STARTING) || - table.getState().equals(TableState.READY_TO_START)) || - !match.isDoneSideboarding() || - (!matchPlayer.hasQuit() && match.getGame() != null && matchPlayer.getPlayer().isInGame())) { + humanPlayers++; + if ((table.getState().equals(TableState.WAITING) + || table.getState().equals(TableState.STARTING) + || table.getState().equals(TableState.READY_TO_START)) + || !match.isDoneSideboarding() + || (!matchPlayer.hasQuit() && match.getGame() != null && matchPlayer.getPlayer().isInGame())) { User user = UserManager.getInstance().getUser(userPlayerEntry.getKey()); if (user == null) { logger.debug("- Active user of match is missing: " + matchPlayer.getName()); @@ -953,10 +944,10 @@ public class TableController { } return true; } - + void cleanUp() { if (!table.isTournamentSubTable()) { - for(Map.Entry entry: userPlayerMap.entrySet()) { + for (Map.Entry entry : userPlayerMap.entrySet()) { User user = UserManager.getInstance().getUser(entry.getKey()); if (user != null) { user.removeTable(entry.getValue()); @@ -969,11 +960,11 @@ public class TableController { public synchronized TableState getTableState() { return getTable().getState(); } - + public synchronized boolean changeTableState(TableState newTableState) { switch (newTableState) { case WAITING: - if (getTable().getState().equals(TableState.STARTING)){ + if (getTable().getState().equals(TableState.STARTING)) { // tournament already started return false; } diff --git a/Mage.Server/src/main/java/mage/server/User.java b/Mage.Server/src/main/java/mage/server/User.java index 183e0704ca9..b8003da32d0 100644 --- a/Mage.Server/src/main/java/mage/server/User.java +++ b/Mage.Server/src/main/java/mage/server/User.java @@ -1,16 +1,16 @@ /* * Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,7 +20,7 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. @@ -43,6 +43,7 @@ import mage.game.Table; import mage.game.tournament.TournamentPlayer; import mage.interfaces.callback.ClientCallback; import mage.players.net.UserData; +import mage.players.net.UserGroup; import mage.server.draft.DraftSession; import mage.server.game.GameManager; import mage.server.game.GameSessionPlayer; @@ -53,7 +54,6 @@ import mage.server.util.SystemUtil; import mage.view.TableClientMessage; import org.apache.log4j.Logger; - /** * * @author BetaSteward_at_googlemail.com @@ -63,12 +63,13 @@ public class User { private static final Logger logger = Logger.getLogger(User.class); public enum UserState { + Created, Connected, Disconnected, Reconnected, Expired; } private final UUID userId; - private final String userName; - private final String host; + private final String userName; + private final String host; private final Date connectionTime; private final Map tables; private final ArrayList tablesToDelete; @@ -90,10 +91,10 @@ public class User { this.userName = userName; this.host = host; this.userState = UserState.Created; - + this.connectionTime = new Date(); this.lastActivity = new Date(); - + this.tables = new ConcurrentHashMap<>(); this.gameSessions = new ConcurrentHashMap<>(); this.draftSessions = new ConcurrentHashMap<>(); @@ -155,16 +156,16 @@ public class User { long secondsDisconnected = getSecondsDisconnected(); long secondsLeft; String sign = ""; - if (secondsDisconnected > (3 * 60)) { - sign="-"; - secondsLeft = secondsDisconnected - (3 *60); + if (secondsDisconnected > (3 * 60)) { + sign = "-"; + secondsLeft = secondsDisconnected - (3 * 60); } else { - secondsLeft = (3 * 60) - secondsDisconnected; + secondsLeft = (3 * 60) - secondsDisconnected; } int minutes = (int) secondsLeft / 60; int seconds = (int) secondsLeft % 60; - return new StringBuilder(sign).append(Integer.toString(minutes)).append(":").append(seconds > 9 ? seconds: "0" + Integer.toString(seconds)).toString(); + return new StringBuilder(sign).append(Integer.toString(minutes)).append(":").append(seconds > 9 ? seconds : "0" + Integer.toString(seconds)).toString(); } public long getSecondsDisconnected() { @@ -217,11 +218,11 @@ public class User { fireCallback(new ClientCallback("showGameEndDialog", gameId)); } - public void showUserMessage(final String titel, String message) { + public void showUserMessage(final String titel, String message) { List messageData = new LinkedList<>(); messageData.add(titel); messageData.add(message); - fireCallback(new ClientCallback("showUserMessage", null, messageData )); + fireCallback(new ClientCallback("showUserMessage", null, messageData)); } public boolean ccWatchGame(final UUID gameId) { @@ -248,7 +249,7 @@ public class User { GameManager.getInstance().sendPlayerManaType(gameId, playerId, userId, data); } - public void sendPlayerBoolean(final UUID gameId, final Boolean data) { + public void sendPlayerBoolean(final UUID gameId, final Boolean data) { lastActivity = new Date(); GameManager.getInstance().sendPlayerBoolean(gameId, userId, data); } @@ -275,14 +276,15 @@ public class User { return true; } logger.trace(new StringBuilder("isExpired: User ").append(userName).append(" lastActivity: ").append(lastActivity).append(" expired: ").append(expired).toString()); - return false; /*userState == UserState.Disconnected && */ + return false; /*userState == UserState.Disconnected && */ + } private void reconnect() { - for (Entry entry: tables.entrySet()) { + for (Entry entry : tables.entrySet()) { ccJoinedTable(entry.getValue().getRoomId(), entry.getValue().getId(), entry.getValue().isTournament()); } - for (Entry entry: userTournaments.entrySet()) { + for (Entry entry : userTournaments.entrySet()) { TournamentController tournamentController = TournamentManager.getInstance().getTournamentController(entry.getValue()); if (tournamentController != null) { ccTournamentStarted(entry.getValue(), entry.getKey()); @@ -290,22 +292,22 @@ public class User { } } - for (Entry entry: gameSessions.entrySet()) { + for (Entry entry : gameSessions.entrySet()) { ccGameStarted(entry.getValue().getGameId(), entry.getKey()); entry.getValue().init(); GameManager.getInstance().sendPlayerString(entry.getValue().getGameId(), userId, ""); } - for (Entry entry: draftSessions.entrySet()) { + for (Entry entry : draftSessions.entrySet()) { ccDraftStarted(entry.getValue().getDraftId(), entry.getKey()); entry.getValue().init(); entry.getValue().update(); } - - for (Entry entry: constructing.entrySet()) { + + for (Entry entry : constructing.entrySet()) { entry.getValue().construct(0); // TODO: Check if this is correct } - for (Entry entry: sideboarding.entrySet()) { + for (Entry entry : sideboarding.entrySet()) { TableController controller = TableManager.getInstance().getController(entry.getKey()); ccSideboard(entry.getValue(), entry.getKey(), controller.getRemainingTime(), controller.getOptions().isLimited()); } @@ -355,32 +357,32 @@ public class User { sideboarding.remove(tableId); } - public void remove(DisconnectReason reason) { + public void remove(DisconnectReason reason) { logger.trace("REMOVE " + getName() + " Draft sessions " + draftSessions.size()); - for (DraftSession draftSession: draftSessions.values()) { + for (DraftSession draftSession : draftSessions.values()) { draftSession.setKilled(); } draftSessions.clear(); logger.trace("REMOVE " + getName() + " Tournament sessions " + userTournaments.size()); - for (UUID tournamentId: userTournaments.values()) { + for (UUID tournamentId : userTournaments.values()) { TournamentManager.getInstance().quit(tournamentId, getId()); } userTournaments.clear(); logger.trace("REMOVE " + getName() + " Tables " + tables.size()); - for (Entry entry: tables.entrySet()) { + for (Entry entry : tables.entrySet()) { logger.debug("-- leave tableId: " + entry.getValue().getId()); TableManager.getInstance().leaveTable(userId, entry.getValue().getId()); } tables.clear(); - logger.trace("REMOVE " + getName() + " Game sessions: " + gameSessions.size() ); - for (GameSessionPlayer gameSessionPlayer: gameSessions.values()) { - logger.debug("-- kill game session of gameId: " + gameSessionPlayer.getGameId() ); + logger.trace("REMOVE " + getName() + " Game sessions: " + gameSessions.size()); + for (GameSessionPlayer gameSessionPlayer : gameSessions.values()) { + logger.debug("-- kill game session of gameId: " + gameSessionPlayer.getGameId()); GameManager.getInstance().quitMatch(gameSessionPlayer.getGameId(), userId); gameSessionPlayer.quitGame(); } gameSessions.clear(); logger.trace("REMOVE " + getName() + " watched Games " + watchedGames.size()); - for (UUID gameId: watchedGames) { + for (UUID gameId : watchedGames) { GameManager.getInstance().stopWatching(gameId, userId); } watchedGames.clear(); @@ -389,10 +391,17 @@ public class User { } public void setUserData(UserData userData) { - this.userData = userData; + if (this.userData != null) { + this.userData.update(userData); + } else { + this.userData = userData; + } } public UserData getUserData() { + if (userData == null) {// default these to avaiod NPE -> will be updated from client short after + return new UserData(UserGroup.DEFAULT, 0, false, false, false, null, "world.png", false); + } return this.userData; } @@ -428,7 +437,7 @@ public class User { } if (!isConnected()) { - tournamentPlayer.setDisconnectInfo(" (discon. "+ getDisconnectDuration() + ")"); + tournamentPlayer.setDisconnectInfo(" (discon. " + getDisconnectDuration() + ")"); } else { tournamentPlayer.setDisconnectInfo(""); } @@ -460,7 +469,7 @@ public class User { } } if (!tablesToDelete.isEmpty()) { - for(UUID keyId: tablesToDelete) { + for (UUID keyId : tablesToDelete) { removeTable(keyId); } tablesToDelete.clear(); @@ -513,8 +522,8 @@ public class User { if (isConnected()) { return pingInfo; } else { - return " (discon. "+ getDisconnectDuration() + ")"; + return " (discon. " + getDisconnectDuration() + ")"; } } - + } 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 55c92050658..485ce0252c2 100644 --- a/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java +++ b/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java @@ -1,31 +1,30 @@ /* -* 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. -*/ - + * 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.server.game; import java.io.Serializable; @@ -73,16 +72,16 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable { private final ConcurrentHashMap tables = new ConcurrentHashMap<>(); - public GamesRoomImpl() { + public GamesRoomImpl() { updateExecutor.scheduleAtFixedRate(new Runnable() { @Override - public void run(){ + public void run() { try { update(); } catch (Exception ex) { logger.fatal("Games room update exception! " + ex.toString(), ex); } - + } }, 2, 2, TimeUnit.SECONDS); } @@ -97,12 +96,11 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable { ArrayList matchList = new ArrayList<>(); List allTables = new ArrayList<>(tables.values()); Collections.sort(allTables, new TableListSorter()); - for (Table table: allTables) { + for (Table table : allTables) { if (table.getState() != TableState.FINISHED) { tableList.add(new TableView(table)); - } - else if (matchList.size() < 50) { - if (table.isTournament()) { + } else if (matchList.size() < 50) { + if (table.isTournament()) { matchList.add(new MatchView(table)); } else { matchList.add(new MatchView(table)); @@ -113,23 +111,23 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable { TournamentManager.getInstance().removeTournament(table.getTournament().getId()); } this.removeTable(table.getId()); - } + } } tableView = tableList; matchView = matchList; List users = new ArrayList<>(); for (User user : UserManager.getInstance().getUsers()) { try { - users.add(new UsersView(user.getUserData().getFlagName(), user.getName(), user.getInfo(), user.getGameInfo(), user.getPingInfo())); + users.add(new UsersView(user.getUserData().getFlagName(), user.getName(), user.getInfo(), user.getGameInfo(), user.getPingInfo())); } catch (Exception ex) { logger.fatal("User update exception: " + user.getName() + " - " + ex.toString(), ex); users.add(new UsersView(user.getUserData().getFlagName(), user.getName(), user.getInfo(), "[exception]", user.getPingInfo())); } } - Collections.sort(users, new UserNameSorter()); + Collections.sort(users, new UserNameSorter()); List roomUserInfo = new ArrayList<>(); - roomUserInfo.add(new RoomUsersView(users, + roomUserInfo.add(new RoomUsersView(users, GameManager.getInstance().getNumberActiveGames(), ThreadExecutor.getInstance().getActiveThreads(ThreadExecutor.getInstance().getGameExecutor()), ConfigSettings.getInstance().getMaxGameThreads() @@ -218,18 +216,19 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable { /** * Sorts the tables for table and match view of the client room - * + * * @author LevelX2 */ class TableListSorter implements Comparator
{ + @Override public int compare(Table one, Table two) { if (!one.getState().equals(TableState.SIDEBOARDING) && !one.getState().equals(TableState.DUELING)) { - if (one.getState().compareTo(two.getState()) != 0 ) { + if (one.getState().compareTo(two.getState()) != 0) { return one.getState().compareTo(two.getState()); } } else if (!two.getState().equals(TableState.SIDEBOARDING) && !two.getState().equals(TableState.DUELING)) { - if (one.getState().compareTo(two.getState()) != 0 ) { + if (one.getState().compareTo(two.getState()) != 0) { return one.getState().compareTo(two.getState()); } } @@ -259,8 +258,9 @@ class TableListSorter implements Comparator
{ } class UserNameSorter implements Comparator { + @Override public int compare(UsersView one, UsersView two) { return one.getUserName().compareToIgnoreCase(two.getUserName()); } -} \ No newline at end of file +} diff --git a/Mage.Server/src/main/java/mage/server/tournament/TournamentController.java b/Mage.Server/src/main/java/mage/server/tournament/TournamentController.java index 2136cd33465..fa26d966f17 100644 --- a/Mage.Server/src/main/java/mage/server/tournament/TournamentController.java +++ b/Mage.Server/src/main/java/mage/server/tournament/TournamentController.java @@ -1,31 +1,30 @@ /* -* Copyright 2011 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. -*/ - + * Copyright 2011 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.server.tournament; import java.util.Map.Entry; @@ -63,7 +62,6 @@ import mage.view.ChatMessage.SoundToPlay; import mage.view.TournamentView; import org.apache.log4j.Logger; - /** * * @author BetaSteward_at_googlemail.com @@ -89,57 +87,57 @@ public class TournamentController { private void init() { tournament.addTableEventListener( - new Listener () { - @Override - public void event(TableEvent event) { - switch (event.getEventType()) { - case CHECK_STATE_PLAYERS: - checkPlayersState(); - break; - case INFO: - ChatManager.getInstance().broadcast(chatId, "", event.getMessage(), MessageColor.BLACK, true, MessageType.STATUS); - logger.debug(tournament.getId() + " " + event.getMessage()); - break; - case START_DRAFT: - startDraft(event.getDraft()); - break; - case CONSTRUCT: - if (!isAbort()) { - construct(); - } else { - endTournament(); - } - break; - case START_MATCH: - if (!isAbort()) { - initTournament(); // set state - startMatch(event.getPair(), event.getMatchOptions()); - } - break; - case END: - endTournament(); - break; - } - } - } - ); - tournament.addPlayerQueryEventListener( - new Listener () { - @Override - public void event(PlayerQueryEvent event) { - try { - switch (event.getQueryType()) { + new Listener() { + @Override + public void event(TableEvent event) { + switch (event.getEventType()) { + case CHECK_STATE_PLAYERS: + checkPlayersState(); + break; + case INFO: + ChatManager.getInstance().broadcast(chatId, "", event.getMessage(), MessageColor.BLACK, true, MessageType.STATUS); + logger.debug(tournament.getId() + " " + event.getMessage()); + break; + case START_DRAFT: + startDraft(event.getDraft()); + break; case CONSTRUCT: - construct(event.getPlayerId(), event.getMax()); + if (!isAbort()) { + construct(); + } else { + endTournament(); + } + break; + case START_MATCH: + if (!isAbort()) { + initTournament(); // set state + startMatch(event.getPair(), event.getMatchOptions()); + } + break; + case END: + endTournament(); break; } - } catch (MageException ex) { - logger.fatal("Player event listener error", ex); } } - } ); - for (TournamentPlayer player: tournament.getPlayers()) { + tournament.addPlayerQueryEventListener( + new Listener() { + @Override + public void event(PlayerQueryEvent event) { + try { + switch (event.getQueryType()) { + case CONSTRUCT: + construct(event.getPlayerId(), event.getMax()); + break; + } + } catch (MageException ex) { + logger.fatal("Player event listener error", ex); + } + } + } + ); + for (TournamentPlayer player : tournament.getPlayers()) { if (!player.getPlayer().isHuman()) { player.setJoined(); logger.debug("player " + player.getPlayer().getId() + " has joined tournament " + tournament.getId()); @@ -163,7 +161,7 @@ public class TournamentController { if (tournamentSessions.containsKey(playerId)) { logger.debug("player reopened tournament panel userId: " + userId + " tournamentId: " + tournament.getId()); return; - } + } // first join of player TournamentSession tournamentSession = new TournamentSession(tournament, userId, tableId, playerId); tournamentSessions.put(playerId, tournamentSession); @@ -172,22 +170,22 @@ public class TournamentController { user.addTournament(playerId, tournament.getId()); TournamentPlayer player = tournament.getPlayer(playerId); player.setJoined(); - logger.debug("player " +player.getPlayer().getName() + " - client has joined tournament " + tournament.getId()); + logger.debug("player " + player.getPlayer().getName() + " - client has joined tournament " + tournament.getId()); ChatManager.getInstance().broadcast(chatId, "", player.getPlayer().getLogName() + " has joined the tournament", MessageColor.BLACK, true, MessageType.STATUS); checkStart(); } else { - logger.error("User not found userId: " + userId + " tournamentId: " + tournament.getId()); + logger.error("User not found userId: " + userId + " tournamentId: " + tournament.getId()); } } public void rejoin(UUID playerId) { TournamentSession tournamentSession = tournamentSessions.get(playerId); if (tournamentSession == null) { - logger.fatal("Tournament session not found - playerId:" + playerId + " tournamentId " + tournament.getId()); + logger.fatal("Tournament session not found - playerId:" + playerId + " tournamentId " + tournament.getId()); return; } if (!tournamentSession.init()) { - logger.fatal("Unable to initialize client userId: " + tournamentSession.userId + " tournamentId " + tournament.getId()); + logger.fatal("Unable to initialize client userId: " + tournamentSession.userId + " tournamentId " + tournament.getId()); return; } tournamentSession.update(); @@ -196,12 +194,12 @@ public class TournamentController { private void checkStart() { if (!started && allJoined()) { ThreadExecutor.getInstance().getCallExecutor().execute( - new Runnable() { - @Override - public void run() { - startTournament(); - } - }); + new Runnable() { + @Override + public void run() { + startTournament(); + } + }); } } @@ -209,7 +207,7 @@ public class TournamentController { if (!tournament.allJoined()) { return false; } - for (TournamentPlayer player: tournament.getPlayers()) { + for (TournamentPlayer player : tournament.getPlayers()) { if (player.getPlayer().isHuman() && tournamentSessions.get(player.getPlayer().getId()) == null) { return false; } @@ -218,9 +216,9 @@ public class TournamentController { } private synchronized void startTournament() { - for (final TournamentSession tournamentSession: tournamentSessions.values()) { + for (final TournamentSession tournamentSession : tournamentSessions.values()) { if (!tournamentSession.init()) { - logger.fatal("Unable to initialize client userId: " + tournamentSession.userId + " tournamentId " + tournament.getId()); + logger.fatal("Unable to initialize client userId: " + tournamentSession.userId + " tournamentId " + tournament.getId()); //TODO: generate client error message return; } @@ -231,10 +229,10 @@ public class TournamentController { } private void endTournament() { - for (TournamentPlayer player: tournament.getPlayers()) { + for (TournamentPlayer player : tournament.getPlayers()) { player.setStateAtTournamentEnd(); } - for (final TournamentSession tournamentSession: tournamentSessions.values()) { + for (final TournamentSession tournamentSession : tournamentSessions.values()) { tournamentSession.tournamentOver(); } this.tournamentSessions.clear(); @@ -296,8 +294,8 @@ public class TournamentController { TournamentPlayer player = tournament.getPlayer(playerId); if (player != null && !player.hasQuit()) { tournamentSessions.get(playerId).submitDeck(deck); - ChatManager.getInstance().broadcast(chatId, "", player.getPlayer().getLogName() + " has submitted his tournament deck", MessageColor.BLACK, true, MessageType.STATUS, SoundToPlay.PlayerSubmittedDeck); - } + ChatManager.getInstance().broadcast(chatId, "", player.getPlayer().getLogName() + " has submitted his tournament deck", MessageColor.BLACK, true, MessageType.STATUS, SoundToPlay.PlayerSubmittedDeck); + } } } @@ -387,7 +385,7 @@ public class TournamentController { private boolean checkToReplaceDraftPlayerByAi(UUID userId, TournamentPlayer leavingPlayer) { int humans = 0; - for (TournamentPlayer tPlayer :tournament.getPlayers()) { + for (TournamentPlayer tPlayer : tournament.getPlayers()) { if (tPlayer.getPlayer().isHuman()) { humans++; } @@ -415,7 +413,7 @@ public class TournamentController { } private UUID getPlayerUserId(UUID playerId) { - for (Entry entry: userPlayerMap.entrySet()) { + for (Entry entry : userPlayerMap.entrySet()) { if (entry.getValue().equals(playerId)) { return entry.getKey(); } @@ -437,7 +435,7 @@ public class TournamentController { } private void checkPlayersState() { - for (TournamentPlayer tournamentPlayer: tournament.getPlayers()) { + for (TournamentPlayer tournamentPlayer : tournament.getPlayers()) { if (!tournamentPlayer.isEliminated() && tournamentPlayer.getPlayer().isHuman()) { if (tournamentSessions.containsKey(tournamentPlayer.getPlayer().getId())) { if (tournamentSessions.get(tournamentPlayer.getPlayer().getId()).isKilled()) { @@ -452,22 +450,22 @@ public class TournamentController { } } - + public void cleanUpOnRemoveTournament() { ChatManager.getInstance().destroyChatSession(chatId); } /** - * Check tournaments that are not already finished, if they are in a still valid state + * Check tournaments that are not already finished, if they are in a still + * valid state * * @param tableState state of the tournament table - * @return true - if tournament is valid - * false - if tournament is not valid and should be removed + * @return true - if tournament is valid false - if tournament is not valid + * and should be removed */ - public boolean isTournamentStillValid(TableState tableState) { int activePlayers = 0; - for (Entry entry: userPlayerMap.entrySet()) { + for (Entry entry : userPlayerMap.entrySet()) { TournamentPlayer tournamentPlayer = tournament.getPlayer(entry.getValue()); if (tournamentPlayer != null) { if (!tournamentPlayer.hasQuit()) { @@ -480,14 +478,14 @@ public class TournamentController { } else { activePlayers++; } - } - } + } + } } else { // tournament player is missing logger.debug("Tournament player is missing - tournamentId: " + tournament.getId() + " state: " + tableState.toString()); } } - for(TournamentPlayer tournamentPlayer: tournament.getPlayers()) { + for (TournamentPlayer tournamentPlayer : tournament.getPlayers()) { if (!tournamentPlayer.getPlayer().isHuman()) { if (!tournamentPlayer.hasQuit()) { activePlayers++; diff --git a/Mage.Sets/src/mage/sets/alarareborn/ArsenalThresher.java b/Mage.Sets/src/mage/sets/alarareborn/ArsenalThresher.java index 0f9a30c2e8c..16bc181405a 100644 --- a/Mage.Sets/src/mage/sets/alarareborn/ArsenalThresher.java +++ b/Mage.Sets/src/mage/sets/alarareborn/ArsenalThresher.java @@ -99,7 +99,7 @@ class ArsenalThresherEffect extends OneShotEffect { Permanent arsenalThresher = game.getPermanent(source.getSourceId()); FilterArtifactCard filter = new FilterArtifactCard(); filter.add(new AnotherCardPredicate()); - if (you.chooseUse(Outcome.Benefit, "Do you want to reveal other artifacts in your hand?", game)) { + if (you.chooseUse(Outcome.Benefit, "Do you want to reveal other artifacts in your hand?", source, game)) { Cards cards = new CardsImpl(); if (you.getHand().count(filter, source.getSourceId(), source.getControllerId(), game) > 0) { TargetCardInHand target = new TargetCardInHand(0, Integer.MAX_VALUE, filter); diff --git a/Mage.Sets/src/mage/sets/alarareborn/EtherwroughtPage.java b/Mage.Sets/src/mage/sets/alarareborn/EtherwroughtPage.java index 7e3d9fb67f1..d5179abf898 100644 --- a/Mage.Sets/src/mage/sets/alarareborn/EtherwroughtPage.java +++ b/Mage.Sets/src/mage/sets/alarareborn/EtherwroughtPage.java @@ -111,7 +111,7 @@ class EtherwroughtPageEffect extends OneShotEffect { CardsImpl cards = new CardsImpl(); cards.add(card); controller.lookAtCards("Etherwrought Page", cards, game); - if (controller.chooseUse(Outcome.Neutral, "Do you wish to put the card into your graveyard?", game)) { + if (controller.chooseUse(Outcome.Neutral, "Do you wish to put the card into your graveyard?", source, game)) { return controller.moveCards(card, Zone.LIBRARY, Zone.GRAVEYARD, source, game); } return true; diff --git a/Mage.Sets/src/mage/sets/alarareborn/SovereignsOfLostAlara.java b/Mage.Sets/src/mage/sets/alarareborn/SovereignsOfLostAlara.java index f6f70200a1d..a04ea9aaf23 100644 --- a/Mage.Sets/src/mage/sets/alarareborn/SovereignsOfLostAlara.java +++ b/Mage.Sets/src/mage/sets/alarareborn/SovereignsOfLostAlara.java @@ -139,7 +139,7 @@ class SovereignsOfLostAlaraEffect extends OneShotEffect { FilterCard filter = new FilterCard("aura that could enchant the lone attacking creature"); filter.add(new SubtypePredicate("Aura")); filter.add(new AuraCardCanAttachToPermanentId(attackingCreature.getId())); - if (you.chooseUse(Outcome.Benefit, "Do you want to search your library?", game)) { + if (you.chooseUse(Outcome.Benefit, "Do you want to search your library?", source, game)) { TargetCardInLibrary target = new TargetCardInLibrary(filter); target.setNotTarget(true); if (you.searchLibrary(target, game)) { diff --git a/Mage.Sets/src/mage/sets/alarareborn/VectisDominator.java b/Mage.Sets/src/mage/sets/alarareborn/VectisDominator.java index e315a53fe22..6c3e4d6f24f 100644 --- a/Mage.Sets/src/mage/sets/alarareborn/VectisDominator.java +++ b/Mage.Sets/src/mage/sets/alarareborn/VectisDominator.java @@ -104,7 +104,7 @@ class VectisDominatorEffect extends OneShotEffect { if (player != null) { cost.clearPaid(); final StringBuilder sb = new StringBuilder("Pay 2 life? (Otherwise ").append(targetCreature.getName()).append(" will be tapped)"); - if (player.chooseUse(Outcome.Benefit, sb.toString(), game)) { + if (player.chooseUse(Outcome.Benefit, sb.toString(), source, game)) { cost.pay(source, game, targetCreature.getControllerId(), targetCreature.getControllerId(), true); } if (!cost.isPaid()) { diff --git a/Mage.Sets/src/mage/sets/anthologyjacevschandra/TerrainGenerator.java b/Mage.Sets/src/mage/sets/anthologyjacevschandra/TerrainGenerator.java index 3a67a293630..70d9d0ece9b 100644 --- a/Mage.Sets/src/mage/sets/anthologyjacevschandra/TerrainGenerator.java +++ b/Mage.Sets/src/mage/sets/anthologyjacevschandra/TerrainGenerator.java @@ -106,7 +106,7 @@ class PutLandOnBattlefieldEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (player == null || !player.chooseUse(Outcome.PutLandInPlay, choiceText, game)) { + if (player == null || !player.chooseUse(Outcome.PutLandInPlay, choiceText, source, game)) { return false; } diff --git a/Mage.Sets/src/mage/sets/avacynrestored/BrunaLightOfAlabaster.java b/Mage.Sets/src/mage/sets/avacynrestored/BrunaLightOfAlabaster.java index a43cb08b871..50c4d359344 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/BrunaLightOfAlabaster.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/BrunaLightOfAlabaster.java @@ -122,7 +122,7 @@ class BrunaLightOfAlabasterEffect extends OneShotEffect { return false; } - while (player.isInGame() && player.chooseUse(Outcome.Benefit, "Attach an Aura from the battlefield?", game)) { + while (player.isInGame() && player.chooseUse(Outcome.Benefit, "Attach an Aura from the battlefield?", source, game)) { Target targetAura = new TargetPermanent(filterAura); if (player.choose(Outcome.Benefit, targetAura, source.getSourceId(), game)) { Permanent aura = game.getPermanent(targetAura.getFirstTarget()); @@ -137,7 +137,7 @@ class BrunaLightOfAlabasterEffect extends OneShotEffect { } int count = player.getHand().count(filterAuraCard, game); - while (player.isInGame() && count > 0 && player.chooseUse(Outcome.Benefit, "Attach an Aura from your hand?", game)) { + while (player.isInGame() && count > 0 && player.chooseUse(Outcome.Benefit, "Attach an Aura from your hand?", source, game)) { TargetCard targetAura = new TargetCard(Zone.PICK, filterAuraCard); if (player.choose(Outcome.Benefit, player.getHand(), targetAura, game)) { Card aura = game.getCard(targetAura.getFirstTarget()); @@ -151,7 +151,7 @@ class BrunaLightOfAlabasterEffect extends OneShotEffect { } count = player.getGraveyard().count(filterAuraCard, game); - while (player.isInGame() && count > 0 && player.chooseUse(Outcome.Benefit, "Attach an Aura from your graveyard?", game)) { + while (player.isInGame() && count > 0 && player.chooseUse(Outcome.Benefit, "Attach an Aura from your graveyard?", source, game)) { TargetCard targetAura = new TargetCard(Zone.PICK, filterAuraCard); if (player.choose(Outcome.Benefit, player.getGraveyard(), targetAura, game)) { Card aura = game.getCard(targetAura.getFirstTarget()); diff --git a/Mage.Sets/src/mage/sets/avacynrestored/DescendantsPath.java b/Mage.Sets/src/mage/sets/avacynrestored/DescendantsPath.java index a6f0e7964a5..0bb9524661a 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/DescendantsPath.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/DescendantsPath.java @@ -110,7 +110,7 @@ class DescendantsPathEffect extends OneShotEffect { } if (found) { game.informPlayers(sourceObject.getLogName() + ": Found a creature that shares a creature type with the revealed card."); - if (controller.chooseUse(Outcome.Benefit, "Cast the card?", game)) { + if (controller.chooseUse(Outcome.Benefit, "Cast the card?", source, game)) { controller.cast(card.getSpellAbility(), game, true); } else { game.informPlayers(sourceObject.getLogName() + ": " + controller.getLogName() + " canceled casting the card."); diff --git a/Mage.Sets/src/mage/sets/avacynrestored/Fettergeist.java b/Mage.Sets/src/mage/sets/avacynrestored/Fettergeist.java index 74ad7a641ac..6b8cec80c85 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/Fettergeist.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/Fettergeist.java @@ -105,7 +105,7 @@ class FettergeistUnlessPaysEffect extends OneShotEffect { if (count == 0) { return true; } - if (player.chooseUse(Outcome.Benefit, "Pay " + count + "?", game)) { + if (player.chooseUse(Outcome.Benefit, "Pay " + count + "?", source, game)) { GenericManaCost cost = new GenericManaCost(count); if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { return true; diff --git a/Mage.Sets/src/mage/sets/avacynrestored/KillingWave.java b/Mage.Sets/src/mage/sets/avacynrestored/KillingWave.java index 2fbd65300ad..8b81ec6c96e 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/KillingWave.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/KillingWave.java @@ -106,7 +106,7 @@ class KillingWaveEffect extends OneShotEffect { int playerLife = player.getLife(); for (Permanent creature : creatures) { String message = "Pay " + amount + " life? If you don't, " + creature.getName() + " will be sacrificed."; - if (playerLife - amount - lifePaid >= 0 && player != null && player.chooseUse(Outcome.Neutral, message, game)) { + if (playerLife - amount - lifePaid >= 0 && player != null && player.chooseUse(Outcome.Neutral, message, source, game)) { game.informPlayers(player.getLogName() + " pays " + amount + " life. He will not sacrifice " + creature.getName()); lifePaid += amount; } else { diff --git a/Mage.Sets/src/mage/sets/avacynrestored/PrimalSurge.java b/Mage.Sets/src/mage/sets/avacynrestored/PrimalSurge.java index ebd4d5178bf..7dd2e0918d0 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/PrimalSurge.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/PrimalSurge.java @@ -100,7 +100,7 @@ class PrimalSurgeEffect extends OneShotEffect { if ((cardType.contains(CardType.ARTIFACT) || cardType.contains(CardType.CREATURE) || cardType.contains(CardType.ENCHANTMENT) || cardType.contains(CardType.LAND) || cardType.contains(CardType.PLANESWALKER)) - && player.chooseUse(Outcome.PutCardInPlay, "Put " + card.getName() + " onto the battlefield?", game)) { + && player.chooseUse(Outcome.PutCardInPlay, "Put " + card.getName() + " onto the battlefield?", source, game)) { card.moveToZone(Zone.BATTLEFIELD, source.getSourceId(), game, false); Permanent permanent = game.getPermanent(card.getId()); diff --git a/Mage.Sets/src/mage/sets/avacynrestored/VexingDevil.java b/Mage.Sets/src/mage/sets/avacynrestored/VexingDevil.java index d06ce403fe0..bbf11eb0170 100644 --- a/Mage.Sets/src/mage/sets/avacynrestored/VexingDevil.java +++ b/Mage.Sets/src/mage/sets/avacynrestored/VexingDevil.java @@ -89,7 +89,7 @@ class VexingDevilEffect extends OneShotEffect { if (controller != null && permanent != null) { for (UUID opponentUuid : game.getOpponents(source.getControllerId())) { Player opponent = game.getPlayer(opponentUuid); - if (opponent != null && opponent.chooseUse(Outcome.LoseLife, "Make " + permanent.getLogName() + " deal 4 damage to you?", game)) { + if (opponent != null && opponent.chooseUse(Outcome.LoseLife, "Make " + permanent.getLogName() + " deal 4 damage to you?", source, game)) { game.informPlayers(opponent.getLogName() + " has chosen to receive 4 damage from " + permanent.getLogName()); opponent.damage(4, permanent.getId(), game, false, true); permanent.sacrifice(source.getSourceId(), game); diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/IwamoriOfTheOpenFist.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/IwamoriOfTheOpenFist.java index 6d0beacd944..98bc1dbe5f7 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/IwamoriOfTheOpenFist.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/IwamoriOfTheOpenFist.java @@ -113,7 +113,7 @@ class IwamoriOfTheOpenFistEffect extends OneShotEffect { Player opponent = game.getPlayer(playerId); Target target = new TargetCardInHand(filter); if (opponent != null && target.canChoose(source.getSourceId(), opponent.getId(), game)) { - if (opponent.chooseUse(Outcome.PutCreatureInPlay, "Put a legendary creature card from your hand onto the battlefield?", game)) { + if (opponent.chooseUse(Outcome.PutCreatureInPlay, "Put a legendary creature card from your hand onto the battlefield?", source, game)) { if (target.chooseTarget(Outcome.PutCreatureInPlay, opponent.getId(), source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/OgreMarauder.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/OgreMarauder.java index 530f6624ee3..cc0ed1bcf5f 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/OgreMarauder.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/OgreMarauder.java @@ -99,7 +99,7 @@ class OgreMarauderEffect extends OneShotEffect { if (defender != null && sourceObject != null) { Cost cost = new SacrificeTargetCost(new TargetControlledCreaturePermanent()); if (cost.canPay(source, source.getSourceId(), defendingPlayerId, game) && - defender.chooseUse(Outcome.LoseAbility, "Sacrifice a creature to prevent that " + sourceObject.getLogName() + " can't be blocked?", game)) { + defender.chooseUse(Outcome.LoseAbility, "Sacrifice a creature to prevent that " + sourceObject.getLogName() + " can't be blocked?", source, game)) { if (!cost.pay(source, game, source.getSourceId(), defendingPlayerId, false)) { // cost was not payed - so source can't be blocked ContinuousEffect effect = new CantBeBlockedSourceEffect(Duration.EndOfTurn); diff --git a/Mage.Sets/src/mage/sets/betrayersofkamigawa/ToilsOfNightAndDay.java b/Mage.Sets/src/mage/sets/betrayersofkamigawa/ToilsOfNightAndDay.java index 57e893e3b37..56722fff90e 100644 --- a/Mage.Sets/src/mage/sets/betrayersofkamigawa/ToilsOfNightAndDay.java +++ b/Mage.Sets/src/mage/sets/betrayersofkamigawa/ToilsOfNightAndDay.java @@ -90,9 +90,9 @@ public class ToilsOfNightAndDay extends CardImpl { for (UUID targetId : source.getTargets().get(0).getTargets()) { Permanent permanent = game.getPermanent(targetId); if (permanent != null) { - if (player.chooseUse(Outcome.Tap, new StringBuilder("Tap ").append(permanent.getName()).append("?").toString(), game)) { + if (player.chooseUse(Outcome.Tap, new StringBuilder("Tap ").append(permanent.getName()).append("?").toString(), source, game)) { permanent.tap(game); - } else if (player.chooseUse(Outcome.Untap, new StringBuilder("Untap ").append(permanent.getName()).append("?").toString(), game)) { + } else if (player.chooseUse(Outcome.Untap, new StringBuilder("Untap ").append(permanent.getName()).append("?").toString(), source, game)) { permanent.untap(game); } } diff --git a/Mage.Sets/src/mage/sets/bornofthegods/ArbiterOfTheIdeal.java b/Mage.Sets/src/mage/sets/bornofthegods/ArbiterOfTheIdeal.java index 99f5dc30029..0ace0030458 100644 --- a/Mage.Sets/src/mage/sets/bornofthegods/ArbiterOfTheIdeal.java +++ b/Mage.Sets/src/mage/sets/bornofthegods/ArbiterOfTheIdeal.java @@ -122,7 +122,7 @@ class ArbiterOfTheIdealEffect extends OneShotEffect { player.revealCards("Arbiter of the Ideal", cards, game); if (card != null) { - if (filter.match(card, game) && player.chooseUse(outcome, new StringBuilder("Put ").append(card.getName()).append("onto battlefield?").toString(), game)) { + if (filter.match(card, game) && player.chooseUse(outcome, new StringBuilder("Put ").append(card.getName()).append("onto battlefield?").toString(), source, game)) { card.putOntoBattlefield(game, Zone.LIBRARY, source.getSourceId(), source.getControllerId()); Permanent permanent = game.getPermanent(card.getId()); if (permanent != null) { diff --git a/Mage.Sets/src/mage/sets/bornofthegods/FloodtideSerpent.java b/Mage.Sets/src/mage/sets/bornofthegods/FloodtideSerpent.java index 1b0262eedf8..962b63f5287 100644 --- a/Mage.Sets/src/mage/sets/bornofthegods/FloodtideSerpent.java +++ b/Mage.Sets/src/mage/sets/bornofthegods/FloodtideSerpent.java @@ -100,7 +100,7 @@ class FloodtideSerpentReplacementEffect extends ReplacementEffectImpl { if ( player != null ) { ReturnToHandTargetPermanentCost attackCost = new ReturnToHandTargetPermanentCost(new TargetControlledPermanent(filter)); if ( attackCost.canPay(source, source.getSourceId(), event.getPlayerId(), game) && - player.chooseUse(Outcome.Neutral, "Return an enchantment you control to hand to attack?", game) ) + player.chooseUse(Outcome.Neutral, "Return an enchantment you control to hand to attack?", source, game) ) { if (attackCost.pay(source, game, source.getSourceId(), event.getPlayerId(), true) ) { return false; diff --git a/Mage.Sets/src/mage/sets/bornofthegods/HeroOfLeinaTower.java b/Mage.Sets/src/mage/sets/bornofthegods/HeroOfLeinaTower.java index 713c52c575c..7611a108558 100644 --- a/Mage.Sets/src/mage/sets/bornofthegods/HeroOfLeinaTower.java +++ b/Mage.Sets/src/mage/sets/bornofthegods/HeroOfLeinaTower.java @@ -95,7 +95,7 @@ class HeroOfLeinaTowerEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player you = game.getPlayer(source.getControllerId()); ManaCosts cost = new ManaCostsImpl("{X}"); - if (you != null && you.chooseUse(Outcome.BoostCreature, "Do you want to to pay {X}?", game)) { + if (you != null && you.chooseUse(Outcome.BoostCreature, "Do you want to to pay {X}?", source, game)) { int costX = you.announceXMana(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source); cost.add(new GenericManaCost(costX)); if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { diff --git a/Mage.Sets/src/mage/sets/bornofthegods/HeroesPodium.java b/Mage.Sets/src/mage/sets/bornofthegods/HeroesPodium.java index 79e27e57ee5..d8610794d79 100644 --- a/Mage.Sets/src/mage/sets/bornofthegods/HeroesPodium.java +++ b/Mage.Sets/src/mage/sets/bornofthegods/HeroesPodium.java @@ -171,7 +171,7 @@ class HeroesPodiumEffect extends OneShotEffect { player.lookAtCards("Heroes' Podium", cards, game); // You may reveal a legendary creature card from among them and put it into your hand. - if (!cards.isEmpty() && legendaryIncluded && player.chooseUse(outcome, "Put a legendary creature card into your hand?", game)) { + if (!cards.isEmpty() && legendaryIncluded && player.chooseUse(outcome, "Put a legendary creature card into your hand?", source, game)) { if (cards.size() == 1) { Card card = cards.getRandom(game); cards.remove(card); diff --git a/Mage.Sets/src/mage/sets/bornofthegods/MogisGodOfSlaughter.java b/Mage.Sets/src/mage/sets/bornofthegods/MogisGodOfSlaughter.java index d20bef30364..85fb229bf73 100644 --- a/Mage.Sets/src/mage/sets/bornofthegods/MogisGodOfSlaughter.java +++ b/Mage.Sets/src/mage/sets/bornofthegods/MogisGodOfSlaughter.java @@ -127,7 +127,7 @@ class DoUnlessTargetPaysCost extends OneShotEffect { } message = CardUtil.replaceSourceName(message, mageObject.getLogName()); cost.clearPaid(); - if (cost.canPay(source, source.getSourceId(), player.getId(), game) && player.chooseUse(executingEffect.getOutcome(), message, game)) { + if (cost.canPay(source, source.getSourceId(), player.getId(), game) && player.chooseUse(executingEffect.getOutcome(), message, source, game)) { cost.pay(source, game, source.getSourceId(), player.getId(), false); } if (!cost.isPaid()) { diff --git a/Mage.Sets/src/mage/sets/bornofthegods/OracleOfBones.java b/Mage.Sets/src/mage/sets/bornofthegods/OracleOfBones.java index 1e171ceaa60..15fa1489e8a 100644 --- a/Mage.Sets/src/mage/sets/bornofthegods/OracleOfBones.java +++ b/Mage.Sets/src/mage/sets/bornofthegods/OracleOfBones.java @@ -108,7 +108,7 @@ class OracleOfBonesCastEffect extends OneShotEffect { if (controller != null) { Target target = new TargetCardInHand(filter); if (target.canChoose(source.getSourceId(), controller.getId(), game) && - controller.chooseUse(outcome, "Cast an instant or sorcery card from your hand without paying its mana cost?", game)) { + controller.chooseUse(outcome, "Cast an instant or sorcery card from your hand without paying its mana cost?", source, game)) { Card cardToCast = null; boolean cancel = false; while (controller.isInGame() && !cancel) { diff --git a/Mage.Sets/src/mage/sets/bornofthegods/SatyrWayfinder.java b/Mage.Sets/src/mage/sets/bornofthegods/SatyrWayfinder.java index 64eb989e36f..11c738d3975 100644 --- a/Mage.Sets/src/mage/sets/bornofthegods/SatyrWayfinder.java +++ b/Mage.Sets/src/mage/sets/bornofthegods/SatyrWayfinder.java @@ -104,7 +104,7 @@ class SatyrWayfinderEffect extends OneShotEffect { controller.revealCards(sourceObject.getName(), cards, game); TargetCard target = new TargetCard(Zone.LIBRARY, filterPutInHand); if (properCardFound && - controller.chooseUse(outcome, "Put a land card into your hand?", game) && + controller.chooseUse(outcome, "Put a land card into your hand?", source, game) && controller.choose(Outcome.DrawCard, cards, target, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/CallousDeceiver.java b/Mage.Sets/src/mage/sets/championsofkamigawa/CallousDeceiver.java index 9fa127b7987..da39e9bfc1e 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/CallousDeceiver.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/CallousDeceiver.java @@ -28,19 +28,14 @@ package mage.sets.championsofkamigawa; 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.MageObject; import mage.abilities.Ability; import mage.abilities.common.LimitedTimesPerTurnActivatedAbility; -import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.Cost; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.LookLibraryControllerEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; @@ -49,6 +44,11 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.Cards; import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.game.Game; import mage.players.Player; @@ -66,12 +66,10 @@ public class CallousDeceiver extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(3); // {1}: Look at the top card of your library. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new LookLibraryControllerEffect(), new GenericManaCost(1))); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new LookLibraryControllerEffect(), new GenericManaCost(1))); - // {2}: Reveal the top card of your library. If it's a land card, {this} gets +1/+0 and gains flying until end of turn. - Ability ability = new CallousDeceiverAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1,0,Duration.EndOfTurn), new ManaCostsImpl("{2}")); - ability.addEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance(),Duration.EndOfTurn)); - this.addAbility(ability); + // {2}: Reveal the top card of your library. If it's a land card, {this} gets +1/+0 and gains flying until end of turn. Activate this ability only once each turn. + this.addAbility(new LimitedTimesPerTurnActivatedAbility(Zone.BATTLEFIELD, new CallousDeceiverEffect(), new ManaCostsImpl("{2}"))); } public CallousDeceiver(final CallousDeceiver card) { @@ -85,38 +83,39 @@ public class CallousDeceiver extends CardImpl { } -class CallousDeceiverAbility extends LimitedTimesPerTurnActivatedAbility { +class CallousDeceiverEffect extends OneShotEffect { - public CallousDeceiverAbility(Zone zone, Effect effect, Cost cost) { - super(zone, effect, cost); + public CallousDeceiverEffect() { + super(Outcome.BoostCreature); + this.staticText = "Reveal the top card of your library. If it's a land card, {this} gets +1/+0 and gains flying until end of turn"; } - public CallousDeceiverAbility(CallousDeceiverAbility ability) { - super(ability); + public CallousDeceiverEffect(final CallousDeceiverEffect effect) { + super(effect); } - @Override - public CallousDeceiverAbility copy() { - return new CallousDeceiverAbility(this); - } + @Override + public CallousDeceiverEffect copy() { + return new CallousDeceiverEffect(this); + } - @Override - public boolean checkIfClause(Game game) { - Player player = game.getPlayer(this.getControllerId()); - if (player != null) { - Cards cards = new CardsImpl(); - Card card = player.getLibrary().getFromTop(game); - cards.add(card); - player.revealCards("Callous Deceiver", cards, game); - if (card != null && card.getCardType().contains(CardType.LAND)) { - return true; - } + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = source.getSourceObject(game); + if (controller != null && sourceObject != null) { + Cards cards = new CardsImpl(); + Card card = controller.getLibrary().getFromTop(game); + if (card != null) { + cards.add(card); + controller.revealCards(sourceObject.getIdName(), cards, game); + if (card.getCardType().contains(CardType.LAND)) { + game.addEffect(new BoostSourceEffect(1, 0, Duration.EndOfTurn), source); + game.addEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), source); } - return false; + } + return true; } - - @Override - public String getRule() { - return "{2}: Reveal the top card of your library. If it's a land card, {this} gets +1/+0 and gains flying until end of turn. Activate this ability only once each turn."; + return false; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/CutTheTethers.java b/Mage.Sets/src/mage/sets/championsofkamigawa/CutTheTethers.java index 2582b063a7f..8b8bfd29f6d 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/CutTheTethers.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/CutTheTethers.java @@ -96,7 +96,7 @@ class CutTheTethersEffect extends OneShotEffect { Player player = game.getPlayer(creature.getControllerId()); if (player != null) { boolean paid = false; - if (player.chooseUse(outcome, new StringBuilder("Pay {3} to keep ").append(creature.getName()).append(" on the battlefield?").toString(), game)) { + if (player.chooseUse(outcome, new StringBuilder("Pay {3} to keep ").append(creature.getName()).append(" on the battlefield?").toString(), source, game)) { Cost cost = new GenericManaCost(3); if (!cost.pay(source, game, source.getSourceId(), creature.getControllerId(), false)) { paid = true; diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/GhostlyPrison.java b/Mage.Sets/src/mage/sets/championsofkamigawa/GhostlyPrison.java index 72b4101982b..a59826a420c 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/GhostlyPrison.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/GhostlyPrison.java @@ -103,7 +103,7 @@ class GhostlyPrisonReplacementEffect extends ReplacementEffectImpl { if ( player != null && event.getTargetId().equals(source.getControllerId())) { ManaCostsImpl attackTax = new ManaCostsImpl("{2}"); if (attackTax.canPay(source, source.getSourceId(), event.getPlayerId(), game) && - player.chooseUse(Outcome.Benefit, "Pay {2} to attack player?", game) ) { + player.chooseUse(Outcome.Benefit, "Pay {2} to attack player?", source, game) ) { if (attackTax.payOrRollback(source, game, this.getId(), event.getPlayerId())) { return false; } diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/GiftsUngiven.java b/Mage.Sets/src/mage/sets/championsofkamigawa/GiftsUngiven.java index c40bae528da..d35a0c4b9bf 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/GiftsUngiven.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/GiftsUngiven.java @@ -27,7 +27,6 @@ */ package mage.sets.championsofkamigawa; -import java.util.List; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -56,9 +55,9 @@ public class GiftsUngiven extends CardImpl { super(ownerId, 62, "Gifts Ungiven", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{3}{U}"); this.expansionSetCode = "CHK"; - // Search your library for up to four cards with different names and reveal them. Target opponent chooses two of those cards. Put the chosen cards into your graveyard and the rest into your hand. Then shuffle your library. this.getSpellAbility().addEffect(new GiftsUngivenEffect()); + this.getSpellAbility().addTarget(new TargetOpponent()); } public GiftsUngiven(final GiftsUngiven card) { @@ -94,7 +93,10 @@ class GiftsUngivenEffect extends OneShotEffect { if (player == null || sourceCard == null) { return false; } - + Player opponent = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (opponent == null) { + return false; + } GiftsUngivenTarget target = new GiftsUngivenTarget(); if (player.searchLibrary(target, game)) { if (target.getTargets().size() > 0) { @@ -105,34 +107,20 @@ class GiftsUngivenEffect extends OneShotEffect { cards.add(card); } } - player.revealCards(sourceCard.getName(), cards, game); + player.revealCards(sourceCard.getIdName(), cards, game); CardsImpl cardsToKeep = new CardsImpl(); if (cards.size() > 2) { cardsToKeep.addAll(cards); - - Player opponent; - if (game.getOpponents(player.getId()).size() > 1) { - TargetOpponent targetOpponent = new TargetOpponent(); - player.chooseTarget(outcome, targetOpponent, source, game); - opponent = game.getPlayer(target.getFirstTarget()); - } else { - opponent = game.getPlayer(game.getOpponents(player.getId()).iterator().next()); - } TargetCard targetDiscard = new TargetCard(2, Zone.LIBRARY, new FilterCard("cards to put in graveyard")); - if (opponent != null && opponent.choose(Outcome.Discard, cards, targetDiscard, game)) { + if (opponent.choose(Outcome.Discard, cards, targetDiscard, game)) { cardsToKeep.removeAll(targetDiscard.getTargets()); cards.removeAll(cardsToKeep); } } player.moveCards(cards, Zone.LIBRARY, Zone.GRAVEYARD, source, game); - for (UUID cardId : cardsToKeep) { - Card card = game.getCard(cardId); - if (card != null) { - player.moveCardToHandWithInfo(card, source.getSourceId(), game, Zone.LIBRARY); - } - } + player.moveCards(cardsToKeep, Zone.LIBRARY, Zone.HAND, source, game); } player.shuffleLibrary(game); return true; diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/Hinder.java b/Mage.Sets/src/mage/sets/championsofkamigawa/Hinder.java index afdac715e26..dac84fa0c2d 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/Hinder.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/Hinder.java @@ -163,7 +163,7 @@ class HinderReplacementEffect extends ReplacementEffectImpl { Card card = (Card) targetObject; Player player = game.getPlayer(source.getControllerId()); if (player != null) { - boolean top = player.chooseUse(Outcome.Neutral, "Put " + card.getName() + " on top of the library? Otherwise it will be put on the bottom.", game); + boolean top = player.chooseUse(Outcome.Neutral, "Put " + card.getName() + " on top of the library? Otherwise it will be put on the bottom.", source, game); if (card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, top, event.getAppliedEffects())) { game.informPlayers(player.getLogName() + " has put " + card.getName() + " on " + (top ? "top" : "the bottom") + " of the library."); } diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/InameLifeAspect.java b/Mage.Sets/src/mage/sets/championsofkamigawa/InameLifeAspect.java index 1d26ed807d8..f9352d28dc8 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/InameLifeAspect.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/InameLifeAspect.java @@ -106,7 +106,7 @@ class InameLifeAspectEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source.getSourceId()); if (controller != null && sourceObject != null) { - if (controller.chooseUse(outcome, "Exile " + sourceObject.getLogName() + " to return Spirit cards?", game)) { + if (controller.chooseUse(outcome, "Exile " + sourceObject.getLogName() + " to return Spirit cards?", source, game)) { new ExileSourceEffect().apply(game, source); return new ReturnToHandTargetEffect().apply(game, source); } diff --git a/Mage.Sets/src/mage/sets/championsofkamigawa/ThroughTheBreach.java b/Mage.Sets/src/mage/sets/championsofkamigawa/ThroughTheBreach.java index a7401b052da..86980d0f771 100644 --- a/Mage.Sets/src/mage/sets/championsofkamigawa/ThroughTheBreach.java +++ b/Mage.Sets/src/mage/sets/championsofkamigawa/ThroughTheBreach.java @@ -102,7 +102,7 @@ class ThroughTheBreachEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - if (controller.chooseUse(Outcome.PutCreatureInPlay, choiceText, game)) { + if (controller.chooseUse(Outcome.PutCreatureInPlay, choiceText, source, game)) { TargetCardInHand target = new TargetCardInHand(new FilterCreatureCard()); if (controller.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { Card card = game.getCard(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/sets/coldsnap/ArcumDagsson.java b/Mage.Sets/src/mage/sets/coldsnap/ArcumDagsson.java index 599c9f69ceb..653bb2a81d0 100644 --- a/Mage.Sets/src/mage/sets/coldsnap/ArcumDagsson.java +++ b/Mage.Sets/src/mage/sets/coldsnap/ArcumDagsson.java @@ -115,7 +115,7 @@ class ArcumDagssonEffect extends OneShotEffect { Player player = game.getPlayer(artifactCreature.getControllerId()); if (player != null) { artifactCreature.sacrifice(source.getSourceId(), game); - if (player.chooseUse(Outcome.PutCardInPlay, "Search your library for a noncreature artifact card?", game)) { + if (player.chooseUse(Outcome.PutCardInPlay, "Search your library for a noncreature artifact card?", source, game)) { TargetCardInLibrary target = new TargetCardInLibrary(filter); if (player.searchLibrary(target, game)) { Card card = game.getCard(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/sets/coldsnap/ScryingSheets.java b/Mage.Sets/src/mage/sets/coldsnap/ScryingSheets.java index f0a1d5e8b51..5196fbb0293 100644 --- a/Mage.Sets/src/mage/sets/coldsnap/ScryingSheets.java +++ b/Mage.Sets/src/mage/sets/coldsnap/ScryingSheets.java @@ -100,7 +100,7 @@ class ScryingSheetsEffect extends OneShotEffect { cards.add(card); player.lookAtCards("Scrying Sheets", cards, game); if (card.getSupertype().contains("Snow")) { - if (player.chooseUse(outcome, new StringBuilder("Reveal ").append(card.getName()).append(" and put it into your hand?").toString(), game)) { + if (player.chooseUse(outcome, new StringBuilder("Reveal ").append(card.getName()).append(" and put it into your hand?").toString(), source, game)) { card = player.getLibrary().removeFromTop(game); player.moveCardToHandWithInfo(card, source.getSourceId(), game, Zone.LIBRARY); player.revealCards("Scrying Sheets", cards, game); diff --git a/Mage.Sets/src/mage/sets/commander/ChorusOfTheConclave.java b/Mage.Sets/src/mage/sets/commander/ChorusOfTheConclave.java index fc8e0235a80..7454b495669 100644 --- a/Mage.Sets/src/mage/sets/commander/ChorusOfTheConclave.java +++ b/Mage.Sets/src/mage/sets/commander/ChorusOfTheConclave.java @@ -112,7 +112,7 @@ class ChorusOfTheConclaveReplacementEffect extends ReplacementEffectImpl { int xCost = 0; Player you = game.getPlayer(source.getControllerId()); if (you != null) { - if (you.chooseUse(Outcome.Benefit, "Do you wish to pay the additonal cost to add +1/+1 counters to the creature you cast?", game)) { + if (you.chooseUse(Outcome.Benefit, "Do you wish to pay the additonal cost to add +1/+1 counters to the creature you cast?", source, game)) { xCost += playerPaysXGenericMana(you, source, game); // save the x value to be available for ETB replacement effect Object object = game.getState().getValue("spellX" + source.getSourceId()); diff --git a/Mage.Sets/src/mage/sets/commander/KaaliaOfTheVast.java b/Mage.Sets/src/mage/sets/commander/KaaliaOfTheVast.java index 562935d4c6a..ae71daeb4db 100644 --- a/Mage.Sets/src/mage/sets/commander/KaaliaOfTheVast.java +++ b/Mage.Sets/src/mage/sets/commander/KaaliaOfTheVast.java @@ -149,7 +149,7 @@ class KaaliaOfTheVastEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (player == null || !player.chooseUse(Outcome.PutCreatureInPlay, "Put an Angel, Demon, or Dragon creature card from your hand onto the battlefield tapped and attacking?", game)) { + if (player == null || !player.chooseUse(Outcome.PutCreatureInPlay, "Put an Angel, Demon, or Dragon creature card from your hand onto the battlefield tapped and attacking?", source, game)) { return false; } TargetCardInHand target = new TargetCardInHand(filter); diff --git a/Mage.Sets/src/mage/sets/commander/TheMimeoplasm.java b/Mage.Sets/src/mage/sets/commander/TheMimeoplasm.java index 0397ca4cff8..5be1bed0a24 100644 --- a/Mage.Sets/src/mage/sets/commander/TheMimeoplasm.java +++ b/Mage.Sets/src/mage/sets/commander/TheMimeoplasm.java @@ -100,7 +100,7 @@ class TheMimeoplasmEffect extends OneShotEffect { Permanent permanent = game.getPermanent(source.getSourceId()); if (controller != null && permanent != null) { if (new CardsInAllGraveyardsCount(new FilterCreatureCard()).calculate(game, source, this) >= 2) { - if (controller.chooseUse(Outcome.Benefit, "Do you want to exile two creature cards from graveyards?", game)) { + if (controller.chooseUse(Outcome.Benefit, "Do you want to exile two creature cards from graveyards?", source, game)) { TargetCardInGraveyard targetCopy = new TargetCardInGraveyard(new FilterCreatureCard("creature card to become a copy of")); TargetCardInGraveyard targetCounters = new TargetCardInGraveyard(new FilterCreatureCard("creature card to determine amount of additional +1/+1 counters")); if (controller.choose(Outcome.Copy, targetCopy, source.getSourceId(), game)) { diff --git a/Mage.Sets/src/mage/sets/commander/VeteranExplorer.java b/Mage.Sets/src/mage/sets/commander/VeteranExplorer.java index 6e4a6390a3b..7644250ea4c 100644 --- a/Mage.Sets/src/mage/sets/commander/VeteranExplorer.java +++ b/Mage.Sets/src/mage/sets/commander/VeteranExplorer.java @@ -114,7 +114,7 @@ class VeteranExplorerEffect extends OneShotEffect { } private void chooseAndSearchLibrary(List usingPlayers, Player player, Ability source, Game game) { - if (player.chooseUse(Outcome.PutCardInPlay, "Search your library for up to two basic land cards and put them onto the battlefield?", game)) { + if (player.chooseUse(Outcome.PutCardInPlay, "Search your library for up to two basic land cards and put them onto the battlefield?", source, game)) { usingPlayers.add(player); TargetCardInLibrary target = new TargetCardInLibrary(0, 2, new FilterBasicLandCard()); if (player.searchLibrary(target, game)) { diff --git a/Mage.Sets/src/mage/sets/commander/WhirlpoolWhelm.java b/Mage.Sets/src/mage/sets/commander/WhirlpoolWhelm.java index b3309730759..88036f444a0 100644 --- a/Mage.Sets/src/mage/sets/commander/WhirlpoolWhelm.java +++ b/Mage.Sets/src/mage/sets/commander/WhirlpoolWhelm.java @@ -90,7 +90,7 @@ class WhirlpoolWhelmEffect extends OneShotEffect { if (controller != null) { boolean topOfLibrary = false; if (ClashEffect.getInstance().apply(game, source)) { - topOfLibrary = controller.chooseUse(outcome, "Put " + creature.getLogName() + " to top of libraray instead?" , game); + topOfLibrary = controller.chooseUse(outcome, "Put " + creature.getLogName() + " to top of libraray instead?" , source, game); } if (topOfLibrary) { controller.moveCardToHandWithInfo(creature, source.getSourceId(), game, Zone.BATTLEFIELD); diff --git a/Mage.Sets/src/mage/sets/commander/WildRicochet.java b/Mage.Sets/src/mage/sets/commander/WildRicochet.java index 6b411aa35d7..7c6f93ea12a 100644 --- a/Mage.Sets/src/mage/sets/commander/WildRicochet.java +++ b/Mage.Sets/src/mage/sets/commander/WildRicochet.java @@ -92,7 +92,7 @@ class WildRicochetEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Spell spell = game.getStack().getSpell(source.getFirstTarget()); Player you = game.getPlayer(source.getControllerId()); - if (spell != null && you != null && you.chooseUse(Outcome.Benefit, "Do you wish to choose new targets for " + spell.getName() + "?", game)) { + if (spell != null && you != null && you.chooseUse(Outcome.Benefit, "Do you wish to choose new targets for " + spell.getName() + "?", source, game)) { spell.chooseNewTargets(game, you.getId()); } if (spell != null) { @@ -100,7 +100,7 @@ class WildRicochetEffect extends OneShotEffect { copy.setControllerId(source.getControllerId()); copy.setCopiedSpell(true); game.getStack().push(copy); - if (you != null && you.chooseUse(Outcome.Benefit, "Do you wish to choose new targets for the copied " + spell.getName() + "?", game)) { + if (you != null && you.chooseUse(Outcome.Benefit, "Do you wish to choose new targets for the copied " + spell.getName() + "?", source, game)) { return copy.chooseNewTargets(game, you.getId()); } } diff --git a/Mage.Sets/src/mage/sets/commander2013/CurseOfChaos.java b/Mage.Sets/src/mage/sets/commander2013/CurseOfChaos.java index cb4931a6e3c..a0d5c026d22 100644 --- a/Mage.Sets/src/mage/sets/commander2013/CurseOfChaos.java +++ b/Mage.Sets/src/mage/sets/commander2013/CurseOfChaos.java @@ -141,7 +141,7 @@ class CurseOfChaosEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player attacker = game.getPlayer(this.getTargetPointer().getFirst(game, source)); if (attacker != null) { - if (attacker.getHand().size() > 0 && attacker.chooseUse(outcome, "Discard a card and draw a card?", game)){ + if (attacker.getHand().size() > 0 && attacker.chooseUse(outcome, "Discard a card and draw a card?", source, game)){ attacker.discard(1, false, source, game); attacker.drawCards(1, game); } diff --git a/Mage.Sets/src/mage/sets/commander2013/CurseOfInertia.java b/Mage.Sets/src/mage/sets/commander2013/CurseOfInertia.java index 45f60abb0cf..5f674df5b66 100644 --- a/Mage.Sets/src/mage/sets/commander2013/CurseOfInertia.java +++ b/Mage.Sets/src/mage/sets/commander2013/CurseOfInertia.java @@ -141,11 +141,11 @@ class CurseOfInertiaTapOrUntapTargetEffect extends OneShotEffect { Permanent targetPermanent = game.getPermanent(getTargetPointer().getFirst(game, source)); if (targetPermanent != null) { if (targetPermanent.isTapped()) { - if (player.chooseUse(Outcome.Untap, "Untap that permanent?", game)) { + if (player.chooseUse(Outcome.Untap, "Untap that permanent?", source, game)) { targetPermanent.untap(game); } } else { - if (player.chooseUse(Outcome.Tap, "Tap that permanent?", game)) { + if (player.chooseUse(Outcome.Tap, "Tap that permanent?", source, game)) { targetPermanent.tap(game); } } diff --git a/Mage.Sets/src/mage/sets/commander2013/JelevaNephaliasScourge.java b/Mage.Sets/src/mage/sets/commander2013/JelevaNephaliasScourge.java index 2c9f4f77f2f..4fbc4aba7cb 100644 --- a/Mage.Sets/src/mage/sets/commander2013/JelevaNephaliasScourge.java +++ b/Mage.Sets/src/mage/sets/commander2013/JelevaNephaliasScourge.java @@ -152,7 +152,7 @@ class JelevaNephaliasCastEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - if (controller.chooseUse(outcome, "Cast an instant or sorcery from exile?", game)) { + if (controller.chooseUse(outcome, "Cast an instant or sorcery from exile?", source, game)) { TargetCardInExile target = new TargetCardInExile(new FilterInstantOrSorceryCard(), CardUtil.getCardExileZoneId(game, source)); if (controller.choose(Outcome.PlayForFree, game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source)), target, game)) { Card card = game.getCard(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/sets/commander2013/LimDulsVault.java b/Mage.Sets/src/mage/sets/commander2013/LimDulsVault.java index 7a3b813c945..70324bd4e97 100644 --- a/Mage.Sets/src/mage/sets/commander2013/LimDulsVault.java +++ b/Mage.Sets/src/mage/sets/commander2013/LimDulsVault.java @@ -105,7 +105,7 @@ class LimDulsVaultEffect extends OneShotEffect { } } player.lookAtCards("Lim-Dul's Vault", cards, game); - doAgain = player.chooseUse(outcome, "Pay 1 lfe and look at the next 5 cards?", game); + doAgain = player.chooseUse(outcome, "Pay 1 lfe and look at the next 5 cards?", source, game); if (doAgain) { player.loseLife(1, game); } else { diff --git a/Mage.Sets/src/mage/sets/commander2013/PlagueBoiler.java b/Mage.Sets/src/mage/sets/commander2013/PlagueBoiler.java index 4ea19f2722f..e02eaaca2de 100644 --- a/Mage.Sets/src/mage/sets/commander2013/PlagueBoiler.java +++ b/Mage.Sets/src/mage/sets/commander2013/PlagueBoiler.java @@ -101,7 +101,7 @@ class PlagueBoilerEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); Permanent sourcePermanent = game.getPermanent(source.getSourceId()); if (controller != null && sourcePermanent != null) { - if (!sourcePermanent.getCounters().containsKey(CounterType.PLAGUE) || controller.chooseUse(outcome, "Put a plague counter on? (No removes one)", game)) { + if (!sourcePermanent.getCounters().containsKey(CounterType.PLAGUE) || controller.chooseUse(outcome, "Put a plague counter on? (No removes one)", source, game)) { return new AddCountersSourceEffect(CounterType.PLAGUE.createInstance(), true).apply(game, source); } else { return new RemoveCounterSourceEffect(CounterType.PLAGUE.createInstance()).apply(game, source); diff --git a/Mage.Sets/src/mage/sets/commander2013/SwordOfTheParuns.java b/Mage.Sets/src/mage/sets/commander2013/SwordOfTheParuns.java index 5af02c7199b..1257d41af76 100644 --- a/Mage.Sets/src/mage/sets/commander2013/SwordOfTheParuns.java +++ b/Mage.Sets/src/mage/sets/commander2013/SwordOfTheParuns.java @@ -123,11 +123,11 @@ class MayTapOrUntapAttachedEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); if (equipedCreature != null && player != null) { if (equipedCreature.isTapped()) { - if (player.chooseUse(Outcome.Untap, "Untap equipped creature?", game)) { + if (player.chooseUse(Outcome.Untap, "Untap equipped creature?", source, game)) { equipedCreature.untap(game); } } else { - if (player.chooseUse(Outcome.Tap, "Tap equipped creature?", game)) { + if (player.chooseUse(Outcome.Tap, "Tap equipped creature?", source, game)) { equipedCreature.tap(game); } } diff --git a/Mage.Sets/src/mage/sets/commander2013/TemptWithDiscovery.java b/Mage.Sets/src/mage/sets/commander2013/TemptWithDiscovery.java index d14c411cc48..e684acd3028 100644 --- a/Mage.Sets/src/mage/sets/commander2013/TemptWithDiscovery.java +++ b/Mage.Sets/src/mage/sets/commander2013/TemptWithDiscovery.java @@ -102,7 +102,7 @@ class TemptWithDiscoveryEffect extends OneShotEffect { for (UUID playerId : game.getOpponents(controller.getId())) { Player opponent = game.getPlayer(playerId); if (opponent != null) { - if (opponent.chooseUse(outcome, "Search your library for a land card and put it onto the battlefield?", game)) { + if (opponent.chooseUse(outcome, "Search your library for a land card and put it onto the battlefield?", source, game)) { target.clearChosen(); opponentsUsedSearch++; if (opponent.searchLibrary(target, game)) { diff --git a/Mage.Sets/src/mage/sets/commander2013/TemptWithGlory.java b/Mage.Sets/src/mage/sets/commander2013/TemptWithGlory.java index 8927b6bde98..dc0da22a51e 100644 --- a/Mage.Sets/src/mage/sets/commander2013/TemptWithGlory.java +++ b/Mage.Sets/src/mage/sets/commander2013/TemptWithGlory.java @@ -94,7 +94,7 @@ class TemptWithGloryEffect extends OneShotEffect { for (UUID playerId : game.getOpponents(controller.getId())) { Player opponent = game.getPlayer(playerId); if (opponent != null) { - if (opponent.chooseUse(outcome, "Put a +1/+1 counter on each creature you control?", game)) { + if (opponent.chooseUse(outcome, "Put a +1/+1 counter on each creature you control?", source, game)) { opponentsAddedCounters++; addCounterToEachCreature(playerId, counter, game); game.informPlayers(opponent.getLogName() + " added a +1/+1 counter on each of its creatures"); diff --git a/Mage.Sets/src/mage/sets/commander2013/TemptWithImmortality.java b/Mage.Sets/src/mage/sets/commander2013/TemptWithImmortality.java index 1ad0e580460..633914244a2 100644 --- a/Mage.Sets/src/mage/sets/commander2013/TemptWithImmortality.java +++ b/Mage.Sets/src/mage/sets/commander2013/TemptWithImmortality.java @@ -102,7 +102,7 @@ class TemptWithImmortalityEffect extends OneShotEffect { Target targetOpponent = new TargetCardInGraveyard(filter); if (targetOpponent.canChoose(source.getSourceId(), opponent.getId(), game)) { - if (opponent.chooseUse(outcome, new StringBuilder("Return a creature card from your graveyard to the battlefield?").toString(), game)) { + if (opponent.chooseUse(outcome, new StringBuilder("Return a creature card from your graveyard to the battlefield?").toString(), source, game)) { if (opponent.chooseTarget(outcome, targetOpponent, source, game)) { Card card = game.getCard(targetOpponent.getFirstTarget()); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/commander2013/TemptWithReflections.java b/Mage.Sets/src/mage/sets/commander2013/TemptWithReflections.java index 6451a9eab73..53cecb0c1c1 100644 --- a/Mage.Sets/src/mage/sets/commander2013/TemptWithReflections.java +++ b/Mage.Sets/src/mage/sets/commander2013/TemptWithReflections.java @@ -104,7 +104,7 @@ class TemptWithReflectionsEffect extends OneShotEffect { do { if (game.getOpponents(source.getControllerId()).contains(player.getId())) { String decision; - if (player.chooseUse(outcome, "Put a copy of target creature onto the battlefield for you?", game)) { + if (player.chooseUse(outcome, "Put a copy of target creature onto the battlefield for you?", source, game)) { playersSaidYes.add(player.getId()); decision = " chooses to copy "; } else { diff --git a/Mage.Sets/src/mage/sets/commander2013/TemptWithVengeance.java b/Mage.Sets/src/mage/sets/commander2013/TemptWithVengeance.java index 13511b636d3..06a6df8d5f9 100644 --- a/Mage.Sets/src/mage/sets/commander2013/TemptWithVengeance.java +++ b/Mage.Sets/src/mage/sets/commander2013/TemptWithVengeance.java @@ -94,7 +94,7 @@ class TemptWithVengeanceEffect extends OneShotEffect { for (UUID playerId : game.getOpponents(controller.getId())) { Player opponent = game.getPlayer(playerId); if (opponent != null) { - if (opponent.chooseUse(outcome, "Put " + xValue + " Elemental Tokens onto the battlefield?", game)) { + if (opponent.chooseUse(outcome, "Put " + xValue + " Elemental Tokens onto the battlefield?", source, game)) { opponentsAddedTokens += xValue; tokenCopy.putOntoBattlefield(xValue, game, source.getSourceId(), playerId, false, false); } diff --git a/Mage.Sets/src/mage/sets/commander2013/WarCadence.java b/Mage.Sets/src/mage/sets/commander2013/WarCadence.java index d34d2bd6ab5..c2032efb958 100644 --- a/Mage.Sets/src/mage/sets/commander2013/WarCadence.java +++ b/Mage.Sets/src/mage/sets/commander2013/WarCadence.java @@ -92,7 +92,7 @@ class WarCadenceReplacementEffect extends ReplacementEffectImpl { String mana = new StringBuilder("{").append(amount).append("}").toString(); ManaCostsImpl cost = new ManaCostsImpl(mana); if ( cost.canPay(source, source.getSourceId(), event.getPlayerId(), game) && - player.chooseUse(Outcome.Benefit, new StringBuilder("Pay ").append(mana).append(" to declare blocker?").toString(), game) ) { + player.chooseUse(Outcome.Benefit, new StringBuilder("Pay ").append(mana).append(" to declare blocker?").toString(), source, game) ) { if (cost.payOrRollback(source, game, source.getSourceId(), event.getPlayerId())) { return false; } diff --git a/Mage.Sets/src/mage/sets/commander2014/AssaultSuit.java b/Mage.Sets/src/mage/sets/commander2014/AssaultSuit.java index 42d7ff1ed97..8840a4cba29 100644 --- a/Mage.Sets/src/mage/sets/commander2014/AssaultSuit.java +++ b/Mage.Sets/src/mage/sets/commander2014/AssaultSuit.java @@ -160,7 +160,7 @@ class AssaultSuitGainControlEffect extends OneShotEffect { if (equipment.getAttachedTo() != null) { Permanent equippedCreature = game.getPermanent(equipment.getAttachedTo()); if (equippedCreature != null && controller.chooseUse(outcome, - "Let have " + activePlayer.getLogName() + " gain control of " + equippedCreature.getLogName() + "?", game)) { + "Let have " + activePlayer.getLogName() + " gain control of " + equippedCreature.getLogName() + "?", source, game)) { equippedCreature.untap(game); ContinuousEffect effect = new GainControlTargetEffect(Duration.EndOfTurn, activePlayer.getId()); effect.setTargetPointer(new FixedTarget(equipment.getAttachedTo())); diff --git a/Mage.Sets/src/mage/sets/commander2014/NahiriTheLithomancer.java b/Mage.Sets/src/mage/sets/commander2014/NahiriTheLithomancer.java index 3fad57eafff..826add7420e 100644 --- a/Mage.Sets/src/mage/sets/commander2014/NahiriTheLithomancer.java +++ b/Mage.Sets/src/mage/sets/commander2014/NahiriTheLithomancer.java @@ -139,7 +139,7 @@ class NahiriTheLithomancerFirstAbilityEffect extends OneShotEffect { //TODO: Make sure the Equipment can legally enchant the token, preferably on targetting. Target target = new TargetControlledPermanent(0, 1, filter, true); if (target.canChoose(source.getSourceId(), controller.getId(), game) && - controller.chooseUse(outcome, "Attach an Equipment you control to the created Token?", game)) { + controller.chooseUse(outcome, "Attach an Equipment you control to the created Token?", source, game)) { if (target.choose(Outcome.Neutral, source.getControllerId(), source.getSourceId(), game)) { Permanent equipmentPermanent = game.getPermanent(target.getFirstTarget()); if (equipmentPermanent != null) { @@ -199,7 +199,7 @@ class NahiriTheLithomancerSecondAbilityEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - if (controller.chooseUse(Outcome.PutCardInPlay, "Put an Equipment from hand? (No = from graveyard)", game)) { + if (controller.chooseUse(Outcome.PutCardInPlay, "Put an Equipment from hand? (No = from graveyard)", source, game)) { Target target = new TargetCardInHand(0, 1, filter); controller.choose(outcome, target, source.getSourceId(), game); Card card = controller.getHand().get(target.getFirstTarget(), game); diff --git a/Mage.Sets/src/mage/sets/commander2014/ShaperParasite.java b/Mage.Sets/src/mage/sets/commander2014/ShaperParasite.java index 99317c8f732..93b2ee92d09 100644 --- a/Mage.Sets/src/mage/sets/commander2014/ShaperParasite.java +++ b/Mage.Sets/src/mage/sets/commander2014/ShaperParasite.java @@ -106,7 +106,7 @@ class ShaperParasiteEffect extends ContinuousEffectImpl { super.init(source, game); Player player = game.getPlayer(source.getControllerId()); String message = "Should the target creature get -2/+2 instead of +2/-2?"; - if (player != null && player.chooseUse(Outcome.Neutral, message, game)) { + if (player != null && player.chooseUse(Outcome.Neutral, message, source, game)) { this.power *= -1; this.toughness *= -1; } diff --git a/Mage.Sets/src/mage/sets/commander2014/WaveOfVitriol.java b/Mage.Sets/src/mage/sets/commander2014/WaveOfVitriol.java index bf1405c76a0..19994d3145c 100644 --- a/Mage.Sets/src/mage/sets/commander2014/WaveOfVitriol.java +++ b/Mage.Sets/src/mage/sets/commander2014/WaveOfVitriol.java @@ -124,7 +124,7 @@ class WaveOfVitriolEffect extends OneShotEffect { } game.getState().handleSimultaneousEvent(game); for(Map.Entry entry: sacrificedLands.entrySet()) { - if (entry.getKey().chooseUse(Outcome.PutLandInPlay, "Search your library for up to " + entry.getValue() + " basic lands?", game)) { + if (entry.getKey().chooseUse(Outcome.PutLandInPlay, "Search your library for up to " + entry.getValue() + " basic lands?", source, game)) { Target target = new TargetCardInLibrary(0, entry.getValue(), new FilterBasicLandCard()); entry.getKey().chooseTarget(outcome, target, source, game); for(UUID targetId: target.getTargets()) { diff --git a/Mage.Sets/src/mage/sets/conflux/MaelstromArchangel.java b/Mage.Sets/src/mage/sets/conflux/MaelstromArchangel.java index dacb2b6bc61..073e0230c0a 100644 --- a/Mage.Sets/src/mage/sets/conflux/MaelstromArchangel.java +++ b/Mage.Sets/src/mage/sets/conflux/MaelstromArchangel.java @@ -101,7 +101,7 @@ class MaelstromArchangelCastEffect extends OneShotEffect { if (controller != null) { Target target = new TargetCardInHand(filter); if (target.canChoose(source.getSourceId(), controller.getId(), game) && - controller.chooseUse(outcome, "Cast a nonland card from your hand without paying its mana cost?", game)) { + controller.chooseUse(outcome, "Cast a nonland card from your hand without paying its mana cost?", source, game)) { Card cardToCast = null; boolean cancel = false; while (controller.isInGame() && !cancel) { diff --git a/Mage.Sets/src/mage/sets/conflux/MasterTransmuter.java b/Mage.Sets/src/mage/sets/conflux/MasterTransmuter.java index 5c150f9121d..98fb20c1ff8 100644 --- a/Mage.Sets/src/mage/sets/conflux/MasterTransmuter.java +++ b/Mage.Sets/src/mage/sets/conflux/MasterTransmuter.java @@ -104,7 +104,7 @@ class MasterTransmuterEffect extends OneShotEffect { if (controller != null) { Target target = new TargetCardInHand(new FilterArtifactCard("an artifact card from your hand")); if (target.canChoose(source.getSourceId(), source.getControllerId(), game) - && controller.chooseUse(outcome, "Put an artifact from your hand to battlefield?", game) + && controller.chooseUse(outcome, "Put an artifact from your hand to battlefield?", source, game) && controller.chooseTarget(outcome, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/conflux/PathToExile.java b/Mage.Sets/src/mage/sets/conflux/PathToExile.java index 66e23cbdc7e..bc78ddb72ef 100644 --- a/Mage.Sets/src/mage/sets/conflux/PathToExile.java +++ b/Mage.Sets/src/mage/sets/conflux/PathToExile.java @@ -94,7 +94,7 @@ class PathToExileEffect extends OneShotEffect { Player player = game.getPlayer(permanent.getControllerId()); // if the zone change to exile gets replaced does not prevent the target controller to be able to search controller.moveCardToExileWithInfo(permanent, null, "", source.getSourceId(), game, Zone.BATTLEFIELD, true); - if (player.chooseUse(Outcome.PutCardInPlay, "Search your library for a basic land card?", game)) { + if (player.chooseUse(Outcome.PutCardInPlay, "Search your library for a basic land card?", source, game)) { TargetCardInLibrary target = new TargetCardInLibrary(new FilterBasicLandCard()); if (player.searchLibrary(target, game)) { Card card = player.getLibrary().getCard(target.getFirstTarget(), game); diff --git a/Mage.Sets/src/mage/sets/conspiracy/CoercivePortal.java b/Mage.Sets/src/mage/sets/conspiracy/CoercivePortal.java index 7dcd761408a..b08a39c58dd 100644 --- a/Mage.Sets/src/mage/sets/conspiracy/CoercivePortal.java +++ b/Mage.Sets/src/mage/sets/conspiracy/CoercivePortal.java @@ -92,7 +92,7 @@ class CoercivePortalEffect extends OneShotEffect { for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { - if (player.chooseUse(Outcome.DestroyPermanent, "Choose carnage?", game)) { + if (player.chooseUse(Outcome.DestroyPermanent, "Choose carnage?", source, game)) { carnageCount++; game.informPlayers(player.getLogName() + " has chosen: carnage"); } diff --git a/Mage.Sets/src/mage/sets/conspiracy/TyrantsChoice.java b/Mage.Sets/src/mage/sets/conspiracy/TyrantsChoice.java index 845b4b01c34..8b2613ffe2f 100644 --- a/Mage.Sets/src/mage/sets/conspiracy/TyrantsChoice.java +++ b/Mage.Sets/src/mage/sets/conspiracy/TyrantsChoice.java @@ -88,7 +88,7 @@ class TyrantsChoiceEffect extends OneShotEffect { for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { - if (player.chooseUse(Outcome.Sacrifice, "Choose death?", game)) { + if (player.chooseUse(Outcome.Sacrifice, "Choose death?", source, game)) { deathCount++; game.informPlayers(player.getLogName() + " has chosen: death"); } diff --git a/Mage.Sets/src/mage/sets/darkascension/CallToTheKindred.java b/Mage.Sets/src/mage/sets/darkascension/CallToTheKindred.java index 664e4a8e004..7d0fcaf0d4d 100644 --- a/Mage.Sets/src/mage/sets/darkascension/CallToTheKindred.java +++ b/Mage.Sets/src/mage/sets/darkascension/CallToTheKindred.java @@ -141,7 +141,7 @@ class CallToTheKindredEffect extends OneShotEffect { sb.delete(sb.length() - 2, sb.length()); filter.setMessage(sb.toString()); - if (cards.count(filter, game) > 0 && player.chooseUse(Outcome.DrawCard, "Do you wish to put a creature card onto the battlefield?", game)) { + if (cards.count(filter, game) > 0 && player.chooseUse(Outcome.DrawCard, "Do you wish to put a creature card onto the battlefield?", source, game)) { TargetCard target = new TargetCard(Zone.PICK, filter); if (player.choose(Outcome.PutCreatureInPlay, cards, target, game)) { diff --git a/Mage.Sets/src/mage/sets/darkascension/Counterlash.java b/Mage.Sets/src/mage/sets/darkascension/Counterlash.java index 6b1e86113ce..cafcf179979 100644 --- a/Mage.Sets/src/mage/sets/darkascension/Counterlash.java +++ b/Mage.Sets/src/mage/sets/darkascension/Counterlash.java @@ -96,7 +96,7 @@ class CounterlashEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); if (stackObject != null && player != null) { game.getStack().counter(source.getFirstTarget(), source.getSourceId(), game); - if (player.chooseUse(Outcome.PutCardInPlay, "Cast a nonland card in your hand that shares a card type with that spell without paying its mana cost?", game)) { + if (player.chooseUse(Outcome.PutCardInPlay, "Cast a nonland card in your hand that shares a card type with that spell without paying its mana cost?", source, game)) { FilterCard filter = new FilterCard(); ArrayList> types = new ArrayList>(); for (CardType type: stackObject.getCardType()) { diff --git a/Mage.Sets/src/mage/sets/darkascension/CurseOfEchoes.java b/Mage.Sets/src/mage/sets/darkascension/CurseOfEchoes.java index bc023ef8818..297f33647d9 100644 --- a/Mage.Sets/src/mage/sets/darkascension/CurseOfEchoes.java +++ b/Mage.Sets/src/mage/sets/darkascension/CurseOfEchoes.java @@ -152,7 +152,7 @@ class CurseOfEchoesEffect extends OneShotEffect { for (UUID playerId: game.getPlayerList()) { if (!playerId.equals(spell.getControllerId())) { Player player = game.getPlayer(playerId); - if (player.chooseUse(Outcome.Copy, chooseMessage, game)) { + if (player.chooseUse(Outcome.Copy, chooseMessage, source, game)) { Spell copy = spell.copySpell(); copy.setControllerId(playerId); copy.setCopiedSpell(true); diff --git a/Mage.Sets/src/mage/sets/darkascension/SpitefulShadows.java b/Mage.Sets/src/mage/sets/darkascension/SpitefulShadows.java index 0d273b38a4e..a874f847366 100644 --- a/Mage.Sets/src/mage/sets/darkascension/SpitefulShadows.java +++ b/Mage.Sets/src/mage/sets/darkascension/SpitefulShadows.java @@ -58,12 +58,12 @@ public class SpitefulShadows extends CardImpl { this.expansionSetCode = "DKA"; this.subtype.add("Aura"); - // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.UnboostCreature)); this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + // Whenever enchanted creature is dealt damage, it deals that much damage to its controller. this.addAbility(new SpitefulShadowsTriggeredAbility()); } @@ -135,16 +135,16 @@ class SpitefulShadowsEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Integer damageAmount = (Integer) this.getValue("damageAmount"); - UUID targetId = this.targetPointer.getFirst(game, source); - if (damageAmount != null && targetId != null) { - Permanent permanent = game.getPermanent(targetId); + if (damageAmount != null) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); if (permanent == null) { - permanent = (Permanent) game.getLastKnownInformation(targetId, Zone.BATTLEFIELD); + FixedTarget fixedTarget = (FixedTarget) getTargetPointer(); + permanent = (Permanent) game.getLastKnownInformation(fixedTarget.getTarget(), Zone.BATTLEFIELD, fixedTarget.getZoneChangeCounter()); } if (permanent != null) { Player player = game.getPlayer(permanent.getControllerId()); if (player != null) { - player.damage(damageAmount, targetId, game, false, true); + player.damage(damageAmount, permanent.getId(), game, false, true); return true; } } diff --git a/Mage.Sets/src/mage/sets/darksteel/AEtherVial.java b/Mage.Sets/src/mage/sets/darksteel/AEtherVial.java index b675857cc8d..baa5d24d1c4 100644 --- a/Mage.Sets/src/mage/sets/darksteel/AEtherVial.java +++ b/Mage.Sets/src/mage/sets/darksteel/AEtherVial.java @@ -109,7 +109,7 @@ class AEtherVialEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); if (player == null || player.getHand().count(filter, game) == 0 - || !player.chooseUse(this.outcome, choiceText, game)) { + || !player.chooseUse(this.outcome, choiceText, source, game)) { return false; } diff --git a/Mage.Sets/src/mage/sets/darksteel/PanopticMirror.java b/Mage.Sets/src/mage/sets/darksteel/PanopticMirror.java index cc850ad7d53..4c565ce4e71 100644 --- a/Mage.Sets/src/mage/sets/darksteel/PanopticMirror.java +++ b/Mage.Sets/src/mage/sets/darksteel/PanopticMirror.java @@ -109,7 +109,7 @@ class PanopticMirrorExileEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); if (player == null || player.getHand().count(filter, game) == 0 - || !player.chooseUse(this.outcome, choiceText, game)) { + || !player.chooseUse(this.outcome, choiceText, source, game)) { return false; } @@ -177,7 +177,7 @@ class PanopticMirrorCastEffect extends OneShotEffect { } if(cardToCopy != null){ Card copy = game.copyCard(cardToCopy, source, source.getControllerId()); - if (controller.chooseUse(outcome, "Cast the copied card without paying mana cost?", game)) { + if (controller.chooseUse(outcome, "Cast the copied card without paying mana cost?", source, game)) { return controller.cast(copy.getSpellAbility(), game, true); } } diff --git a/Mage.Sets/src/mage/sets/darksteel/SerumPowder.java b/Mage.Sets/src/mage/sets/darksteel/SerumPowder.java index 3b07147d6d0..217b49f519b 100644 --- a/Mage.Sets/src/mage/sets/darksteel/SerumPowder.java +++ b/Mage.Sets/src/mage/sets/darksteel/SerumPowder.java @@ -87,7 +87,7 @@ class SerumPowderReplaceEffect extends ReplacementEffectImpl { Player controller = game.getPlayer(source.getControllerId()); Card sourceCard = game.getCard(source.getSourceId()); if (controller != null && sourceCard != null) { - if (!controller.chooseUse(outcome, "Exile all cards from hand and draw that many cards?", game)) { + if (!controller.chooseUse(outcome, "Exile all cards from hand and draw that many cards?", source, game)) { return false; } int cardsHand = controller.getHand().size(); diff --git a/Mage.Sets/src/mage/sets/darksteel/SwordOfLightAndShadow.java b/Mage.Sets/src/mage/sets/darksteel/SwordOfLightAndShadow.java index 1d4414a3c46..b090e5ffd8b 100644 --- a/Mage.Sets/src/mage/sets/darksteel/SwordOfLightAndShadow.java +++ b/Mage.Sets/src/mage/sets/darksteel/SwordOfLightAndShadow.java @@ -172,7 +172,7 @@ class SwordOfLightAndShadowReturnToHandTargetEffect extends OneShotEffect { return false; } if (!source.getTargets().isEmpty() && targetPointer.getFirst(game, source) != null) { - if (controller.chooseUse(outcome, "Return creature card from graveyard to hand?", game)) { + if (controller.chooseUse(outcome, "Return creature card from graveyard to hand?", source, game)) { for (UUID targetId : targetPointer.getTargets(game, source)) { switch (game.getState().getZone(targetId)) { case GRAVEYARD: diff --git a/Mage.Sets/src/mage/sets/dissension/ResearchDevelopment.java b/Mage.Sets/src/mage/sets/dissension/ResearchDevelopment.java index 353b431a555..959e9e2fc81 100644 --- a/Mage.Sets/src/mage/sets/dissension/ResearchDevelopment.java +++ b/Mage.Sets/src/mage/sets/dissension/ResearchDevelopment.java @@ -102,7 +102,7 @@ class ResearchEffect extends OneShotEffect { StringBuilder textToAsk = new StringBuilder(choiceText); textToAsk.append(" (0)"); int count = 0; - while (player.chooseUse(Outcome.Benefit, textToAsk.toString(), game)) { + while (player.chooseUse(Outcome.Benefit, textToAsk.toString(), source, game)) { Cards cards = player.getSideboard(); if(cards.isEmpty()) { game.informPlayer(player, "You have no cards outside the game."); @@ -172,7 +172,7 @@ class DevelopmentEffect extends OneShotEffect { for (UUID opponentUuid : opponents) { Player opponent = game.getPlayer(opponentUuid); if (opponent != null && opponent.chooseUse(Outcome.Detriment, - "Allow " + player.getLogName() + " to draw a card instead? (" + Integer.toString(i+1) + ")", game)) { + "Allow " + player.getLogName() + " to draw a card instead? (" + Integer.toString(i+1) + ")", source, game)) { game.informPlayers(opponent.getLogName() + " had chosen to let " + player.getLogName() + " draw a card."); player.drawCards(1, game); putToken = false; diff --git a/Mage.Sets/src/mage/sets/dragonsmaze/HiddenStrings.java b/Mage.Sets/src/mage/sets/dragonsmaze/HiddenStrings.java index f10ce2e4e7c..51132bc9b05 100644 --- a/Mage.Sets/src/mage/sets/dragonsmaze/HiddenStrings.java +++ b/Mage.Sets/src/mage/sets/dragonsmaze/HiddenStrings.java @@ -99,11 +99,11 @@ class HiddenStringsEffect extends OneShotEffect { Permanent permanent = game.getPermanent(targetId); if (permanent != null) { if (permanent.isTapped()) { - if (player.chooseUse(Outcome.Untap, new StringBuilder("Untap ").append(permanent.getName()).append("?").toString(), game)) { + if (player.chooseUse(Outcome.Untap, new StringBuilder("Untap ").append(permanent.getName()).append("?").toString(), source, game)) { permanent.untap(game); } } else { - if (player.chooseUse(Outcome.Tap, new StringBuilder("Tap ").append(permanent.getName()).append("?").toString(), game)) { + if (player.chooseUse(Outcome.Tap, new StringBuilder("Tap ").append(permanent.getName()).append("?").toString(), source, game)) { permanent.tap(game); } } diff --git a/Mage.Sets/src/mage/sets/dragonsmaze/PossibilityStorm.java b/Mage.Sets/src/mage/sets/dragonsmaze/PossibilityStorm.java index 0b751240674..a937018ec39 100644 --- a/Mage.Sets/src/mage/sets/dragonsmaze/PossibilityStorm.java +++ b/Mage.Sets/src/mage/sets/dragonsmaze/PossibilityStorm.java @@ -150,7 +150,7 @@ class PossibilityStormEffect extends OneShotEffect { if (card != null && sharesType(card, spell.getCardType()) && !card.getCardType().contains(CardType.LAND) && card.getSpellAbility().getTargets().canChoose(spellController.getId(), game)) { - if (spellController.chooseUse(Outcome.PlayForFree, "Cast " + card.getLogName() + " without paying cost?", game)) { + if (spellController.chooseUse(Outcome.PlayForFree, "Cast " + card.getLogName() + " without paying cost?", source, game)) { spellController.cast(card.getSpellAbility(), game, true); } } diff --git a/Mage.Sets/src/mage/sets/dragonsoftarkir/ArashinSovereign.java b/Mage.Sets/src/mage/sets/dragonsoftarkir/ArashinSovereign.java index a34bc3eac6d..2b2439a2595 100644 --- a/Mage.Sets/src/mage/sets/dragonsoftarkir/ArashinSovereign.java +++ b/Mage.Sets/src/mage/sets/dragonsoftarkir/ArashinSovereign.java @@ -94,7 +94,7 @@ class ArashinSovereignEffect extends OneShotEffect { Card sourceCard = game.getCard(source.getSourceId()); if (controller != null && sourceCard != null) { if (game.getState().getZone(source.getSourceId()) == Zone.GRAVEYARD) { - boolean onTop = controller.chooseUse(outcome, "Put " + sourceCard.getName() + " on top of it's owners library (otherwise on bottom)?", game); + boolean onTop = controller.chooseUse(outcome, "Put " + sourceCard.getName() + " on top of it's owners library (otherwise on bottom)?", source, game); controller.moveCardToLibraryWithInfo(sourceCard, source.getSourceId(), game, Zone.GRAVEYARD, onTop, true); } return true; diff --git a/Mage.Sets/src/mage/sets/dragonsoftarkir/DeathmistRaptor.java b/Mage.Sets/src/mage/sets/dragonsoftarkir/DeathmistRaptor.java index d6295186c56..098a319ff68 100644 --- a/Mage.Sets/src/mage/sets/dragonsoftarkir/DeathmistRaptor.java +++ b/Mage.Sets/src/mage/sets/dragonsoftarkir/DeathmistRaptor.java @@ -102,7 +102,7 @@ class DeathmistRaptorEffect extends OneShotEffect { MageObject sourceObject = source.getSourceObjectIfItStillExists(game); if (controller != null && (sourceObject instanceof Card)) { controller.putOntoBattlefieldWithInfo((Card) sourceObject, game, Zone.GRAVEYARD, source.getSourceId(), false, - controller.chooseUse(Outcome.Detriment, "Return " + sourceObject.getLogName() + " face down to battlefield (otherwise face up)?", game)); + controller.chooseUse(Outcome.Detriment, "Return " + sourceObject.getLogName() + " face down to battlefield (otherwise face up)?", source, game)); return true; } return false; diff --git a/Mage.Sets/src/mage/sets/dragonsoftarkir/MysticMeditation.java b/Mage.Sets/src/mage/sets/dragonsoftarkir/MysticMeditation.java index 1fcdf2154d5..46b1afc78a8 100644 --- a/Mage.Sets/src/mage/sets/dragonsoftarkir/MysticMeditation.java +++ b/Mage.Sets/src/mage/sets/dragonsoftarkir/MysticMeditation.java @@ -92,7 +92,7 @@ class MysticMeditationEffect extends OneShotEffect { filter.add(new CardTypePredicate(CardType.CREATURE)); if (controller != null && controller.getHand().count(filter, game) > 0 - && controller.chooseUse(Outcome.Discard, "Do you want to discard a creature card? If you don't, you must discard 2 cards", game)) { + && controller.chooseUse(Outcome.Discard, "Do you want to discard a creature card? If you don't, you must discard 2 cards", source, game)) { Cost cost = new DiscardTargetCost(new TargetCardInHand(filter)); if (cost.canPay(source, source.getSourceId(), controller.getId(), game)) { if (cost.pay(source, game, source.getSourceId(), controller.getId(), false)) { diff --git a/Mage.Sets/src/mage/sets/dragonsoftarkir/NarsetTranscendent.java b/Mage.Sets/src/mage/sets/dragonsoftarkir/NarsetTranscendent.java index 39e70a117dd..a490b0d3a06 100644 --- a/Mage.Sets/src/mage/sets/dragonsoftarkir/NarsetTranscendent.java +++ b/Mage.Sets/src/mage/sets/dragonsoftarkir/NarsetTranscendent.java @@ -121,7 +121,7 @@ class NarsetTranscendentEffect1 extends OneShotEffect { cards.add(card); controller.lookAtCards(sourceObject.getName(), cards, game); if (!card.getCardType().contains(CardType.CREATURE) && !card.getCardType().contains(CardType.LAND)) { - if (controller.chooseUse(outcome, "Reveal " + card.getName() + " and put it into your hand?", game)) { + if (controller.chooseUse(outcome, "Reveal " + card.getName() + " and put it into your hand?", source, game)) { controller.moveCardToHandWithInfo(card, source.getSourceId(), game, Zone.LIBRARY); controller.revealCards(sourceObject.getName(), cards, game); } diff --git a/Mage.Sets/src/mage/sets/dragonsoftarkir/QalSismaBehemoth.java b/Mage.Sets/src/mage/sets/dragonsoftarkir/QalSismaBehemoth.java index 06f698c20a9..b32f307659c 100644 --- a/Mage.Sets/src/mage/sets/dragonsoftarkir/QalSismaBehemoth.java +++ b/Mage.Sets/src/mage/sets/dragonsoftarkir/QalSismaBehemoth.java @@ -104,7 +104,7 @@ class QalSismaBehemothEffect extends ReplacementEffectImpl { } ManaCostsImpl attackBlockTax = new ManaCostsImpl("{2}"); if (attackBlockTax.canPay(source, source.getSourceId(), event.getPlayerId(), game) - && player.chooseUse(Outcome.Neutral, chooseText, game)) { + && player.chooseUse(Outcome.Neutral, chooseText, source, game)) { if (attackBlockTax.payOrRollback(source, game, source.getSourceId(), event.getPlayerId())) { return false; } diff --git a/Mage.Sets/src/mage/sets/dragonsoftarkir/RevealingWind.java b/Mage.Sets/src/mage/sets/dragonsoftarkir/RevealingWind.java index a057081e31d..71108179dac 100644 --- a/Mage.Sets/src/mage/sets/dragonsoftarkir/RevealingWind.java +++ b/Mage.Sets/src/mage/sets/dragonsoftarkir/RevealingWind.java @@ -101,7 +101,7 @@ class RevealingWindEffect extends OneShotEffect { MageObject sourceObject = source.getSourceObject(game); if (controller != null && sourceObject != null) { while (game.getBattlefield().count(filter, source.getOriginalId(), source.getControllerId(), game) > 0 && - controller.chooseUse(outcome, "Look at a face-down attacking creature?", game)) { + controller.chooseUse(outcome, "Look at a face-down attacking creature?", source, game)) { if (!controller.isInGame()) { return false; } diff --git a/Mage.Sets/src/mage/sets/dragonsoftarkir/SilumgarsScorn.java b/Mage.Sets/src/mage/sets/dragonsoftarkir/SilumgarsScorn.java index a8788977031..f6bbf26fd3b 100644 --- a/Mage.Sets/src/mage/sets/dragonsoftarkir/SilumgarsScorn.java +++ b/Mage.Sets/src/mage/sets/dragonsoftarkir/SilumgarsScorn.java @@ -132,7 +132,7 @@ class SilumgarsScornCounterEffect extends OneShotEffect { if (condition) { return game.getStack().counter(spell.getId(), source.getSourceId(), game); } - if (!(player.chooseUse(Outcome.Benefit, "Would you like to pay {1} to prevent counter effect?", game) && + if (!(player.chooseUse(Outcome.Benefit, "Would you like to pay {1} to prevent counter effect?", source, game) && new GenericManaCost(1).pay(source, game, spell.getSourceId(), spell.getControllerId(), false))) { return game.getStack().counter(spell.getId(), source.getSourceId(), game); } diff --git a/Mage.Sets/src/mage/sets/dragonsoftarkir/SwiftWarkite.java b/Mage.Sets/src/mage/sets/dragonsoftarkir/SwiftWarkite.java index 26ba71120ca..d3a8b1757eb 100644 --- a/Mage.Sets/src/mage/sets/dragonsoftarkir/SwiftWarkite.java +++ b/Mage.Sets/src/mage/sets/dragonsoftarkir/SwiftWarkite.java @@ -117,7 +117,7 @@ class SwiftWarkiteEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - if (controller.chooseUse(Outcome.PutCardInPlay, "Put a creature card from your hand? (No = from your graveyard)", game)) { + if (controller.chooseUse(Outcome.PutCardInPlay, "Put a creature card from your hand? (No = from your graveyard)", source, game)) { Target target = new TargetCardInHand(0, 1, filter); controller.choose(outcome, target, source.getSourceId(), game); Card card = controller.getHand().get(target.getFirstTarget(), game); diff --git a/Mage.Sets/src/mage/sets/eventide/Evershrike.java b/Mage.Sets/src/mage/sets/eventide/Evershrike.java index 411fca6c81b..f413f47643e 100644 --- a/Mage.Sets/src/mage/sets/eventide/Evershrike.java +++ b/Mage.Sets/src/mage/sets/eventide/Evershrike.java @@ -122,7 +122,7 @@ class EvershrikeEffect extends OneShotEffect { filterAuraCard.add(new AuraCardCanAttachToPermanentId(evershrikePermanent.getId())); filterAuraCard.add(new ConvertedManaCostPredicate(ComparisonType.LessThan, xAmount)); int count = controller.getHand().count(filterAuraCard, game); - while (controller.isInGame() && count > 0 && controller.chooseUse(Outcome.Benefit, "Do you wish to put an Aura card from your hand onto Evershrike", game)) { + while (controller.isInGame() && count > 0 && controller.chooseUse(Outcome.Benefit, "Do you wish to put an Aura card from your hand onto Evershrike", source, game)) { TargetCard targetAura = new TargetCard(Zone.PICK, filterAuraCard); if (controller.choose(Outcome.Benefit, controller.getHand(), targetAura, game)) { Card aura = game.getCard(targetAura.getFirstTarget()); diff --git a/Mage.Sets/src/mage/sets/eventide/MindwrackLiege.java b/Mage.Sets/src/mage/sets/eventide/MindwrackLiege.java index 43fb85a3b22..eda9db62341 100644 --- a/Mage.Sets/src/mage/sets/eventide/MindwrackLiege.java +++ b/Mage.Sets/src/mage/sets/eventide/MindwrackLiege.java @@ -128,7 +128,7 @@ class MindwrackLiegeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (player == null || !player.chooseUse(Outcome.PutCreatureInPlay, choiceText, game)) { + if (player == null || !player.chooseUse(Outcome.PutCreatureInPlay, choiceText, source, game)) { return false; } diff --git a/Mage.Sets/src/mage/sets/eventide/Necroskitter.java b/Mage.Sets/src/mage/sets/eventide/Necroskitter.java index 5d67ee26ccd..e3945c2cc46 100644 --- a/Mage.Sets/src/mage/sets/eventide/Necroskitter.java +++ b/Mage.Sets/src/mage/sets/eventide/Necroskitter.java @@ -59,7 +59,7 @@ public class Necroskitter extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(4); - // Wither + // Wither (This deals damage to creatures in the form of -1/-1 counters.) this.addAbility(WitherAbility.getInstance()); // Whenever a creature an opponent controls with a -1/-1 counter on it dies, you may return that card to the battlefield under your control. diff --git a/Mage.Sets/src/mage/sets/eventide/RiseOfTheHobgoblins.java b/Mage.Sets/src/mage/sets/eventide/RiseOfTheHobgoblins.java index 7dcda6a51f9..a168f001040 100644 --- a/Mage.Sets/src/mage/sets/eventide/RiseOfTheHobgoblins.java +++ b/Mage.Sets/src/mage/sets/eventide/RiseOfTheHobgoblins.java @@ -116,7 +116,7 @@ class RiseOfTheHobgoblinsEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player you = game.getPlayer(source.getControllerId()); ManaCosts cost = new ManaCostsImpl<>("{X}"); - if (you != null && you.chooseUse(Outcome.Neutral, "Do you want to to pay {X}?", game)) { + if (you != null && you.chooseUse(Outcome.Neutral, "Do you want to to pay {X}?", source, game)) { int costX = you.announceXMana(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source); cost.add(new GenericManaCost(costX)); if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { diff --git a/Mage.Sets/src/mage/sets/exodus/ErraticPortal.java b/Mage.Sets/src/mage/sets/exodus/ErraticPortal.java index 49b4ef3f46b..66f16ccb7c3 100644 --- a/Mage.Sets/src/mage/sets/exodus/ErraticPortal.java +++ b/Mage.Sets/src/mage/sets/exodus/ErraticPortal.java @@ -102,7 +102,7 @@ class ErraticPortalEffect extends OneShotEffect { Player player = game.getPlayer(targetCreature.getControllerId()); if (player != null) { cost.clearPaid(); - if (player.chooseUse(Outcome.Benefit, "Pay {1}? (Otherwise " + targetCreature.getLogName() +" will be returned to its owner's hand)", game)) { + if (player.chooseUse(Outcome.Benefit, "Pay {1}? (Otherwise " + targetCreature.getLogName() +" will be returned to its owner's hand)", source, game)) { cost.pay(source, game, targetCreature.getControllerId(), targetCreature.getControllerId(), false); } if (!cost.isPaid()) { diff --git a/Mage.Sets/src/mage/sets/exodus/ExaltedDragon.java b/Mage.Sets/src/mage/sets/exodus/ExaltedDragon.java index 12b39be1e82..f0aa723125a 100644 --- a/Mage.Sets/src/mage/sets/exodus/ExaltedDragon.java +++ b/Mage.Sets/src/mage/sets/exodus/ExaltedDragon.java @@ -103,7 +103,7 @@ class ExaltedDragonReplacementEffect extends ReplacementEffectImpl { if ( player != null ) { SacrificeTargetCost attackCost = new SacrificeTargetCost(new TargetControlledPermanent(filter)); if ( attackCost.canPay(source, source.getSourceId(), event.getPlayerId(), game) && - player.chooseUse(Outcome.Neutral, "Sacrifice a land?", game) ) + player.chooseUse(Outcome.Neutral, "Sacrifice a land?", source, game) ) { if (attackCost.pay(source, game, source.getSourceId(), event.getPlayerId(), false) ) { return false; diff --git a/Mage.Sets/src/mage/sets/fatereforged/TemurSabertooth.java b/Mage.Sets/src/mage/sets/fatereforged/TemurSabertooth.java index 9a6f19c3839..465bb3dcfda 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/TemurSabertooth.java +++ b/Mage.Sets/src/mage/sets/fatereforged/TemurSabertooth.java @@ -105,7 +105,7 @@ class TemurSabertoothEffect extends OneShotEffect { if (controller != null) { Target target = new TargetPermanent(1,1, filter, true); if (target.canChoose(source.getSourceId(), controller.getId(), game)) { - if (controller.chooseUse(outcome, "Return another creature to hand?", game) && + if (controller.chooseUse(outcome, "Return another creature to hand?", source, game) && controller.chooseTarget(outcome, target, source, game)) { Permanent toHand = game.getPermanent(target.getFirstTarget()); if (toHand != null) { diff --git a/Mage.Sets/src/mage/sets/fatereforged/WriteIntoBeing.java b/Mage.Sets/src/mage/sets/fatereforged/WriteIntoBeing.java index 06df7949b25..8b6397af6c2 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/WriteIntoBeing.java +++ b/Mage.Sets/src/mage/sets/fatereforged/WriteIntoBeing.java @@ -112,7 +112,7 @@ class WriteIntoBeingEffect extends OneShotEffect { if (controller.getLibrary().size() > 0) { Card cardToPutBack = controller.getLibrary().getFromTop(game); String position = "on top"; - if (controller.chooseUse(Outcome.Detriment, "Put " + cardToPutBack.getName() + " on bottom of library?", game)) { + if (controller.chooseUse(Outcome.Detriment, "Put " + cardToPutBack.getName() + " on bottom of library?", source, game)) { cardToPutBack.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); position = "on bottom"; } diff --git a/Mage.Sets/src/mage/sets/fifthdawn/DisruptionAura.java b/Mage.Sets/src/mage/sets/fifthdawn/DisruptionAura.java index 2820115cb82..9cb5e3fcf4a 100644 --- a/Mage.Sets/src/mage/sets/fifthdawn/DisruptionAura.java +++ b/Mage.Sets/src/mage/sets/fifthdawn/DisruptionAura.java @@ -110,7 +110,7 @@ class DisruptionAuraEffect extends OneShotEffect { String message = CardUtil.replaceSourceName("Pay {this} mana cost ?", permanent.getLogName()); Cost cost = permanent.getManaCost().copy(); - if (player.chooseUse(Outcome.Benefit, message, game)) { + if (player.chooseUse(Outcome.Benefit, message, source, game)) { cost.clearPaid(); if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { return true; diff --git a/Mage.Sets/src/mage/sets/fifthdawn/FoldIntoAEther.java b/Mage.Sets/src/mage/sets/fifthdawn/FoldIntoAEther.java index 5304727f9c0..7ddcccce951 100644 --- a/Mage.Sets/src/mage/sets/fifthdawn/FoldIntoAEther.java +++ b/Mage.Sets/src/mage/sets/fifthdawn/FoldIntoAEther.java @@ -95,7 +95,7 @@ class FoldIntoAEtherEffect extends OneShotEffect { if (game.getStack().counter(source.getFirstTarget(), source.getSourceId(), game)) { TargetCardInHand target = new TargetCardInHand(new FilterCreatureCard()); if (player != null - && player.chooseUse(Outcome.Neutral, "Put a creature card from your hand in play?", game) + && player.chooseUse(Outcome.Neutral, "Put a creature card from your hand in play?", source, game) && player.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/fifthdawn/ReversalOfFortune.java b/Mage.Sets/src/mage/sets/fifthdawn/ReversalOfFortune.java index 05a49050c48..b418addb3d4 100644 --- a/Mage.Sets/src/mage/sets/fifthdawn/ReversalOfFortune.java +++ b/Mage.Sets/src/mage/sets/fifthdawn/ReversalOfFortune.java @@ -106,7 +106,7 @@ class ReversalOfFortuneEffect extends OneShotEffect { //If you do, you may cast the copy without paying its mana cost if(card != null){ Card copiedCard = game.copyCard(card, source, source.getControllerId()); - if (controller.chooseUse(outcome, "Cast the copied card without paying mana cost?", game)) { + if (controller.chooseUse(outcome, "Cast the copied card without paying mana cost?", source, game)) { controller.cast(copiedCard.getSpellAbility(), game, true); } } diff --git a/Mage.Sets/src/mage/sets/fifthedition/FerozsBan.java b/Mage.Sets/src/mage/sets/fifthedition/FerozsBan.java new file mode 100644 index 00000000000..283c78fdc59 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fifthedition/FerozsBan.java @@ -0,0 +1,65 @@ +/* + * 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.fifthedition; + +import java.util.UUID; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.cost.SpellsCostIncreasementAllEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreatureCard; + +/** + * + * @author LoneFox + + */ +public class FerozsBan extends CardImpl { + + public FerozsBan(UUID ownerId) { + super(ownerId, 370, "Feroz's Ban", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{6}"); + this.expansionSetCode = "5ED"; + + // Creature spells cost {2} more to cast. + Effect effect = new SpellsCostIncreasementAllEffect(new FilterCreatureCard(), 2); + effect.setText("Creature spells cost {2} more to cast."); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + } + + public FerozsBan(final FerozsBan card) { + super(card); + } + + @Override + public FerozsBan copy() { + return new FerozsBan(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fifthedition/ShieldWall.java b/Mage.Sets/src/mage/sets/fifthedition/ShieldWall.java new file mode 100644 index 00000000000..bffa90cf0f3 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fifthedition/ShieldWall.java @@ -0,0 +1,55 @@ +/* + * 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.fifthedition; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author LoneFox + + */ +public class ShieldWall extends mage.sets.legends.ShieldWall { + + public ShieldWall(UUID ownerId) { + super(ownerId); + this.cardNumber = 339; + this.expansionSetCode = "5ED"; + this.rarity = Rarity.COMMON; + } + + public ShieldWall(final ShieldWall card) { + super(card); + } + + @Override + public ShieldWall copy() { + return new ShieldWall(this); + } +} diff --git a/Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java b/Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java index 422f7065d09..107198b3830 100644 --- a/Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java +++ b/Mage.Sets/src/mage/sets/fifthedition/SylvanLibrary.java @@ -61,7 +61,6 @@ public class SylvanLibrary extends CardImpl { super(ownerId, 191, "Sylvan Library", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); this.expansionSetCode = "5ED"; - // At the beginning of your draw step, you may draw two additional cards. If you do, choose two cards in your hand drawn this turn. For each of those cards, pay 4 life or put the card on top of your library. this.addAbility(new BeginningOfDrawTriggeredAbility(new SylvanLibraryEffect(), TargetController.YOU, true), new CardsDrawnThisTurnWatcher()); @@ -81,7 +80,7 @@ class SylvanLibraryEffect extends OneShotEffect { public SylvanLibraryEffect() { super(Outcome.LoseLife); - this.staticText = "draw two additional cards. If you do, choose two cards in your hand drawn this turn. For each of those cards, pay 4 life or put the card on top of your library"; + this.staticText = "you may draw two additional cards. If you do, choose two cards in your hand drawn this turn. For each of those cards, pay 4 life or put the card on top of your library"; } public SylvanLibraryEffect(final SylvanLibraryEffect effect) { @@ -111,18 +110,18 @@ class SylvanLibraryEffect extends OneShotEffect { } int numberOfTargets = Math.min(2, cards.size()); if (numberOfTargets > 0) { - TargetCardInHand target = new TargetCardInHand(numberOfTargets, new FilterCard(new StringBuilder(numberOfTargets).append(" cards of cards drawn this turn").toString())); + TargetCardInHand target = new TargetCardInHand(numberOfTargets, new FilterCard(numberOfTargets + " cards of cards drawn this turn")); controller.chooseTarget(outcome, cards, target, source, game); Cards cardsPutBack = new CardsImpl(); - for (UUID cardId :target.getTargets()) { + for (UUID cardId : target.getTargets()) { Card card = cards.get(cardId, game); if (card != null) { if (controller.canPayLifeCost() && controller.getLife() >= 4 - && controller.chooseUse(outcome, new StringBuilder("Pay 4 life for ").append(card.getName()).append("? (Otherwise it's put on top of your library)").toString(), game)) { + && controller.chooseUse(outcome, "Pay 4 life for " + card.getLogName() + "? (Otherwise it's put on top of your library)", source, game)) { controller.loseLife(4, game); - game.informPlayers(new StringBuilder(controller.getLogName()).append(" pays 4 life to keep a card on hand").toString()); + game.informPlayers(controller.getLogName() + " pays 4 life to keep a card on hand"); } else { cardsPutBack.add(card); } @@ -146,7 +145,7 @@ class SylvanLibraryEffect extends OneShotEffect { card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); } if (numberOfCardsToPutBack > 0) { - game.informPlayers(new StringBuilder(controller.getLogName()).append(" puts ").append(numberOfCardsToPutBack).append(" card(s) back to library").toString()); + game.informPlayers(controller.getLogName() + " puts " + numberOfCardsToPutBack + " card(s) back to library"); } } } @@ -160,7 +159,6 @@ class CardsDrawnThisTurnWatcher extends Watcher { private final Set cardsDrawnThisTurn = new HashSet(); - public CardsDrawnThisTurnWatcher() { super("CardsDrawnThisTurnWatcher", WatcherScope.PLAYER); } diff --git a/Mage.Sets/src/mage/sets/fourthedition/ForceOfNature.java b/Mage.Sets/src/mage/sets/fourthedition/ForceOfNature.java index e1e9cd6060c..49ae48923a3 100644 --- a/Mage.Sets/src/mage/sets/fourthedition/ForceOfNature.java +++ b/Mage.Sets/src/mage/sets/fourthedition/ForceOfNature.java @@ -96,7 +96,7 @@ class ForceOfNatureEffect extends OneShotEffect { if (controller != null) { Cost cost = new ManaCostsImpl("{G}{G}{G}{G}"); String message = "Would you like to pay {G}{G}{G}{G} to prevent taking 8 damage from {this}?"; - if (!(controller.chooseUse(Outcome.Benefit, message, game) + if (!(controller.chooseUse(Outcome.Benefit, message, source, game) && cost.pay(source, game, source.getSourceId(), controller.getId(), false))) { controller.damage(8, source.getSourceId(), game, false, true); } diff --git a/Mage.Sets/src/mage/sets/fourthedition/Immolation.java b/Mage.Sets/src/mage/sets/fourthedition/Immolation.java new file mode 100644 index 00000000000..31eea4474c7 --- /dev/null +++ b/Mage.Sets/src/mage/sets/fourthedition/Immolation.java @@ -0,0 +1,74 @@ +/* + * 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.fourthedition; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author ilcartographer + */ +public class Immolation extends CardImpl { + + public Immolation(UUID ownerId) { + super(ownerId, 222, "Immolation", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{R}"); + this.expansionSetCode = "4ED"; + this.subtype.add("Aura"); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Enchanted creature gets +2/-2. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(2, -2))); + } + + public Immolation(final Immolation card) { + super(card); + } + + @Override + public Immolation copy() { + return new Immolation(this); + } +} diff --git a/Mage.Sets/src/mage/sets/futuresight/GlitteringWish.java b/Mage.Sets/src/mage/sets/futuresight/GlitteringWish.java index 3f4ea5a174f..9f2aa2e6e1a 100644 --- a/Mage.Sets/src/mage/sets/futuresight/GlitteringWish.java +++ b/Mage.Sets/src/mage/sets/futuresight/GlitteringWish.java @@ -110,7 +110,7 @@ class GlitteringWishEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - while (player.chooseUse(Outcome.Benefit, choiceText, game)) { + while (player.chooseUse(Outcome.Benefit, choiceText, source, game)) { Cards cards = player.getSideboard(); if(cards.isEmpty()) { game.informPlayer(player, "You have no cards outside the game."); diff --git a/Mage.Sets/src/mage/sets/gameday/ScaleguardSentinels.java b/Mage.Sets/src/mage/sets/gameday/ScaleguardSentinels.java index 07ed157378b..5167e1c6d68 100644 --- a/Mage.Sets/src/mage/sets/gameday/ScaleguardSentinels.java +++ b/Mage.Sets/src/mage/sets/gameday/ScaleguardSentinels.java @@ -28,7 +28,6 @@ package mage.sets.gameday; import java.util.UUID; - import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; @@ -60,9 +59,9 @@ public class ScaleguardSentinels extends CardImpl { static { filter.add(new SubtypePredicate("Dragon")); } - + public ScaleguardSentinels(UUID ownerId) { - super(ownerId, 43, "Scaleguard Sentinels", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{G}{G}"); + super(ownerId, 44, "Scaleguard Sentinels", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{G}{G}"); this.expansionSetCode = "MGDC"; this.subtype.add("Human"); this.subtype.add("Soldier"); @@ -71,27 +70,27 @@ public class ScaleguardSentinels extends CardImpl { // As an additional cost to cast Scaleguard Sentinels, you may reveal a Dragon card from your hand. this.getSpellAbility().addEffect(new InfoEffect("As an additional cost to cast {this}, you may reveal a Dragon card from your hand")); - + // Scaleguard Sentinels enters the battlefield with a +1/+1 counter on it if you revealed a Dragon card or controlled a Dragon as you cast Scaleguard Sentinels. this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(), true), ScaleguardSentinelsCondition.getInstance(), true, "{this} enters the battlefield with a +1/+1 counter on it if you revealed a Dragon card or controlled a Dragon as you cast {this}", ""), new DragonOnTheBattlefieldWhileSpellWasCastWatcher()); - + } - + @Override public void adjustCosts(Ability ability, Game game) { if (ability.getAbilityType().equals(AbilityType.SPELL)) { Player controller = game.getPlayer(ability.getControllerId()); if (controller != null) { if (controller.getHand().count(filter, game) > 0) { - ability.addCost(new RevealTargetFromHandCost(new TargetCardInHand(0,1, filter))); + ability.addCost(new RevealTargetFromHandCost(new TargetCardInHand(0, 1, filter))); } } } } - + public ScaleguardSentinels(final ScaleguardSentinels card) { super(card); } diff --git a/Mage.Sets/src/mage/sets/gameday/ThunderbreakRegent.java b/Mage.Sets/src/mage/sets/gameday/ThunderbreakRegent.java index b1f1ae38133..dd73ff45471 100644 --- a/Mage.Sets/src/mage/sets/gameday/ThunderbreakRegent.java +++ b/Mage.Sets/src/mage/sets/gameday/ThunderbreakRegent.java @@ -52,7 +52,7 @@ import mage.target.targetpointer.FixedTarget; public class ThunderbreakRegent extends CardImpl { public ThunderbreakRegent(UUID ownerId) { - super(ownerId, 44, "Thunderbreak Regent", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); + super(ownerId, 43, "Thunderbreak Regent", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); this.expansionSetCode = "MGDC"; this.subtype.add("Dragon"); this.power = new MageInt(4); @@ -106,7 +106,7 @@ class ThunderbreakRegentTriggeredAbility extends TriggeredAbilityImpl { if (game.getOpponents(this.controllerId).contains(event.getPlayerId())) { Permanent creature = game.getPermanent(event.getTargetId()); if (creature != null && filter.match(creature, getSourceId(), getControllerId(), game)) { - for (Effect effect: this.getEffects()) { + for (Effect effect : this.getEffects()) { effect.setTargetPointer(new FixedTarget(event.getPlayerId())); } return true; diff --git a/Mage.Sets/src/mage/sets/gatecrash/DiluvianPrimordial.java b/Mage.Sets/src/mage/sets/gatecrash/DiluvianPrimordial.java index 634afc77153..b97e56ead71 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/DiluvianPrimordial.java +++ b/Mage.Sets/src/mage/sets/gatecrash/DiluvianPrimordial.java @@ -127,7 +127,7 @@ class DiluvianPrimordialEffect extends OneShotEffect { if (target instanceof TargetCardInOpponentsGraveyard) { Card targetCard = game.getCard(target.getFirstTarget()); if (targetCard != null) { - if (controller.chooseUse(outcome, "Cast " + targetCard.getLogName() +"?", game)) { + if (controller.chooseUse(outcome, "Cast " + targetCard.getLogName() +"?", source, game)) { // TODO: Handle the case if the cast is not possible, so the replacement effect shouldn't be active ContinuousEffect effect = new DiluvianPrimordialReplacementEffect(); effect.setTargetPointer(new FixedTarget(targetCard.getId())); diff --git a/Mage.Sets/src/mage/sets/gatecrash/DomriRade.java b/Mage.Sets/src/mage/sets/gatecrash/DomriRade.java index 0ec1e13590c..40ec318e1bd 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/DomriRade.java +++ b/Mage.Sets/src/mage/sets/gatecrash/DomriRade.java @@ -126,7 +126,7 @@ class DomriRadeEffect1 extends OneShotEffect { cards.add(card); controller.lookAtCards(sourceObject.getName(), cards, game); if (card.getCardType().contains(CardType.CREATURE)) { - if (controller.chooseUse(outcome, "Reveal " + card.getName() + " and put it into your hand?", game)) { + if (controller.chooseUse(outcome, "Reveal " + card.getName() + " and put it into your hand?", source, game)) { controller.moveCardToHandWithInfo(card, source.getSourceId(), game, Zone.LIBRARY); controller.revealCards(sourceObject.getName(), cards, game); } diff --git a/Mage.Sets/src/mage/sets/gatecrash/GideonChampionOfJustice.java b/Mage.Sets/src/mage/sets/gatecrash/GideonChampionOfJustice.java index 78e4322ff31..ddff7d83638 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/GideonChampionOfJustice.java +++ b/Mage.Sets/src/mage/sets/gatecrash/GideonChampionOfJustice.java @@ -34,6 +34,7 @@ import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.CountersCount; +import mage.abilities.dynamicvalue.common.PermanentsTargetOpponentControlsCount; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.PreventAllDamageToSourceEffect; @@ -45,7 +46,6 @@ import mage.cards.CardImpl; import mage.constants.*; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.Token; @@ -68,7 +68,7 @@ public class GideonChampionOfJustice extends CardImpl { // +1: Put a loyalty counter on Gideon, Champion of Justice for each creature target opponent controls. LoyaltyAbility ability1 = new LoyaltyAbility( - new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(0), new PermanentsTargetOpponentControlsCount(), true), 1); + new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(0), new PermanentsTargetOpponentControlsCount(new FilterCreaturePermanent()), true), 1); ability1.addTarget(new TargetOpponent()); this.addAbility(ability1); @@ -92,39 +92,6 @@ public class GideonChampionOfJustice extends CardImpl { } } -class PermanentsTargetOpponentControlsCount implements DynamicValue { - - public PermanentsTargetOpponentControlsCount() { - } - - @Override - public int calculate(Game game, Ability sourceAbility, Effect effect) { - if (sourceAbility.getFirstTarget() != null) { - FilterCreaturePermanent filter = new FilterCreaturePermanent(); - filter.add(new ControllerIdPredicate(sourceAbility.getFirstTarget())); - int value = game.getBattlefield().count(filter, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game); - return value; - } else { - return 0; - } - } - - @Override - public DynamicValue copy() { - return new PermanentsTargetOpponentControlsCount(); - } - - @Override - public String toString() { - return "X"; - } - - @Override - public String getMessage() { - return "creature target opponent controls"; - } -} - class GideonExileAllOtherPermanentsEffect extends OneShotEffect { public GideonExileAllOtherPermanentsEffect() { diff --git a/Mage.Sets/src/mage/sets/gatecrash/IllusionistsBracers.java b/Mage.Sets/src/mage/sets/gatecrash/IllusionistsBracers.java index 83a86cc47b6..7143298d447 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/IllusionistsBracers.java +++ b/Mage.Sets/src/mage/sets/gatecrash/IllusionistsBracers.java @@ -140,7 +140,7 @@ class CopyActivatedAbilityEffect extends OneShotEffect { newAbility.newId(); game.getStack().push(new StackAbility(newAbility, source.getControllerId())); if (newAbility.getTargets().size() > 0) { - if (controller.chooseUse(newAbility.getEffects().get(0).getOutcome(), "Choose new targets?", game)) { + if (controller.chooseUse(newAbility.getEffects().get(0).getOutcome(), "Choose new targets?", source, game)) { newAbility.getTargets().clearChosen(); if (newAbility.getTargets().chooseTargets(newAbility.getEffects().get(0).getOutcome(), source.getControllerId(), newAbility, game) == false) { return false; diff --git a/Mage.Sets/src/mage/sets/gatecrash/SpellRupture.java b/Mage.Sets/src/mage/sets/gatecrash/SpellRupture.java index 044ed10c370..3fd85eafe88 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/SpellRupture.java +++ b/Mage.Sets/src/mage/sets/gatecrash/SpellRupture.java @@ -99,7 +99,7 @@ class SpellRuptureCounterUnlessPaysEffect extends OneShotEffect { int amount = new greatestPowerCountCreatureYouControl().calculate(game, source, this); GenericManaCost cost = new GenericManaCost(amount); StringBuilder sb = new StringBuilder("Pay {").append(amount).append("}? (otherwise ").append(spell.getName()).append(" will be countered)"); - if (player.chooseUse(Outcome.Benefit, sb.toString(), game)) { + if (player.chooseUse(Outcome.Benefit, sb.toString(), source, game)) { cost.pay(source, game, source.getSourceId(), player.getId(), false); } if (!cost.isPaid()) { diff --git a/Mage.Sets/src/mage/sets/gatecrash/UnexpectedResults.java b/Mage.Sets/src/mage/sets/gatecrash/UnexpectedResults.java index 3fb0e6c321f..e5a485d81f2 100644 --- a/Mage.Sets/src/mage/sets/gatecrash/UnexpectedResults.java +++ b/Mage.Sets/src/mage/sets/gatecrash/UnexpectedResults.java @@ -119,12 +119,12 @@ class UnexpectedResultEffect extends OneShotEffect { controller.revealCards(sourceCard.getName(), new CardsImpl(card), game); if (card.getCardType().contains(CardType.LAND)) { String message = "Put " + card.getName() + " onto the battlefield?"; - if (controller.chooseUse(Outcome.PutLandInPlay, message, game)) { + if (controller.chooseUse(Outcome.PutLandInPlay, message, source, game)) { card.putOntoBattlefield(game, Zone.LIBRARY, source.getSourceId(), source.getControllerId()); return sourceCard.moveToZone(Zone.HAND, source.getSourceId(), game, false); } } else { - if (controller.chooseUse(outcome, new StringBuilder("Cast ").append(card.getName()).append(" without paying its mana cost?").toString(), game)) { + if (controller.chooseUse(outcome, new StringBuilder("Cast ").append(card.getName()).append(" without paying its mana cost?").toString(), source, game)) { return controller.cast(card.getSpellAbility(), game, true); } } diff --git a/Mage.Sets/src/mage/sets/homelands/FaerieNoble.java b/Mage.Sets/src/mage/sets/homelands/FaerieNoble.java new file mode 100644 index 00000000000..8224da5cb4f --- /dev/null +++ b/Mage.Sets/src/mage/sets/homelands/FaerieNoble.java @@ -0,0 +1,54 @@ +/* + * 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.homelands; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author ilcartographer + */ +public class FaerieNoble extends mage.sets.masterseditioniii.FaerieNoble { + + public FaerieNoble(UUID ownerId) { + super(ownerId); + this.cardNumber = 57; + this.expansionSetCode = "HML"; + this.rarity = Rarity.RARE; + } + + public FaerieNoble(final FaerieNoble card) { + super(card); + } + + @Override + public FaerieNoble copy() { + return new FaerieNoble(this); + } +} diff --git a/Mage.Sets/src/mage/sets/homelands/FerozsBan.java b/Mage.Sets/src/mage/sets/homelands/FerozsBan.java new file mode 100644 index 00000000000..0a6f8dcf5ac --- /dev/null +++ b/Mage.Sets/src/mage/sets/homelands/FerozsBan.java @@ -0,0 +1,53 @@ +/* + * 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.homelands; + +import java.util.UUID; + +/** + * + * @author LoneFox + + */ +public class FerozsBan extends mage.sets.fifthedition.FerozsBan { + + public FerozsBan(UUID ownerId) { + super(ownerId); + this.cardNumber = 132; + this.expansionSetCode = "HML"; + } + + public FerozsBan(final FerozsBan card) { + super(card); + } + + @Override + public FerozsBan copy() { + return new FerozsBan(this); + } +} diff --git a/Mage.Sets/src/mage/sets/iceage/MysticRemora.java b/Mage.Sets/src/mage/sets/iceage/MysticRemora.java index 4d9f6ae3efb..c3db8986718 100644 --- a/Mage.Sets/src/mage/sets/iceage/MysticRemora.java +++ b/Mage.Sets/src/mage/sets/iceage/MysticRemora.java @@ -145,8 +145,8 @@ class MysticRemoraTriggeredAbility extends TriggeredAbilityImpl { if (controller != null && opponent != null && sourceObject != null) { Cost cost = new GenericManaCost(4); String message = "Would you like to pay {4} to prevent the opponent to draw a card?"; - if (!(opponent.chooseUse(Outcome.Benefit, message, game) && cost.pay(source, game, source.getSourceId(), opponent.getId(), false))) { - if(controller.chooseUse(Outcome.DrawCard, "Draw a card (" + sourceObject.getLogName() +")", game)) { + if (!(opponent.chooseUse(Outcome.Benefit, message, source, game) && cost.pay(source, game, source.getSourceId(), opponent.getId(), false))) { + if(controller.chooseUse(Outcome.DrawCard, "Draw a card (" + sourceObject.getLogName() +")", source, game)) { controller.drawCards(1, game); } } diff --git a/Mage.Sets/src/mage/sets/iceage/SibilantSpirit.java b/Mage.Sets/src/mage/sets/iceage/SibilantSpirit.java index e0e4714d808..d90eb584316 100644 --- a/Mage.Sets/src/mage/sets/iceage/SibilantSpirit.java +++ b/Mage.Sets/src/mage/sets/iceage/SibilantSpirit.java @@ -91,7 +91,7 @@ class SibilantSpiritEffect extends OneShotEffect { UUID defenderId = game.getCombat().getDefenderId(source.getSourceId()); Player defender = game.getPlayer(defenderId); if (defender != null) { - if (defender.chooseUse(outcome, "Draw a card?", game)) { + if (defender.chooseUse(outcome, "Draw a card?", source, game)) { defender.drawCards(1, game); } } diff --git a/Mage.Sets/src/mage/sets/iceage/Thoughtleech.java b/Mage.Sets/src/mage/sets/iceage/Thoughtleech.java new file mode 100644 index 00000000000..4c8d19ea7ea --- /dev/null +++ b/Mage.Sets/src/mage/sets/iceage/Thoughtleech.java @@ -0,0 +1,53 @@ +/* + * 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.iceage; + +import java.util.UUID; + +/** + * + * @author LoneFox + + */ +public class Thoughtleech extends mage.sets.seventhedition.Thoughtleech { + + public Thoughtleech(UUID ownerId) { + super(ownerId); + this.cardNumber = 157; + this.expansionSetCode = "ICE"; + } + + public Thoughtleech(final Thoughtleech card) { + super(card); + } + + @Override + public Thoughtleech copy() { + return new Thoughtleech(this); + } +} diff --git a/Mage.Sets/src/mage/sets/iceage/ZursWeirding.java b/Mage.Sets/src/mage/sets/iceage/ZursWeirding.java index cfc246e3fed..ebee9cfe3df 100644 --- a/Mage.Sets/src/mage/sets/iceage/ZursWeirding.java +++ b/Mage.Sets/src/mage/sets/iceage/ZursWeirding.java @@ -114,7 +114,7 @@ class ZursWeirdingReplacementEffect extends ReplacementEffectImpl { while (!currentPlayer.getId().equals(player.getId())) { if (currentPlayer.canPayLifeCost() && currentPlayer.getLife() >= 2 && - currentPlayer.chooseUse(Outcome.Benefit, message, game)) { + currentPlayer.chooseUse(Outcome.Benefit, message, source, game)) { currentPlayer.loseLife(2, game); player.moveCards(card, Zone.LIBRARY, Zone.GRAVEYARD, source, game); // game.getState().getRevealed().reset(); diff --git a/Mage.Sets/src/mage/sets/innistrad/CaravanVigil.java b/Mage.Sets/src/mage/sets/innistrad/CaravanVigil.java index bfb77513ee3..aed1c1e2af2 100644 --- a/Mage.Sets/src/mage/sets/innistrad/CaravanVigil.java +++ b/Mage.Sets/src/mage/sets/innistrad/CaravanVigil.java @@ -100,7 +100,7 @@ class CaravanVigilEffect extends OneShotEffect { Cards cards = new CardsImpl(); cards.add(card); if (MorbidCondition.getInstance().apply(game, source) - && controller.chooseUse(Outcome.PutLandInPlay, "Do you wish to put the card onto the battlefield instead?", game)) { + && controller.chooseUse(Outcome.PutLandInPlay, "Do you wish to put the card onto the battlefield instead?", source, game)) { controller.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); } else { controller.moveCardToHandWithInfo(card, source.getSourceId(), game, Zone.LIBRARY); diff --git a/Mage.Sets/src/mage/sets/innistrad/DelverOfSecrets.java b/Mage.Sets/src/mage/sets/innistrad/DelverOfSecrets.java index 71a1d172fb3..66fd5b8742d 100644 --- a/Mage.Sets/src/mage/sets/innistrad/DelverOfSecrets.java +++ b/Mage.Sets/src/mage/sets/innistrad/DelverOfSecrets.java @@ -109,7 +109,7 @@ class DelverOfSecretsEffect extends OneShotEffect { Cards cards = new CardsImpl(); cards.add(card); player.lookAtCards(sourcePermanent.getName(), cards, game); - if (player.chooseUse(Outcome.DrawCard, "Do you wish to reveal the card at the top of the library?", game)) { + if (player.chooseUse(Outcome.DrawCard, "Do you wish to reveal the card at the top of the library?", source, game)) { player.revealCards(sourcePermanent.getName(), cards, game); if (filter.match(card, game)) { return new TransformSourceEffect(true, true).apply(game, source); diff --git a/Mage.Sets/src/mage/sets/innistrad/GhostQuarter.java b/Mage.Sets/src/mage/sets/innistrad/GhostQuarter.java index c0e0ddaed59..aeba8786b36 100644 --- a/Mage.Sets/src/mage/sets/innistrad/GhostQuarter.java +++ b/Mage.Sets/src/mage/sets/innistrad/GhostQuarter.java @@ -99,7 +99,7 @@ class GhostQuarterEffect extends OneShotEffect { Permanent permanent = (Permanent) game.getPermanentOrLKIBattlefield(source.getFirstTarget()); // if indestructible effect should work also if (permanent != null) { Player player = game.getPlayer(permanent.getControllerId()); - if (player.chooseUse(Outcome.PutLandInPlay, "Do you wish to search for a basic land, put it onto the battlefield and then shuffle your library?", game)) { + if (player.chooseUse(Outcome.PutLandInPlay, "Do you wish to search for a basic land, put it onto the battlefield and then shuffle your library?", source, game)) { TargetCardInLibrary target = new TargetCardInLibrary(new FilterBasicLandCard()); if (player.searchLibrary(target, game)) { Card card = player.getLibrary().getCard(target.getFirstTarget(), game); diff --git a/Mage.Sets/src/mage/sets/innistrad/MentorOfTheMeek.java b/Mage.Sets/src/mage/sets/innistrad/MentorOfTheMeek.java index b1ae0dfe392..e93a09d59c6 100644 --- a/Mage.Sets/src/mage/sets/innistrad/MentorOfTheMeek.java +++ b/Mage.Sets/src/mage/sets/innistrad/MentorOfTheMeek.java @@ -25,13 +25,14 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.innistrad; import java.util.UUID; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; @@ -50,6 +51,7 @@ import mage.filter.predicate.permanent.AnotherPredicate; public class MentorOfTheMeek extends CardImpl { private static final FilterPermanent filter = new FilterControlledCreaturePermanent("another creature with power 2 or less"); + static { filter.add(new AnotherPredicate()); filter.add(new PowerPredicate(Filter.ComparisonType.LessThan, 3)); @@ -65,8 +67,10 @@ public class MentorOfTheMeek extends CardImpl { this.toughness = new MageInt(2); //Whenever another creature with power 2 or less enters the battlefield under your control, you may pay 1. If you do, draw a card. - this.addAbility(new EntersBattlefieldControlledTriggeredAbility( - Zone.BATTLEFIELD, new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new ManaCostsImpl("{1}")),filter, true)); + Effect effect = new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new ManaCostsImpl("{1}")); + Ability ability = new EntersBattlefieldControlledTriggeredAbility( + Zone.BATTLEFIELD, effect, filter, false); + this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/sets/innistrad/MurderOfCrows.java b/Mage.Sets/src/mage/sets/innistrad/MurderOfCrows.java index 1e4a5d8e570..87a3eeedd45 100644 --- a/Mage.Sets/src/mage/sets/innistrad/MurderOfCrows.java +++ b/Mage.Sets/src/mage/sets/innistrad/MurderOfCrows.java @@ -88,7 +88,7 @@ class MurderOfCrowsEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (player != null && player.chooseUse(Outcome.DrawCard, "Do you wish to draw a card? If you do, discard a card.", game)) { + if (player != null && player.chooseUse(Outcome.DrawCard, "Do you wish to draw a card? If you do, discard a card.", source, game)) { if (player.drawCards(1, game) > 0) { player.discard(1, source, game); } diff --git a/Mage.Sets/src/mage/sets/innistrad/RooftopStorm.java b/Mage.Sets/src/mage/sets/innistrad/RooftopStorm.java index d68c3e38571..c844ff26839 100644 --- a/Mage.Sets/src/mage/sets/innistrad/RooftopStorm.java +++ b/Mage.Sets/src/mage/sets/innistrad/RooftopStorm.java @@ -98,7 +98,7 @@ class RooftopStormCostReductionEffect extends CostModificationEffectImpl { if (sourceCard != null && sourceCard.hasSubtype("Zombie")) { Player player = game.getPlayer(spell.getControllerId()); if (player != null && - (CardUtil.isCheckPlayableMode(spell) || player.chooseUse(Outcome.Benefit, "Pay {0} rather than pay the mana cost for Zombie creature", game))) { + (CardUtil.isCheckPlayableMode(spell) || player.chooseUse(Outcome.Benefit, "Pay {0} rather than pay the mana cost for Zombie creature", source, game))) { spell.getManaCostsToPay().clear(); spell.getManaCostsToPay().addAll(new ManaCostsImpl<>("{0}")); return true; diff --git a/Mage.Sets/src/mage/sets/invasion/FirebrandRanger.java b/Mage.Sets/src/mage/sets/invasion/FirebrandRanger.java index 98ccf3f084d..0f293697d6e 100644 --- a/Mage.Sets/src/mage/sets/invasion/FirebrandRanger.java +++ b/Mage.Sets/src/mage/sets/invasion/FirebrandRanger.java @@ -107,7 +107,7 @@ class PutLandOnBattlefieldEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (player == null || !player.chooseUse(Outcome.PutLandInPlay, choiceText, game)) { + if (player == null || !player.chooseUse(Outcome.PutLandInPlay, choiceText, source, game)) { return false; } diff --git a/Mage.Sets/src/mage/sets/journeyintonyx/AthreosGodOfPassage.java b/Mage.Sets/src/mage/sets/journeyintonyx/AthreosGodOfPassage.java index 412b1ecaad7..b5024166052 100644 --- a/Mage.Sets/src/mage/sets/journeyintonyx/AthreosGodOfPassage.java +++ b/Mage.Sets/src/mage/sets/journeyintonyx/AthreosGodOfPassage.java @@ -130,7 +130,7 @@ class AthreosGodOfPassageReturnEffect extends OneShotEffect { if (opponent != null) { Cost cost = new PayLifeCost(3); if (cost.canPay(source, source.getSourceId(), opponent.getId(), game) - && opponent.chooseUse(outcome, new StringBuilder("Pay 3 live to prevent that ").append(creature.getLogName()).append(" returns to ").append(controller.getLogName()).append("'s hand?").toString(), game)) { + && opponent.chooseUse(outcome, new StringBuilder("Pay 3 live to prevent that ").append(creature.getLogName()).append(" returns to ").append(controller.getLogName()).append("'s hand?").toString(), source, game)) { if (cost.pay(source, game, source.getSourceId(), opponent.getId(), false)) { paid = true; } diff --git a/Mage.Sets/src/mage/sets/journeyintonyx/DakraMystic.java b/Mage.Sets/src/mage/sets/journeyintonyx/DakraMystic.java index 6c9afba1eb6..627a22afca9 100644 --- a/Mage.Sets/src/mage/sets/journeyintonyx/DakraMystic.java +++ b/Mage.Sets/src/mage/sets/journeyintonyx/DakraMystic.java @@ -103,7 +103,7 @@ class DakraMysticEffect extends OneShotEffect { player.revealCards(player.getLogName(), new CardsImpl(player.getLibrary().getFromTop(game)), game); } } - if (controller.chooseUse(outcome, "Put revealed cards into graveyard?", game)) { + if (controller.chooseUse(outcome, "Put revealed cards into graveyard?", source, game)) { for(UUID playerId: controller.getInRange()) { Player player = game.getPlayer(playerId); if (player != null && player.getLibrary().size() > 0) { diff --git a/Mage.Sets/src/mage/sets/journeyintonyx/DesertersQuarters.java b/Mage.Sets/src/mage/sets/journeyintonyx/DesertersQuarters.java index c68db17f83b..41c34c3891e 100644 --- a/Mage.Sets/src/mage/sets/journeyintonyx/DesertersQuarters.java +++ b/Mage.Sets/src/mage/sets/journeyintonyx/DesertersQuarters.java @@ -100,14 +100,13 @@ class DesertersQuartersTapTargetEffect extends TapTargetEffect { if (sourcePermanent != null) { sourcePermanent.addConnectedCard("DesertersQuarters", permanent.getId()); } - if (permanent != null) { + if (permanent != null) { permanent.tap(game); } } return true; } - @Override public DesertersQuartersTapTargetEffect copy() { return new DesertersQuartersTapTargetEffect(this); @@ -144,7 +143,7 @@ class DesertersQuartersRestrictionEffect extends RestrictionEffect { } @Override - public boolean canBeUntapped(Permanent permanent, Game game) { + public boolean canBeUntapped(Permanent permanent, Ability source, Game game) { return false; } diff --git a/Mage.Sets/src/mage/sets/journeyintonyx/DiscipleOfDeceit.java b/Mage.Sets/src/mage/sets/journeyintonyx/DiscipleOfDeceit.java index 0604b7b6604..e5e87c1bbcc 100644 --- a/Mage.Sets/src/mage/sets/journeyintonyx/DiscipleOfDeceit.java +++ b/Mage.Sets/src/mage/sets/journeyintonyx/DiscipleOfDeceit.java @@ -104,7 +104,7 @@ class DiscipleOfDeceitEffect extends OneShotEffect { Cost cost = new DiscardTargetCost(new TargetCardInHand(new FilterNonlandCard())); String message = "Discard a nonland card to search your library?"; if (cost.canPay(source, source.getSourceId(), source.getControllerId(), game) - && player.chooseUse(Outcome.Detriment, message, game)) { + && player.chooseUse(Outcome.Detriment, message, source, game)) { if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { Card card = game.getCard(cost.getTargets().getFirstTarget()); if (card == null) { diff --git a/Mage.Sets/src/mage/sets/journeyintonyx/OppressiveRays.java b/Mage.Sets/src/mage/sets/journeyintonyx/OppressiveRays.java index a22d2e1fd2f..22e10574718 100644 --- a/Mage.Sets/src/mage/sets/journeyintonyx/OppressiveRays.java +++ b/Mage.Sets/src/mage/sets/journeyintonyx/OppressiveRays.java @@ -118,7 +118,7 @@ class OppressiveRaysEffect extends ReplacementEffectImpl { } ManaCostsImpl attackBlockTax = new ManaCostsImpl("{3}"); if (attackBlockTax.canPay(source, source.getSourceId(), event.getPlayerId(), game) - && player.chooseUse(Outcome.Neutral, chooseText, game)) { + && player.chooseUse(Outcome.Neutral, chooseText, source, game)) { if (attackBlockTax.payOrRollback(source, game, source.getSourceId(), event.getPlayerId())) { return false; } diff --git a/Mage.Sets/src/mage/sets/judgment/BreakingPoint.java b/Mage.Sets/src/mage/sets/judgment/BreakingPoint.java index 9dbac265357..7ee870ae3ab 100644 --- a/Mage.Sets/src/mage/sets/judgment/BreakingPoint.java +++ b/Mage.Sets/src/mage/sets/judgment/BreakingPoint.java @@ -66,34 +66,39 @@ public class BreakingPoint extends CardImpl { } class BreakingPointDestroyEffect extends OneShotEffect { - + public BreakingPointDestroyEffect() { super(Outcome.Benefit); - this.staticText = "Any player may have Breaking Point deal 6 damage to him or her. If no one does, destroy all creatures. Creatures destroyed this way can't be regenerated."; + this.staticText = "Any player may have {this} deal 6 damage to him or her. If no one does, destroy all creatures. Creatures destroyed this way can't be regenerated."; } - + public BreakingPointDestroyEffect(final BreakingPointDestroyEffect effect) { super(effect); } - + @Override public BreakingPointDestroyEffect copy() { return new BreakingPointDestroyEffect(this); } - + @Override public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + StackObject spell = null; - for(StackObject object : game.getStack()){ - if(object instanceof Spell && object.getSourceId().equals(source.getSourceId())){ + for (StackObject object : game.getStack()) { + if (object instanceof Spell && object.getSourceId().equals(source.getSourceId())) { spell = object; } } - if(spell != null){ + if (spell != null) { boolean destroyCreatures = true; - for(UUID uuid : game.getPlayerList()){ - Player player = game.getPlayer(uuid); - if(player != null && player.chooseUse(Outcome.Detriment, "Have " + spell.getName() + " deal 6 damage to you?", game)){ + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null && player.chooseUse(Outcome.Detriment, "Have " + spell.getLogName() + " deal 6 damage to you?", source, game)) { destroyCreatures = false; player.damage(6, source.getSourceId(), game, false, true); game.informPlayers(player.getLogName() + " has " + spell.getName() + " deal 6 to him or her"); diff --git a/Mage.Sets/src/mage/sets/judgment/Browbeat.java b/Mage.Sets/src/mage/sets/judgment/Browbeat.java index fb71c3674c5..224518820e7 100644 --- a/Mage.Sets/src/mage/sets/judgment/Browbeat.java +++ b/Mage.Sets/src/mage/sets/judgment/Browbeat.java @@ -97,7 +97,7 @@ class BrowbeatDrawEffect extends OneShotEffect { boolean drawCards = true; for(UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)){ Player player = game.getPlayer(playerId); - if (player != null && player.chooseUse(Outcome.Detriment, "Have " + spell.getLogName() + " deal 5 damage to you?", game)){ + if (player != null && player.chooseUse(Outcome.Detriment, "Have " + spell.getLogName() + " deal 5 damage to you?", source, game)){ drawCards = false; player.damage(5, source.getSourceId(), game, false, true); game.informPlayers(player.getLogName() + " has " + spell.getLogName() + " deal 5 to him or her"); diff --git a/Mage.Sets/src/mage/sets/judgment/BurningWish.java b/Mage.Sets/src/mage/sets/judgment/BurningWish.java index 412d18b6db0..8036f321e15 100644 --- a/Mage.Sets/src/mage/sets/judgment/BurningWish.java +++ b/Mage.Sets/src/mage/sets/judgment/BurningWish.java @@ -98,7 +98,7 @@ class BurningWishEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - while (player.chooseUse(Outcome.Benefit, choiceText, game)) { + while (player.chooseUse(Outcome.Benefit, choiceText, source, game)) { Cards cards = player.getSideboard(); if(cards.isEmpty()) { game.informPlayer(player, "You have no cards outside the game."); diff --git a/Mage.Sets/src/mage/sets/judgment/CunningWish.java b/Mage.Sets/src/mage/sets/judgment/CunningWish.java index aa28eab96f4..3a334aab0da 100644 --- a/Mage.Sets/src/mage/sets/judgment/CunningWish.java +++ b/Mage.Sets/src/mage/sets/judgment/CunningWish.java @@ -98,7 +98,7 @@ class CunningWishEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - while (player.chooseUse(Outcome.Benefit, choiceText, game)) { + while (player.chooseUse(Outcome.Benefit, choiceText, source, game)) { Cards cards = player.getSideboard(); if(cards.isEmpty()) { game.informPlayer(player, "You have no cards outside the game."); diff --git a/Mage.Sets/src/mage/sets/judgment/DeathWish.java b/Mage.Sets/src/mage/sets/judgment/DeathWish.java index 8f083160b88..f6129647953 100644 --- a/Mage.Sets/src/mage/sets/judgment/DeathWish.java +++ b/Mage.Sets/src/mage/sets/judgment/DeathWish.java @@ -95,7 +95,7 @@ class DeathWishEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - while (player.chooseUse(Outcome.Benefit, choiceText, game)) { + while (player.chooseUse(Outcome.Benefit, choiceText, source, game)) { Cards cards = player.getSideboard(); if(cards.isEmpty()) { game.informPlayer(player, "You have no cards outside the game."); diff --git a/Mage.Sets/src/mage/sets/judgment/GoldenWish.java b/Mage.Sets/src/mage/sets/judgment/GoldenWish.java index 6d701bd779f..2b76472ddf7 100644 --- a/Mage.Sets/src/mage/sets/judgment/GoldenWish.java +++ b/Mage.Sets/src/mage/sets/judgment/GoldenWish.java @@ -101,7 +101,7 @@ class GoldenWishEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - while (player.chooseUse(Outcome.Benefit, choiceText, game)) { + while (player.chooseUse(Outcome.Benefit, choiceText, source, game)) { Cards cards = player.getSideboard(); if(cards.isEmpty()) { game.informPlayer(player, "You have no cards outside the game."); diff --git a/Mage.Sets/src/mage/sets/judgment/LivingWish.java b/Mage.Sets/src/mage/sets/judgment/LivingWish.java index 3f83b6ef145..907c97c9655 100644 --- a/Mage.Sets/src/mage/sets/judgment/LivingWish.java +++ b/Mage.Sets/src/mage/sets/judgment/LivingWish.java @@ -101,7 +101,7 @@ class LivingWishEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - while (player.chooseUse(Outcome.Benefit, choiceText, game)) { + while (player.chooseUse(Outcome.Benefit, choiceText, source, game)) { Cards cards = player.getSideboard(); if(cards.isEmpty()) { game.informPlayer(player, "You have no cards outside the game."); diff --git a/Mage.Sets/src/mage/sets/khansoftarkir/CleverImpersonator.java b/Mage.Sets/src/mage/sets/khansoftarkir/CleverImpersonator.java index 2e0cc1e3a3f..87503dfe207 100644 --- a/Mage.Sets/src/mage/sets/khansoftarkir/CleverImpersonator.java +++ b/Mage.Sets/src/mage/sets/khansoftarkir/CleverImpersonator.java @@ -52,10 +52,10 @@ public class CleverImpersonator extends CardImpl { this.power = new MageInt(0); this.toughness = new MageInt(0); - // You have may Clever Impersonator enter the battlefield as a copy of any nonland permanent on the battlefield. + // You may have Clever Impersonator enter the battlefield as a copy of any nonland permanent on the battlefield. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new EntersBattlefieldEffect(new CopyPermanentEffect(new FilterNonlandPermanent()), - "You may have {this} enter the battlefield as a copy of any nonland permanent on the battlefield", + "You may have {this} enter the battlefield as a copy of any nonland permanent on the battlefield", true))); } diff --git a/Mage.Sets/src/mage/sets/khansoftarkir/SeeTheUnwritten.java b/Mage.Sets/src/mage/sets/khansoftarkir/SeeTheUnwritten.java index 248f02ab30f..bf66ae2db31 100644 --- a/Mage.Sets/src/mage/sets/khansoftarkir/SeeTheUnwritten.java +++ b/Mage.Sets/src/mage/sets/khansoftarkir/SeeTheUnwritten.java @@ -125,7 +125,7 @@ class SeeTheUnwrittenEffect extends OneShotEffect { if (!cards.isEmpty()) { controller.revealCards(sourceObject.getName(), cards, game); - if (creatureCardsFound > 0 && controller.chooseUse(outcome, "Put creature(s) into play?", game)) { + if (creatureCardsFound > 0 && controller.chooseUse(outcome, "Put creature(s) into play?", source, game)) { int cardsToChoose = Math.min(numberOfCardsToPutIntoPlay, creatureCardsFound); TargetCard target = new TargetCard(cardsToChoose, cardsToChoose, Zone.LIBRARY, filter); if (controller.choose(Outcome.PutCreatureInPlay, cards, target, game)) { diff --git a/Mage.Sets/src/mage/sets/khansoftarkir/VillainousWealth.java b/Mage.Sets/src/mage/sets/khansoftarkir/VillainousWealth.java index aba4dd07822..05f841c7266 100644 --- a/Mage.Sets/src/mage/sets/khansoftarkir/VillainousWealth.java +++ b/Mage.Sets/src/mage/sets/khansoftarkir/VillainousWealth.java @@ -113,7 +113,7 @@ class VillainousWealthEffect extends OneShotEffect { } ExileZone exileZone = game.getExile().getExileZone(exileId); while (exileZone != null && exileZone.count(filter, game) > 0 - && controller.chooseUse(Outcome.PlayForFree, "Cast cards exiled with " + mageObject.getLogName() +" without paying its mana cost?", game)) { + && controller.chooseUse(Outcome.PlayForFree, "Cast cards exiled with " + mageObject.getLogName() +" without paying its mana cost?", source, game)) { TargetCardInExile target = new TargetCardInExile(0,1, filter, exileId, false); while (exileZone.count(filter, game) > 0 && controller.choose(Outcome.PlayForFree, exileZone, target, game)) { Card card = game.getCard(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/sets/legends/ChainLightning.java b/Mage.Sets/src/mage/sets/legends/ChainLightning.java index 7ea83e1c98d..21f95b87186 100644 --- a/Mage.Sets/src/mage/sets/legends/ChainLightning.java +++ b/Mage.Sets/src/mage/sets/legends/ChainLightning.java @@ -103,7 +103,7 @@ class ChainLightningEffect extends OneShotEffect { } } if (affectedPlayer != null) { - if (affectedPlayer.chooseUse(Outcome.Copy, "Pay {R}{R} to copy the spell?", game)) { + if (affectedPlayer.chooseUse(Outcome.Copy, "Pay {R}{R} to copy the spell?", source, game)) { Cost cost = new ManaCostsImpl("{R}{R}"); if (cost.pay(source, game, source.getSourceId(), affectedPlayer.getId(), false)) { Spell spell = game.getStack().getSpell(source.getSourceId()); diff --git a/Mage.Sets/src/mage/sets/legends/FireSprites.java b/Mage.Sets/src/mage/sets/legends/FireSprites.java new file mode 100644 index 00000000000..891f8adff9d --- /dev/null +++ b/Mage.Sets/src/mage/sets/legends/FireSprites.java @@ -0,0 +1,52 @@ +/* + * 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.legends; + +import java.util.UUID; + +/** + * + * @author ilcartographer + */ +public class FireSprites extends mage.sets.masterseditioniii.FireSprites { + + public FireSprites(UUID ownerId) { + super(ownerId); + this.cardNumber = 100; + this.expansionSetCode = "LEG"; + } + + public FireSprites(final FireSprites card) { + super(card); + } + + @Override + public FireSprites copy() { + return new FireSprites(this); + } +} diff --git a/Mage.Sets/src/mage/sets/legends/Immolation.java b/Mage.Sets/src/mage/sets/legends/Immolation.java new file mode 100644 index 00000000000..f5f28fd1812 --- /dev/null +++ b/Mage.Sets/src/mage/sets/legends/Immolation.java @@ -0,0 +1,52 @@ +/* + * 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.legends; + +import java.util.UUID; + +/** + * + * @author ilcartographer + */ +public class Immolation extends mage.sets.fourthedition.Immolation { + + public Immolation(UUID ownerId) { + super(ownerId); + this.cardNumber = 151; + this.expansionSetCode = "LEG"; + } + + public Immolation(final Immolation card) { + super(card); + } + + @Override + public Immolation copy() { + return new Immolation(this); + } +} diff --git a/Mage.Sets/src/mage/sets/legends/KoboldDrillSergeant.java b/Mage.Sets/src/mage/sets/legends/KoboldDrillSergeant.java new file mode 100644 index 00000000000..34746880322 --- /dev/null +++ b/Mage.Sets/src/mage/sets/legends/KoboldDrillSergeant.java @@ -0,0 +1,52 @@ +/* + * 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.legends; + +import java.util.UUID; + +/** + * + * @author ilcartographer + */ +public class KoboldDrillSergeant extends mage.sets.masterseditioniii.KoboldDrillSergeant { + + public KoboldDrillSergeant(UUID ownerId) { + super(ownerId); + this.cardNumber = 152; + this.expansionSetCode = "LEG"; + } + + public KoboldDrillSergeant(final KoboldDrillSergeant card) { + super(card); + } + + @Override + public KoboldDrillSergeant copy() { + return new KoboldDrillSergeant(this); + } +} diff --git a/Mage.Sets/src/mage/sets/legends/KoboldOverlord.java b/Mage.Sets/src/mage/sets/legends/KoboldOverlord.java new file mode 100644 index 00000000000..bdc85bb17a1 --- /dev/null +++ b/Mage.Sets/src/mage/sets/legends/KoboldOverlord.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.legends; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; + +/** + * + * @author ilcartographer + */ +public class KoboldOverlord extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Kobold creatures"); + + static { + filter.add(new SubtypePredicate("Kobold")); + } + + public KoboldOverlord(UUID ownerId) { + super(ownerId, 153, "Kobold Overlord", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{1}{R}"); + this.expansionSetCode = "LEG"; + this.subtype.add("Kobold"); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // First strike + this.addAbility(FirstStrikeAbility.getInstance()); + // Other Kobold creatures you control have first strike. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(FirstStrikeAbility.getInstance(), Duration.WhileOnBattlefield, filter, true))); + } + + public KoboldOverlord(final KoboldOverlord card) { + super(card); + } + + @Override + public KoboldOverlord copy() { + return new KoboldOverlord(this); + } +} diff --git a/Mage.Sets/src/mage/sets/legends/ShieldWall.java b/Mage.Sets/src/mage/sets/legends/ShieldWall.java new file mode 100644 index 00000000000..374a7bcab56 --- /dev/null +++ b/Mage.Sets/src/mage/sets/legends/ShieldWall.java @@ -0,0 +1,60 @@ +/* + * 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.legends; + +import java.util.UUID; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; + +/** + * + * @author LoneFox + + */ +public class ShieldWall extends CardImpl { + + public ShieldWall(UUID ownerId) { + super(ownerId, 205, "Shield Wall", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{1}{W}"); + this.expansionSetCode = "LEG"; + + // Creatures you control get +0/+2 until end of turn. + this.getSpellAbility().addEffect(new BoostControlledEffect(0, 2, Duration.EndOfTurn)); + } + + public ShieldWall(final ShieldWall card) { + super(card); + } + + @Override + public ShieldWall copy() { + return new ShieldWall(this); + } +} diff --git a/Mage.Sets/src/mage/sets/legends/TheTabernacleAtPendrellVale.java b/Mage.Sets/src/mage/sets/legends/TheTabernacleAtPendrellVale.java index a46fdfceeec..c938ac247c4 100644 --- a/Mage.Sets/src/mage/sets/legends/TheTabernacleAtPendrellVale.java +++ b/Mage.Sets/src/mage/sets/legends/TheTabernacleAtPendrellVale.java @@ -89,7 +89,7 @@ class DestroySourceUnlessPaysEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(source.getSourceId()); if (player != null && permanent != null) { - if (player.chooseUse(Outcome.Benefit, "Pay " + cost.getText() + "?", game)) { + if (player.chooseUse(Outcome.Benefit, "Pay " + cost.getText() + "?", source, game)) { cost.clearPaid(); if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { return true; diff --git a/Mage.Sets/src/mage/sets/legends/WallOfWonder.java b/Mage.Sets/src/mage/sets/legends/WallOfWonder.java new file mode 100644 index 00000000000..70cadb80a2f --- /dev/null +++ b/Mage.Sets/src/mage/sets/legends/WallOfWonder.java @@ -0,0 +1,55 @@ +/* + * 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.legends; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author LoneFox + + */ +public class WallOfWonder extends mage.sets.seventhedition.WallOfWonder { + + public WallOfWonder(UUID ownerId) { + super(ownerId); + this.cardNumber = 85; + this.expansionSetCode = "LEG"; + this.rarity = Rarity.UNCOMMON; + } + + public WallOfWonder(final WallOfWonder card) { + super(card); + } + + @Override + public WallOfWonder copy() { + return new WallOfWonder(this); + } +} diff --git a/Mage.Sets/src/mage/sets/legions/DarkSupplicant.java b/Mage.Sets/src/mage/sets/legions/DarkSupplicant.java index 867129eb40b..36d802aa735 100644 --- a/Mage.Sets/src/mage/sets/legions/DarkSupplicant.java +++ b/Mage.Sets/src/mage/sets/legions/DarkSupplicant.java @@ -115,7 +115,7 @@ class DarkSupplicantEffect extends OneShotEffect { return false; } // Library check - if (player.chooseUse(Outcome.Benefit, "Do you want to search your library for Scion of Darkness?", game)) { + if (player.chooseUse(Outcome.Benefit, "Do you want to search your library for Scion of Darkness?", source, game)) { if (player.searchLibrary(target, game)) { if (target.getTargets().size() > 0) { for (UUID cardId : (List) target.getTargets()) { @@ -131,7 +131,7 @@ class DarkSupplicantEffect extends OneShotEffect { player.shuffleLibrary(game); } // Graveyard check - if (player.chooseUse(Outcome.Benefit, "Do you want to search your graveyard for Scion of Darkness?", game)) { + if (player.chooseUse(Outcome.Benefit, "Do you want to search your graveyard for Scion of Darkness?", source, game)) { Cards graveyard = player.getGraveyard().copy(); for (UUID card : graveyard) { Card checkCard = game.getCard(card); @@ -142,7 +142,7 @@ class DarkSupplicantEffect extends OneShotEffect { } } // Hand check - if (player.chooseUse(Outcome.Benefit, "Do you want to search your hand for Scion of Darkness?", game)) { + if (player.chooseUse(Outcome.Benefit, "Do you want to search your hand for Scion of Darkness?", source, game)) { Cards hand = player.getHand().copy(); for (UUID card : hand) { Card checkCard = game.getCard(card); diff --git a/Mage.Sets/src/mage/sets/limitedalpha/DemonicHordes.java b/Mage.Sets/src/mage/sets/limitedalpha/DemonicHordes.java index 09ae87d9e4e..b0b6516f12c 100644 --- a/Mage.Sets/src/mage/sets/limitedalpha/DemonicHordes.java +++ b/Mage.Sets/src/mage/sets/limitedalpha/DemonicHordes.java @@ -109,7 +109,7 @@ class DemonicHordesEffect extends OneShotEffect { if (!sb.toString().toLowerCase().startsWith("exile ") && !sb.toString().toLowerCase().startsWith("return ")) { sb.insert(0, "Pay "); } - if (controller.chooseUse(Outcome.Benefit, sb.toString(), game)) { + if (controller.chooseUse(Outcome.Benefit, sb.toString(), source, game)) { cost.clearPaid(); if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { return true; diff --git a/Mage.Sets/src/mage/sets/limitedalpha/NaturalSelection.java b/Mage.Sets/src/mage/sets/limitedalpha/NaturalSelection.java index a9c1236857d..38657372332 100644 --- a/Mage.Sets/src/mage/sets/limitedalpha/NaturalSelection.java +++ b/Mage.Sets/src/mage/sets/limitedalpha/NaturalSelection.java @@ -121,7 +121,7 @@ class NaturalSelectionEffect extends OneShotEffect { Card card = cards.get(cards.iterator().next(), game); card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); } - if (you.chooseUse(Outcome.Neutral, "You may have that player shuffle his or her library", game)){ + if (you.chooseUse(Outcome.Neutral, "You may have that player shuffle his or her library", source, game)){ player.shuffleLibrary(game); } return true; diff --git a/Mage.Sets/src/mage/sets/limitedalpha/PowerSink.java b/Mage.Sets/src/mage/sets/limitedalpha/PowerSink.java index 6f053180675..38dc92a34b6 100644 --- a/Mage.Sets/src/mage/sets/limitedalpha/PowerSink.java +++ b/Mage.Sets/src/mage/sets/limitedalpha/PowerSink.java @@ -100,7 +100,7 @@ class PowerSinkCounterUnlessPaysEffect extends OneShotEffect { if (amount > 0) { GenericManaCost cost = new GenericManaCost(amount); StringBuilder sb = new StringBuilder("Pay ").append(cost.getText()).append("?"); - if (player.chooseUse(Outcome.Benefit, sb.toString(), game)) { + if (player.chooseUse(Outcome.Benefit, sb.toString(), source, game)) { if (cost.pay(source, game, source.getSourceId(), player.getId(), false)) { game.informPlayers(new StringBuilder(sourceObject.getName()).append(": additional cost was paid").toString()); return true; diff --git a/Mage.Sets/src/mage/sets/lorwyn/AquitectsWill.java b/Mage.Sets/src/mage/sets/lorwyn/AquitectsWill.java index a92d4b2eaa9..8604c8ab21e 100644 --- a/Mage.Sets/src/mage/sets/lorwyn/AquitectsWill.java +++ b/Mage.Sets/src/mage/sets/lorwyn/AquitectsWill.java @@ -41,7 +41,8 @@ import mage.constants.Layer; import mage.constants.Rarity; import mage.constants.SubLayer; import mage.counters.CounterType; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetLandPermanent; @@ -52,22 +53,28 @@ import mage.target.common.TargetLandPermanent; */ public class AquitectsWill extends CardImpl { + private final static FilterControlledPermanent filter = new FilterControlledPermanent("Merfolk"); + + static { + filter.add(new SubtypePredicate("Merfolk")); + } + public AquitectsWill(UUID ownerId) { super(ownerId, 52, "Aquitect's Will", Rarity.COMMON, new CardType[]{CardType.TRIBAL, CardType.SORCERY}, "{U}"); this.expansionSetCode = "LRW"; this.subtype.add("Merfolk"); - // Put a flood counter on target land. + // Put a flood counter on target land. this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.FLOOD.createInstance())); this.getSpellAbility().addTarget(new TargetLandPermanent()); - + // That land is an Island in addition to its other types for as long as it has a flood counter on it. this.getSpellAbility().addEffect(new AquitectsWillEffect(Duration.Custom, false, false, "Island")); - + // If you control a Merfolk, draw a card. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( - new DrawCardSourceControllerEffect(1), - new PermanentsOnTheBattlefieldCondition(new FilterControlledCreaturePermanent("Merfolk", "Merfolk")), + new DrawCardSourceControllerEffect(1), + new PermanentsOnTheBattlefieldCondition(filter), "If you control a Merfolk, draw a card")); } @@ -101,7 +108,7 @@ class AquitectsWillEffect extends BecomesBasicLandTargetEffect { } else if (land.getCounters().getCount(CounterType.FLOOD) > 0) { // only if Flood counter is on the object it becomes an Island.(it would be possible to remove and return the counters with e.g. Fate Transfer if the land becomes a creature too) super.apply(layer, sublayer, source, game); - } + } return true; } diff --git a/Mage.Sets/src/mage/sets/lorwyn/Guile.java b/Mage.Sets/src/mage/sets/lorwyn/Guile.java index 6f319450be5..4e9977188f4 100644 --- a/Mage.Sets/src/mage/sets/lorwyn/Guile.java +++ b/Mage.Sets/src/mage/sets/lorwyn/Guile.java @@ -111,7 +111,7 @@ class GuileReplacementEffect extends ReplacementEffectImpl { if (spell != null && guileController != null) { Card spellCard = spell.getCard(); guileController.moveCardToExileWithInfo(spellCard, null, "", source.getSourceId(), game, Zone.STACK, true); - if (guileController.chooseUse(Outcome.PlayForFree, "Cast that card for free?", game)) { + if (guileController.chooseUse(Outcome.PlayForFree, "Cast that card for free?", source, game)) { guileController.cast(spellCard.getSpellAbility(), game, true); } return true; diff --git a/Mage.Sets/src/mage/sets/lorwyn/HordeOfNotions.java b/Mage.Sets/src/mage/sets/lorwyn/HordeOfNotions.java index de87235ec59..ab05c32d1e8 100644 --- a/Mage.Sets/src/mage/sets/lorwyn/HordeOfNotions.java +++ b/Mage.Sets/src/mage/sets/lorwyn/HordeOfNotions.java @@ -115,11 +115,11 @@ class HordeOfNotionsEffect extends OneShotEffect { if (card != null ) { // Probably there is no Elemental land, but who knows if (card.getCardType().contains(CardType.LAND) && controller.canPlayLand() && - controller.chooseUse(outcome, "Play " + card.getName() + " from your graveyard for free?", game)) { + controller.chooseUse(outcome, "Play " + card.getName() + " from your graveyard for free?", source, game)) { controller.playLand(card, game); } else { if (card.getSpellAbility().canChooseTarget(game) && - controller.chooseUse(outcome, "Play " + card.getName() + " from your graveyard for free?", game)) { + controller.chooseUse(outcome, "Play " + card.getName() + " from your graveyard for free?", source, game)) { controller.cast(card.getSpellAbility(), game, true); } } diff --git a/Mage.Sets/src/mage/sets/lorwyn/IncandescentSoulstoke.java b/Mage.Sets/src/mage/sets/lorwyn/IncandescentSoulstoke.java index 995d396e080..1d2c1474769 100644 --- a/Mage.Sets/src/mage/sets/lorwyn/IncandescentSoulstoke.java +++ b/Mage.Sets/src/mage/sets/lorwyn/IncandescentSoulstoke.java @@ -122,7 +122,7 @@ class IncandescentSoulstokeEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - if (controller.chooseUse(Outcome.PutCreatureInPlay, choiceText, game)) { + if (controller.chooseUse(Outcome.PutCreatureInPlay, choiceText, source, game)) { FilterCard filter = new FilterCreatureCard(); filter.add(new SubtypePredicate(("Elemental"))); TargetCardInHand target = new TargetCardInHand(filter); diff --git a/Mage.Sets/src/mage/sets/lorwyn/RingsOfBrighthearth.java b/Mage.Sets/src/mage/sets/lorwyn/RingsOfBrighthearth.java index 51675f87b0c..e591c15973e 100644 --- a/Mage.Sets/src/mage/sets/lorwyn/RingsOfBrighthearth.java +++ b/Mage.Sets/src/mage/sets/lorwyn/RingsOfBrighthearth.java @@ -130,7 +130,7 @@ class RingsOfBrighthearthEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); ManaCostsImpl cost = new ManaCostsImpl("{2}"); if (player != null) { - if (player.chooseUse(Outcome.Benefit, "Pay " + cost.getText() + "? If you do, copy that ability. You may choose new targets for the copy.", game)) { + if (player.chooseUse(Outcome.Benefit, "Pay " + cost.getText() + "? If you do, copy that ability. You may choose new targets for the copy.", source, game)) { if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { Ability ability = (Ability) getValue("stackAbility"); Player controller = game.getPlayer(source.getControllerId()); @@ -140,7 +140,7 @@ class RingsOfBrighthearthEffect extends OneShotEffect { newAbility.newId(); game.getStack().push(new StackAbility(newAbility, source.getControllerId())); if (newAbility.getTargets().size() > 0) { - if (controller.chooseUse(newAbility.getEffects().get(0).getOutcome(), "Choose new targets?", game)) { + if (controller.chooseUse(newAbility.getEffects().get(0).getOutcome(), "Choose new targets?", source, game)) { newAbility.getTargets().clearChosen(); if (newAbility.getTargets().chooseTargets(newAbility.getEffects().get(0).getOutcome(), source.getControllerId(), newAbility, game) == false) { return false; diff --git a/Mage.Sets/src/mage/sets/lorwyn/SilvergillAdept.java b/Mage.Sets/src/mage/sets/lorwyn/SilvergillAdept.java index bf85fd0790d..9ec52f20fd7 100644 --- a/Mage.Sets/src/mage/sets/lorwyn/SilvergillAdept.java +++ b/Mage.Sets/src/mage/sets/lorwyn/SilvergillAdept.java @@ -27,9 +27,7 @@ */ package mage.sets.lorwyn; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; +import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -39,14 +37,15 @@ import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInHand; -import java.util.UUID; - /** * * @author North @@ -106,7 +105,7 @@ class SilvergillAdeptCost extends CostImpl { paid = false; if (player.getHand().count(filter, game) > 0 - && player.chooseUse(Outcome.Benefit, "Reveal a Merfolk card? Otherwise pay {3}.", game)) { + && player.chooseUse(Outcome.Benefit, "Reveal a Merfolk card? Otherwise pay {3}.", ability, game)) { TargetCardInHand target = new TargetCardInHand(filter); if (player.choose(Outcome.Benefit, target, sourceId, game)) { Card card = player.getHand().get(target.getFirstTarget(), game); diff --git a/Mage.Sets/src/mage/sets/magic2010/DjinnOfWishes.java b/Mage.Sets/src/mage/sets/magic2010/DjinnOfWishes.java index 82d9180f716..1ad585e45f5 100644 --- a/Mage.Sets/src/mage/sets/magic2010/DjinnOfWishes.java +++ b/Mage.Sets/src/mage/sets/magic2010/DjinnOfWishes.java @@ -110,7 +110,7 @@ class DjinnOfWishesEffect extends OneShotEffect { player.getLibrary().removeFromTop(game); boolean used = false; - if (player.chooseUse(Outcome.PlayForFree, "Play " + card.getName() + " without paying its mana cost?", game)) { + if (player.chooseUse(Outcome.PlayForFree, "Play " + card.getName() + " without paying its mana cost?", source, game)) { if (card.getCardType().contains(CardType.LAND)) { // If the revealed card is a land, you can play it only if it's your turn and you haven't yet played a land this turn. if (game.getActivePlayerId().equals(player.getId()) && player.canPlayLand()) { diff --git a/Mage.Sets/src/mage/sets/magic2010/LurkingPredators.java b/Mage.Sets/src/mage/sets/magic2010/LurkingPredators.java index be9f78607e3..9a1a0795565 100644 --- a/Mage.Sets/src/mage/sets/magic2010/LurkingPredators.java +++ b/Mage.Sets/src/mage/sets/magic2010/LurkingPredators.java @@ -100,7 +100,7 @@ class LurkingPredatorsEffect extends OneShotEffect { if (card.getCardType().contains(CardType.CREATURE)) { card = player.getLibrary().removeFromTop(game); card.putOntoBattlefield(game, Zone.HAND, source.getSourceId(), source.getControllerId()); - } else if (player.chooseUse(Outcome.Neutral, "Put " + card.getName() + " on the bottom of your library?", game)) { + } else if (player.chooseUse(Outcome.Neutral, "Put " + card.getName() + " on the bottom of your library?", source, game)) { card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); } } diff --git a/Mage.Sets/src/mage/sets/magic2010/SphinxAmbassador.java b/Mage.Sets/src/mage/sets/magic2010/SphinxAmbassador.java index d695774a914..d45e92ec373 100644 --- a/Mage.Sets/src/mage/sets/magic2010/SphinxAmbassador.java +++ b/Mage.Sets/src/mage/sets/magic2010/SphinxAmbassador.java @@ -124,7 +124,7 @@ class SphinxAmbassadorEffect extends OneShotEffect { game.informPlayers(new StringBuilder(sourcePermanent.getName()).append(", named card: [").append(cardName).append("]").toString()); if (!card.getName().equals(cardName) && card.getCardType().contains(CardType.CREATURE)) { - if (player.chooseUse(outcome, new StringBuilder("Put ").append(card.getName()).append(" onto the battlefield?").toString(), game)) { + if (player.chooseUse(outcome, new StringBuilder("Put ").append(card.getName()).append(" onto the battlefield?").toString(), source, game)) { player.putOntoBattlefieldWithInfo(card, game, Zone.LIBRARY, source.getSourceId()); } } diff --git a/Mage.Sets/src/mage/sets/magic2011/ReassemblingSkeleton.java b/Mage.Sets/src/mage/sets/magic2011/ReassemblingSkeleton.java index e0ffb0f2321..8610b43ac5f 100644 --- a/Mage.Sets/src/mage/sets/magic2011/ReassemblingSkeleton.java +++ b/Mage.Sets/src/mage/sets/magic2011/ReassemblingSkeleton.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,23 +20,22 @@ * 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.magic2011; import java.util.UUID; -import mage.constants.CardType; -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.ReturnSourceFromGraveyardToBattlefieldEffect; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; /** * @@ -53,6 +52,7 @@ public class ReassemblingSkeleton extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(1); + // {1}{B}: Return Reassembling Skeleton from your graveyard to the battlefield tapped. this.addAbility(new SimpleActivatedAbility(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(true), new ManaCostsImpl("{1}{B}"))); } diff --git a/Mage.Sets/src/mage/sets/magic2012/ArachnusSpinner.java b/Mage.Sets/src/mage/sets/magic2012/ArachnusSpinner.java index 8bd0579c31a..e4b69485863 100644 --- a/Mage.Sets/src/mage/sets/magic2012/ArachnusSpinner.java +++ b/Mage.Sets/src/mage/sets/magic2012/ArachnusSpinner.java @@ -123,7 +123,7 @@ class ArachnusSpinnerEffect extends OneShotEffect { Card card = null; Zone zone = null; - if (player.chooseUse(Outcome.Neutral, "Search your graveyard for Arachnus Web?", game)) { + if (player.chooseUse(Outcome.Neutral, "Search your graveyard for Arachnus Web?", source, game)) { TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(filter); if (player.choose(Outcome.PutCardInPlay, player.getGraveyard(), target, game)) { card = game.getCard(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/sets/magic2012/DoublingChant.java b/Mage.Sets/src/mage/sets/magic2012/DoublingChant.java index 6b66ea382e3..339fc133bef 100644 --- a/Mage.Sets/src/mage/sets/magic2012/DoublingChant.java +++ b/Mage.Sets/src/mage/sets/magic2012/DoublingChant.java @@ -103,7 +103,7 @@ class DoublingChantEffect extends OneShotEffect { StringBuilder sb = new StringBuilder(); sb.append("Search for ").append(creatureName).append(" in your library?"); - if (player.chooseUse(Outcome.PutCreatureInPlay, sb.toString(), game)) { + if (player.chooseUse(Outcome.PutCreatureInPlay, sb.toString(), source, game)) { FilterCreatureCard filter = new FilterCreatureCard("creature card named" + creatureName); filter.add(new NamePredicate(creatureName)); TargetCardInLibrary target = new TargetCardInLibrary(filter); diff --git a/Mage.Sets/src/mage/sets/magic2013/LilianaOfTheDarkRealms.java b/Mage.Sets/src/mage/sets/magic2013/LilianaOfTheDarkRealms.java index 5eb20f16df4..b706cc764c0 100644 --- a/Mage.Sets/src/mage/sets/magic2013/LilianaOfTheDarkRealms.java +++ b/Mage.Sets/src/mage/sets/magic2013/LilianaOfTheDarkRealms.java @@ -133,7 +133,7 @@ class LilianaOfTheDarkRealmsEffect extends ContinuousEffectImpl { Player player = game.getPlayer(source.getControllerId()); String message = "Should the target creature get -X/-X instead of +X/+X?"; - if (player != null && player.chooseUse(Outcome.Neutral, message, game)) { + if (player != null && player.chooseUse(Outcome.Neutral, message, source, game)) { this.amount *= -1; } } diff --git a/Mage.Sets/src/mage/sets/magic2013/MindclawShaman.java b/Mage.Sets/src/mage/sets/magic2013/MindclawShaman.java index efb3c3fe931..9a349e30d5b 100644 --- a/Mage.Sets/src/mage/sets/magic2013/MindclawShaman.java +++ b/Mage.Sets/src/mage/sets/magic2013/MindclawShaman.java @@ -117,7 +117,7 @@ class MindclawShamanEffect extends OneShotEffect { if (controller.choose(Outcome.Benefit, targetOpponent.getHand(), target, game)) { Card chosenCard = targetOpponent.getHand().get(target.getFirstTarget(), game); if (chosenCard != null) { - if (controller.chooseUse(Outcome.Benefit, "Cast the chosen card?", game)) { + if (controller.chooseUse(Outcome.Benefit, "Cast the chosen card?", source, game)) { controller.cast(chosenCard.getSpellAbility(), game, true); } else { game.informPlayers(sourceObject.getLogName() +": " + controller.getLogName() + " canceled casting the card."); diff --git a/Mage.Sets/src/mage/sets/magic2013/ShimianSpecter.java b/Mage.Sets/src/mage/sets/magic2013/ShimianSpecter.java index 8b38fd97f2a..a8753258aba 100644 --- a/Mage.Sets/src/mage/sets/magic2013/ShimianSpecter.java +++ b/Mage.Sets/src/mage/sets/magic2013/ShimianSpecter.java @@ -148,7 +148,7 @@ class ShimianSpecterEffect extends OneShotEffect { // search cards in Library // If the player has no nonland cards in his or her hand, you can still search that player's library and have him or her shuffle it. - if (chosenCard != null || controller.chooseUse(outcome, "Search library anyway?", game)) { + if (chosenCard != null || controller.chooseUse(outcome, "Search library anyway?", source, game)) { TargetCardInLibrary targetCardsLibrary = new TargetCardInLibrary(0, Integer.MAX_VALUE, filterNamedCards); controller.searchLibrary(targetCardsLibrary, game, targetPlayer.getId()); for(UUID cardId: targetCardsLibrary.getTargets()) { diff --git a/Mage.Sets/src/mage/sets/magic2013/Spelltwine.java b/Mage.Sets/src/mage/sets/magic2013/Spelltwine.java index 518d0f0a236..b37080dda6b 100644 --- a/Mage.Sets/src/mage/sets/magic2013/Spelltwine.java +++ b/Mage.Sets/src/mage/sets/magic2013/Spelltwine.java @@ -111,7 +111,7 @@ class SpelltwineEffect extends OneShotEffect { controller.moveCardToExileWithInfo(cardTwo, null, "", source.getSourceId(), game, Zone.GRAVEYARD, true); } boolean castCardOne = true; - if (cardOne != null && controller.chooseUse(Outcome.Neutral, "Cast the copy of " + cardOne.getName() + " first?", game)) { + if (cardOne != null && controller.chooseUse(Outcome.Neutral, "Cast the copy of " + cardOne.getName() + " first?", source, game)) { Card copyOne = game.copyCard(cardOne, source, controller.getId()); controller.cast(copyOne.getSpellAbility(), game, true); castCardOne = false; diff --git a/Mage.Sets/src/mage/sets/magic2014/AjanisChosen.java b/Mage.Sets/src/mage/sets/magic2014/AjanisChosen.java index d4f12cbb1f8..62e2921c40a 100644 --- a/Mage.Sets/src/mage/sets/magic2014/AjanisChosen.java +++ b/Mage.Sets/src/mage/sets/magic2014/AjanisChosen.java @@ -110,7 +110,7 @@ class AjanisChosenEffect extends OneShotEffect { { Permanent oldCreature = game.getPermanent(enchantement.getAttachedTo()); - if(oldCreature != null && enchantement.getSpellAbility().getTargets().get(0).canTarget(tokenPermanent.getId(), game) && player.chooseUse(Outcome.Neutral, "Attach " + enchantement.getName() + " to the token ?", game)) + if(oldCreature != null && enchantement.getSpellAbility().getTargets().get(0).canTarget(tokenPermanent.getId(), game) && player.chooseUse(Outcome.Neutral, "Attach " + enchantement.getName() + " to the token ?", source, game)) { if(oldCreature.removeAttachment(enchantement.getId(), game)){ tokenPermanent.addAttachment(enchantement.getId(), game); diff --git a/Mage.Sets/src/mage/sets/magic2014/ChandraPyromaster.java b/Mage.Sets/src/mage/sets/magic2014/ChandraPyromaster.java index a9f736fb55e..1ce15ed3de0 100644 --- a/Mage.Sets/src/mage/sets/magic2014/ChandraPyromaster.java +++ b/Mage.Sets/src/mage/sets/magic2014/ChandraPyromaster.java @@ -295,13 +295,13 @@ class ChandraPyromasterEffect3 extends OneShotEffect { Card copy1 = card.copy(); Card copy2 = card.copy(); Card copy3 = card.copy(); - if (copy1 != null && you.chooseUse(outcome, "Do you wish to cast copy 1 of " + card.getName(), game)) { + if (copy1 != null && you.chooseUse(outcome, "Do you wish to cast copy 1 of " + card.getName(), source, game)) { you.cast(copy1.getSpellAbility(), game, true); } - if (copy2 != null && you.chooseUse(outcome, "Do you wish to cast copy 2 of " + card.getName(), game)) { + if (copy2 != null && you.chooseUse(outcome, "Do you wish to cast copy 2 of " + card.getName(), source, game)) { you.cast(copy2.getSpellAbility(), game, true); } - if (copy3 != null && you.chooseUse(outcome, "Do you wish to cast copy 3 of " + card.getName(), game)) { + if (copy3 != null && you.chooseUse(outcome, "Do you wish to cast copy 3 of " + card.getName(), source, game)) { you.cast(copy3.getSpellAbility(), game, true); } return true; diff --git a/Mage.Sets/src/mage/sets/magic2014/EliteArcanist.java b/Mage.Sets/src/mage/sets/magic2014/EliteArcanist.java index a6096095dd2..d79a6a5a1b7 100644 --- a/Mage.Sets/src/mage/sets/magic2014/EliteArcanist.java +++ b/Mage.Sets/src/mage/sets/magic2014/EliteArcanist.java @@ -176,7 +176,7 @@ class EliteArcanistCopyEffect extends OneShotEffect { if (copiedCard != null) { game.getExile().add(source.getSourceId(), "",copiedCard); game.getState().setZone(copiedCard.getId(), Zone.EXILED); - if (controller.chooseUse(outcome, "Cast the copied card without paying mana cost?", game)) { + if (controller.chooseUse(outcome, "Cast the copied card without paying mana cost?", source, game)) { return controller.cast(copiedCard.getSpellAbility(), game, true); } } diff --git a/Mage.Sets/src/mage/sets/magic2014/GarrukCallerOfBeasts.java b/Mage.Sets/src/mage/sets/magic2014/GarrukCallerOfBeasts.java index 33dce957c07..a4fc59d7c98 100644 --- a/Mage.Sets/src/mage/sets/magic2014/GarrukCallerOfBeasts.java +++ b/Mage.Sets/src/mage/sets/magic2014/GarrukCallerOfBeasts.java @@ -143,7 +143,7 @@ class GarrukCallerOfBeastsPutOntoBattlefieldEffect extends OneShotEffect { if (controller.getHand().count(filterGreenCreature, game) > 0) { if (controller.chooseUse(Outcome.PutCreatureInPlay, - "Put a green creature card onto the battlefield?", game)) { + "Put a green creature card onto the battlefield?", source, game)) { Target target = new TargetCardInHand(filterGreenCreature); if (controller.chooseTarget(outcome, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/sets/magic2014/IntoTheWilds.java b/Mage.Sets/src/mage/sets/magic2014/IntoTheWilds.java index 6317d0a0c7b..b08c6e32598 100644 --- a/Mage.Sets/src/mage/sets/magic2014/IntoTheWilds.java +++ b/Mage.Sets/src/mage/sets/magic2014/IntoTheWilds.java @@ -102,7 +102,7 @@ class IntoTheWildsEffect extends OneShotEffect { player.lookAtCards("Into the Wilds", cards, game); if (filter.match(card, game)) { String message = "Put " + card.getName() + " onto the battlefield?"; - if (player.chooseUse(outcome, message, game)) { + if (player.chooseUse(outcome, message, source, game)) { return card.putOntoBattlefield(game, Zone.LIBRARY, source.getSourceId(), source.getControllerId(), false); } } diff --git a/Mage.Sets/src/mage/sets/magic2014/JacesMindseeker.java b/Mage.Sets/src/mage/sets/magic2014/JacesMindseeker.java index 2c7791d42d9..bf8354a2869 100644 --- a/Mage.Sets/src/mage/sets/magic2014/JacesMindseeker.java +++ b/Mage.Sets/src/mage/sets/magic2014/JacesMindseeker.java @@ -126,7 +126,7 @@ class JaceMindseekerEffect extends OneShotEffect { if (controller != null) { TargetCard target = new TargetCard(Zone.GRAVEYARD, filter); // zone should be ignored here target.setNotTarget(true); - if (controller.chooseUse(outcome, "Cast an instant or sorcery card from among them for free?", game) + if (controller.chooseUse(outcome, "Cast an instant or sorcery card from among them for free?", source, game) && controller.choose(outcome, cardsToCast, target, game)) { Card card = cardsToCast.get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/magic2014/StrionicResonator.java b/Mage.Sets/src/mage/sets/magic2014/StrionicResonator.java index 3b5a1d0fe23..c05126f8ba0 100644 --- a/Mage.Sets/src/mage/sets/magic2014/StrionicResonator.java +++ b/Mage.Sets/src/mage/sets/magic2014/StrionicResonator.java @@ -102,7 +102,7 @@ class StrionicResonatorEffect extends OneShotEffect { newAbility.newId(); game.getStack().push(new StackAbility(newAbility, source.getControllerId())); if (newAbility.getTargets().size() > 0) { - if (controller.chooseUse(newAbility.getEffects().get(0).getOutcome(), "Choose new targets?", game)) { + if (controller.chooseUse(newAbility.getEffects().get(0).getOutcome(), "Choose new targets?", source, game)) { newAbility.getTargets().clearChosen(); if (newAbility.getTargets().chooseTargets(newAbility.getEffects().get(0).getOutcome(), source.getControllerId(), newAbility, game) == false) { return false; diff --git a/Mage.Sets/src/mage/sets/magic2015/AEtherspouts.java b/Mage.Sets/src/mage/sets/magic2015/AEtherspouts.java index 20101ee502a..c0590adff87 100644 --- a/Mage.Sets/src/mage/sets/magic2015/AEtherspouts.java +++ b/Mage.Sets/src/mage/sets/magic2015/AEtherspouts.java @@ -111,7 +111,7 @@ class AEtherspoutsEffect extends OneShotEffect { ArrayList permanentsToBottom = new ArrayList<>(); for (Permanent permanent:game.getState().getBattlefield().getActivePermanents(new FilterAttackingCreature(), player.getId(), source.getSourceId(), game)) { if (permanent.getOwnerId().equals(player.getId())) { - if (player.chooseUse(outcome, "Put " + permanent.getLogName() + " to the top? (else it goes to bottom)", game)) { + if (player.chooseUse(outcome, "Put " + permanent.getLogName() + " to the top? (else it goes to bottom)", source, game)) { permanentsToTop.add(permanent); game.informPlayers(permanent.getLogName() + " goes to the top of " + player.getLogName() + "'s library"); } else { diff --git a/Mage.Sets/src/mage/sets/magic2015/BoonweaverGiant.java b/Mage.Sets/src/mage/sets/magic2015/BoonweaverGiant.java index bf8f69116f1..12075176452 100644 --- a/Mage.Sets/src/mage/sets/magic2015/BoonweaverGiant.java +++ b/Mage.Sets/src/mage/sets/magic2015/BoonweaverGiant.java @@ -108,7 +108,7 @@ class BoonweaverGiantEffect extends OneShotEffect { Card card = null; Zone zone = null; - if (player.chooseUse(Outcome.Neutral, "Search your graveyard for an Aura card?", game)) { + if (player.chooseUse(Outcome.Neutral, "Search your graveyard for an Aura card?", source, game)) { TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(filter); if (player.choose(Outcome.PutCardInPlay, player.getGraveyard(), target, game)) { card = game.getCard(target.getFirstTarget()); @@ -117,7 +117,7 @@ class BoonweaverGiantEffect extends OneShotEffect { } } } - if (card == null && player.chooseUse(Outcome.Neutral, "Search your Hand for an Aura card?", game)) { + if (card == null && player.chooseUse(Outcome.Neutral, "Search your Hand for an Aura card?", source, game)) { TargetCardInHand target = new TargetCardInHand(filter); if (player.choose(Outcome.PutCardInPlay, player.getHand(), target, game)) { card = game.getCard(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/sets/magic2015/IndulgentTormentor.java b/Mage.Sets/src/mage/sets/magic2015/IndulgentTormentor.java index 47b279a96e3..5918480369a 100644 --- a/Mage.Sets/src/mage/sets/magic2015/IndulgentTormentor.java +++ b/Mage.Sets/src/mage/sets/magic2015/IndulgentTormentor.java @@ -101,14 +101,14 @@ class IndulgentTormentorEffect extends OneShotEffect { if (opponent != null) { Cost cost = new SacrificeTargetCost(new TargetControlledCreaturePermanent()); if (cost.canPay(source, source.getSourceId(), opponent.getId(), game) - && opponent.chooseUse(outcome, "Sacrifice a creature to prevent the card draw?", game)) { + && opponent.chooseUse(outcome, "Sacrifice a creature to prevent the card draw?", source, game)) { if (cost.pay(source, game, source.getSourceId(), opponent.getId(), false)) { return true; } } cost = new PayLifeCost(3); if (cost.canPay(source, source.getSourceId(), opponent.getId(), game) - && opponent.chooseUse(outcome, "Pay 3 life to prevent the card draw?", game)) { + && opponent.chooseUse(outcome, "Pay 3 life to prevent the card draw?", source, game)) { if (cost.pay(source, game, source.getSourceId(), opponent.getId(), false)) { return true; } diff --git a/Mage.Sets/src/mage/sets/magic2015/KurkeshOnakkeAncient.java b/Mage.Sets/src/mage/sets/magic2015/KurkeshOnakkeAncient.java index 3838c745cda..91c880acb42 100644 --- a/Mage.Sets/src/mage/sets/magic2015/KurkeshOnakkeAncient.java +++ b/Mage.Sets/src/mage/sets/magic2015/KurkeshOnakkeAncient.java @@ -140,7 +140,7 @@ class KurkeshOnakkeAncientEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); ColoredManaCost cost = new ColoredManaCost(ColoredManaSymbol.R); if (player != null) { - if (player.chooseUse(Outcome.Benefit, "Pay " + cost.getText() + "? If you do, copy that ability. You may choose new targets for the copy.", game)) { + if (player.chooseUse(Outcome.Benefit, "Pay " + cost.getText() + "? If you do, copy that ability. You may choose new targets for the copy.", source, game)) { if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { Ability ability = (Ability) getValue("stackAbility"); Player controller = game.getPlayer(source.getControllerId()); @@ -150,7 +150,7 @@ class KurkeshOnakkeAncientEffect extends OneShotEffect { newAbility.newId(); game.getStack().push(new StackAbility(newAbility, source.getControllerId())); if (newAbility.getTargets().size() > 0) { - if (controller.chooseUse(newAbility.getEffects().get(0).getOutcome(), "Choose new targets?", game)) { + if (controller.chooseUse(newAbility.getEffects().get(0).getOutcome(), "Choose new targets?", source, game)) { newAbility.getTargets().clearChosen(); if (newAbility.getTargets().chooseTargets(newAbility.getEffects().get(0).getOutcome(), source.getControllerId(), newAbility, game) == false) { return false; diff --git a/Mage.Sets/src/mage/sets/magic2015/MasterOfPredicaments.java b/Mage.Sets/src/mage/sets/magic2015/MasterOfPredicaments.java index 07ca8b4566b..ff504769e1b 100644 --- a/Mage.Sets/src/mage/sets/magic2015/MasterOfPredicaments.java +++ b/Mage.Sets/src/mage/sets/magic2015/MasterOfPredicaments.java @@ -112,7 +112,7 @@ class MasterOfPredicamentsEffect extends OneShotEffect { return false; } boolean guessWrong; - if (attackedPlayer.chooseUse(Outcome.Detriment, "Is the chosen card's converted mana cost greater than 4?", game)) { + if (attackedPlayer.chooseUse(Outcome.Detriment, "Is the chosen card's converted mana cost greater than 4?", source, game)) { game.informPlayers(attackedPlayer.getLogName() + " guessed that the chosen card's converted mana cost is greater than 4"); guessWrong = cardFromHand.getManaCost().convertedManaCost() <= 4; } else { @@ -124,7 +124,7 @@ class MasterOfPredicamentsEffect extends OneShotEffect { if (cardFromHand.getCardType().contains(CardType.LAND)) { // If the revealed card is a land, you can't cast it. So nothing happens } else { - if (controller.chooseUse(outcome, "Cast " + cardFromHand.getName() + " without paying its mana cost?", game)) { + if (controller.chooseUse(outcome, "Cast " + cardFromHand.getName() + " without paying its mana cost?", source, game)) { controller.cast(cardFromHand.getSpellAbility(), game, true); } } diff --git a/Mage.Sets/src/mage/sets/magic2015/Quickling.java b/Mage.Sets/src/mage/sets/magic2015/Quickling.java index c23893233e4..21d407e9e75 100644 --- a/Mage.Sets/src/mage/sets/magic2015/Quickling.java +++ b/Mage.Sets/src/mage/sets/magic2015/Quickling.java @@ -103,7 +103,7 @@ class QuicklingEffect extends OneShotEffect { if (controller != null) { boolean targetChosen = false; TargetPermanent target = new TargetPermanent(1, 1, filter, true); - if (target.canChoose(controller.getId(), game) && controller.chooseUse(outcome, "Return another creature you control to its owner's hand?", game)) { + if (target.canChoose(controller.getId(), game) && controller.chooseUse(outcome, "Return another creature you control to its owner's hand?", source, game)) { controller.chooseTarget(Outcome.ReturnToHand, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if ( permanent != null ) { diff --git a/Mage.Sets/src/mage/sets/magic2015/SliverHive.java b/Mage.Sets/src/mage/sets/magic2015/SliverHive.java index d28e5e4d8eb..3bcd1d26d85 100644 --- a/Mage.Sets/src/mage/sets/magic2015/SliverHive.java +++ b/Mage.Sets/src/mage/sets/magic2015/SliverHive.java @@ -33,10 +33,10 @@ import mage.MageInt; import mage.MageObject; import mage.Mana; import mage.abilities.Ability; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.common.ControlPermanentCost; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.mana.ColorlessManaAbility; import mage.abilities.mana.ConditionalAnyColorManaAbility; @@ -56,8 +56,9 @@ import mage.game.permanent.token.Token; * @author emerald000 */ public class SliverHive extends CardImpl { - + private static final FilterControlledPermanent filter = new FilterControlledPermanent("Sliver"); + static { filter.add(new SubtypePredicate("Sliver")); } @@ -68,14 +69,15 @@ public class SliverHive extends CardImpl { // {T}: Add {1} to your mana pool. this.addAbility(new ColorlessManaAbility()); - + // {T}: Add one mana of any color to your mana pool. Spend this mana only to cast a Sliver spell. this.addAbility(new ConditionalAnyColorManaAbility(new TapSourceCost(), 1, new SliverHiveManaBuilder(), true)); - + // {5}, {T}: Put a 1/1 colorless Sliver creature token onto the battlefield. Activate this ability only if you control a Sliver. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new SliverToken()), new TapSourceCost()); + Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new SliverToken()), new TapSourceCost(), + new PermanentsOnTheBattlefieldCondition(filter), + "{5}, {T}: Put a 1/1 colorless Sliver creature token onto the battlefield. Activate this ability only if you control a Sliver."); ability.addCost(new GenericManaCost(5)); - ability.addCost(new ControlPermanentCost(filter)); this.addAbility(ability); } @@ -136,4 +138,4 @@ class SliverToken extends Token { power = new MageInt(1); toughness = new MageInt(1); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/magicorigins/MizziumMeddler.java b/Mage.Sets/src/mage/sets/magicorigins/MizziumMeddler.java index 9521c64b235..c0a7dc19aec 100644 --- a/Mage.Sets/src/mage/sets/magicorigins/MizziumMeddler.java +++ b/Mage.Sets/src/mage/sets/magicorigins/MizziumMeddler.java @@ -136,7 +136,7 @@ class MizziumMeddlerEffect extends OneShotEffect { twoTimesTarget = true; continue; } - if (name != null && player.chooseUse(Outcome.Neutral, new StringBuilder("Change target from ").append(name).append(" to ").append(sourceObject.getName()).append("?").toString(), game)) { + if (name != null && player.chooseUse(Outcome.Neutral, new StringBuilder("Change target from ").append(name).append(" to ").append(sourceObject.getName()).append("?").toString(), source, game)) { if (target.canTarget(stackObject.getControllerId(), source.getSourceId(), sourceAbility, game)) { oldTarget = game.getObject(targets.getFirstTarget()); target.remove(targetId); diff --git a/Mage.Sets/src/mage/sets/masterseditioniii/Exorcist.java b/Mage.Sets/src/mage/sets/masterseditioniii/Exorcist.java new file mode 100644 index 00000000000..d695b9d6950 --- /dev/null +++ b/Mage.Sets/src/mage/sets/masterseditioniii/Exorcist.java @@ -0,0 +1,82 @@ +/* + * 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.masterseditioniii; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author ilcartographer + */ +public class Exorcist extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("black creature"); + static { + filter.add(new ColorPredicate(ObjectColor.BLACK)); + } + + public Exorcist(UUID ownerId) { + super(ownerId, 10, "Exorcist", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{W}{W}"); + this.expansionSetCode = "ME3"; + this.subtype.add("Human"); + this.subtype.add("Cleric"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {1}{W}, {tap}: Destroy target black creature. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, + new DestroyTargetEffect(), + new ManaCostsImpl("{1}{W}")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); + } + + public Exorcist(final Exorcist card) { + super(card); + } + + @Override + public Exorcist copy() { + return new Exorcist(this); + } +} diff --git a/Mage.Sets/src/mage/sets/masterseditioniii/FaerieNoble.java b/Mage.Sets/src/mage/sets/masterseditioniii/FaerieNoble.java new file mode 100644 index 00000000000..c53dac27a65 --- /dev/null +++ b/Mage.Sets/src/mage/sets/masterseditioniii/FaerieNoble.java @@ -0,0 +1,84 @@ +/* + * 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.masterseditioniii; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; + +/** + * + * @author ilcartographer + */ +public class FaerieNoble extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Faerie creatures"); + + static { + filter.add(new SubtypePredicate("Faerie")); + } + + public FaerieNoble(UUID ownerId) { + super(ownerId, 117, "Faerie Noble", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{2}{G}"); + this.expansionSetCode = "ME3"; + this.subtype.add("Faerie"); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // Other Faerie creatures you control get +0/+1. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(0, 1, Duration.WhileOnBattlefield, filter, true))); + // {tap}: Other Faerie creatures you control get +1/+0 until end of turn. + Effect effect = new BoostControlledEffect(1, 0, Duration.WhileOnBattlefield, filter, true); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new TapSourceCost()); + this.addAbility(ability); + } + + public FaerieNoble(final FaerieNoble card) { + super(card); + } + + @Override + public FaerieNoble copy() { + return new FaerieNoble(this); + } +} diff --git a/Mage.Sets/src/mage/sets/masterseditioniii/FalseDefeat.java b/Mage.Sets/src/mage/sets/masterseditioniii/FalseDefeat.java new file mode 100644 index 00000000000..3992c614056 --- /dev/null +++ b/Mage.Sets/src/mage/sets/masterseditioniii/FalseDefeat.java @@ -0,0 +1,61 @@ +/* + * 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.masterseditioniii; + +import java.util.UUID; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.common.FilterCreatureCard; +import mage.target.common.TargetCardInYourGraveyard; + +/** + * + * @author ilcartographer + */ +public class FalseDefeat extends CardImpl { + + public FalseDefeat(UUID ownerId) { + super(ownerId, 11, "False Defeat", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{3}{W}"); + this.expansionSetCode = "ME3"; + + // Return target creature card from your graveyard to the battlefield. + this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); + } + + public FalseDefeat(final FalseDefeat card) { + super(card); + } + + @Override + public FalseDefeat copy() { + return new FalseDefeat(this); + } +} diff --git a/Mage.Sets/src/mage/sets/masterseditioniii/FireSprites.java b/Mage.Sets/src/mage/sets/masterseditioniii/FireSprites.java new file mode 100644 index 00000000000..f5cf1eb740f --- /dev/null +++ b/Mage.Sets/src/mage/sets/masterseditioniii/FireSprites.java @@ -0,0 +1,74 @@ +/* + * 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.masterseditioniii; + +import java.util.UUID; +import mage.MageInt; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.mana.RedManaAbility; +import mage.abilities.mana.SimpleManaAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author ilcartographer + */ +public class FireSprites extends CardImpl { + + public FireSprites(UUID ownerId) { + super(ownerId, 118, "Fire Sprites", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{1}{G}"); + this.expansionSetCode = "ME3"; + this.subtype.add("Faerie"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // {G}, {tap}: Add {R} to your mana pool. + Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, Mana.RedMana, new ManaCostsImpl("{G}")); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + public FireSprites(final FireSprites card) { + super(card); + } + + @Override + public FireSprites copy() { + return new FireSprites(this); + } +} diff --git a/Mage.Sets/src/mage/sets/masterseditioniii/Immolation.java b/Mage.Sets/src/mage/sets/masterseditioniii/Immolation.java new file mode 100644 index 00000000000..5f3f42a8765 --- /dev/null +++ b/Mage.Sets/src/mage/sets/masterseditioniii/Immolation.java @@ -0,0 +1,52 @@ +/* + * 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.masterseditioniii; + +import java.util.UUID; + +/** + * + * @author ilcartographer + */ +public class Immolation extends mage.sets.fourthedition.Immolation { + + public Immolation(UUID ownerId) { + super(ownerId); + this.cardNumber = 103; + this.expansionSetCode = "ME3"; + } + + public Immolation(final Immolation card) { + super(card); + } + + @Override + public Immolation copy() { + return new Immolation(this); + } +} diff --git a/Mage.Sets/src/mage/sets/masterseditioniii/KoboldDrillSergeant.java b/Mage.Sets/src/mage/sets/masterseditioniii/KoboldDrillSergeant.java new file mode 100644 index 00000000000..225d0176d3e --- /dev/null +++ b/Mage.Sets/src/mage/sets/masterseditioniii/KoboldDrillSergeant.java @@ -0,0 +1,79 @@ +/* + * 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.masterseditioniii; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; + +/** + * + * @author ilcartographer + */ +public class KoboldDrillSergeant extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Kobold creatures"); + + static { + filter.add(new SubtypePredicate("Kobold")); + } + + public KoboldDrillSergeant(UUID ownerId) { + super(ownerId, 104, "Kobold Drill Sergeant", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{R}"); + this.expansionSetCode = "ME3"; + this.subtype.add("Kobold"); + this.subtype.add("Soldier"); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // Other Kobold creatures you control get +0/+1 and have trample. + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(0, 1, Duration.WhileOnBattlefield, filter, true)); + ability.addEffect(new GainAbilityControlledEffect(TrampleAbility.getInstance(), Duration.WhileOnBattlefield, filter, true)); + this.addAbility(ability); + } + + public KoboldDrillSergeant(final KoboldDrillSergeant card) { + super(card); + } + + @Override + public KoboldDrillSergeant copy() { + return new KoboldDrillSergeant(this); + } +} diff --git a/Mage.Sets/src/mage/sets/masterseditioniii/KoboldOverlord.java b/Mage.Sets/src/mage/sets/masterseditioniii/KoboldOverlord.java new file mode 100644 index 00000000000..c642a81f799 --- /dev/null +++ b/Mage.Sets/src/mage/sets/masterseditioniii/KoboldOverlord.java @@ -0,0 +1,54 @@ +/* + * 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.masterseditioniii; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author ilcartographer + */ +public class KoboldOverlord extends mage.sets.legends.KoboldOverlord { + + public KoboldOverlord(UUID ownerId) { + super(ownerId); + this.cardNumber = 105; + this.expansionSetCode = "ME3"; + this.rarity = Rarity.UNCOMMON; + } + + public KoboldOverlord(final KoboldOverlord card) { + super(card); + } + + @Override + public KoboldOverlord copy() { + return new KoboldOverlord(this); + } +} diff --git a/Mage.Sets/src/mage/sets/masterseditioniii/LuBuMasterAtArms.java b/Mage.Sets/src/mage/sets/masterseditioniii/LuBuMasterAtArms.java new file mode 100644 index 00000000000..36f87573865 --- /dev/null +++ b/Mage.Sets/src/mage/sets/masterseditioniii/LuBuMasterAtArms.java @@ -0,0 +1,67 @@ +/* + * 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.masterseditioniii; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.HorsemanshipAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; + +/** + * + * @author ilcartographer + */ +public class LuBuMasterAtArms extends CardImpl { + + public LuBuMasterAtArms(UUID ownerId) { + super(ownerId, 108, "Lu Bu, Master-at-Arms", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{5}{R}"); + this.expansionSetCode = "ME3"; + this.supertype.add("Legendary"); + this.subtype.add("Human"); + this.subtype.add("Soldier"); + this.subtype.add("Warrior"); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // Haste; horsemanship + this.addAbility(HasteAbility.getInstance()); + this.addAbility(HorsemanshipAbility.getInstance()); + } + + public LuBuMasterAtArms(final LuBuMasterAtArms card) { + super(card); + } + + @Override + public LuBuMasterAtArms copy() { + return new LuBuMasterAtArms(this); + } +} diff --git a/Mage.Sets/src/mage/sets/masterseditioniv/HasranOgress.java b/Mage.Sets/src/mage/sets/masterseditioniv/HasranOgress.java index f183ab6e5a5..ecaabd74092 100644 --- a/Mage.Sets/src/mage/sets/masterseditioniv/HasranOgress.java +++ b/Mage.Sets/src/mage/sets/masterseditioniv/HasranOgress.java @@ -91,7 +91,7 @@ class HasranOgressEffect extends OneShotEffect { if (controller != null) { Cost cost = new ManaCostsImpl("{2}"); String message = "Would you like to pay {2} to prevent taking 3 damage from Hasran Ogress?"; - if (!(controller.chooseUse(Outcome.Benefit, message, game) + if (!(controller.chooseUse(Outcome.Benefit, message, source, game) && cost.pay(source, game, source.getSourceId(), controller.getId(), false))) { controller.damage(3, source.getSourceId(), game, false, true); } diff --git a/Mage.Sets/src/mage/sets/masterseditioniv/Squall.java b/Mage.Sets/src/mage/sets/masterseditioniv/Squall.java new file mode 100644 index 00000000000..2ab5ac74eed --- /dev/null +++ b/Mage.Sets/src/mage/sets/masterseditioniv/Squall.java @@ -0,0 +1,55 @@ +/* + * 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.masterseditioniv; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author LoneFox + + */ +public class Squall extends mage.sets.starter1999.Squall { + + public Squall(UUID ownerId) { + super(ownerId); + this.cardNumber = 168; + this.expansionSetCode = "ME4"; + this.rarity = Rarity.UNCOMMON; + } + + public Squall(final Squall card) { + super(card); + } + + @Override + public Squall copy() { + return new Squall(this); + } +} diff --git a/Mage.Sets/src/mage/sets/mercadianmasques/HornOfPlenty.java b/Mage.Sets/src/mage/sets/mercadianmasques/HornOfPlenty.java index 49db6732148..6873cd06f09 100644 --- a/Mage.Sets/src/mage/sets/mercadianmasques/HornOfPlenty.java +++ b/Mage.Sets/src/mage/sets/mercadianmasques/HornOfPlenty.java @@ -96,7 +96,7 @@ class HornOfPlentyEffect extends OneShotEffect { caster = game.getPlayer(spell.getControllerId()); } if (caster != null) { - if (caster.chooseUse(Outcome.DrawCard, "Pay {1} to draw a card at the beginning of the next end step?", game)) { + if (caster.chooseUse(Outcome.DrawCard, "Pay {1} to draw a card at the beginning of the next end step?", source, game)) { Cost cost = new ManaCostsImpl("{1}"); if (cost.pay(source, game, source.getSourceId(), caster.getId(), false)) { Effect effect = new DrawCardTargetEffect(1); diff --git a/Mage.Sets/src/mage/sets/mercadianmasques/Squall.java b/Mage.Sets/src/mage/sets/mercadianmasques/Squall.java new file mode 100644 index 00000000000..3b7a20c7143 --- /dev/null +++ b/Mage.Sets/src/mage/sets/mercadianmasques/Squall.java @@ -0,0 +1,53 @@ +/* + * 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.mercadianmasques; + +import java.util.UUID; + +/** + * + * @author LoneFox + + */ +public class Squall extends mage.sets.starter1999.Squall { + + public Squall(UUID ownerId) { + super(ownerId); + this.cardNumber = 275; + this.expansionSetCode = "MMQ"; + } + + public Squall(final Squall card) { + super(card); + } + + @Override + public Squall copy() { + return new Squall(this); + } +} diff --git a/Mage.Sets/src/mage/sets/mirage/AmberPrison.java b/Mage.Sets/src/mage/sets/mirage/AmberPrison.java index 502ac964fb9..3653f69be88 100644 --- a/Mage.Sets/src/mage/sets/mirage/AmberPrison.java +++ b/Mage.Sets/src/mage/sets/mirage/AmberPrison.java @@ -59,21 +59,21 @@ import mage.target.TargetPermanent; public class AmberPrison extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("artifact, creature, or land"); - + static { filter.add(Predicates.or( new CardTypePredicate(CardType.ARTIFACT), new CardTypePredicate(CardType.CREATURE), new CardTypePredicate(CardType.LAND))); } - + public AmberPrison(UUID ownerId) { super(ownerId, 257, "Amber Prison", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{4}"); this.expansionSetCode = "MIR"; // You may choose not to untap Amber Prison during your untap step. this.addAbility(new SkipUntapOptionalAbility()); - + // {4}, {tap}: Tap target artifact, creature, or land. That permanent doesn't untap during its controller's untap step for as long as Amber Prison remains tapped. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AmberPrisonTapTargetEffect(), new GenericManaCost(4)); ability.addCost(new TapSourceCost()); @@ -99,7 +99,7 @@ class AmberPrisonTapTargetEffect extends OneShotEffect { super(Outcome.Tap); this.staticText = "Tap target artifact, creature, or land. That permanent doesn't untap during its controller's untap step for as long as {source} remains tapped."; } - + public AmberPrisonTapTargetEffect(final AmberPrisonTapTargetEffect effect) { super(effect); } @@ -108,7 +108,7 @@ class AmberPrisonTapTargetEffect extends OneShotEffect { public AmberPrisonTapTargetEffect copy() { return new AmberPrisonTapTargetEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Permanent sourcePermanent = game.getPermanent(source.getSourceId()); @@ -123,7 +123,7 @@ class AmberPrisonTapTargetEffect extends OneShotEffect { } return true; } - + } class AmberPrisonRestrictionEffect extends RestrictionEffect { @@ -131,7 +131,7 @@ class AmberPrisonRestrictionEffect extends RestrictionEffect { public AmberPrisonRestrictionEffect() { super(Duration.WhileOnBattlefield); } - + public AmberPrisonRestrictionEffect(final AmberPrisonRestrictionEffect effect) { super(effect); } @@ -140,7 +140,7 @@ class AmberPrisonRestrictionEffect extends RestrictionEffect { public AmberPrisonRestrictionEffect copy() { return new AmberPrisonRestrictionEffect(this); } - + @Override public boolean applies(Permanent permanent, Ability source, Game game) { Permanent sourcePermanent = game.getPermanent(source.getSourceId()); @@ -153,12 +153,11 @@ class AmberPrisonRestrictionEffect extends RestrictionEffect { } @Override - public boolean canBeUntapped(Permanent permanent, Game game) { + public boolean canBeUntapped(Permanent permanent, Ability source, Game game) { return false; } - -} +} class AmberPrisonUntapTriggeredAbility extends TriggeredAbilityImpl { @@ -167,11 +166,11 @@ class AmberPrisonUntapTriggeredAbility extends TriggeredAbilityImpl { this.usesStack = false; this.ruleVisible = false; } - + public AmberPrisonUntapTriggeredAbility(final AmberPrisonUntapTriggeredAbility ability) { super(ability); } - + @Override public AmberPrisonUntapTriggeredAbility copy() { return new AmberPrisonUntapTriggeredAbility(this); @@ -193,7 +192,7 @@ class AmberPrisonReleaseOnUntapEffect extends OneShotEffect { public AmberPrisonReleaseOnUntapEffect() { super(Outcome.Detriment); } - + public AmberPrisonReleaseOnUntapEffect(final AmberPrisonReleaseOnUntapEffect effect) { super(effect); } @@ -202,7 +201,7 @@ class AmberPrisonReleaseOnUntapEffect extends OneShotEffect { public AmberPrisonReleaseOnUntapEffect copy() { return new AmberPrisonReleaseOnUntapEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Permanent sourcePermanent = game.getPermanent(source.getSourceId()); @@ -212,5 +211,5 @@ class AmberPrisonReleaseOnUntapEffect extends OneShotEffect { } return false; } - + } diff --git a/Mage.Sets/src/mage/sets/mirage/Flash.java b/Mage.Sets/src/mage/sets/mirage/Flash.java index 01c899fc554..02a8f7a0749 100644 --- a/Mage.Sets/src/mage/sets/mirage/Flash.java +++ b/Mage.Sets/src/mage/sets/mirage/Flash.java @@ -91,7 +91,7 @@ class FlashEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (player == null || !player.chooseUse(Outcome.PutCreatureInPlay, choiceText, game)) { + if (player == null || !player.chooseUse(Outcome.PutCreatureInPlay, choiceText, source, game)) { return false; } @@ -103,7 +103,7 @@ class FlashEffect extends OneShotEffect { ManaCosts reducedCost = CardUtil.removeVariableManaCost(CardUtil.reduceCost(card.getManaCost(), 2)); StringBuilder sb = new StringBuilder("Pay ").append(reducedCost.getText()).append("?"); - if (player.chooseUse(Outcome.Benefit, sb.toString(), game)) { + if (player.chooseUse(Outcome.Benefit, sb.toString(), source, game)) { reducedCost.clearPaid(); if (reducedCost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { return true; diff --git a/Mage.Sets/src/mage/sets/mirage/IllicitAuction.java b/Mage.Sets/src/mage/sets/mirage/IllicitAuction.java index 88f7483736c..472c481860c 100644 --- a/Mage.Sets/src/mage/sets/mirage/IllicitAuction.java +++ b/Mage.Sets/src/mage/sets/mirage/IllicitAuction.java @@ -99,7 +99,7 @@ class IllicitAuctionEffect extends GainControlTargetEffect { Player currentPlayer = playerList.getNextInRange(controller, game); while (currentPlayer != winner) { String text = winner.getLogName() + " has bet " + highBid + " life" + (highBid > 1 ? "s" : "") + ". Top the bid?"; - if (currentPlayer.chooseUse(Outcome.Detriment, text, game)) { + if (currentPlayer.chooseUse(Outcome.Detriment, text, source, game)) { int newBid = currentPlayer.getAmount(highBid + 1, Integer.MAX_VALUE, "Choose bid", game); if (newBid > highBid) { highBid = newBid; diff --git a/Mage.Sets/src/mage/sets/mirage/NocturnalRaid.java b/Mage.Sets/src/mage/sets/mirage/NocturnalRaid.java new file mode 100644 index 00000000000..8f6df45a8f8 --- /dev/null +++ b/Mage.Sets/src/mage/sets/mirage/NocturnalRaid.java @@ -0,0 +1,68 @@ +/* + * 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.mirage; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; + +/** + * + * @author LoneFox + + */ +public class NocturnalRaid extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("black creatures"); + static { + filter.add(new ColorPredicate(ObjectColor.BLACK)); + } + + public NocturnalRaid(UUID ownerId) { + super(ownerId, 30, "Nocturnal Raid", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{2}{B}{B}"); + this.expansionSetCode = "MIR"; + + // Black creatures get +2/+0 until end of turn. + this.getSpellAbility().addEffect(new BoostAllEffect(2, 0, Duration.EndOfTurn, filter, false)); + } + + public NocturnalRaid(final NocturnalRaid card) { + super(card); + } + + @Override + public NocturnalRaid copy() { + return new NocturnalRaid(this); + } +} diff --git a/Mage.Sets/src/mage/sets/mirrodin/CrystalShard.java b/Mage.Sets/src/mage/sets/mirrodin/CrystalShard.java index 03a2101ae59..5b6e779b376 100644 --- a/Mage.Sets/src/mage/sets/mirrodin/CrystalShard.java +++ b/Mage.Sets/src/mage/sets/mirrodin/CrystalShard.java @@ -106,7 +106,7 @@ class CrystalShardEffect extends OneShotEffect { if (player != null) { cost.clearPaid(); final StringBuilder sb = new StringBuilder("Pay {1}? (Otherwise ").append(targetCreature.getName()).append(" will be returned to its owner's hand)"); - if (player.chooseUse(Outcome.Benefit, sb.toString(), game)) { + if (player.chooseUse(Outcome.Benefit, sb.toString(), source, game)) { cost.pay(source, game, targetCreature.getControllerId(), targetCreature.getControllerId(), false); } if (!cost.isPaid()) { diff --git a/Mage.Sets/src/mage/sets/mirrodin/FieryGambit.java b/Mage.Sets/src/mage/sets/mirrodin/FieryGambit.java index 9fb75bfa18d..25be1b7f876 100644 --- a/Mage.Sets/src/mage/sets/mirrodin/FieryGambit.java +++ b/Mage.Sets/src/mage/sets/mirrodin/FieryGambit.java @@ -95,7 +95,7 @@ class FieryGambitEffect extends OneShotEffect { while (controller.flipCoin(game)) { ++flipsWon; if (!controller.chooseUse(outcome, new StringBuilder("You won ").append(flipsWon).append(flipsWon == 1?" flip.":" flips.") - .append(" Flip another coin?").toString(), game)) { + .append(" Flip another coin?").toString(), source, game)) { controllerStopped = true; break; } diff --git a/Mage.Sets/src/mage/sets/mirrodin/IsochronScepter.java b/Mage.Sets/src/mage/sets/mirrodin/IsochronScepter.java index 2e723551388..c66fe327f6a 100644 --- a/Mage.Sets/src/mage/sets/mirrodin/IsochronScepter.java +++ b/Mage.Sets/src/mage/sets/mirrodin/IsochronScepter.java @@ -155,12 +155,12 @@ class IsochronScepterCopyEffect extends OneShotEffect { if (scepter != null && scepter.getImprinted() != null && !scepter.getImprinted().isEmpty()) { Card imprintedInstant = game.getCard(scepter.getImprinted().get(0)); if (imprintedInstant != null && game.getState().getZone(imprintedInstant.getId()).equals(Zone.EXILED)) { - if (controller.chooseUse(outcome, new StringBuilder("Create a copy of ").append(imprintedInstant.getName()).append("?").toString(), game)) { + if (controller.chooseUse(outcome, new StringBuilder("Create a copy of ").append(imprintedInstant.getName()).append("?").toString(), source, game)) { Card copiedCard = game.copyCard(imprintedInstant, source, source.getControllerId()); if (copiedCard != null) { game.getExile().add(source.getSourceId(), "",copiedCard); game.getState().setZone(copiedCard.getId(), Zone.EXILED); - if (controller.chooseUse(outcome, "Cast the copied card without paying mana cost?", game)) { + if (controller.chooseUse(outcome, "Cast the copied card without paying mana cost?", source, game)) { controller.cast(copiedCard.getSpellAbility(), game, true); } } diff --git a/Mage.Sets/src/mage/sets/mirrodin/KrarksThumb.java b/Mage.Sets/src/mage/sets/mirrodin/KrarksThumb.java index fda4d43fcc2..36535622b0e 100644 --- a/Mage.Sets/src/mage/sets/mirrodin/KrarksThumb.java +++ b/Mage.Sets/src/mage/sets/mirrodin/KrarksThumb.java @@ -86,7 +86,7 @@ class KrarksThumbEffect extends ReplacementEffectImpl { if (!game.isSimulation()) { game.informPlayers("[Flip a coin] " + player.getLogName() + (secondCoinFlip ? " won (head)." : " lost (tail).")); } - if (player.chooseUse(outcome, "Ignore the first coin flip?", game)) { + if (player.chooseUse(outcome, "Ignore the first coin flip?", source, game)) { event.setFlag(secondCoinFlip); game.informPlayers(new StringBuilder(player.getLogName()).append(" ignores the first coin flip.").toString()); } else { diff --git a/Mage.Sets/src/mage/sets/mirrodin/ScytheOfTheWretched.java b/Mage.Sets/src/mage/sets/mirrodin/ScytheOfTheWretched.java index 6000151549e..341aecb7194 100644 --- a/Mage.Sets/src/mage/sets/mirrodin/ScytheOfTheWretched.java +++ b/Mage.Sets/src/mage/sets/mirrodin/ScytheOfTheWretched.java @@ -89,9 +89,6 @@ class ScytheOfTheWretchedTriggeredAbility extends TriggeredAbilityImpl { public ScytheOfTheWretchedTriggeredAbility() { super(Zone.ALL, new ScytheOfTheWretchedReanimateEffect(), false); - Effect effect = new AttachEffect(Outcome.AddAbility); - effect.setText("Attach {this} to that creature."); - addEffect(effect); } public ScytheOfTheWretchedTriggeredAbility(final ScytheOfTheWretchedTriggeredAbility ability) { @@ -115,7 +112,7 @@ class ScytheOfTheWretchedTriggeredAbility extends TriggeredAbilityImpl { Permanent equippedCreature = getEquippedCreature(game); for (MageObjectReference mor : zoneChange.getTarget().getDealtDamageByThisTurn()) { Permanent permanent = (Permanent) game.getLastKnownInformation(mor.getSourceId(), Zone.BATTLEFIELD); - if((equippedCreature != null && mor.refersTo(equippedCreature, game)) + if ((equippedCreature != null && mor.refersTo(equippedCreature, game)) || (permanent != null && permanent.getAttachments().contains(getSourceId()))) { setTarget(new FixedTarget(event.getTargetId())); return true; @@ -149,7 +146,7 @@ class ScytheOfTheWretchedReanimateEffect extends OneShotEffect { public ScytheOfTheWretchedReanimateEffect() { super(Outcome.PutCreatureInPlay); - this.staticText = "return that card to the battlefield under your control"; + this.staticText = "return that card to the battlefield under your control. Attach {this} to that creature"; } public ScytheOfTheWretchedReanimateEffect(final ScytheOfTheWretchedReanimateEffect effect) { @@ -163,6 +160,9 @@ class ScytheOfTheWretchedReanimateEffect extends OneShotEffect { if (card != null && controller != null) { Zone currentZone = game.getState().getZone(card.getId()); controller.putOntoBattlefieldWithInfo(card, game, currentZone, source.getSourceId()); + Effect effect = new AttachEffect(Outcome.AddAbility); + effect.setTargetPointer(new FixedTarget(card.getId())); + effect.apply(game, source); return true; } diff --git a/Mage.Sets/src/mage/sets/mirrodin/TajNarSwordsmith.java b/Mage.Sets/src/mage/sets/mirrodin/TajNarSwordsmith.java index 355c3c258fe..33a834624fb 100644 --- a/Mage.Sets/src/mage/sets/mirrodin/TajNarSwordsmith.java +++ b/Mage.Sets/src/mage/sets/mirrodin/TajNarSwordsmith.java @@ -94,7 +94,7 @@ class TajNarSwordsmithEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (player != null && player.chooseUse(Outcome.BoostCreature, "Do you want to to pay {X}?", game)) { + if (player != null && player.chooseUse(Outcome.BoostCreature, "Do you want to to pay {X}?", source, game)) { int costX = player.announceXMana(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source); Cost cost = new GenericManaCost(costX); if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { diff --git a/Mage.Sets/src/mage/sets/mirrodinbesieged/DistantMemories.java b/Mage.Sets/src/mage/sets/mirrodinbesieged/DistantMemories.java index aa0efa15012..72776234990 100644 --- a/Mage.Sets/src/mage/sets/mirrodinbesieged/DistantMemories.java +++ b/Mage.Sets/src/mage/sets/mirrodinbesieged/DistantMemories.java @@ -103,7 +103,7 @@ class DistantMemoriesEffect extends OneShotEffect { Set opponents = game.getOpponents(source.getControllerId()); for (UUID opponentUuid : opponents) { Player opponent = game.getPlayer(opponentUuid); - if (opponent != null && !putInHand && opponent.chooseUse(Outcome.Neutral, sb.toString(), game)) { + if (opponent != null && !putInHand && opponent.chooseUse(Outcome.Neutral, sb.toString(), source, game)) { putInHand = true; } } diff --git a/Mage.Sets/src/mage/sets/mirrodinbesieged/Galvanoth.java b/Mage.Sets/src/mage/sets/mirrodinbesieged/Galvanoth.java index bd36a38bb6e..7cac9ff0fbb 100644 --- a/Mage.Sets/src/mage/sets/mirrodinbesieged/Galvanoth.java +++ b/Mage.Sets/src/mage/sets/mirrodinbesieged/Galvanoth.java @@ -92,7 +92,7 @@ class GalvanothEffect extends OneShotEffect { if (card.getCardType().contains(CardType.INSTANT) || card.getCardType().contains(CardType.SORCERY)) { StringBuilder message = new StringBuilder("Cast ").append(card.getName()).append(" without paying its mana cost?"); - if (controller.chooseUse(Outcome.PlayForFree, message.toString(), game)) { + if (controller.chooseUse(Outcome.PlayForFree, message.toString(), source, game)) { controller.getLibrary().removeFromTop(game); controller.cast(card.getSpellAbility(), game, true); } diff --git a/Mage.Sets/src/mage/sets/mirrodinbesieged/KnowledgePool.java b/Mage.Sets/src/mage/sets/mirrodinbesieged/KnowledgePool.java index d2146f6213b..40475118a59 100644 --- a/Mage.Sets/src/mage/sets/mirrodinbesieged/KnowledgePool.java +++ b/Mage.Sets/src/mage/sets/mirrodinbesieged/KnowledgePool.java @@ -162,7 +162,7 @@ class KnowledgePoolEffect2 extends OneShotEffect { if (spell != null) { if (spell.moveToExile(source.getSourceId(), "Knowledge Pool Exile", source.getSourceId(), game)) { Player player = game.getPlayer(spell.getControllerId()); - if (player != null && player.chooseUse(Outcome.PlayForFree, "Cast another nonland card exiled with Knowledge Pool without paying that card's mana cost?", game)) { + if (player != null && player.chooseUse(Outcome.PlayForFree, "Cast another nonland card exiled with Knowledge Pool without paying that card's mana cost?", source, game)) { TargetCardInExile target = new TargetCardInExile(filter, source.getSourceId()); while (player.choose(Outcome.PlayForFree, game.getExile().getExileZone(source.getSourceId()), target, game)) { Card card = game.getCard(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/sets/mirrodinbesieged/Mirrorworks.java b/Mage.Sets/src/mage/sets/mirrodinbesieged/Mirrorworks.java index 7e0ecbd7775..6bc55444c9a 100644 --- a/Mage.Sets/src/mage/sets/mirrodinbesieged/Mirrorworks.java +++ b/Mage.Sets/src/mage/sets/mirrodinbesieged/Mirrorworks.java @@ -144,7 +144,7 @@ class MirrorworksEffect extends OneShotEffect { } if (target != null) { Cost cost = new ManaCostsImpl("{2}"); - if (player.chooseUse(outcome, new StringBuilder("Pay ").append(cost.getText()).append(" and put a token copy of ").append(target.getName()).append(" onto the battlefield").toString(), game)) { + if (player.chooseUse(outcome, new StringBuilder("Pay ").append(cost.getText()).append(" and put a token copy of ").append(target.getName()).append(" onto the battlefield").toString(), source, game)) { cost.clearPaid(); if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { if (target instanceof Permanent) { diff --git a/Mage.Sets/src/mage/sets/mirrodinbesieged/MitoticManipulation.java b/Mage.Sets/src/mage/sets/mirrodinbesieged/MitoticManipulation.java index 142686364c4..def18f8114c 100644 --- a/Mage.Sets/src/mage/sets/mirrodinbesieged/MitoticManipulation.java +++ b/Mage.Sets/src/mage/sets/mirrodinbesieged/MitoticManipulation.java @@ -117,7 +117,7 @@ class MitoticManipulationEffect extends OneShotEffect { } player.lookAtCards("Mitotic Manipulation", cards, game); - if (!cardsFound.isEmpty() && player.chooseUse(Outcome.PutCardInPlay, "Do you wish to put a card on the battlefield?", game)) { + if (!cardsFound.isEmpty() && player.chooseUse(Outcome.PutCardInPlay, "Do you wish to put a card on the battlefield?", source, game)) { TargetCard target = new TargetCard(Zone.PICK, filter); if (player.choose(Outcome.PutCardInPlay, cardsFound, target, game)) { diff --git a/Mage.Sets/src/mage/sets/modernmasters/PetalsOfInsight.java b/Mage.Sets/src/mage/sets/modernmasters/PetalsOfInsight.java index 5c80d722a0f..8a75832ee6b 100644 --- a/Mage.Sets/src/mage/sets/modernmasters/PetalsOfInsight.java +++ b/Mage.Sets/src/mage/sets/modernmasters/PetalsOfInsight.java @@ -98,7 +98,7 @@ class PetalsOfInsightEffect extends OneShotEffect { } } player.lookAtCards("Petals of Insight", cards, game); - if (player.chooseUse(outcome, "Put the cards on the bottom of your library in any order?", game)) { + if (player.chooseUse(outcome, "Put the cards on the bottom of your library in any order?", source, game)) { player.putCardsOnBottomOfLibrary(cards, game, source, true); Card spellCard = game.getStack().getSpell(source.getSourceId()).getCard(); if (spellCard != null) { diff --git a/Mage.Sets/src/mage/sets/morningtide/LeafCrownedElder.java b/Mage.Sets/src/mage/sets/morningtide/LeafCrownedElder.java index 3280ed71a29..29bf162db7e 100644 --- a/Mage.Sets/src/mage/sets/morningtide/LeafCrownedElder.java +++ b/Mage.Sets/src/mage/sets/morningtide/LeafCrownedElder.java @@ -87,7 +87,7 @@ class LeafCrownedElderPlayEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); Card card = game.getCard(getTargetPointer().getFirst(game, source)); if (player != null && card != null) { - if (player.chooseUse(Outcome.PlayForFree, "Play " + card.getName() + " without paying its mana cost?", game)) { + if (player.chooseUse(Outcome.PlayForFree, "Play " + card.getName() + " without paying its mana cost?", source, game)) { if (card.getCardType().contains(CardType.LAND)) { // If the revealed card is a land, you can play it only if it's your turn and you haven't yet played a land this turn. if (game.getActivePlayerId().equals(player.getId()) && player.canPlayLand()) { diff --git a/Mage.Sets/src/mage/sets/nemesis/BelbesPortal.java b/Mage.Sets/src/mage/sets/nemesis/BelbesPortal.java index c596012adbe..5b3e8c7cb73 100644 --- a/Mage.Sets/src/mage/sets/nemesis/BelbesPortal.java +++ b/Mage.Sets/src/mage/sets/nemesis/BelbesPortal.java @@ -108,7 +108,7 @@ class BelbesPortalPutCreatureOnBattlefieldEffect extends OneShotEffect { String choiceText = "Put a " + subtype.toLowerCase() + " creature card from your hand onto the battlefield?"; if (player != null) { - if (player.chooseUse(Outcome.PutCreatureInPlay, choiceText, game)) { + if (player.chooseUse(Outcome.PutCreatureInPlay, choiceText, source, game)) { FilterCreatureCard creatureTypeFilter = new FilterCreatureCard(); creatureTypeFilter.add(new SubtypePredicate(subtype)); diff --git a/Mage.Sets/src/mage/sets/nemesis/RootwaterThief.java b/Mage.Sets/src/mage/sets/nemesis/RootwaterThief.java index 7329fbab21e..d7450641687 100644 --- a/Mage.Sets/src/mage/sets/nemesis/RootwaterThief.java +++ b/Mage.Sets/src/mage/sets/nemesis/RootwaterThief.java @@ -99,7 +99,7 @@ class RootwaterThiefEffect extends OneShotEffect { } String message = "Pay {2} to exile a card from damaged player's library?"; Cost cost = new ManaCostsImpl("{2}"); - if(controller.chooseUse(Outcome.Benefit, message, game) && cost.pay(source, game, source.getSourceId(), controller.getId(), false)) + if(controller.chooseUse(Outcome.Benefit, message, source, game) && cost.pay(source, game, source.getSourceId(), controller.getId(), false)) { TargetCardInLibrary target = new TargetCardInLibrary(); if (controller.searchLibrary(target, game, damagedPlayer.getId())) { diff --git a/Mage.Sets/src/mage/sets/newphyrexia/AuriokSurvivors.java b/Mage.Sets/src/mage/sets/newphyrexia/AuriokSurvivors.java index 7137d9740eb..a0683532031 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/AuriokSurvivors.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/AuriokSurvivors.java @@ -98,7 +98,7 @@ class AuriokSurvivorsEffect extends OneShotEffect { Permanent sourcePermanent = game.getPermanent(source.getSourceId()); Player player = game.getPlayer(source.getControllerId()); if (p != null && player != null && sourcePermanent != null) { - if (player.chooseUse(Outcome.Benefit, "Attach " + p.getName() + " to " + sourcePermanent.getName() + "?", game)) { + if (player.chooseUse(Outcome.Benefit, "Attach " + p.getName() + " to " + sourcePermanent.getName() + "?", source, game)) { sourcePermanent.addAttachment(p.getId(), game); } return true; diff --git a/Mage.Sets/src/mage/sets/newphyrexia/BlindZealot.java b/Mage.Sets/src/mage/sets/newphyrexia/BlindZealot.java index 6bee1ff994d..e5b269d8625 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/BlindZealot.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/BlindZealot.java @@ -108,10 +108,10 @@ class BlindZealotTriggeredAbility extends TriggeredAbilityImpl { if (player != null && sourcePermanent != null) { StringBuilder sb = new StringBuilder(); - sb.append("Do you wish to sacrifice ").append(sourcePermanent.getName()); + sb.append("Do you wish to sacrifice ").append(sourcePermanent.getIdName()); sb.append(" to destroy target creature controlled by "); sb.append(game.getPlayer(event.getTargetId()).getLogName()).append("?"); - if (player.chooseUse(Outcome.DestroyPermanent, sb.toString(), game)) { + if (player.chooseUse(Outcome.DestroyPermanent, sb.toString(), this, game)) { FilterCreaturePermanent filter = new FilterCreaturePermanent(); filter.add(new ControllerIdPredicate(event.getTargetId())); filter.setMessage("creature controlled by " + game.getPlayer(event.getTargetId()).getLogName()); diff --git a/Mage.Sets/src/mage/sets/newphyrexia/HexParasite.java b/Mage.Sets/src/mage/sets/newphyrexia/HexParasite.java index c38d7fc2fd7..e1190a24fbc 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/HexParasite.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/HexParasite.java @@ -101,7 +101,7 @@ class HexParasiteEffect extends OneShotEffect { int removed = 0; String[] counterNames = permanent.getCounters().keySet().toArray(new String[0]); for (String counterName : counterNames) { - if (player.chooseUse(Outcome.Neutral, "Do you want to remove " + counterName + " counters?", game)) { + if (player.chooseUse(Outcome.Neutral, "Do you want to remove " + counterName + " counters?", source, game)) { if (permanent.getCounters().get(counterName).getCount() == 1 || toRemove == 1) { permanent.getCounters().removeCounter(counterName, 1); } diff --git a/Mage.Sets/src/mage/sets/newphyrexia/NornsAnnex.java b/Mage.Sets/src/mage/sets/newphyrexia/NornsAnnex.java index fef771c08df..6c5c07386a9 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/NornsAnnex.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/NornsAnnex.java @@ -103,7 +103,7 @@ class NornsAnnexReplacementEffect extends ReplacementEffectImpl { if (player != null) { ManaCostsImpl propagandaTax = new ManaCostsImpl("{WP}"); if (propagandaTax.canPay(source, source.getSourceId(), event.getPlayerId(), game) - && player.chooseUse(Outcome.Benefit, "Pay to declare attacker?", game)) { + && player.chooseUse(Outcome.Benefit, "Pay to declare attacker?", source, game)) { if (propagandaTax.payOrRollback(source, game, source.getSourceId(), event.getPlayerId())) { return false; } diff --git a/Mage.Sets/src/mage/sets/newphyrexia/PraetorsGrasp.java b/Mage.Sets/src/mage/sets/newphyrexia/PraetorsGrasp.java index 79671b61280..de9c500e10d 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/PraetorsGrasp.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/PraetorsGrasp.java @@ -149,7 +149,7 @@ class PraetorsGraspPlayEffect extends AsThoughEffectImpl { if (exileId != null && controller != null) { ExileZone exileZone = game.getExile().getExileZone(exileId); if (exileZone != null && exileZone.contains(cardId)) { - if (controller.chooseUse(outcome, "Play the exiled card?", game)) { + if (controller.chooseUse(outcome, "Play the exiled card?", source, game)) { return true; } } else { @@ -198,7 +198,7 @@ class PraetorsGraspRevealEffect extends AsThoughEffectImpl { Player controller = game.getPlayer(source.getControllerId()); Card card = game.getCard(cardId); if (controller != null && card != null && game.getState().getZone(cardId) == Zone.EXILED) { - if (controller.chooseUse(outcome, "Reveal exiled card?", game)) { + if (controller.chooseUse(outcome, "Reveal exiled card?", source, game)) { Cards cards = new CardsImpl(card); controller.lookAtCards("Exiled with " + sourceObject.getIdName(), cards, game); } diff --git a/Mage.Sets/src/mage/sets/newphyrexia/PsychicSurgery.java b/Mage.Sets/src/mage/sets/newphyrexia/PsychicSurgery.java index 45073f0eb6d..35a26e0db75 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/PsychicSurgery.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/PsychicSurgery.java @@ -138,7 +138,7 @@ class PsychicSurgeryEffect extends OneShotEffect { } player.lookAtCards("Psychic Surgery", cards, game); - if (!cards.isEmpty() && player.chooseUse(Outcome.Exile, "Do you wish to exile a card?", game)) { + if (!cards.isEmpty() && player.chooseUse(Outcome.Exile, "Do you wish to exile a card?", source, game)) { TargetCard target = new TargetCard(Zone.PICK, new FilterCard("card to exile")); if (player.choose(Outcome.Exile, cards, target, game)) { Card card = cards.get(target.getFirstTarget(), game); diff --git a/Mage.Sets/src/mage/sets/newphyrexia/Spellskite.java b/Mage.Sets/src/mage/sets/newphyrexia/Spellskite.java index 1c8d098634c..6c6db8f49c8 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/Spellskite.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/Spellskite.java @@ -133,7 +133,7 @@ class SpellskiteEffect extends OneShotEffect { twoTimesTarget = true; continue; } - if (name != null && player.chooseUse(Outcome.Neutral, new StringBuilder("Change target from ").append(name).append(" to ").append(sourceObject.getName()).append("?").toString(), game)) { + if (name != null && player.chooseUse(Outcome.Neutral, new StringBuilder("Change target from ").append(name).append(" to ").append(sourceObject.getName()).append("?").toString(), source, game)) { if (target.canTarget(stackObject.getControllerId(), source.getSourceId(), sourceAbility, game)) { oldTarget = game.getObject(targets.getFirstTarget()); target.remove(targetId); diff --git a/Mage.Sets/src/mage/sets/newphyrexia/UnwindingClock.java b/Mage.Sets/src/mage/sets/newphyrexia/UnwindingClock.java index d92ae37450c..be78a7a997f 100644 --- a/Mage.Sets/src/mage/sets/newphyrexia/UnwindingClock.java +++ b/Mage.Sets/src/mage/sets/newphyrexia/UnwindingClock.java @@ -28,6 +28,11 @@ package mage.sets.newphyrexia; import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.RestrictionEffect; +import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Layer; @@ -36,11 +41,6 @@ import mage.constants.PhaseStep; import mage.constants.Rarity; import mage.constants.SubLayer; import mage.constants.Zone; -import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.RestrictionEffect; -import mage.cards.CardImpl; import mage.filter.common.FilterArtifactPermanent; import mage.game.Game; import mage.game.permanent.Permanent; @@ -56,7 +56,7 @@ public class UnwindingClock extends CardImpl { this.expansionSetCode = "NPH"; // Untap all artifacts you control during each other player's untap step. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new UnwindingClockEffect())); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new UnwindingClockEffect())); } public UnwindingClock(final UnwindingClock card) { @@ -96,10 +96,10 @@ class UnwindingClockEffect extends ContinuousEffectImpl { if (!applied && layer.equals(Layer.RulesEffects)) { if (!game.getActivePlayerId().equals(source.getControllerId()) && game.getStep().getType() == PhaseStep.UNTAP) { game.getState().setValue(source.getSourceId() + "applied", true); - for (Permanent artifact: game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { + for (Permanent artifact : game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { boolean untap = true; - for (RestrictionEffect effect: game.getContinuousEffects().getApplicableRestrictionEffects(artifact, game).keySet()) { - untap &= effect.canBeUntapped(artifact, game); + for (RestrictionEffect effect : game.getContinuousEffects().getApplicableRestrictionEffects(artifact, game).keySet()) { + untap &= effect.canBeUntapped(artifact, source, game); } if (untap) { artifact.untap(game); diff --git a/Mage.Sets/src/mage/sets/ninthedition/BalefulStare.java b/Mage.Sets/src/mage/sets/ninthedition/BalefulStare.java new file mode 100644 index 00000000000..c6270de3219 --- /dev/null +++ b/Mage.Sets/src/mage/sets/ninthedition/BalefulStare.java @@ -0,0 +1,114 @@ +/* + * 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.ninthedition; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.RevealHandTargetEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetOpponent; + +/** + * + * @author LoneFox + + */ +public class BalefulStare extends CardImpl { + + public BalefulStare(UUID ownerId) { + super(ownerId, 64, "Baleful Stare", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{2}{U}"); + this.expansionSetCode = "9ED"; + + // Target opponent reveals his or her hand. You draw a card for each Mountain and red card in it. + this.getSpellAbility().addEffect(new RevealHandTargetEffect()); + this.getSpellAbility().addEffect(new BalefulStareEffect()); + this.getSpellAbility().addTarget(new TargetOpponent()); + } + + public BalefulStare(final BalefulStare card) { + super(card); + } + + @Override + public BalefulStare copy() { + return new BalefulStare(this); + } +} + +class BalefulStareEffect extends OneShotEffect { + + private static final FilterCard filter = new FilterCard("Mountain or red card"); + + static { + filter.add(Predicates.or(new SubtypePredicate("Mountain"), + new ColorPredicate(ObjectColor.RED))); + } + + public BalefulStareEffect() { + super(Outcome.DrawCard); + this.staticText = "You draw a card for each Mountain and red card in it"; + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player targetPlayer = game.getPlayer(source.getTargets().getFirstTarget()); + if(controller != null && targetPlayer != null) { + int count = 0; + for(Card card : targetPlayer.getHand().getCards(game)) { + if(filter.match(card, game)) { + count++; + } + } + controller.drawCards(count, game); + return true; + } + return false; + } + + public BalefulStareEffect(final BalefulStareEffect effect) { + super(effect); + } + + @Override + public BalefulStareEffect copy() { + return new BalefulStareEffect(this); + } +} diff --git a/Mage.Sets/src/mage/sets/ninthedition/HuntedWumpus.java b/Mage.Sets/src/mage/sets/ninthedition/HuntedWumpus.java index 6de884915ac..83d5ebc28b9 100644 --- a/Mage.Sets/src/mage/sets/ninthedition/HuntedWumpus.java +++ b/Mage.Sets/src/mage/sets/ninthedition/HuntedWumpus.java @@ -98,7 +98,7 @@ class HuntedWumpusEffect extends OneShotEffect { if (player != null) { TargetCardInHand target = new TargetCardInHand(new FilterCreatureCard()); if (target.canChoose(source.getSourceId(), playerId, game) - && player.chooseUse(Outcome.Neutral, "Put a creature card from your hand in play?", game) + && player.chooseUse(Outcome.Neutral, "Put a creature card from your hand in play?", source, game) && player.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/ninthedition/StorageMatrix.java b/Mage.Sets/src/mage/sets/ninthedition/StorageMatrix.java index 76871a019db..62c863c93ef 100644 --- a/Mage.Sets/src/mage/sets/ninthedition/StorageMatrix.java +++ b/Mage.Sets/src/mage/sets/ninthedition/StorageMatrix.java @@ -29,17 +29,17 @@ package mage.sets.ninthedition; import java.util.HashSet; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.PhaseStep; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.RestrictionEffect; import mage.cards.CardImpl; import mage.choices.Choice; import mage.choices.ChoiceImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.PhaseStep; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -68,14 +68,13 @@ public class StorageMatrix extends CardImpl { } } - - class StorageMatrixRestrictionEffect extends RestrictionEffect { private int turn; private boolean applies; private static final HashSet choice = new HashSet<>(); - static{ + + static { choice.add(CardType.ARTIFACT.toString()); choice.add(CardType.CREATURE.toString()); choice.add(CardType.LAND.toString()); @@ -106,8 +105,8 @@ class StorageMatrixRestrictionEffect extends RestrictionEffect { choiceImpl.setMessage("Untap which kind of permanent?"); choiceImpl.setChoices(choice); Player player = game.getPlayer(game.getActivePlayerId()); - if(player != null){ - while(!player.choose(outcome, choiceImpl, game)) { + if (player != null) { + while (!player.choose(outcome, choiceImpl, game)) { if (player.isInGame()) { return false; } @@ -115,11 +114,11 @@ class StorageMatrixRestrictionEffect extends RestrictionEffect { String choosenType = choiceImpl.getChoice(); game.informPlayers(storageMatrix.getLogName() + ": " + player.getLogName() + " chose to untap " + choosenType); - if(choosenType.equals(CardType.ARTIFACT.toString())){ + if (choosenType.equals(CardType.ARTIFACT.toString())) { type = CardType.ARTIFACT; - }else if(choosenType.equals(CardType.LAND.toString())){ + } else if (choosenType.equals(CardType.LAND.toString())) { type = CardType.LAND; - }else{ + } else { type = CardType.CREATURE; } applies = true; @@ -134,7 +133,7 @@ class StorageMatrixRestrictionEffect extends RestrictionEffect { } @Override - public boolean canBeUntapped(Permanent permanent, Game game) { + public boolean canBeUntapped(Permanent permanent, Ability source, Game game) { return false; } diff --git a/Mage.Sets/src/mage/sets/ninthedition/WitheringGaze.java b/Mage.Sets/src/mage/sets/ninthedition/WitheringGaze.java new file mode 100644 index 00000000000..7794567e2ef --- /dev/null +++ b/Mage.Sets/src/mage/sets/ninthedition/WitheringGaze.java @@ -0,0 +1,53 @@ +/* + * 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.ninthedition; + +import java.util.UUID; + +/** + * + * @author LoneFox + + */ +public class WitheringGaze extends mage.sets.portal.WitheringGaze { + + public WitheringGaze(UUID ownerId) { + super(ownerId); + this.cardNumber = 113; + this.expansionSetCode = "9ED"; + } + + public WitheringGaze(final WitheringGaze card) { + super(card); + } + + @Override + public WitheringGaze copy() { + return new WitheringGaze(this); + } +} diff --git a/Mage.Sets/src/mage/sets/odyssey/BlazingSalvo.java b/Mage.Sets/src/mage/sets/odyssey/BlazingSalvo.java index 86d3a3b3885..8a464d86701 100644 --- a/Mage.Sets/src/mage/sets/odyssey/BlazingSalvo.java +++ b/Mage.Sets/src/mage/sets/odyssey/BlazingSalvo.java @@ -88,7 +88,7 @@ class BlazingSalvoEffect extends OneShotEffect { Player player = game.getPlayer(permanent.getControllerId()); if (player != null) { String message = "Have Blazing Salvo do 5 damage to you?"; - if (player.chooseUse(Outcome.Damage, message, game)){ + if (player.chooseUse(Outcome.Damage, message, source, game)){ player.damage(5, source.getSourceId(), game, true, false); } else { permanent.damage(3, source.getSourceId(), game, false, true); diff --git a/Mage.Sets/src/mage/sets/odyssey/DecayingSoil.java b/Mage.Sets/src/mage/sets/odyssey/DecayingSoil.java index 5f0b340da9a..aae708d61b4 100644 --- a/Mage.Sets/src/mage/sets/odyssey/DecayingSoil.java +++ b/Mage.Sets/src/mage/sets/odyssey/DecayingSoil.java @@ -170,7 +170,7 @@ class DecayingSoilEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - if (player.chooseUse(Outcome.Benefit, " - Pay " + cost.getText() + "?", game)) { + if (player.chooseUse(Outcome.Benefit, " - Pay " + cost.getText() + "?", source, game)) { cost.clearPaid(); if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { UUID target = this.getTargetPointer().getFirst(game, source); diff --git a/Mage.Sets/src/mage/sets/odyssey/DelayingShield.java b/Mage.Sets/src/mage/sets/odyssey/DelayingShield.java index 8d62548220a..28330c160d2 100644 --- a/Mage.Sets/src/mage/sets/odyssey/DelayingShield.java +++ b/Mage.Sets/src/mage/sets/odyssey/DelayingShield.java @@ -138,7 +138,7 @@ class DelayingShieldUpkeepEffect extends OneShotEffect { int numCounters = permanent.getCounters().getCount(CounterType.DELAY); permanent.removeCounters(CounterType.DELAY.createInstance(), game); for (int i = numCounters; i > 0; i--) { - if (player.chooseUse(Outcome.Benefit, "Pay {1}{W}? (" + i + " counters left to pay)", game)) { + if (player.chooseUse(Outcome.Benefit, "Pay {1}{W}? (" + i + " counters left to pay)", source, game)) { Cost cost = new ManaCostsImpl<>("{1}{W}"); if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { continue; diff --git a/Mage.Sets/src/mage/sets/odyssey/MoltenInfluence.java b/Mage.Sets/src/mage/sets/odyssey/MoltenInfluence.java index bf2cbc6973a..e6960785972 100644 --- a/Mage.Sets/src/mage/sets/odyssey/MoltenInfluence.java +++ b/Mage.Sets/src/mage/sets/odyssey/MoltenInfluence.java @@ -98,7 +98,7 @@ class MoltenInfluenceEffect extends OneShotEffect { if (spell != null) { Player player = game.getPlayer(spell.getControllerId()); String message = "Have Molten Influence do 4 damage to you?"; - if (player.chooseUse(Outcome.Damage, message, game)) { + if (player.chooseUse(Outcome.Damage, message, source, game)) { player.damage(4, source.getSourceId(), game, false, true); } else { spell.counter(source.getSourceId(), game); diff --git a/Mage.Sets/src/mage/sets/odyssey/ObstinateFamiliar.java b/Mage.Sets/src/mage/sets/odyssey/ObstinateFamiliar.java index 8112ec82712..4ef53d02384 100644 --- a/Mage.Sets/src/mage/sets/odyssey/ObstinateFamiliar.java +++ b/Mage.Sets/src/mage/sets/odyssey/ObstinateFamiliar.java @@ -109,7 +109,7 @@ class ObstinateFamiliarReplacementEffect extends ReplacementEffectImpl { if (event.getPlayerId().equals(source.getControllerId()) && archmage != null && you != null - && you.chooseUse(Outcome.Benefit, "Would you like to skip drawing a card?", game)) { + && you.chooseUse(Outcome.Benefit, "Would you like to skip drawing a card?", source, game)) { return true; } return false; diff --git a/Mage.Sets/src/mage/sets/odyssey/TaintedPact.java b/Mage.Sets/src/mage/sets/odyssey/TaintedPact.java index 15e8120ff54..09b9c6d6f25 100644 --- a/Mage.Sets/src/mage/sets/odyssey/TaintedPact.java +++ b/Mage.Sets/src/mage/sets/odyssey/TaintedPact.java @@ -100,7 +100,7 @@ class TaintedPactEffect extends OneShotEffect{ break; } names.add(card.getName()); - if (player.chooseUse(outcome, new StringBuilder("Put ").append(card.getName()).append("into your hand?").toString(), game)) { + if (player.chooseUse(outcome, new StringBuilder("Put ").append(card.getName()).append("into your hand?").toString(), source, game)) { //Adds the current card to hand if it is chosen. card.moveToZone(Zone.HAND, source.getSourceId(), game, true); break; diff --git a/Mage.Sets/src/mage/sets/odyssey/ThinkTank.java b/Mage.Sets/src/mage/sets/odyssey/ThinkTank.java index dc8602ec6c8..e29391babff 100644 --- a/Mage.Sets/src/mage/sets/odyssey/ThinkTank.java +++ b/Mage.Sets/src/mage/sets/odyssey/ThinkTank.java @@ -97,7 +97,7 @@ class ThinkTankLookLibraryEffect extends OneShotEffect { CardsImpl cards = new CardsImpl(); cards.add(card); controller.lookAtCards("Think Tank", cards, game); - if (controller.chooseUse(Outcome.Neutral, "Do you wish to put the card into your graveyard?", game)) { + if (controller.chooseUse(Outcome.Neutral, "Do you wish to put the card into your graveyard?", source, game)) { return controller.moveCards(card, Zone.LIBRARY, Zone.GRAVEYARD, source, game); } diff --git a/Mage.Sets/src/mage/sets/odyssey/UnifyingTheory.java b/Mage.Sets/src/mage/sets/odyssey/UnifyingTheory.java index df7da318d11..0fba130c3e8 100644 --- a/Mage.Sets/src/mage/sets/odyssey/UnifyingTheory.java +++ b/Mage.Sets/src/mage/sets/odyssey/UnifyingTheory.java @@ -98,7 +98,7 @@ class UnifyingTheoryEffect extends OneShotEffect { caster = game.getPlayer(spell.getControllerId()); } if (caster != null) { - if (caster.chooseUse(Outcome.DrawCard, "Pay {2} to draw a card?", game)) { + if (caster.chooseUse(Outcome.DrawCard, "Pay {2} to draw a card?", source, game)) { Cost cost = new ManaCostsImpl("{2}"); if (cost.pay(source, game, source.getSourceId(), caster.getId(), false)) { caster.drawCards(1, game); diff --git a/Mage.Sets/src/mage/sets/onslaught/ChainOfVapor.java b/Mage.Sets/src/mage/sets/onslaught/ChainOfVapor.java index 4b15f902077..b03ec15c5ae 100644 --- a/Mage.Sets/src/mage/sets/onslaught/ChainOfVapor.java +++ b/Mage.Sets/src/mage/sets/onslaught/ChainOfVapor.java @@ -98,7 +98,7 @@ class ChainOfVaporEffect extends OneShotEffect { return false; } Player player = game.getPlayer(permanent.getControllerId()); - if (player.chooseUse(Outcome.ReturnToHand, "Sacrifice a land to copy this spell?", game)){ + if (player.chooseUse(Outcome.ReturnToHand, "Sacrifice a land to copy this spell?", source, game)){ TargetControlledPermanent target = new TargetControlledPermanent(new FilterControlledLandPermanent()); if (player.chooseTarget(Outcome.Sacrifice, target, source, game)){ Permanent land = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/sets/onslaught/DeathMatch.java b/Mage.Sets/src/mage/sets/onslaught/DeathMatch.java index 1709fc24685..02e0c180574 100644 --- a/Mage.Sets/src/mage/sets/onslaught/DeathMatch.java +++ b/Mage.Sets/src/mage/sets/onslaught/DeathMatch.java @@ -101,7 +101,7 @@ class DeathMatchEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getTargets().get(0).getTargetController()); if(player != null) { - if(player.chooseUse(outcome, "Give targeted creature -3/-3 ?", game)) { + if(player.chooseUse(outcome, "Give targeted creature -3/-3 ?", source, game)) { game.addEffect(new BoostTargetEffect(-3, -3, Duration.EndOfTurn), source); } return true; diff --git a/Mage.Sets/src/mage/sets/onslaught/ElvishPioneer.java b/Mage.Sets/src/mage/sets/onslaught/ElvishPioneer.java index 510ba22d63d..627da390f2b 100644 --- a/Mage.Sets/src/mage/sets/onslaught/ElvishPioneer.java +++ b/Mage.Sets/src/mage/sets/onslaught/ElvishPioneer.java @@ -105,7 +105,7 @@ class PutLandOnBattlefieldEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (player == null || !player.chooseUse(Outcome.PutLandInPlay, choiceText, game)) { + if (player == null || !player.chooseUse(Outcome.PutLandInPlay, choiceText, source, game)) { return false; } diff --git a/Mage.Sets/src/mage/sets/onslaught/WeirdHarvest.java b/Mage.Sets/src/mage/sets/onslaught/WeirdHarvest.java index 0043bd88025..1be7a060ebc 100644 --- a/Mage.Sets/src/mage/sets/onslaught/WeirdHarvest.java +++ b/Mage.Sets/src/mage/sets/onslaught/WeirdHarvest.java @@ -112,7 +112,7 @@ class WeirdHarvestEffect extends OneShotEffect { } private void chooseAndSearchLibrary(List usingPlayers, Player player, int xValue, Ability source, Game game) { - if (player.chooseUse(Outcome.PutCardInPlay, "Search your library for up " + xValue + " creature cards and put them into your hand?", game)) { + if (player.chooseUse(Outcome.PutCardInPlay, "Search your library for up " + xValue + " creature cards and put them into your hand?", source, game)) { usingPlayers.add(player); TargetCardInLibrary target = new TargetCardInLibrary(0, xValue, new FilterCreatureCard()); if (player.searchLibrary(target, game)) { diff --git a/Mage.Sets/src/mage/sets/pdsslivers/Heartstone.java b/Mage.Sets/src/mage/sets/pdsslivers/Heartstone.java new file mode 100644 index 00000000000..8d85ec679be --- /dev/null +++ b/Mage.Sets/src/mage/sets/pdsslivers/Heartstone.java @@ -0,0 +1,52 @@ +/* + * 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.pdsslivers; + +import java.util.UUID; + +/** + * + * @author pcasaretto_at_gmail.com + */ +public class Heartstone extends mage.sets.stronghold.Heartstone { + + public Heartstone(UUID ownerId) { + super(ownerId); + this.cardNumber = 26; + this.expansionSetCode = "PDS"; + } + + public Heartstone(final Heartstone card) { + super(card); + } + + @Override + public Heartstone copy() { + return new Heartstone(this); + } +} diff --git a/Mage.Sets/src/mage/sets/planarchaos/IntetTheDreamer.java b/Mage.Sets/src/mage/sets/planarchaos/IntetTheDreamer.java index ea9a46de998..88d32915c33 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/IntetTheDreamer.java +++ b/Mage.Sets/src/mage/sets/planarchaos/IntetTheDreamer.java @@ -148,7 +148,7 @@ class IntetTheDreamerEffect extends AsThoughEffectImpl { if (affectedControllerId.equals(source.getControllerId()) && card != null && game.getState().getZone(card.getId()) == Zone.EXILED) { ExileZone zone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter())); if (zone != null && zone.contains(card.getId())) { - if (controller.chooseUse(outcome, "Look at the card?", game)) { + if (controller.chooseUse(outcome, "Look at the card?", source, game)) { Cards cards = new CardsImpl(); cards.add(card); controller.lookAtCards(sourceObject.getName(), cards, game); diff --git a/Mage.Sets/src/mage/sets/planarchaos/Phantasmagorian.java b/Mage.Sets/src/mage/sets/planarchaos/Phantasmagorian.java index 42639488b6c..e8e99f9eb63 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/Phantasmagorian.java +++ b/Mage.Sets/src/mage/sets/planarchaos/Phantasmagorian.java @@ -105,7 +105,7 @@ class CounterSourceEffect extends OneShotEffect { if(spell != null){ for(UUID uuid : game.getPlayerList()){ Player player = game.getPlayer(uuid); - if(player.chooseUse(Outcome.Detriment, "Discard three cards to counter " + spell.getName() + "?", game)){ + if(player.chooseUse(Outcome.Detriment, "Discard three cards to counter " + spell.getName() + "?", source, game)){ DiscardTargetCost cost = new DiscardTargetCost(new TargetCardInHand(3, 3, new FilterCard())); if(cost.pay(source, game, source.getSourceId(), uuid, false)){ game.informPlayers(player.getLogName() + " discards 3 cards to counter " + spell.getName() + "."); diff --git a/Mage.Sets/src/mage/sets/planarchaos/ShivanWumpus.java b/Mage.Sets/src/mage/sets/planarchaos/ShivanWumpus.java index ca963a4d419..725ba9ff154 100644 --- a/Mage.Sets/src/mage/sets/planarchaos/ShivanWumpus.java +++ b/Mage.Sets/src/mage/sets/planarchaos/ShivanWumpus.java @@ -100,7 +100,7 @@ class ShivanWumpusEffect extends PutOnLibrarySourceEffect { Player player = game.getPlayer(playerId); if (player != null && cost.canPay(source, source.getSourceId(), playerId, game) - && player.chooseUse(Outcome.Sacrifice, "Sacrifice a land?", game) + && player.chooseUse(Outcome.Sacrifice, "Sacrifice a land?", source, game) && cost.pay(source, game, source.getSourceId(), playerId, true)) { costPaid = true; } diff --git a/Mage.Sets/src/mage/sets/planechase/ThirstForKnowledge.java b/Mage.Sets/src/mage/sets/planechase/ThirstForKnowledge.java index 62d8030910a..a7106c6c677 100644 --- a/Mage.Sets/src/mage/sets/planechase/ThirstForKnowledge.java +++ b/Mage.Sets/src/mage/sets/planechase/ThirstForKnowledge.java @@ -93,7 +93,7 @@ class ThirstforKnowledgeEffect extends OneShotEffect { filter.add(new CardTypePredicate(CardType.ARTIFACT)); if (you != null && you.getHand().count(filter, game) > 0 - && you.chooseUse(Outcome.Discard, "Do you want to discard an artifact? If you don't, you must discard 2 cards", game)) { + && you.chooseUse(Outcome.Discard, "Do you want to discard an artifact? If you don't, you must discard 2 cards", source, game)) { Cost cost = new DiscardTargetCost(new TargetCardInHand(filter)); if (cost.canPay(source, source.getSourceId(), you.getId(), game)) { if (cost.pay(source, game, source.getSourceId(), you.getId(), false)) { diff --git a/Mage.Sets/src/mage/sets/portal/BalefulStare.java b/Mage.Sets/src/mage/sets/portal/BalefulStare.java new file mode 100644 index 00000000000..f89cf1e238a --- /dev/null +++ b/Mage.Sets/src/mage/sets/portal/BalefulStare.java @@ -0,0 +1,53 @@ +/* + * 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.portal; + +import java.util.UUID; + +/** + * + * @author LoneFox + + */ +public class BalefulStare extends mage.sets.ninthedition.BalefulStare { + + public BalefulStare(UUID ownerId) { + super(ownerId); + this.cardNumber = 43; + this.expansionSetCode = "POR"; + } + + public BalefulStare(final BalefulStare card) { + super(card); + } + + @Override + public BalefulStare copy() { + return new BalefulStare(this); + } +} diff --git a/Mage.Sets/src/mage/sets/portal/Starlight.java b/Mage.Sets/src/mage/sets/portal/Starlight.java new file mode 100644 index 00000000000..ecdf6f369b5 --- /dev/null +++ b/Mage.Sets/src/mage/sets/portal/Starlight.java @@ -0,0 +1,53 @@ +/* + * 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.portal; + +import java.util.UUID; + +/** + * + * @author LoneFox + + */ +public class Starlight extends mage.sets.seventhedition.Starlight { + + public Starlight(UUID ownerId) { + super(ownerId); + this.cardNumber = 191; + this.expansionSetCode = "POR"; + } + + public Starlight(final Starlight card) { + super(card); + } + + @Override + public Starlight copy() { + return new Starlight(this); + } +} diff --git a/Mage.Sets/src/mage/sets/portal/WitheringGaze.java b/Mage.Sets/src/mage/sets/portal/WitheringGaze.java new file mode 100644 index 00000000000..5be12d7efc6 --- /dev/null +++ b/Mage.Sets/src/mage/sets/portal/WitheringGaze.java @@ -0,0 +1,114 @@ +/* + * 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.portal; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.RevealHandTargetEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetOpponent; + +/** + * + * @author LoneFox + + */ +public class WitheringGaze extends CardImpl { + + public WitheringGaze(UUID ownerId) { + super(ownerId, 79, "Withering Gaze", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{2}{U}"); + this.expansionSetCode = "POR"; + + // Target opponent reveals his or her hand. You draw a card for each Forest and green card in it. + this.getSpellAbility().addEffect(new RevealHandTargetEffect()); + this.getSpellAbility().addEffect(new WitheringGazeEffect()); + this.getSpellAbility().addTarget(new TargetOpponent()); + } + + public WitheringGaze(final WitheringGaze card) { + super(card); + } + + @Override + public WitheringGaze copy() { + return new WitheringGaze(this); + } +} + +class WitheringGazeEffect extends OneShotEffect { + + private static final FilterCard filter = new FilterCard("Forest or green card"); + + static { + filter.add(Predicates.or(new SubtypePredicate("Forest"), + new ColorPredicate(ObjectColor.GREEN))); + } + + public WitheringGazeEffect() { + super(Outcome.DrawCard); + this.staticText = "You draw a card for each Forest and green card in it"; + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player targetPlayer = game.getPlayer(source.getTargets().getFirstTarget()); + if(controller != null && targetPlayer != null) { + int count = 0; + for(Card card : targetPlayer.getHand().getCards(game)) { + if(filter.match(card, game)) { + count++; + } + } + controller.drawCards(count, game); + return true; + } + return false; + } + + public WitheringGazeEffect(final WitheringGazeEffect effect) { + super(effect); + } + + @Override + public WitheringGazeEffect copy() { + return new WitheringGazeEffect(this); + } +} diff --git a/Mage.Sets/src/mage/sets/portalthreekingdoms/FalseDefeat.java b/Mage.Sets/src/mage/sets/portalthreekingdoms/FalseDefeat.java new file mode 100644 index 00000000000..99ba984fc86 --- /dev/null +++ b/Mage.Sets/src/mage/sets/portalthreekingdoms/FalseDefeat.java @@ -0,0 +1,54 @@ +/* + * 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.portalthreekingdoms; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author ilcartographer + */ +public class FalseDefeat extends mage.sets.masterseditioniii.FalseDefeat { + + public FalseDefeat(UUID ownerId) { + super(ownerId); + this.cardNumber = 4; + this.expansionSetCode = "PTK"; + this.rarity = Rarity.COMMON; + } + + public FalseDefeat(final FalseDefeat card) { + super(card); + } + + @Override + public FalseDefeat copy() { + return new FalseDefeat(this); + } +} diff --git a/Mage.Sets/src/mage/sets/portalthreekingdoms/LuBuMasterAtArms.java b/Mage.Sets/src/mage/sets/portalthreekingdoms/LuBuMasterAtArms.java new file mode 100644 index 00000000000..c5dfd75ca94 --- /dev/null +++ b/Mage.Sets/src/mage/sets/portalthreekingdoms/LuBuMasterAtArms.java @@ -0,0 +1,52 @@ +/* + * 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.portalthreekingdoms; + +import java.util.UUID; + +/** + * + * @author ilcartographer + */ +public class LuBuMasterAtArms extends mage.sets.masterseditioniii.LuBuMasterAtArms { + + public LuBuMasterAtArms(UUID ownerId) { + super(ownerId); + this.cardNumber = 115; + this.expansionSetCode = "PTK"; + } + + public LuBuMasterAtArms(final LuBuMasterAtArms card) { + super(card); + } + + @Override + public LuBuMasterAtArms copy() { + return new LuBuMasterAtArms(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prereleaseevents/LuBuMasterAtArms.java b/Mage.Sets/src/mage/sets/prereleaseevents/LuBuMasterAtArms.java new file mode 100644 index 00000000000..84cfffc90e2 --- /dev/null +++ b/Mage.Sets/src/mage/sets/prereleaseevents/LuBuMasterAtArms.java @@ -0,0 +1,54 @@ +/* + * 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.prereleaseevents; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author ilcartographer + */ +public class LuBuMasterAtArms extends mage.sets.masterseditioniii.LuBuMasterAtArms { + + public LuBuMasterAtArms(UUID ownerId) { + super(ownerId); + this.cardNumber = 8; + this.expansionSetCode = "PTC"; + this.rarity = Rarity.SPECIAL; + } + + public LuBuMasterAtArms(final LuBuMasterAtArms card) { + super(card); + } + + @Override + public LuBuMasterAtArms copy() { + return new LuBuMasterAtArms(this); + } +} diff --git a/Mage.Sets/src/mage/sets/prophecy/RhysticStudy.java b/Mage.Sets/src/mage/sets/prophecy/RhysticStudy.java index a6e617a28d2..d0864c9e789 100644 --- a/Mage.Sets/src/mage/sets/prophecy/RhysticStudy.java +++ b/Mage.Sets/src/mage/sets/prophecy/RhysticStudy.java @@ -92,8 +92,8 @@ class RhysticStudyDrawEffect extends OneShotEffect { if (controller != null && opponent != null && sourceObject != null) { Cost cost = new GenericManaCost(1); String message = "Would you like to pay {1} to prevent the opponent to draw a card?"; - if (!(opponent.chooseUse(Outcome.Benefit, message, game) && cost.pay(source, game, source.getSourceId(), opponent.getId(), false))) { - if(controller.chooseUse(Outcome.DrawCard, "Draw a card (" + sourceObject.getLogName() +")", game)) { + if (!(opponent.chooseUse(Outcome.Benefit, message, source, game) && cost.pay(source, game, source.getSourceId(), opponent.getId(), false))) { + if(controller.chooseUse(Outcome.DrawCard, "Draw a card (" + sourceObject.getLogName() +")", source, game)) { controller.drawCards(1, game); } } diff --git a/Mage.Sets/src/mage/sets/returntoravnica/DesecrationDemon.java b/Mage.Sets/src/mage/sets/returntoravnica/DesecrationDemon.java index d8ba05431bb..325db6aee01 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/DesecrationDemon.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/DesecrationDemon.java @@ -103,7 +103,7 @@ class DesecrationDemonEffect extends OneShotEffect { filter.add(new ControllerPredicate(TargetController.YOU)); TargetControlledPermanent target = new TargetControlledPermanent(1, 1, filter, false); if (target.canChoose(opponent.getId(), game)) { - if (opponent.chooseUse(Outcome.AIDontUseIt, "Sacrifice a creature to tap " + descrationDemon.getLogName() + "and put a +1/+1 counter on it?", game)) + if (opponent.chooseUse(Outcome.AIDontUseIt, "Sacrifice a creature to tap " + descrationDemon.getLogName() + "and put a +1/+1 counter on it?", source, game)) { opponent.choose(Outcome.Sacrifice, target, source.getSourceId(), game); Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/sets/returntoravnica/EpicExperiment.java b/Mage.Sets/src/mage/sets/returntoravnica/EpicExperiment.java index b7f0c5c403b..e656a073fb3 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/EpicExperiment.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/EpicExperiment.java @@ -110,7 +110,7 @@ class EpicExperimentEffect extends OneShotEffect { filter.add(new ConvertedManaCostPredicate(Filter.ComparisonType.LessThan, source.getManaCostsToPay().getX() + 1)); filter.setMessage("instant and sorcery cards with converted mana cost "+ source.getManaCostsToPay().getX() +" or less"); while (epicExperimentExileZone != null && epicExperimentExileZone.count(filter, game) > 0 - && controller.chooseUse(Outcome.PlayForFree, "Cast cards exiled with " + sourceObject.getLogName() + " without paying its mana cost?", game)) { + && controller.chooseUse(Outcome.PlayForFree, "Cast cards exiled with " + sourceObject.getLogName() + " without paying its mana cost?", source, game)) { TargetCardInExile target = new TargetCardInExile(filter, source.getSourceId()); while (epicExperimentExileZone.count(filter, game) > 0 && controller.choose(Outcome.PlayForFree, epicExperimentExileZone, target, game)) { Card card = game.getCard(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/sets/returntoravnica/GrislySalvage.java b/Mage.Sets/src/mage/sets/returntoravnica/GrislySalvage.java index e030085eb52..06535dcba3e 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/GrislySalvage.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/GrislySalvage.java @@ -108,7 +108,7 @@ class GrislySalvageEffect extends OneShotEffect { if (!cards.isEmpty()) { controller.revealCards(sourceObject.getName(), cards, game); TargetCard target = new TargetCard(Zone.LIBRARY, filterPutInHand); - if (properCardFound && controller.chooseUse(outcome, "Put a creature or land card from the revealed cards into your hand?", game) && + if (properCardFound && controller.chooseUse(outcome, "Put a creature or land card from the revealed cards into your hand?", source, game) && controller.choose(Outcome.DrawCard, cards, target, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/returntoravnica/GuildFeud.java b/Mage.Sets/src/mage/sets/returntoravnica/GuildFeud.java index 1a89c7af155..756e5538fdd 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/GuildFeud.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/GuildFeud.java @@ -105,7 +105,7 @@ class GuildFeudEffect extends OneShotEffect { player.revealCards(player.getName() + " top three library cards", topThreeCards, game); Card creatureToBattlefield; if (!topThreeCards.isEmpty()) { - if (player.chooseUse(Outcome.PutCreatureInPlay, "Put a creature card among them to the battlefield?", game)) { + if (player.chooseUse(Outcome.PutCreatureInPlay, "Put a creature card among them to the battlefield?", source, game)) { TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCreatureCard( "creature card to put on the battlefield")); diff --git a/Mage.Sets/src/mage/sets/returntoravnica/IzzetKeyrune.java b/Mage.Sets/src/mage/sets/returntoravnica/IzzetKeyrune.java index d15df63aa42..e2967876605 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/IzzetKeyrune.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/IzzetKeyrune.java @@ -92,7 +92,7 @@ public class IzzetKeyrune extends CardImpl { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (player != null && player.chooseUse(Outcome.DrawCard, "Do you wish to draw a card? If you do, discard a card.", game)) { + if (player != null && player.chooseUse(Outcome.DrawCard, "Do you wish to draw a card? If you do, discard a card.", source, game)) { if (player.drawCards(1, game) > 0) { player.discard(1, source, game); } diff --git a/Mage.Sets/src/mage/sets/returntoravnica/JaceArchitectOfThought.java b/Mage.Sets/src/mage/sets/returntoravnica/JaceArchitectOfThought.java index c0638aed100..fa1d8f6e552 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/JaceArchitectOfThought.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/JaceArchitectOfThought.java @@ -37,7 +37,6 @@ import mage.abilities.LoyaltyAbility; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.Card; @@ -65,7 +64,6 @@ import mage.target.common.TargetOpponent; import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; - /** * * @@ -78,11 +76,10 @@ public class JaceArchitectOfThought extends CardImpl { this.expansionSetCode = "RTR"; this.subtype.add("Jace"); - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(4)), false)); // +1: Until your next turn, whenever a creature an opponent controls attacks, it gets -1/-0 until end of turn. - this.addAbility(new LoyaltyAbility(new CreateDelayedTriggeredAbilityEffect(new JaceArchitectOfThoughtDelayedTriggeredAbility()),1)); + this.addAbility(new LoyaltyAbility(new JaceArchitectOfThoughtStartEffect1(), 1)); // -2: Reveal the top three cards of your library. An opponent separates those cards into two piles. Put one pile into your hand and the other on the bottom of your library in any order. this.addAbility(new LoyaltyAbility(new JaceArchitectOfThoughtEffect2(), -2)); @@ -102,16 +99,45 @@ public class JaceArchitectOfThought extends CardImpl { } } +class JaceArchitectOfThoughtStartEffect1 extends OneShotEffect { + + public JaceArchitectOfThoughtStartEffect1() { + super(Outcome.UnboostCreature); + this.staticText = "Until your next turn, whenever a creature an opponent controls attacks, it gets -1/-0 until end of turn"; + } + + public JaceArchitectOfThoughtStartEffect1(final JaceArchitectOfThoughtStartEffect1 effect) { + super(effect); + } + + @Override + public JaceArchitectOfThoughtStartEffect1 copy() { + return new JaceArchitectOfThoughtStartEffect1(this); + } + + @Override + public boolean apply(Game game, Ability source) { + DelayedTriggeredAbility delayedAbility = new JaceArchitectOfThoughtDelayedTriggeredAbility(game.getTurnNum()); + delayedAbility.setSourceId(source.getSourceId()); + delayedAbility.setControllerId(source.getControllerId()); + delayedAbility.setSourceObject(source.getSourceObject(game), game); + game.addDelayedTriggeredAbility(delayedAbility); + return true; + } +} + class JaceArchitectOfThoughtDelayedTriggeredAbility extends DelayedTriggeredAbility { private int startingTurn; - - public JaceArchitectOfThoughtDelayedTriggeredAbility() { - super(new BoostTargetEffect(-1,0, Duration.EndOfTurn), Duration.Custom, false); + + public JaceArchitectOfThoughtDelayedTriggeredAbility(int startingTurn) { + super(new BoostTargetEffect(-1, 0, Duration.EndOfTurn), Duration.Custom, false); + this.startingTurn = startingTurn; } - public JaceArchitectOfThoughtDelayedTriggeredAbility(JaceArchitectOfThoughtDelayedTriggeredAbility ability) { + public JaceArchitectOfThoughtDelayedTriggeredAbility(final JaceArchitectOfThoughtDelayedTriggeredAbility ability) { super(ability); + this.startingTurn = ability.startingTurn; } @Override @@ -135,12 +161,6 @@ class JaceArchitectOfThoughtDelayedTriggeredAbility extends DelayedTriggeredAbil return new JaceArchitectOfThoughtDelayedTriggeredAbility(this); } - @Override - public void init(Game game) { - startingTurn = game.getTurnNum(); - } - - @Override public boolean isInactive(Game game) { return game.getActivePlayerId().equals(getControllerId()) && game.getTurnNum() != startingTurn; @@ -195,10 +215,10 @@ class JaceArchitectOfThoughtEffect2 extends OneShotEffect { opponent = game.getPlayer(targetOpponent.getFirstTarget()); } } - if (opponent == null) { + if (opponent == null) { opponent = game.getPlayer(opponents.iterator().next()); } - + TargetCard target = new TargetCard(0, cards.size(), Zone.PICK, new FilterCard("cards to put in the first pile")); target.setRequired(false); Cards pile1 = new CardsImpl(); @@ -213,27 +233,27 @@ class JaceArchitectOfThoughtEffect2 extends OneShotEffect { } player.revealCards("Pile 1 (Jace, Architect of Thought)", pile1, game); player.revealCards("Pile 2 (Jace, Architect of Thought)", cards, game); - + postPileToLog("Pile 1", pile1.getCards(game), game); postPileToLog("Pile 2", cards.getCards(game), game); - + Cards cardsToHand = cards; Cards cardsToLibrary = pile1; List cardPile1 = new ArrayList<>(); List cardPile2 = new ArrayList<>(); - for (UUID cardId: pile1) { + for (UUID cardId : pile1) { cardPile1.add(game.getCard(cardId)); } - for (UUID cardId: cards) { + for (UUID cardId : cards) { cardPile2.add(game.getCard(cardId)); } boolean pileChoice = player.choosePile(Outcome.Neutral, "Choose a pile to to put into your hand.", cardPile1, cardPile2, game); - if (pileChoice){ + if (pileChoice) { cardsToHand = pile1; cardsToLibrary = cards; } - game.informPlayers(player.getLogName() +" chose pile" + (pileChoice?"1":"2")); + game.informPlayers(player.getLogName() + " chose pile" + (pileChoice ? "1" : "2")); for (UUID cardUuid : cardsToHand) { Card card = cardsToHand.get(cardUuid, game); @@ -260,11 +280,11 @@ class JaceArchitectOfThoughtEffect2 extends OneShotEffect { } return false; } - + private void postPileToLog(String pileName, Set cards, Game game) { StringBuilder message = new StringBuilder(pileName).append(": "); for (Card card : cards) { - message.append(card.getName()).append(" "); + message.append(card.getName()).append(" "); } if (cards.isEmpty()) { message.append(" (empty)"); @@ -320,15 +340,14 @@ class JaceArchitectOfThoughtEffect3 extends OneShotEffect { FilterCard filter = new FilterCard("card to cast without mana costs"); TargetCardInExile target = new TargetCardInExile(filter, source.getSourceId()); while (jaceExileZone.count(filter, game) > 0 && controller.choose(Outcome.PlayForFree, jaceExileZone, target, game)) { - Card card = game.getCard(target.getFirstTarget()); - if (card != null) { + Card card = game.getCard(target.getFirstTarget()); + if (card != null) { - if (controller.cast(card.getSpellAbility(), game, true)) - { - game.getExile().removeCard(card, game); - } + if (controller.cast(card.getSpellAbility(), game, true)) { + game.getExile().removeCard(card, game); } - target.clearChosen(); + } + target.clearChosen(); } return true; diff --git a/Mage.Sets/src/mage/sets/returntoravnica/SoulTithe.java b/Mage.Sets/src/mage/sets/returntoravnica/SoulTithe.java index 3c429990008..753401fbf69 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/SoulTithe.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/SoulTithe.java @@ -109,7 +109,7 @@ class SoulTitheSacrificeSourceUnlessPaysEffect extends OneShotEffect { MageObject sourceObject = source.getSourceObject(game); if (player != null && permanent != null && sourceObject != null) { int cmc = permanent.getManaCost().convertedManaCost(); - if (player.chooseUse(Outcome.Benefit, "Pay {" + cmc + "} for " + permanent.getName() + "? (otherwise you sacrifice it)", game)) { + if (player.chooseUse(Outcome.Benefit, "Pay {" + cmc + "} for " + permanent.getName() + "? (otherwise you sacrifice it)", source, game)) { Cost cost = new GenericManaCost(cmc); if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { return true; diff --git a/Mage.Sets/src/mage/sets/returntoravnica/SphereOfSafety.java b/Mage.Sets/src/mage/sets/returntoravnica/SphereOfSafety.java index 203b13ab4f9..6c9ee272bc3 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/SphereOfSafety.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/SphereOfSafety.java @@ -115,7 +115,7 @@ class SphereOfSafetyReplacementEffect extends ReplacementEffectImpl { int ce = countEnchantments.calculate(game, source, this); ManaCostsImpl safetyCosts = new ManaCostsImpl("{"+ ce +"}"); if ( safetyCosts.canPay(source, source.getSourceId(), event.getPlayerId(), game) && - player.chooseUse(Outcome.Benefit, "Pay {"+ ce +"} to declare attacker?", game) ) { + player.chooseUse(Outcome.Benefit, "Pay {"+ ce +"} to declare attacker?", source, game) ) { if (safetyCosts.payOrRollback(source, game, this.getId(), event.getPlayerId())) { return false; } diff --git a/Mage.Sets/src/mage/sets/returntoravnica/UrbanBurgeoning.java b/Mage.Sets/src/mage/sets/returntoravnica/UrbanBurgeoning.java index b108ac96043..166c927fe94 100644 --- a/Mage.Sets/src/mage/sets/returntoravnica/UrbanBurgeoning.java +++ b/Mage.Sets/src/mage/sets/returntoravnica/UrbanBurgeoning.java @@ -25,10 +25,17 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.returntoravnica; import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.RestrictionEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; import mage.constants.AttachmentType; import mage.constants.CardType; import mage.constants.Duration; @@ -38,14 +45,6 @@ import mage.constants.PhaseStep; import mage.constants.Rarity; import mage.constants.SubLayer; import mage.constants.Zone; -import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.RestrictionEffect; -import mage.abilities.effects.common.AttachEffect; -import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; -import mage.abilities.keyword.EnchantAbility; -import mage.cards.CardImpl; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; @@ -59,12 +58,11 @@ public class UrbanBurgeoning extends CardImpl { static final String rule = "Enchanted land has \"Untap this land during each other player's untap step.\""; - public UrbanBurgeoning (UUID ownerId) { + public UrbanBurgeoning(UUID ownerId) { super(ownerId, 138, "Urban Burgeoning", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{G}"); this.expansionSetCode = "RTR"; this.subtype.add("Aura"); - // Enchant land TargetPermanent auraTarget = new TargetLandPermanent(); this.getSpellAbility().addTarget(auraTarget); @@ -77,7 +75,7 @@ public class UrbanBurgeoning extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(gainedAbility, AttachmentType.AURA, Duration.WhileOnBattlefield, rule))); } - public UrbanBurgeoning (final UrbanBurgeoning card) { + public UrbanBurgeoning(final UrbanBurgeoning card) { super(card); } @@ -114,8 +112,8 @@ class UrbanBurgeoningUntapEffect extends ContinuousEffectImpl { game.getState().setValue(source.getSourceId() + "applied", true); Permanent land = game.getPermanent(source.getSourceId()); boolean untap = true; - for (RestrictionEffect effect: game.getContinuousEffects().getApplicableRestrictionEffects(land, game).keySet()) { - untap &= effect.canBeUntapped(land, game); + for (RestrictionEffect effect : game.getContinuousEffects().getApplicableRestrictionEffects(land, game).keySet()) { + untap &= effect.canBeUntapped(land, source, game); } if (untap) { land.untap(game); diff --git a/Mage.Sets/src/mage/sets/riseoftheeldrazi/HellcarverDemon.java b/Mage.Sets/src/mage/sets/riseoftheeldrazi/HellcarverDemon.java index 7a840918c4a..0f479e09c9f 100644 --- a/Mage.Sets/src/mage/sets/riseoftheeldrazi/HellcarverDemon.java +++ b/Mage.Sets/src/mage/sets/riseoftheeldrazi/HellcarverDemon.java @@ -113,7 +113,7 @@ class HellcarverDemonEffect extends OneShotEffect { } } - while (player != null && player.isInGame() && player.chooseUse(Outcome.PlayForFree, "Cast another nonland card exiled with Hellcarver Demon without paying that card's mana cost?", game)) { + while (player != null && player.isInGame() && player.chooseUse(Outcome.PlayForFree, "Cast another nonland card exiled with Hellcarver Demon without paying that card's mana cost?", source, game)) { TargetCardInExile target = new TargetCardInExile(filter, source.getSourceId()); while (player.choose(Outcome.PlayForFree, game.getExile().getExileZone(source.getSourceId()), target, game)) { Card card = game.getCard(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/sets/saviorsofkamigawa/BloodClock.java b/Mage.Sets/src/mage/sets/saviorsofkamigawa/BloodClock.java index af22a86067b..6beffb21683 100644 --- a/Mage.Sets/src/mage/sets/saviorsofkamigawa/BloodClock.java +++ b/Mage.Sets/src/mage/sets/saviorsofkamigawa/BloodClock.java @@ -91,7 +91,7 @@ class BloodClockEffect extends OneShotEffect { if (player == null) { return false; } - if (player.getLife() > 2 && player.chooseUse(Outcome.Neutral, "Pay 2 life? If you don't, return a permanent you control to its owner's hand.", game)) { + if (player.getLife() > 2 && player.chooseUse(Outcome.Neutral, "Pay 2 life? If you don't, return a permanent you control to its owner's hand.", source, game)) { player.loseLife(2, game); game.informPlayers(player.getLogName() + " pays 2 life. He will not return a permanent he or she controls."); return true; diff --git a/Mage.Sets/src/mage/sets/saviorsofkamigawa/ChoiceOfDamnations.java b/Mage.Sets/src/mage/sets/saviorsofkamigawa/ChoiceOfDamnations.java index b654d9ed6ad..b17320ccbb4 100644 --- a/Mage.Sets/src/mage/sets/saviorsofkamigawa/ChoiceOfDamnations.java +++ b/Mage.Sets/src/mage/sets/saviorsofkamigawa/ChoiceOfDamnations.java @@ -93,7 +93,7 @@ class ChoiceOfDamnationsEffect extends OneShotEffect { int amount = targetPlayer.getAmount(0, Integer.MAX_VALUE, "Chooses a number", game); Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - if (controller.chooseUse(outcome, "Shall " + targetPlayer.getLogName() + " lose " + amount + " life?", game)) { + if (controller.chooseUse(outcome, "Shall " + targetPlayer.getLogName() + " lose " + amount + " life?", source, game)) { targetPlayer.loseLife(amount, game); } else { int numberPermanents = game.getState().getBattlefield().countAll(new FilterPermanent(), targetPlayer.getId(), game); diff --git a/Mage.Sets/src/mage/sets/saviorsofkamigawa/CowedByWisdom.java b/Mage.Sets/src/mage/sets/saviorsofkamigawa/CowedByWisdom.java index 42d10820b90..0176bd77ecd 100644 --- a/Mage.Sets/src/mage/sets/saviorsofkamigawa/CowedByWisdom.java +++ b/Mage.Sets/src/mage/sets/saviorsofkamigawa/CowedByWisdom.java @@ -125,7 +125,7 @@ class CowedByWisdomEffect extends ReplacementEffectImpl { } ManaCostsImpl attackBlockTax = new ManaCostsImpl("{" + cardsInHand + "}"); if (attackBlockTax.canPay(source, source.getSourceId(), event.getPlayerId(), game) - && player.chooseUse(Outcome.Neutral, chooseText, game)) { + && player.chooseUse(Outcome.Neutral, chooseText, source, game)) { if (attackBlockTax.payOrRollback(source, game, source.getSourceId(), event.getPlayerId())) { return false; } diff --git a/Mage.Sets/src/mage/sets/saviorsofkamigawa/InameAsOne.java b/Mage.Sets/src/mage/sets/saviorsofkamigawa/InameAsOne.java index e7246a95664..395a947b44a 100644 --- a/Mage.Sets/src/mage/sets/saviorsofkamigawa/InameAsOne.java +++ b/Mage.Sets/src/mage/sets/saviorsofkamigawa/InameAsOne.java @@ -115,7 +115,7 @@ class InameAsOneEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source.getSourceId()); if (controller != null && sourceObject != null) { - if (controller.chooseUse(outcome, "Exile " + sourceObject.getLogName() + " to return Spirit card?", game)) { + if (controller.chooseUse(outcome, "Exile " + sourceObject.getLogName() + " to return Spirit card?", source, game)) { // In a Commander game, you may send Iname to the Command Zone instead of exiling it during the resolution // of its ability. If you do, its ability still works. Iname's ability only requires that you attempted to // exile it, not that it actually gets to the exile zone. This is similar to how destroying a creature diff --git a/Mage.Sets/src/mage/sets/saviorsofkamigawa/PainsReward.java b/Mage.Sets/src/mage/sets/saviorsofkamigawa/PainsReward.java index 5d61a72b1cc..6da149da127 100644 --- a/Mage.Sets/src/mage/sets/saviorsofkamigawa/PainsReward.java +++ b/Mage.Sets/src/mage/sets/saviorsofkamigawa/PainsReward.java @@ -94,7 +94,7 @@ class PainsRewardEffect extends OneShotEffect { Player currentPlayer = playerList.getNextInRange(controller, game); while (currentPlayer != winner) { String text = winner.getLogName() + " has bet " + highBid + " life" + (highBid > 1 ? "s" : "") + ". Top the bid?"; - if (currentPlayer.chooseUse(Outcome.Detriment, text, game)) { + if (currentPlayer.chooseUse(Outcome.Detriment, text, source, game)) { int newBid = currentPlayer.getAmount(highBid + 1, Integer.MAX_VALUE, "Choose amount of life to bid", game); if (newBid > highBid) { highBid = newBid; diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/GolemsHeart.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/GolemsHeart.java index 0f12cba5cd3..d17984aa46e 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/GolemsHeart.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/GolemsHeart.java @@ -25,7 +25,6 @@ * 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; @@ -46,13 +45,15 @@ import mage.game.stack.Spell; */ public class GolemsHeart extends CardImpl { - public GolemsHeart (UUID ownerId) { + public GolemsHeart(UUID ownerId) { super(ownerId, 161, "Golem's Heart", Rarity.UNCOMMON, new CardType[]{CardType.ARTIFACT}, "{2}"); this.expansionSetCode = "SOM"; + + // Whenever a player casts an artifact spell, you may gain 1 life. this.addAbility(new GolemsHeartAbility()); } - public GolemsHeart (final GolemsHeart card) { + public GolemsHeart(final GolemsHeart card) { super(card); } @@ -80,7 +81,7 @@ class GolemsHeartAbility extends TriggeredAbilityImpl { @Override public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == EventType.CAST_SPELL; + return event.getType() == EventType.SPELL_CAST; } @Override @@ -94,4 +95,4 @@ class GolemsHeartAbility extends TriggeredAbilityImpl { return "Whenever a player casts an artifact spell, you may gain 1 life."; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/NimDeathmantle.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/NimDeathmantle.java index 060d2c19887..45f8b9878cc 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/NimDeathmantle.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/NimDeathmantle.java @@ -162,7 +162,7 @@ class NimDeathmantleEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); Permanent equipment = game.getPermanent(source.getSourceId()); if (player != null && equipment != null) { - if (player.chooseUse(Outcome.Benefit, equipment.getName() + " - Pay " + cost.getText() + "?", game)) { + if (player.chooseUse(Outcome.Benefit, equipment.getName() + " - Pay " + cost.getText() + "?", source, game)) { cost.clearPaid(); if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { UUID target = targetPointer.getFirst(game, source); diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/PainfulQuandary.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/PainfulQuandary.java index 7fb923d0381..8966440f999 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/PainfulQuandary.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/PainfulQuandary.java @@ -92,7 +92,7 @@ class PainfulQuandryEffect extends OneShotEffect { boolean paid = false; Cost cost = new DiscardTargetCost(new TargetCardInHand()); if (cost.canPay(source, source.getSourceId(), player.getId(), game) - && player.chooseUse(Outcome.Detriment, "Discard a card (otherwise you lose 5 life)?", game)) { + && player.chooseUse(Outcome.Detriment, "Discard a card (otherwise you lose 5 life)?", source, game)) { paid = cost.pay(source, game, source.getSourceId(), player.getId(), false); } if (!paid) { diff --git a/Mage.Sets/src/mage/sets/scarsofmirrodin/RustTick.java b/Mage.Sets/src/mage/sets/scarsofmirrodin/RustTick.java index df5b37004db..db24b404062 100644 --- a/Mage.Sets/src/mage/sets/scarsofmirrodin/RustTick.java +++ b/Mage.Sets/src/mage/sets/scarsofmirrodin/RustTick.java @@ -28,10 +28,6 @@ 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.Mode; @@ -43,11 +39,14 @@ import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.RestrictionEffect; import mage.abilities.effects.common.TapTargetEffect; import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetArtifactPermanent; - /** * @author nantuko */ @@ -112,7 +111,6 @@ class RustTickTapTargetEffect extends TapTargetEffect { return true; } - @Override public RustTickTapTargetEffect copy() { return new RustTickTapTargetEffect(this); @@ -149,7 +147,7 @@ class RustTickRestrictionEffect extends RestrictionEffect { } @Override - public boolean canBeUntapped(Permanent permanent, Game game) { + public boolean canBeUntapped(Permanent permanent, Ability source, Game game) { return false; } diff --git a/Mage.Sets/src/mage/sets/seventhedition/BalefulStare.java b/Mage.Sets/src/mage/sets/seventhedition/BalefulStare.java new file mode 100644 index 00000000000..dd27713ec3a --- /dev/null +++ b/Mage.Sets/src/mage/sets/seventhedition/BalefulStare.java @@ -0,0 +1,53 @@ +/* + * 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.seventhedition; + +import java.util.UUID; + +/** + * + * @author LoneFox + + */ +public class BalefulStare extends mage.sets.ninthedition.BalefulStare { + + public BalefulStare(UUID ownerId) { + super(ownerId); + this.cardNumber = 62; + this.expansionSetCode = "7ED"; + } + + public BalefulStare(final BalefulStare card) { + super(card); + } + + @Override + public BalefulStare copy() { + return new BalefulStare(this); + } +} diff --git a/Mage.Sets/src/mage/sets/seventhedition/BellowingFiend.java b/Mage.Sets/src/mage/sets/seventhedition/BellowingFiend.java new file mode 100644 index 00000000000..770e36f7b87 --- /dev/null +++ b/Mage.Sets/src/mage/sets/seventhedition/BellowingFiend.java @@ -0,0 +1,53 @@ +/* + * 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.seventhedition; + +import java.util.UUID; + +/** + * + * @author LoneFox + + */ +public class BellowingFiend extends mage.sets.tempest.BellowingFiend { + + public BellowingFiend(UUID ownerId) { + super(ownerId); + this.cardNumber = 119; + this.expansionSetCode = "7ED"; + } + + public BellowingFiend(final BellowingFiend card) { + super(card); + } + + @Override + public BellowingFiend copy() { + return new BellowingFiend(this); + } +} diff --git a/Mage.Sets/src/mage/sets/seventhedition/Caltrops.java b/Mage.Sets/src/mage/sets/seventhedition/Caltrops.java new file mode 100644 index 00000000000..4973ea3e7bf --- /dev/null +++ b/Mage.Sets/src/mage/sets/seventhedition/Caltrops.java @@ -0,0 +1,53 @@ +/* + * 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.seventhedition; + +import java.util.UUID; + +/** + * + * @author LoneFox + + */ +public class Caltrops extends mage.sets.urzasdestiny.Caltrops { + + public Caltrops(UUID ownerId) { + super(ownerId); + this.cardNumber = 288; + this.expansionSetCode = "7ED"; + } + + public Caltrops(final Caltrops card) { + super(card); + } + + @Override + public Caltrops copy() { + return new Caltrops(this); + } +} diff --git a/Mage.Sets/src/mage/sets/seventhedition/Disorder.java b/Mage.Sets/src/mage/sets/seventhedition/Disorder.java new file mode 100644 index 00000000000..6207775dd47 --- /dev/null +++ b/Mage.Sets/src/mage/sets/seventhedition/Disorder.java @@ -0,0 +1,110 @@ +/* + * 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.seventhedition; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageAllEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author LoneFox + + */ +public class Disorder extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("white creature"); + + static { + filter.add(new ColorPredicate(ObjectColor.WHITE)); + } + + public Disorder(UUID ownerId) { + super(ownerId, 179, "Disorder", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{1}{R}"); + this.expansionSetCode = "7ED"; + + // Disorder deals 2 damage to each white creature and each player who controls a white creature. + this.getSpellAbility().addEffect(new DamageAllEffect(2, filter)); + this.getSpellAbility().addEffect(new DisorderEffect()); + } + + public Disorder(final Disorder card) { + super(card); + } + + @Override + public Disorder copy() { + return new Disorder(this); + } +} + +class DisorderEffect extends OneShotEffect { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("white creature"); + + static { + filter.add(new ColorPredicate(ObjectColor.WHITE)); + } + + public DisorderEffect() { + super(Outcome.Damage); + this.staticText = "and each player who controls a white creature"; } + + public DisorderEffect(final DisorderEffect effect) { + super(effect); + } + + @Override + public DisorderEffect copy() { + return new DisorderEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for(Player player : game.getPlayers().values()) { + FilterCreaturePermanent filter = new FilterCreaturePermanent(); + filter.add(new ControllerIdPredicate(player.getId())); + filter.add(new ColorPredicate(ObjectColor.WHITE)); + if(game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) > 0) { + player.damage(2, source.getSourceId(), game, false, true); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/seventhedition/FerozsBan.java b/Mage.Sets/src/mage/sets/seventhedition/FerozsBan.java new file mode 100644 index 00000000000..f41e36e490d --- /dev/null +++ b/Mage.Sets/src/mage/sets/seventhedition/FerozsBan.java @@ -0,0 +1,53 @@ +/* + * 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.seventhedition; + +import java.util.UUID; + +/** + * + * @author LoneFox + + */ +public class FerozsBan extends mage.sets.fifthedition.FerozsBan { + + public FerozsBan(UUID ownerId) { + super(ownerId); + this.cardNumber = 295; + this.expansionSetCode = "7ED"; + } + + public FerozsBan(final FerozsBan card) { + super(card); + } + + @Override + public FerozsBan copy() { + return new FerozsBan(this); + } +} diff --git a/Mage.Sets/src/mage/sets/seventhedition/GraftedSkullcap.java b/Mage.Sets/src/mage/sets/seventhedition/GraftedSkullcap.java new file mode 100644 index 00000000000..f141c9371cd --- /dev/null +++ b/Mage.Sets/src/mage/sets/seventhedition/GraftedSkullcap.java @@ -0,0 +1,53 @@ +/* + * 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.seventhedition; + +import java.util.UUID; + +/** + * + * @author LoneFox + + */ +public class GraftedSkullcap extends mage.sets.urzassaga.GraftedSkullcap { + + public GraftedSkullcap(UUID ownerId) { + super(ownerId); + this.cardNumber = 298; + this.expansionSetCode = "7ED"; + } + + public GraftedSkullcap(final GraftedSkullcap card) { + super(card); + } + + @Override + public GraftedSkullcap copy() { + return new GraftedSkullcap(this); + } +} diff --git a/Mage.Sets/src/mage/sets/seventhedition/Impatience.java b/Mage.Sets/src/mage/sets/seventhedition/Impatience.java new file mode 100644 index 00000000000..1e3ae7e8495 --- /dev/null +++ b/Mage.Sets/src/mage/sets/seventhedition/Impatience.java @@ -0,0 +1,83 @@ +/* + * 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.seventhedition; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.game.Game; +import mage.watchers.common.CastSpellLastTurnWatcher; + +/** + * + * @author LoneFox + + */ +public class Impatience extends CardImpl { + + public Impatience(UUID ownerId) { + super(ownerId, 197, "Impatience", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); + this.expansionSetCode = "7ED"; + + // At the beginning of each player's end step, if that player didn't cast a spell this turn, Impatience deals 2 damage to him or her. + Effect effect = new DamageTargetEffect(2); + effect.setText("{this} deals 2 damage to him or her."); + this.addAbility(new BeginningOfEndStepTriggeredAbility(Zone.BATTLEFIELD, effect, TargetController.ANY, + new ImpatienceCondition(), false)); + } + + public Impatience(final Impatience card) { + super(card); + } + + @Override + public Impatience copy() { + return new Impatience(this); + } +} + +class ImpatienceCondition implements Condition { + + @Override + public boolean apply(Game game, Ability source) { + CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get("CastSpellLastTurnWatcher"); + return watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(game.getActivePlayerId()) == 0; + } + + public String toString() { + return "if that player didn't cast a spell this turn"; + } +} diff --git a/Mage.Sets/src/mage/sets/seventhedition/NaturesRevolt.java b/Mage.Sets/src/mage/sets/seventhedition/NaturesRevolt.java new file mode 100644 index 00000000000..ecbe73895ee --- /dev/null +++ b/Mage.Sets/src/mage/sets/seventhedition/NaturesRevolt.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.sets.seventhedition; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.BecomesCreatureAllEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterLandPermanent; +import mage.game.permanent.token.Token; + +/** + * + * @author LoneFox + + */ +public class NaturesRevolt extends CardImpl { + + public NaturesRevolt(UUID ownerId) { + super(ownerId, 260, "Nature's Revolt", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}{G}"); + this.expansionSetCode = "7ED"; + + // All lands are 2/2 creatures that are still lands. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BecomesCreatureAllEffect(new NaturesRevoltToken(), + "lands", new FilterLandPermanent(), Duration.WhileOnBattlefield))); + } + + public NaturesRevolt(final NaturesRevolt card) { + super(card); + } + + @Override + public NaturesRevolt copy() { + return new NaturesRevolt(this); + } +} + +class NaturesRevoltToken extends Token { + public NaturesRevoltToken() { + super("Land", "2/2 creature"); + cardType.add(CardType.CREATURE); + power = new MageInt(2); + toughness = new MageInt(2); + } +} diff --git a/Mage.Sets/src/mage/sets/seventhedition/NocturnalRaid.java b/Mage.Sets/src/mage/sets/seventhedition/NocturnalRaid.java new file mode 100644 index 00000000000..f5680793e8d --- /dev/null +++ b/Mage.Sets/src/mage/sets/seventhedition/NocturnalRaid.java @@ -0,0 +1,53 @@ +/* + * 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.seventhedition; + +import java.util.UUID; + +/** + * + * @author LoneFox + + */ +public class NocturnalRaid extends mage.sets.mirage.NocturnalRaid { + + public NocturnalRaid(UUID ownerId) { + super(ownerId); + this.cardNumber = 151; + this.expansionSetCode = "7ED"; + } + + public NocturnalRaid(final NocturnalRaid card) { + super(card); + } + + @Override + public NocturnalRaid copy() { + return new NocturnalRaid(this); + } +} diff --git a/Mage.Sets/src/mage/sets/seventhedition/Reprocess.java b/Mage.Sets/src/mage/sets/seventhedition/Reprocess.java new file mode 100644 index 00000000000..b02114d2ed4 --- /dev/null +++ b/Mage.Sets/src/mage/sets/seventhedition/Reprocess.java @@ -0,0 +1,113 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.seventhedition; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author LoneFox + + */ +public class Reprocess extends CardImpl { + + public Reprocess(UUID ownerId) { + super(ownerId, 159, "Reprocess", Rarity.RARE, new CardType[]{CardType.SORCERY}, "{2}{B}{B}"); + this.expansionSetCode = "7ED"; + + // Sacrifice any number of artifacts, creatures, and/or lands. Draw a card for each permanent sacrificed this way. + this.getSpellAbility().addEffect(new ReprocessEffect()); + } + + public Reprocess(final Reprocess card) { + super(card); + } + + @Override + public Reprocess copy() { + return new Reprocess(this); + } +} + +class ReprocessEffect extends OneShotEffect { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("artifacts, creatures, and/or lands"); + + static { + filter.add(Predicates.or(new CardTypePredicate(CardType.ARTIFACT), new CardTypePredicate(CardType.CREATURE), + new CardTypePredicate(CardType.LAND))); + } + + public ReprocessEffect() { + super(Outcome.Neutral); + staticText = "Sacrifice any number of artifacts, creatures, and/or lands. Draw a card for each permanent sacrificed this way."; + } + + public ReprocessEffect(final ReprocessEffect effect) { + super(effect); + } + + @Override + public ReprocessEffect copy() { + return new ReprocessEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null){ + return false; + } + int amount = 0; + TargetControlledPermanent toSacrifice = new TargetControlledPermanent(0, Integer.MAX_VALUE, filter, true); + if(player.chooseTarget(Outcome.Sacrifice, toSacrifice, source, game)) { + for(Object uuid : toSacrifice.getTargets()){ + Permanent permanent = game.getPermanent((UUID)uuid); + if(permanent != null){ + permanent.sacrifice(source.getSourceId(), game); + amount++; + } + } + player.drawCards(amount, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/seventhedition/ShieldWall.java b/Mage.Sets/src/mage/sets/seventhedition/ShieldWall.java new file mode 100644 index 00000000000..d35854f792a --- /dev/null +++ b/Mage.Sets/src/mage/sets/seventhedition/ShieldWall.java @@ -0,0 +1,55 @@ +/* + * 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.seventhedition; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author LoneFox + + */ +public class ShieldWall extends mage.sets.legends.ShieldWall { + + public ShieldWall(UUID ownerId) { + super(ownerId); + this.cardNumber = 44; + this.expansionSetCode = "7ED"; + this.rarity = Rarity.COMMON; + } + + public ShieldWall(final ShieldWall card) { + super(card); + } + + @Override + public ShieldWall copy() { + return new ShieldWall(this); + } +} diff --git a/Mage.Sets/src/mage/sets/seventhedition/SouthernPaladin.java b/Mage.Sets/src/mage/sets/seventhedition/SouthernPaladin.java new file mode 100644 index 00000000000..4a7cacace63 --- /dev/null +++ b/Mage.Sets/src/mage/sets/seventhedition/SouthernPaladin.java @@ -0,0 +1,82 @@ +/* + * 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.seventhedition; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; + +/** + * + * @author LoneFox + + */ +public class SouthernPaladin extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("red"); + + static { + filter.add(new ColorPredicate(ObjectColor.RED)); + } + + public SouthernPaladin(UUID ownerId) { + super(ownerId, 46, "Southern Paladin", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{W}{W}"); + this.expansionSetCode = "7ED"; + this.subtype.add("Human"); + this.subtype.add("Knight"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // {W}{W}, {tap}: Destroy target red permanent. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), new ManaCostsImpl("{W}{W}")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + public SouthernPaladin(final SouthernPaladin card) { + super(card); + } + + @Override + public SouthernPaladin copy() { + return new SouthernPaladin(this); + } +} diff --git a/Mage.Sets/src/mage/sets/seventhedition/Squall.java b/Mage.Sets/src/mage/sets/seventhedition/Squall.java new file mode 100644 index 00000000000..b59c8591612 --- /dev/null +++ b/Mage.Sets/src/mage/sets/seventhedition/Squall.java @@ -0,0 +1,53 @@ +/* + * 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.seventhedition; + +import java.util.UUID; + +/** + * + * @author LoneFox + + */ +public class Squall extends mage.sets.starter1999.Squall { + + public Squall(UUID ownerId) { + super(ownerId); + this.cardNumber = 271; + this.expansionSetCode = "7ED"; + } + + public Squall(final Squall card) { + super(card); + } + + @Override + public Squall copy() { + return new Squall(this); + } +} diff --git a/Mage.Sets/src/mage/sets/seventhedition/Starlight.java b/Mage.Sets/src/mage/sets/seventhedition/Starlight.java new file mode 100644 index 00000000000..e5dfe48fd36 --- /dev/null +++ b/Mage.Sets/src/mage/sets/seventhedition/Starlight.java @@ -0,0 +1,72 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.sets.seventhedition; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.dynamicvalue.common.PermanentsTargetOpponentControlsCount; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.common.TargetOpponent; + +/** + * + * @author LoneFox + + */ +public class Starlight extends CardImpl { + + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("black creature"); + + static { + filter.add(new ColorPredicate(ObjectColor.BLACK)); + } + + public Starlight(UUID ownerId) { + super(ownerId, 49, "Starlight", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{1}{W}"); + this.expansionSetCode = "7ED"; + + // You gain 3 life for each black creature target opponent controls. + this.getSpellAbility().addEffect(new GainLifeEffect(new PermanentsTargetOpponentControlsCount(filter, 3))); + this.getSpellAbility().addTarget(new TargetOpponent()); + } + + public Starlight(final Starlight card) { + super(card); + } + + @Override + public Starlight copy() { + return new Starlight(this); + } +} diff --git a/Mage.Sets/src/mage/sets/seventhedition/TaintedAEther.java b/Mage.Sets/src/mage/sets/seventhedition/TaintedAEther.java new file mode 100644 index 00000000000..fa4bf8e3c43 --- /dev/null +++ b/Mage.Sets/src/mage/sets/seventhedition/TaintedAEther.java @@ -0,0 +1,53 @@ +/* + * 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.seventhedition; + +import java.util.UUID; + +/** + * + * @author LoneFox + + */ +public class TaintedAEther extends mage.sets.urzassaga.TaintedAEther { + + public TaintedAEther(UUID ownerId) { + super(ownerId); + this.cardNumber = 167; + this.expansionSetCode = "7ED"; + } + + public TaintedAEther(final TaintedAEther card) { + super(card); + } + + @Override + public TaintedAEther copy() { + return new TaintedAEther(this); + } +} diff --git a/Mage.Sets/src/mage/sets/seventhedition/TelepathicSpies.java b/Mage.Sets/src/mage/sets/seventhedition/TelepathicSpies.java new file mode 100644 index 00000000000..e774577563f --- /dev/null +++ b/Mage.Sets/src/mage/sets/seventhedition/TelepathicSpies.java @@ -0,0 +1,53 @@ +/* + * 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.seventhedition; + +import java.util.UUID; + +/** + * + * @author LoneFox + + */ +public class TelepathicSpies extends mage.sets.urzasdestiny.TelepathicSpies { + + public TelepathicSpies(UUID ownerId) { + super(ownerId); + this.cardNumber = 101; + this.expansionSetCode = "7ED"; + } + + public TelepathicSpies(final TelepathicSpies card) { + super(card); + } + + @Override + public TelepathicSpies copy() { + return new TelepathicSpies(this); + } +} diff --git a/Mage.Sets/src/mage/sets/seventhedition/Thoughtleech.java b/Mage.Sets/src/mage/sets/seventhedition/Thoughtleech.java new file mode 100644 index 00000000000..2354dc80e48 --- /dev/null +++ b/Mage.Sets/src/mage/sets/seventhedition/Thoughtleech.java @@ -0,0 +1,101 @@ +/* + * 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.seventhedition; + +import java.util.UUID; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent.EventType; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; + +/** + * + * @author LoneFox + + */ +public class Thoughtleech extends CardImpl { + + public Thoughtleech(UUID ownerId) { + super(ownerId, 274, "Thoughtleech", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{G}{G}"); + this.expansionSetCode = "7ED"; + + // Whenever an Island an opponent controls becomes tapped, you may gain 1 life. + this.addAbility(new ThoughtleechTriggeredAbility()); + } + + public Thoughtleech(final Thoughtleech card) { + super(card); + } + + @Override + public Thoughtleech copy() { + return new Thoughtleech(this); + } +} + +class ThoughtleechTriggeredAbility extends TriggeredAbilityImpl { + + ThoughtleechTriggeredAbility() { + super(Zone.BATTLEFIELD, new GainLifeEffect(1), true); + } + + ThoughtleechTriggeredAbility(final ThoughtleechTriggeredAbility ability) { + super(ability); + } + + @Override + public ThoughtleechTriggeredAbility copy() { + return new ThoughtleechTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.TAPPED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Permanent p = game.getPermanent(event.getTargetId()); + if(p != null && p.getSubtype().contains("Island")) { + if(game.getOpponents(this.controllerId).contains(p.getControllerId())) + return true; + } + return false; + } + + @Override + public String getRule() { + return "Whenever an Island an opponent controls becomes tapped, " + modes.getText(); + } +} diff --git a/Mage.Sets/src/mage/sets/seventhedition/WallOfWonder.java b/Mage.Sets/src/mage/sets/seventhedition/WallOfWonder.java new file mode 100644 index 00000000000..8626e9783a1 --- /dev/null +++ b/Mage.Sets/src/mage/sets/seventhedition/WallOfWonder.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.sets.seventhedition; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.combat.CanAttackAsThoughtItDidntHaveDefenderSourceEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.DefenderAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Rarity; +import mage.constants.Zone; + +/** + * + * @author LoneFox + + */ +public class WallOfWonder extends CardImpl { + + public WallOfWonder(UUID ownerId) { + super(ownerId, 112, "Wall of Wonder", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{U}{U}"); + this.expansionSetCode = "7ED"; + this.subtype.add("Wall"); + this.power = new MageInt(1); + this.toughness = new MageInt(5); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + // {2}{U}{U}: Wall of Wonder gets +4/-4 until end of turn and can attack this turn as though it didn't have defender. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(4, -4, Duration.EndOfTurn), + new ManaCostsImpl("{2}{U}{U}")); + ability.addEffect(new CanAttackAsThoughtItDidntHaveDefenderSourceEffect(Duration.EndOfTurn)); + this.addAbility(ability); + } + + public WallOfWonder(final WallOfWonder card) { + super(card); + } + + @Override + public WallOfWonder copy() { + return new WallOfWonder(this); + } +} diff --git a/Mage.Sets/src/mage/sets/seventhedition/YawgmothsEdict.java b/Mage.Sets/src/mage/sets/seventhedition/YawgmothsEdict.java new file mode 100644 index 00000000000..0c57b335f4b --- /dev/null +++ b/Mage.Sets/src/mage/sets/seventhedition/YawgmothsEdict.java @@ -0,0 +1,53 @@ +/* + * 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.seventhedition; + +import java.util.UUID; + +/** + * + * @author LoneFox + + */ +public class YawgmothsEdict extends mage.sets.urzassaga.YawgmothsEdict { + + public YawgmothsEdict(UUID ownerId) { + super(ownerId); + this.cardNumber = 171; + this.expansionSetCode = "7ED"; + } + + public YawgmothsEdict(final YawgmothsEdict card) { + super(card); + } + + @Override + public YawgmothsEdict copy() { + return new YawgmothsEdict(this); + } +} diff --git a/Mage.Sets/src/mage/sets/shadowmoor/DramaticEntrance.java b/Mage.Sets/src/mage/sets/shadowmoor/DramaticEntrance.java index e85f8d10686..c3c0846ab5d 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/DramaticEntrance.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/DramaticEntrance.java @@ -98,7 +98,7 @@ class DramaticEntranceEffect extends OneShotEffect { if (controller != null) { if (controller.getHand().count(filter, game) > 0) { if (controller.chooseUse(Outcome.PutCreatureInPlay, - "Put a green creature card onto the battlefield?", game)) { + "Put a green creature card onto the battlefield?", source, game)) { Target target = new TargetCardInHand(filter); if (controller.chooseTarget(outcome, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/sets/shadowmoor/MemoryPlunder.java b/Mage.Sets/src/mage/sets/shadowmoor/MemoryPlunder.java index c0544f0791c..bedbf0ec5e0 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/MemoryPlunder.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/MemoryPlunder.java @@ -98,7 +98,7 @@ class MemoryPlunderEffect extends OneShotEffect { Card card = game.getCard(getTargetPointer().getFirst(game, source)); if (card != null) { Player player = game.getPlayer(source.getControllerId()); - if (player != null && player.chooseUse(Outcome.Benefit, "Cast " + card.getName() +" without paying cost?", game)) { + if (player != null && player.chooseUse(Outcome.Benefit, "Cast " + card.getName() +" without paying cost?", source, game)) { player.cast(card.getSpellAbility(), game, true); } } diff --git a/Mage.Sets/src/mage/sets/shadowmoor/PlagueOfVermin.java b/Mage.Sets/src/mage/sets/shadowmoor/PlagueOfVermin.java index 9eecc114643..4bf3c7225d6 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/PlagueOfVermin.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/PlagueOfVermin.java @@ -106,7 +106,7 @@ class PlagueOfVerminEffect extends OneShotEffect { if (currentPlayer != null && currentPlayer.isInGame() && controller.getInRange().contains(currentPlayer.getId())) { currentLifePaid = 0; totalPaidLife = 0; - if (currentPlayer.chooseUse(Outcome.AIDontUseIt, "Pay life?", game)) { + if (currentPlayer.chooseUse(Outcome.AIDontUseIt, "Pay life?", source, game)) { totalPaidLife = currentPlayer.getAmount(0, controller.getLife(), "Pay how many life?", game); if (totalPaidLife > 0) { currentPlayer.loseLife(totalPaidLife, game); diff --git a/Mage.Sets/src/mage/sets/shadowmoor/PuresightMerrow.java b/Mage.Sets/src/mage/sets/shadowmoor/PuresightMerrow.java index f9b55a50bb7..115e6c1f8e2 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/PuresightMerrow.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/PuresightMerrow.java @@ -104,7 +104,7 @@ class PuresightMerrowEffect extends OneShotEffect { Cards cards = new CardsImpl(); cards.add(card); controller.lookAtCards("Puresight Merrow", cards, game); - if (controller.chooseUse(Outcome.Removal, "Do you wish to exile the card from the top of your library?", game)) { + if (controller.chooseUse(Outcome.Removal, "Do you wish to exile the card from the top of your library?", source, game)) { controller.moveCardToExileWithInfo(card, source.getSourceId(), sourceObject.getIdName(), source.getSourceId(), game, Zone.LIBRARY, true); } else { game.informPlayers(controller.getLogName() + " puts the card back on top of their library."); diff --git a/Mage.Sets/src/mage/sets/shadowmoor/PutAway.java b/Mage.Sets/src/mage/sets/shadowmoor/PutAway.java index e54f35ad639..df636326b3f 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/PutAway.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/PutAway.java @@ -101,7 +101,7 @@ class PutAwayEffect extends OneShotEffect { } if (you != null) { if (card != null - && you.chooseUse(Outcome.Benefit, "Do you wish to shuffle up to one target card from your graveyard into your library?", game) + && you.chooseUse(Outcome.Benefit, "Do you wish to shuffle up to one target card from your graveyard into your library?", source, game) && game.getState().getZone(card.getId()).match(Zone.GRAVEYARD)) { card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); you.shuffleLibrary(game); diff --git a/Mage.Sets/src/mage/sets/shadowmoor/Tyrannize.java b/Mage.Sets/src/mage/sets/shadowmoor/Tyrannize.java index cc9985ed412..12451e7b893 100644 --- a/Mage.Sets/src/mage/sets/shadowmoor/Tyrannize.java +++ b/Mage.Sets/src/mage/sets/shadowmoor/Tyrannize.java @@ -91,7 +91,7 @@ class TyrannizeEffect extends OneShotEffect { if (player != null) { Cost cost = new PayLifeCost(7); if (!cost.canPay(source, source.getSourceId(), player.getId(), game) - || !player.chooseUse(Outcome.LoseLife, "Pay 7 life?", game) + || !player.chooseUse(Outcome.LoseLife, "Pay 7 life?", source, game) || !cost.pay(source, game, source.getSourceId(), player.getId(), false)) { for (Card card : player.getHand().getCards(game)) { player.discard(card, source, game); diff --git a/Mage.Sets/src/mage/sets/shardsofalara/AdNauseam.java b/Mage.Sets/src/mage/sets/shardsofalara/AdNauseam.java index 492703bbd94..80ee8b645bf 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/AdNauseam.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/AdNauseam.java @@ -89,7 +89,7 @@ class AdNauseamEffect extends OneShotEffect { if (controller == null || sourceCard == null) { return false; } - while (controller.chooseUse(outcome, message, game) && controller.getLibrary().size() > 0) { + while (controller.chooseUse(outcome, message, source, game) && controller.getLibrary().size() > 0) { Card card = controller.getLibrary().removeFromTop(game); if (card != null) { controller.moveCardToHandWithInfo(card, source.getSourceId(), game, Zone.LIBRARY); diff --git a/Mage.Sets/src/mage/sets/shardsofalara/BrilliantUltimatum.java b/Mage.Sets/src/mage/sets/shardsofalara/BrilliantUltimatum.java index 590adf790ea..1f7020d8412 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/BrilliantUltimatum.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/BrilliantUltimatum.java @@ -138,7 +138,7 @@ class BrilliantUltimatumEffect extends OneShotEffect { boolean choice = you.choosePile(Outcome.PlayForFree, "Which pile (play for free)?", pileOne, pileTwo, game); if (choice) { game.informPlayer(you, you.getLogName() + " chose Pile 1."); - while (!pileOne.isEmpty() && you.chooseUse(Outcome.PlayForFree, "Do you want to play a card from Pile 1?", game)) { + while (!pileOne.isEmpty() && you.chooseUse(Outcome.PlayForFree, "Do you want to play a card from Pile 1?", source, game)) { TargetCard targetExiledCard = new TargetCard(Zone.EXILED, new FilterCard()); if (you.chooseTarget(Outcome.PlayForFree, pile1, targetExiledCard, source, game)) { Card card = pile1.get(targetExiledCard.getFirstTarget(), game); @@ -157,7 +157,7 @@ class BrilliantUltimatumEffect extends OneShotEffect { } } else { game.informPlayer(you, you.getLogName() + " chose Pile 2."); - while (!pileTwo.isEmpty() && you.chooseUse(Outcome.PlayForFree, "Do you want to play a card from Pile 2?", game)) { + while (!pileTwo.isEmpty() && you.chooseUse(Outcome.PlayForFree, "Do you want to play a card from Pile 2?", source, game)) { TargetCard targetExiledCard = new TargetCard(Zone.EXILED, new FilterCard()); if (you.chooseTarget(Outcome.PlayForFree, pile2, targetExiledCard, source, game)) { Card card = pile2.get(targetExiledCard.getFirstTarget(), game); diff --git a/Mage.Sets/src/mage/sets/shardsofalara/ClarionUltimatum.java b/Mage.Sets/src/mage/sets/shardsofalara/ClarionUltimatum.java index db50b5b57a5..180c48059a7 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/ClarionUltimatum.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/ClarionUltimatum.java @@ -109,7 +109,7 @@ class ClarionUltimatumEffect extends OneShotEffect { StringBuilder sb = new StringBuilder(); sb.append("Search for ").append(cardName).append(" in your library?"); - if (player.chooseUse(Outcome.PutCardInPlay, sb.toString(), game)) { + if (player.chooseUse(Outcome.PutCardInPlay, sb.toString(), source, game)) { FilterCard filter = new FilterCard("card named " + cardName); filter.add(new NamePredicate(cardName)); TargetCardInLibrary target = new TargetCardInLibrary(filter); diff --git a/Mage.Sets/src/mage/sets/shardsofalara/CovenantOfMinds.java b/Mage.Sets/src/mage/sets/shardsofalara/CovenantOfMinds.java index e1f822f5e5e..963bd22a4ff 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/CovenantOfMinds.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/CovenantOfMinds.java @@ -106,7 +106,7 @@ class CovenantOfMindsEffect extends OneShotEffect { sb.append(" If you don't, those cards are put into his graveyard and he will draw five cards."); Zone zone = Zone.GRAVEYARD; - if (opponent.chooseUse(Outcome.Neutral, sb.toString(), game)) { + if (opponent.chooseUse(Outcome.Neutral, sb.toString(), source, game)) { zone = Zone.HAND; } else { player.drawCards(5, game); @@ -118,7 +118,7 @@ class CovenantOfMindsEffect extends OneShotEffect { } else { StringBuilder sb = new StringBuilder(); sb.append(player.getLogName()).append("'s library is empty? Do you want him to draw five cards?"); - if (!opponent.chooseUse(Outcome.Benefit, sb.toString(), game)) { + if (!opponent.chooseUse(Outcome.Benefit, sb.toString(), source, game)) { player.drawCards(5, game); } } diff --git a/Mage.Sets/src/mage/sets/shardsofalara/FlameblastDragon.java b/Mage.Sets/src/mage/sets/shardsofalara/FlameblastDragon.java index 2f8ef49e6fe..4b364427ca4 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/FlameblastDragon.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/FlameblastDragon.java @@ -92,7 +92,7 @@ class FlameblastDragonEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); ManaCosts cost = new ManaCostsImpl("{X}{R}"); if (player != null) { - if (player.chooseUse(Outcome.Damage, "Pay " + cost.getText() + "? If you do, Flameblast Dragon deals X damage to target creature or player", game)) { + if (player.chooseUse(Outcome.Damage, "Pay " + cost.getText() + "? If you do, Flameblast Dragon deals X damage to target creature or player", source, game)) { int costX = player.announceXMana(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source); cost.add(new GenericManaCost(costX)); if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { diff --git a/Mage.Sets/src/mage/sets/shardsofalara/GiftOfTheGargantuan.java b/Mage.Sets/src/mage/sets/shardsofalara/GiftOfTheGargantuan.java index 19a205b9b45..68c2b74275f 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/GiftOfTheGargantuan.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/GiftOfTheGargantuan.java @@ -112,7 +112,7 @@ class GiftOfTheGargantuanEffect extends OneShotEffect { } player.lookAtCards("Gift of the Gargantuan", cards, game); - if ((creatureCardFound || landCardFound) && player.chooseUse(Outcome.DrawCard, "Do you wish to reveal a creature card and/or a land card and put them into your hand?", game)) { + if ((creatureCardFound || landCardFound) && player.chooseUse(Outcome.DrawCard, "Do you wish to reveal a creature card and/or a land card and put them into your hand?", source, game)) { Cards revealedCards = new CardsImpl(); TargetCard target = new TargetCard(Zone.PICK, new FilterCreatureCard("creature card to reveal and put into your hand")); diff --git a/Mage.Sets/src/mage/sets/shardsofalara/PrinceOfThralls.java b/Mage.Sets/src/mage/sets/shardsofalara/PrinceOfThralls.java index 80f01f08aa5..20d8e4118bf 100644 --- a/Mage.Sets/src/mage/sets/shardsofalara/PrinceOfThralls.java +++ b/Mage.Sets/src/mage/sets/shardsofalara/PrinceOfThralls.java @@ -142,7 +142,7 @@ class PrinceOfThrallsEffect extends OneShotEffect { Player opponent = game.getPlayer(permanent.getControllerId()); if (opponent != null && card != null && permanent != null && source.getControllerId() != null) { PayLifeCost cost = new PayLifeCost(3); - if (opponent.chooseUse(Outcome.Neutral, cost.getText() + " or " + permanent.getName() + " comes back into the battlefield under opponents control", game)) { + if (opponent.chooseUse(Outcome.Neutral, cost.getText() + " or " + permanent.getName() + " comes back into the battlefield under opponents control", source, game)) { cost.clearPaid(); if (cost.pay(source, game, source.getSourceId(), opponent.getId(), true)) { return true; diff --git a/Mage.Sets/src/mage/sets/starter1999/GerrardsWisdom.java b/Mage.Sets/src/mage/sets/starter1999/GerrardsWisdom.java index 49ee41b9192..da9dbc57515 100644 --- a/Mage.Sets/src/mage/sets/starter1999/GerrardsWisdom.java +++ b/Mage.Sets/src/mage/sets/starter1999/GerrardsWisdom.java @@ -28,15 +28,12 @@ package mage.sets.starter1999; import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.MultipliedValue; import mage.abilities.dynamicvalue.common.CardsInControllerHandCount; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.GainLifeEffect; import mage.cards.CardImpl; import mage.constants.CardType; import mage.constants.Rarity; -import mage.game.Game; /** * @@ -50,7 +47,8 @@ public class GerrardsWisdom extends CardImpl { this.expansionSetCode = "S99"; // You gain 2 life for each card in your hand. - this.getSpellAbility().addEffect(new GainLifeEffect(new TwiceCardsInControllerHandCount())); + this.getSpellAbility().addEffect(new GainLifeEffect(new MultipliedValue(new CardsInControllerHandCount(), 2), + "You gain 2 life for each card in your hand")); } public GerrardsWisdom(final GerrardsWisdom card) { @@ -62,20 +60,3 @@ public class GerrardsWisdom extends CardImpl { return new GerrardsWisdom(this); } } - -class TwiceCardsInControllerHandCount extends CardsInControllerHandCount { - @Override - public int calculate(Game game, Ability sourceAbility, Effect effect) { - return 2 * super.calculate(game, sourceAbility, effect); - } - - @Override - public DynamicValue copy() { - return new TwiceCardsInControllerHandCount(); - } - - @Override - public String toString() { - return "2"; - } -} diff --git a/Mage.Sets/src/mage/sets/starter1999/Squall.java b/Mage.Sets/src/mage/sets/starter1999/Squall.java new file mode 100644 index 00000000000..9c71e1ce275 --- /dev/null +++ b/Mage.Sets/src/mage/sets/starter1999/Squall.java @@ -0,0 +1,68 @@ +/* + * 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.starter1999; + +import java.util.UUID; +import mage.abilities.effects.common.DamageAllEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AbilityPredicate; + +/** + * + * @author LoneFox + + */ +public class Squall extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with flying"); + + static { + filter.add(new AbilityPredicate(FlyingAbility.class)); + } + + public Squall(UUID ownerId) { + super(ownerId, 143, "Squall", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{2}{G}"); + this.expansionSetCode = "S99"; + + // Squall deals 2 damage to each creature with flying. + this.getSpellAbility().addEffect(new DamageAllEffect(2, filter)); + } + + public Squall(final Squall card) { + super(card); + } + + @Override + public Squall copy() { + return new Squall(this); + } +} diff --git a/Mage.Sets/src/mage/sets/stronghold/CrovaxTheCursed.java b/Mage.Sets/src/mage/sets/stronghold/CrovaxTheCursed.java index 903d9c6f3c8..e52f5a3b318 100644 --- a/Mage.Sets/src/mage/sets/stronghold/CrovaxTheCursed.java +++ b/Mage.Sets/src/mage/sets/stronghold/CrovaxTheCursed.java @@ -111,7 +111,7 @@ class CrovaxTheCursedEffect extends OneShotEffect { if (controller != null) { Permanent sourceObject = (Permanent) source.getSourceObjectIfItStillExists(game); int creatures = game.getBattlefield().countAll(new FilterCreaturePermanent(), source.getControllerId(), game); - if (creatures > 0 && controller.chooseUse(outcome, "Sacrifice a creature?", game)) { + if (creatures > 0 && controller.chooseUse(outcome, "Sacrifice a creature?", source, game)) { if (new SacrificeControllerEffect(new FilterCreaturePermanent(), 1, "").apply(game, source)) { if (sourceObject != null) { sourceObject.getCounters().addCounter(CounterType.P1P1.createInstance()); diff --git a/Mage.Sets/src/mage/sets/stronghold/Heartstone.java b/Mage.Sets/src/mage/sets/stronghold/Heartstone.java new file mode 100644 index 00000000000..e30efda2bc9 --- /dev/null +++ b/Mage.Sets/src/mage/sets/stronghold/Heartstone.java @@ -0,0 +1,118 @@ +/* + * 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.stronghold; + + import java.util.LinkedHashSet; + import java.util.Set; + import java.util.UUID; + import mage.Mana; + import mage.abilities.Ability; + import mage.abilities.common.SimpleStaticAbility; + import mage.abilities.effects.common.cost.CostModificationEffectImpl; + import mage.cards.CardImpl; + import mage.constants.AbilityType; + import mage.constants.CardType; + import mage.constants.CostModificationType; + import mage.constants.Duration; + import mage.constants.Outcome; + import mage.constants.Rarity; + import mage.constants.Zone; + import mage.filter.common.FilterCreaturePermanent; + import mage.game.Game; + import mage.game.permanent.Permanent; + import mage.players.Player; + import mage.util.CardUtil; + +/** + * + * @author pcasaretto_at_gmail.com + */ +public class Heartstone extends CardImpl { + + public Heartstone(UUID ownerId) { + super(ownerId, 128, "Heartstone", Rarity.UNCOMMON, new CardType[]{CardType.ARTIFACT}, "{3}"); + this.expansionSetCode = "STH"; + + // Activated abilities of creatures cost {1} less to activate. This effect can't reduce the amount of mana an ability costs to activate to less than one mana. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new HeartstoneEffect())); + } + + public Heartstone(final Heartstone card) { + super(card); + } + + @Override + public Heartstone copy() { + return new Heartstone(this); + } +} + +class HeartstoneEffect extends CostModificationEffectImpl { + + private static final String effectText = "Activated abilities of creatures cost {1} less to activate. This effect can't reduce the amount of mana an ability costs to activate to less than one mana."; + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); + + public HeartstoneEffect() { + super(Duration.Custom, Outcome.Benefit, CostModificationType.REDUCE_COST); + staticText = effectText; + } + + public HeartstoneEffect(final HeartstoneEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + Player controller = game.getPlayer(abilityToModify.getControllerId()); + if (controller != null){ + Mana mana = abilityToModify.getManaCostsToPay().getMana(); + if (mana.getColorless() > 1){ + CardUtil.reduceCost(abilityToModify, 1); + } + return true; + } + return false; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + if (abilityToModify.getAbilityType().equals(AbilityType.ACTIVATED)) { + // Activated abilities of creatures + Permanent permanent = game.getPermanent(abilityToModify.getSourceId()); + if (permanent != null && filter.match(permanent, source.getSourceId(), source.getControllerId(), game)) { + return true; + } + } + return false; + } + + @Override + public HeartstoneEffect copy() { + return new HeartstoneEffect(this); + } +} diff --git a/Mage.Sets/src/mage/sets/stronghold/MoxDiamond.java b/Mage.Sets/src/mage/sets/stronghold/MoxDiamond.java index 5438cfc2f5f..2f0a268e56c 100644 --- a/Mage.Sets/src/mage/sets/stronghold/MoxDiamond.java +++ b/Mage.Sets/src/mage/sets/stronghold/MoxDiamond.java @@ -102,7 +102,7 @@ class MoxDiamondReplacementEffect extends ReplacementEffectImpl { TargetCardInHand target = new TargetCardInHand(new FilterLandCard()); Cost cost = new DiscardTargetCost(target); if (cost.canPay(source, source.getSourceId(), source.getControllerId(), game) && - player.chooseUse(outcome, "Discard land? (Otherwise Mox Diamond goes to graveyard)", game) && + player.chooseUse(outcome, "Discard land? (Otherwise Mox Diamond goes to graveyard)", source, game) && player.chooseTarget(Outcome.Discard, target, source, game)){ player.discard(game.getCard(target.getFirstTarget()), source, game); return false; diff --git a/Mage.Sets/src/mage/sets/tempest/BellowingFiend.java b/Mage.Sets/src/mage/sets/tempest/BellowingFiend.java new file mode 100644 index 00000000000..f0d35ca574b --- /dev/null +++ b/Mage.Sets/src/mage/sets/tempest/BellowingFiend.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.sets.tempest; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DealsDamageToACreatureTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageControllerEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author LoneFox + + */ +public class BellowingFiend extends CardImpl { + + public BellowingFiend(UUID ownerId) { + super(ownerId, 2, "Bellowing Fiend", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{4}{B}"); + this.expansionSetCode = "TMP"; + this.subtype.add("Spirit"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + // Whenever Bellowing Fiend deals damage to a creature, Bellowing Fiend deals 3 damage to that creature's controller and 3 damage to you. + Ability ability = new DealsDamageToACreatureTriggeredAbility(new BellowingFiendEffect(), false, false, true); + Effect effect = new DamageControllerEffect(3); + effect.setText("and 3 damage to you"); + ability.addEffect(effect); + this.addAbility(ability); + } + + public BellowingFiend(final BellowingFiend card) { + super(card); + } + + @Override + public BellowingFiend copy() { + return new BellowingFiend(this); + } +} + +class BellowingFiendEffect extends OneShotEffect { + + public BellowingFiendEffect() { + super(Outcome.Detriment); + this.staticText = "{this} deals 3 damage to that creature's controller"; } + + public BellowingFiendEffect(final BellowingFiendEffect effect) { + super(effect); + } + + @Override + public BellowingFiendEffect copy() { + return new BellowingFiendEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + boolean applied = false; + Permanent damagedCreature = game.getPermanentOrLKIBattlefield(targetPointer.getFirst(game, source)); + if(damagedCreature != null) { + Player controller = game.getPlayer(damagedCreature.getControllerId()); + if(controller != null) { + controller.damage(3, source.getSourceId(), game, false, true); applied = true; + } + } + return applied; + } +} diff --git a/Mage.Sets/src/mage/sets/tempest/DreamCache.java b/Mage.Sets/src/mage/sets/tempest/DreamCache.java index 3a3c54336cd..6d223175be0 100644 --- a/Mage.Sets/src/mage/sets/tempest/DreamCache.java +++ b/Mage.Sets/src/mage/sets/tempest/DreamCache.java @@ -87,7 +87,7 @@ class DreamCacheEffect extends OneShotEffect { if (player != null) { player.drawCards(3, game); - boolean putOnTop = player.chooseUse(Outcome.Neutral, "Put cards on top?", game); + boolean putOnTop = player.chooseUse(Outcome.Neutral, "Put cards on top?", source, game); putInLibrary(player, source, game, putOnTop); putInLibrary(player, source, game, putOnTop); diff --git a/Mage.Sets/src/mage/sets/tempest/Lobotomy.java b/Mage.Sets/src/mage/sets/tempest/Lobotomy.java index 039f4ec7194..38c80b50163 100644 --- a/Mage.Sets/src/mage/sets/tempest/Lobotomy.java +++ b/Mage.Sets/src/mage/sets/tempest/Lobotomy.java @@ -141,7 +141,7 @@ class LobotomyEffect extends OneShotEffect { // search cards in Library // If the player has no nonland cards in his or her hand, you can still search that player's library and have him or her shuffle it. - if (chosenCard != null || controller.chooseUse(outcome, "Search library anyway?", game)) { + if (chosenCard != null || controller.chooseUse(outcome, "Search library anyway?", source, game)) { TargetCardInLibrary targetCardsLibrary = new TargetCardInLibrary(0, Integer.MAX_VALUE, filterNamedCards); controller.searchLibrary(targetCardsLibrary, game, targetPlayer.getId()); for(UUID cardId: targetCardsLibrary.getTargets()) { diff --git a/Mage.Sets/src/mage/sets/tempest/Magmasaur.java b/Mage.Sets/src/mage/sets/tempest/Magmasaur.java index 74139e6e266..c305535b675 100644 --- a/Mage.Sets/src/mage/sets/tempest/Magmasaur.java +++ b/Mage.Sets/src/mage/sets/tempest/Magmasaur.java @@ -109,7 +109,7 @@ class MagmasaurEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); Permanent sourceObject = (Permanent)source.getSourceObjectIfItStillExists(game); if (sourceObject != null && controller != null) { - if (controller.chooseUse(outcome, "Remove a +1/+1 counter from " + sourceObject.getLogName() + "?", game)) { + if (controller.chooseUse(outcome, "Remove a +1/+1 counter from " + sourceObject.getLogName() + "?", source, game)) { sourceObject.getCounters().removeCounter(CounterType.P1P1, 1); } else { int counters = sourceObject.getCounters().getCount(CounterType.P1P1); diff --git a/Mage.Sets/src/mage/sets/tempest/NaturesRevolt.java b/Mage.Sets/src/mage/sets/tempest/NaturesRevolt.java new file mode 100644 index 00000000000..e8fe7c2f6de --- /dev/null +++ b/Mage.Sets/src/mage/sets/tempest/NaturesRevolt.java @@ -0,0 +1,53 @@ +/* + * 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.tempest; + +import java.util.UUID; + +/** + * + * @author LoneFox + + */ +public class NaturesRevolt extends mage.sets.seventhedition.NaturesRevolt { + + public NaturesRevolt(UUID ownerId) { + super(ownerId); + this.cardNumber = 134; + this.expansionSetCode = "TMP"; + } + + public NaturesRevolt(final NaturesRevolt card) { + super(card); + } + + @Override + public NaturesRevolt copy() { + return new NaturesRevolt(this); + } +} diff --git a/Mage.Sets/src/mage/sets/tempest/Propaganda.java b/Mage.Sets/src/mage/sets/tempest/Propaganda.java index d366094f9b7..e4f36fd168f 100644 --- a/Mage.Sets/src/mage/sets/tempest/Propaganda.java +++ b/Mage.Sets/src/mage/sets/tempest/Propaganda.java @@ -25,21 +25,19 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.sets.tempest; import java.util.UUID; - -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Rarity; -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.ReplacementEffectImpl; import mage.cards.CardImpl; +import mage.constants.CardType; import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Rarity; +import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.players.Player; @@ -50,14 +48,14 @@ import mage.players.Player; */ public class Propaganda extends CardImpl { - public Propaganda (UUID ownerId) { + public Propaganda(UUID ownerId) { super(ownerId, 80, "Propaganda", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); this.expansionSetCode = "TMP"; this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PropagandaReplacementEffect())); } - public Propaganda (final Propaganda card) { + public Propaganda(final Propaganda card) { super(card); } @@ -71,12 +69,12 @@ class PropagandaReplacementEffect extends ReplacementEffectImpl { private static final String effectText = "Creatures can't attack you unless their controller pays {2} for each creature he or she controls that's attacking you"; - PropagandaReplacementEffect ( ) { + PropagandaReplacementEffect() { super(Duration.WhileOnBattlefield, Outcome.Neutral); staticText = effectText; } - PropagandaReplacementEffect ( PropagandaReplacementEffect effect ) { + PropagandaReplacementEffect(PropagandaReplacementEffect effect) { super(effect); } @@ -100,12 +98,11 @@ class PropagandaReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Player player = game.getPlayer(event.getPlayerId()); - if ( player != null ) { + if (player != null) { ManaCostsImpl attackTax = new ManaCostsImpl("{2}"); - if ( attackTax.canPay(source, source.getSourceId(), event.getPlayerId(), game) && - player.chooseUse(Outcome.Neutral, "Pay {2} to attack player?", game) ) - { - if (attackTax.payOrRollback(source, game, source.getSourceId(), event.getPlayerId()) ) { + if (attackTax.canPay(source, source.getSourceId(), event.getPlayerId(), game) + && player.chooseUse(Outcome.Neutral, "Pay {2} to attack player?", source, game)) { + if (attackTax.payOrRollback(source, game, source.getSourceId(), event.getPlayerId())) { return false; } } @@ -113,7 +110,7 @@ class PropagandaReplacementEffect extends ReplacementEffectImpl { } return false; } - + @Override public PropagandaReplacementEffect copy() { return new PropagandaReplacementEffect(this); diff --git a/Mage.Sets/src/mage/sets/tempest/VhatiIlDal.java b/Mage.Sets/src/mage/sets/tempest/VhatiIlDal.java index 9e5aa3941e4..5eaf3bb9689 100644 --- a/Mage.Sets/src/mage/sets/tempest/VhatiIlDal.java +++ b/Mage.Sets/src/mage/sets/tempest/VhatiIlDal.java @@ -100,7 +100,7 @@ class VhatiIlDalEffect extends OneShotEffect { if (controller != null) { DynamicValue power = null; DynamicValue toughness = null; - if (controller.chooseUse(outcome, "Set power? (otherwise toughness is set)", game)) { + if (controller.chooseUse(outcome, "Set power? (otherwise toughness is set)", source, game)) { power = new StaticValue(1); } else { toughness = new StaticValue(1); diff --git a/Mage.Sets/src/mage/sets/tempestremastered/Cannibalize.java b/Mage.Sets/src/mage/sets/tempestremastered/Cannibalize.java index 6a4df481c13..937f4e74306 100644 --- a/Mage.Sets/src/mage/sets/tempestremastered/Cannibalize.java +++ b/Mage.Sets/src/mage/sets/tempestremastered/Cannibalize.java @@ -103,7 +103,7 @@ class CannibalizeEffect extends OneShotEffect { for(UUID targetId: getTargetPointer().getTargets(game, source)) { Permanent creature = game.getPermanent(targetId); if (creature != null) { - if ((count == 0 && controller.chooseUse(Outcome.Exile, "Exile " + creature.getLogName() +"?", game)) + if ((count == 0 && controller.chooseUse(Outcome.Exile, "Exile " + creature.getLogName() +"?", source, game)) || (count == 1 && !exileDone)) { controller.moveCardToExileWithInfo(creature, null, "", source.getSourceId(), game, Zone.BATTLEFIELD, true); exileDone = true; diff --git a/Mage.Sets/src/mage/sets/tenthedition/Abundance.java b/Mage.Sets/src/mage/sets/tenthedition/Abundance.java index d81ea8fd0ad..767dceb20f1 100644 --- a/Mage.Sets/src/mage/sets/tenthedition/Abundance.java +++ b/Mage.Sets/src/mage/sets/tenthedition/Abundance.java @@ -97,7 +97,7 @@ class AbundanceReplacementEffect extends ReplacementEffectImpl { Player player = game.getPlayer(event.getPlayerId()); if (player != null) { FilterCard filter = new FilterCard(); - if (player.chooseUse(Outcome.Benefit, "Choose land? (No = nonland)", game)) { + if (player.chooseUse(Outcome.Benefit, "Choose land? (No = nonland)", source, game)) { filter.add(new CardTypePredicate(CardType.LAND)); } else { @@ -128,7 +128,7 @@ class AbundanceReplacementEffect extends ReplacementEffectImpl { if (event.getPlayerId().equals(source.getControllerId())) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - return player.chooseUse(Outcome.Benefit, "Choose land or nonland?", game); + return player.chooseUse(Outcome.Benefit, "Choose land or nonland?", source, game); } } return false; diff --git a/Mage.Sets/src/mage/sets/tenthedition/WindbornMuse.java b/Mage.Sets/src/mage/sets/tenthedition/WindbornMuse.java index d028b292dd1..e1d70ddfef0 100644 --- a/Mage.Sets/src/mage/sets/tenthedition/WindbornMuse.java +++ b/Mage.Sets/src/mage/sets/tenthedition/WindbornMuse.java @@ -107,7 +107,7 @@ class WindbornMuseReplacementEffect extends ReplacementEffectImpl { if ( player != null && event.getTargetId().equals(source.getControllerId())) { ManaCostsImpl attackTax = new ManaCostsImpl("{2}"); if ( attackTax.canPay(source, source.getSourceId(), event.getPlayerId(), game) && - player.chooseUse(Outcome.Benefit, "Pay {2} to attack player?", game) ) + player.chooseUse(Outcome.Benefit, "Pay {2} to attack player?", source, game) ) { if (attackTax.payOrRollback(source, game, this.getId(), event.getPlayerId())) { return false; diff --git a/Mage.Sets/src/mage/sets/thedark/Exorcist.java b/Mage.Sets/src/mage/sets/thedark/Exorcist.java new file mode 100644 index 00000000000..0e79d4a60c2 --- /dev/null +++ b/Mage.Sets/src/mage/sets/thedark/Exorcist.java @@ -0,0 +1,54 @@ +/* + * 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.thedark; + +import java.util.UUID; +import mage.constants.Rarity; + +/** + * + * @author ilcartographer + */ +public class Exorcist extends mage.sets.masterseditioniii.Exorcist { + + public Exorcist(UUID ownerId) { + super(ownerId); + this.cardNumber = 79; + this.expansionSetCode = "DRK"; + this.rarity = Rarity.RARE; + } + + public Exorcist(final Exorcist card) { + super(card); + } + + @Override + public Exorcist copy() { + return new Exorcist(this); + } +} diff --git a/Mage.Sets/src/mage/sets/theros/PsychicIntrusion.java b/Mage.Sets/src/mage/sets/theros/PsychicIntrusion.java index d2ae49b8cc4..31c62eccfc8 100644 --- a/Mage.Sets/src/mage/sets/theros/PsychicIntrusion.java +++ b/Mage.Sets/src/mage/sets/theros/PsychicIntrusion.java @@ -108,7 +108,7 @@ class PsychicIntrusionExileEffect extends OneShotEffect { int cardsHand = opponent.getHand().count(filter, game); boolean fromHand = false; if (cardsGraveyard > 0 && cardsHand > 0) { - if (controller.chooseUse(Outcome.Detriment, "Exile card from opponents Hand?", game)) { + if (controller.chooseUse(Outcome.Detriment, "Exile card from opponents Hand?", source, game)) { fromHand = true; } } else { diff --git a/Mage.Sets/src/mage/sets/timespiral/Hypergenesis.java b/Mage.Sets/src/mage/sets/timespiral/Hypergenesis.java index 1a3d5084ec5..eb88827dd9e 100644 --- a/Mage.Sets/src/mage/sets/timespiral/Hypergenesis.java +++ b/Mage.Sets/src/mage/sets/timespiral/Hypergenesis.java @@ -116,7 +116,7 @@ class HypergenesisEffect extends OneShotEffect { } target.clearChosen(); if (target.canChoose(source.getSourceId(), currentPlayer.getId(), game) - && currentPlayer.chooseUse(outcome, "Put card from your hand to play?", game)) { + && currentPlayer.chooseUse(outcome, "Put card from your hand to play?", source, game)) { if (target.chooseTarget(outcome, currentPlayer.getId(), source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/timespiral/PardicDragon.java b/Mage.Sets/src/mage/sets/timespiral/PardicDragon.java index db3e13a78ac..4e02dcd6849 100644 --- a/Mage.Sets/src/mage/sets/timespiral/PardicDragon.java +++ b/Mage.Sets/src/mage/sets/timespiral/PardicDragon.java @@ -114,7 +114,7 @@ class PardicDragonEffect extends OneShotEffect { Player opponent = game.getPlayer(getTargetPointer().getFirst(game, source)); Card sourceCard = game.getCard(source.getSourceId()); if (opponent != null && sourceCard != null) { - if (opponent.chooseUse(outcome, new StringBuilder("Put a time counter on ").append(sourceCard.getName()).append("?").toString(), game)) { + if (opponent.chooseUse(outcome, new StringBuilder("Put a time counter on ").append(sourceCard.getName()).append("?").toString(), source, game)) { sourceCard.addCounters(CounterType.TIME.createInstance(), game); } return true; diff --git a/Mage.Sets/src/mage/sets/unlimitededition/TimeVault.java b/Mage.Sets/src/mage/sets/unlimitededition/TimeVault.java index f81de7e109d..422b4c06183 100644 --- a/Mage.Sets/src/mage/sets/unlimitededition/TimeVault.java +++ b/Mage.Sets/src/mage/sets/unlimitededition/TimeVault.java @@ -119,7 +119,7 @@ class TimeVaultReplacementEffect extends ReplacementEffectImpl { Player player = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(source.getSourceId()); if (player != null && permanent != null) { - if (player.chooseUse(Outcome.Untap, "Skip your turn to untap " + permanent.getName() + "?", game)) { + if (player.chooseUse(Outcome.Untap, "Skip your turn to untap " + permanent.getName() + "?", source, game)) { permanent.untap(game); game.informPlayers(player.getLogName() + " skips his or her turn to untap " + permanent.getLogName()); return true; diff --git a/Mage.Sets/src/mage/sets/urzasdestiny/Caltrops.java b/Mage.Sets/src/mage/sets/urzasdestiny/Caltrops.java new file mode 100644 index 00000000000..4feb59ccfc9 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzasdestiny/Caltrops.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.urzasdestiny; + +import java.util.UUID; +import mage.abilities.common.AttacksAllTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.SetTargetPointer; +import mage.filter.common.FilterCreaturePermanent; + +/** + * + * @author LoneFox + + */ +public class Caltrops extends CardImpl { + + public Caltrops(UUID ownerId) { + super(ownerId, 129, "Caltrops", Rarity.UNCOMMON, new CardType[]{CardType.ARTIFACT}, "{3}"); + this.expansionSetCode = "UDS"; + + // Whenever a creature attacks, Caltrops deals 1 damage to it. + Effect effect = new DamageTargetEffect(1); + effect.setText("{this} deals 1 damage to it"); + this.addAbility(new AttacksAllTriggeredAbility(effect, false, new FilterCreaturePermanent(), + SetTargetPointer.PERMANENT, false)); + } + + public Caltrops(final Caltrops card) { + super(card); + } + + @Override + public Caltrops copy() { + return new Caltrops(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzasdestiny/Impatience.java b/Mage.Sets/src/mage/sets/urzasdestiny/Impatience.java new file mode 100644 index 00000000000..0726bf975e6 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzasdestiny/Impatience.java @@ -0,0 +1,53 @@ +/* + * 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.urzasdestiny; + +import java.util.UUID; + +/** + * + * @author LoneFox + + */ +public class Impatience extends mage.sets.seventhedition.Impatience { + + public Impatience(UUID ownerId) { + super(ownerId); + this.cardNumber = 88; + this.expansionSetCode = "UDS"; + } + + public Impatience(final Impatience card) { + super(card); + } + + @Override + public Impatience copy() { + return new Impatience(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzasdestiny/TelepathicSpies.java b/Mage.Sets/src/mage/sets/urzasdestiny/TelepathicSpies.java new file mode 100644 index 00000000000..02ccd3465b6 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzasdestiny/TelepathicSpies.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.urzasdestiny; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.LookAtTargetPlayerHandEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.target.common.TargetOpponent; + +/** + * + * @author LoneFox + + */ +public class TelepathicSpies extends CardImpl { + + public TelepathicSpies(UUID ownerId) { + super(ownerId, 47, "Telepathic Spies", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{U}"); + this.expansionSetCode = "UDS"; + this.subtype.add("Human"); + this.subtype.add("Wizard"); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When Telepathic Spies enters the battlefield, look at target opponent's hand. + Ability ability = new EntersBattlefieldTriggeredAbility(new LookAtTargetPlayerHandEffect(), false); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + } + + public TelepathicSpies(final TelepathicSpies card) { + super(card); + } + + @Override + public TelepathicSpies copy() { + return new TelepathicSpies(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzaslegacy/SlowMotion.java b/Mage.Sets/src/mage/sets/urzaslegacy/SlowMotion.java index 0f98a4ef562..ffe52f22517 100644 --- a/Mage.Sets/src/mage/sets/urzaslegacy/SlowMotion.java +++ b/Mage.Sets/src/mage/sets/urzaslegacy/SlowMotion.java @@ -106,7 +106,7 @@ class SacrificeEquipedUnlessPaysEffect extends OneShotEffect { Permanent equipped = game.getPermanent(equipment.getAttachedTo()); Player player = game.getPlayer(equipped.getControllerId()); if (player != null && equipped != null) { - if (player.chooseUse(Outcome.Benefit, "Pay " + cost.getText() + "? (Or " + equipped.getName() + " will be sacrificed.)", game)) { + if (player.chooseUse(Outcome.Benefit, "Pay " + cost.getText() + "? (Or " + equipped.getName() + " will be sacrificed.)", source, game)) { cost.clearPaid(); if (cost.pay(source, game, source.getSourceId(), equipped.getControllerId(), false)) { return true; diff --git a/Mage.Sets/src/mage/sets/urzassaga/Catastrophe.java b/Mage.Sets/src/mage/sets/urzassaga/Catastrophe.java index 517a6bfbb0a..9e247516099 100644 --- a/Mage.Sets/src/mage/sets/urzassaga/Catastrophe.java +++ b/Mage.Sets/src/mage/sets/urzassaga/Catastrophe.java @@ -85,7 +85,7 @@ class CatastropheEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - if (controller.chooseUse(outcome, "Destroy all lands? (otherwise all creatures are destroyed)", game)) { + if (controller.chooseUse(outcome, "Destroy all lands? (otherwise all creatures are destroyed)", source, game)) { for (Permanent permanent: game.getBattlefield().getActivePermanents(new FilterLandPermanent(), controller.getId(), source.getSourceId(), game)) { permanent.destroy(source.getSourceId(), game, permanent.getCardType().contains(CardType.CREATURE)); } diff --git a/Mage.Sets/src/mage/sets/urzassaga/CopperGnomes.java b/Mage.Sets/src/mage/sets/urzassaga/CopperGnomes.java index f9a351faed8..2971de2eda7 100644 --- a/Mage.Sets/src/mage/sets/urzassaga/CopperGnomes.java +++ b/Mage.Sets/src/mage/sets/urzassaga/CopperGnomes.java @@ -95,7 +95,7 @@ class PutArtifactOnBattlefieldEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (player == null || !player.chooseUse(Outcome.PutCardInPlay, choiceText, game)) { + if (player == null || !player.chooseUse(Outcome.PutCardInPlay, choiceText, source, game)) { return false; } diff --git a/Mage.Sets/src/mage/sets/urzassaga/Disorder.java b/Mage.Sets/src/mage/sets/urzassaga/Disorder.java new file mode 100644 index 00000000000..61244e35869 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/Disorder.java @@ -0,0 +1,53 @@ +/* + * 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.urzassaga; + +import java.util.UUID; + +/** + * + * @author LoneFox + + */ +public class Disorder extends mage.sets.seventhedition.Disorder { + + public Disorder(UUID ownerId) { + super(ownerId); + this.cardNumber = 181; + this.expansionSetCode = "USG"; + } + + public Disorder(final Disorder card) { + super(card); + } + + @Override + public Disorder copy() { + return new Disorder(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzassaga/Fecundity.java b/Mage.Sets/src/mage/sets/urzassaga/Fecundity.java index 488fa3ab478..f5d5f959177 100644 --- a/Mage.Sets/src/mage/sets/urzassaga/Fecundity.java +++ b/Mage.Sets/src/mage/sets/urzassaga/Fecundity.java @@ -86,7 +86,7 @@ class FecundityEffect extends OneShotEffect { if (permanent != null) { Player controller = game.getPlayer(permanent.getControllerId()); if (controller != null) { - if (controller.chooseUse(outcome, "Draw a card?", game)) { + if (controller.chooseUse(outcome, "Draw a card?", source, game)) { controller.drawCards(1, game); } return true; diff --git a/Mage.Sets/src/mage/sets/urzassaga/GraftedSkullcap.java b/Mage.Sets/src/mage/sets/urzassaga/GraftedSkullcap.java new file mode 100644 index 00000000000..9ee7a370fe8 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/GraftedSkullcap.java @@ -0,0 +1,67 @@ +/* + * 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.urzassaga; + +import java.util.UUID; +import mage.abilities.common.BeginningOfDrawTriggeredAbility; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.discard.DiscardHandControllerEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.TargetController; + +/** + * + * @author LoneFox + + */ +public class GraftedSkullcap extends CardImpl { + + public GraftedSkullcap(UUID ownerId) { + super(ownerId, 296, "Grafted Skullcap", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{4}"); + this.expansionSetCode = "USG"; + + // At the beginning of your draw step, draw an additional card. + this.addAbility(new BeginningOfDrawTriggeredAbility(new DrawCardSourceControllerEffect(1), + TargetController.YOU, false)); + // At the beginning of your end step, discard your hand. + this.addAbility(new BeginningOfEndStepTriggeredAbility(new DiscardHandControllerEffect(), + TargetController.YOU, false)); + } + + public GraftedSkullcap(final GraftedSkullcap card) { + super(card); + } + + @Override + public GraftedSkullcap copy() { + return new GraftedSkullcap(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzassaga/Reprocess.java b/Mage.Sets/src/mage/sets/urzassaga/Reprocess.java new file mode 100644 index 00000000000..b2f8b0a7abc --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/Reprocess.java @@ -0,0 +1,53 @@ +/* + * 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.urzassaga; + +import java.util.UUID; + +/** + * + * @author LoneFox + + */ +public class Reprocess extends mage.sets.seventhedition.Reprocess { + + public Reprocess(UUID ownerId) { + super(ownerId); + this.cardNumber = 154; + this.expansionSetCode = "USG"; + } + + public Reprocess(final Reprocess card) { + super(card); + } + + @Override + public Reprocess copy() { + return new Reprocess(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzassaga/ShowAndTell.java b/Mage.Sets/src/mage/sets/urzassaga/ShowAndTell.java index b347b38e6a6..21b6a651688 100644 --- a/Mage.Sets/src/mage/sets/urzassaga/ShowAndTell.java +++ b/Mage.Sets/src/mage/sets/urzassaga/ShowAndTell.java @@ -109,7 +109,7 @@ class ShowAndTellEffect extends OneShotEffect { for(UUID playerId: game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { - if (player.chooseUse(outcome, "Put an artifact, creature, enchantment, or land card from hand onto the battlefield?", game)) { + if (player.chooseUse(outcome, "Put an artifact, creature, enchantment, or land card from hand onto the battlefield?", source, game)) { target.clearChosen(); if (player.chooseTarget(outcome, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/sets/urzassaga/SneakAttack.java b/Mage.Sets/src/mage/sets/urzassaga/SneakAttack.java index c06fc177a5a..1b447cb9f41 100644 --- a/Mage.Sets/src/mage/sets/urzassaga/SneakAttack.java +++ b/Mage.Sets/src/mage/sets/urzassaga/SneakAttack.java @@ -99,7 +99,7 @@ class SneakAttackEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - if (player.chooseUse(Outcome.PutCreatureInPlay, choiceText, game)) { + if (player.chooseUse(Outcome.PutCreatureInPlay, choiceText, source, game)) { TargetCardInHand target = new TargetCardInHand(new FilterCreatureCard()); if (player.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { Card card = game.getCard(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/sets/urzassaga/TaintedAEther.java b/Mage.Sets/src/mage/sets/urzassaga/TaintedAEther.java new file mode 100644 index 00000000000..24a7e00144b --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/TaintedAEther.java @@ -0,0 +1,74 @@ +/* + * 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.urzassaga; + +import java.util.UUID; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.effects.common.SacrificeEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.Zone; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.constants.SetTargetPointer; + +/** + * + * @author LoneFox + + */ +public class TaintedAEther extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("a creature or a land"); + + static { + filter.add(Predicates.or(new CardTypePredicate(CardType.CREATURE), new CardTypePredicate(CardType.LAND))); + } + + public TaintedAEther(UUID ownerId) { + super(ownerId, 161, "Tainted AEther", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}"); + this.expansionSetCode = "USG"; + + // Whenever a creature enters the battlefield, its controller sacrifices a creature or land. + this.addAbility(new EntersBattlefieldAllTriggeredAbility(Zone.BATTLEFIELD, new SacrificeEffect(filter, 1, ""), + new FilterCreaturePermanent(), false, SetTargetPointer.PLAYER, + "Whenever a creature enters the battlefield, its controller sacrifices a creature or land")); + } + + public TaintedAEther(final TaintedAEther card) { + super(card); + } + + @Override + public TaintedAEther copy() { + return new TaintedAEther(this); + } +} diff --git a/Mage.Sets/src/mage/sets/urzassaga/YawgmothsEdict.java b/Mage.Sets/src/mage/sets/urzassaga/YawgmothsEdict.java new file mode 100644 index 00000000000..1eb35468b89 --- /dev/null +++ b/Mage.Sets/src/mage/sets/urzassaga/YawgmothsEdict.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.urzassaga; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SpellCastOpponentTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.cards.CardImpl; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.SetTargetPointer; +import mage.constants.Zone; +import mage.filter.FilterSpell; +import mage.filter.predicate.mageobject.ColorPredicate; + +/** + * + * @author LoneFox + + */ +public class YawgmothsEdict extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("a white spell"); + + static { + filter.add(new ColorPredicate(ObjectColor.WHITE)); + } + + + public YawgmothsEdict(UUID ownerId) { + super(ownerId, 170, "Yawgmoth's Edict", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}"); + this.expansionSetCode = "USG"; + + // Whenever an opponent casts a white spell, that player loses 1 life and you gain 1 life. + Ability ability = new SpellCastOpponentTriggeredAbility(Zone.BATTLEFIELD, new LoseLifeTargetEffect(1), + filter, false, SetTargetPointer.PLAYER); + Effect effect = new GainLifeEffect(1); + effect.setText("and you gain 1 life"); + ability.addEffect(effect); + this.addAbility(ability); + } + + public YawgmothsEdict(final YawgmothsEdict card) { + super(card); + } + + @Override + public YawgmothsEdict copy() { + return new YawgmothsEdict(this); + } +} diff --git a/Mage.Sets/src/mage/sets/vintagemasters/Eureka.java b/Mage.Sets/src/mage/sets/vintagemasters/Eureka.java index 6d6d850e44e..1900a95d1fe 100644 --- a/Mage.Sets/src/mage/sets/vintagemasters/Eureka.java +++ b/Mage.Sets/src/mage/sets/vintagemasters/Eureka.java @@ -104,7 +104,7 @@ class EurekaEffect extends OneShotEffect { target.clearChosen(); if (target.canChoose(source.getSourceId(), currentPlayer.getId(), game) - && currentPlayer.chooseUse(outcome, "Put permanent from your hand to play?", game)) { + && currentPlayer.chooseUse(outcome, "Put permanent from your hand to play?", source, game)) { if (target.chooseTarget(outcome, currentPlayer.getId(), source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/vintagemasters/MarchesaTheBlackRose.java b/Mage.Sets/src/mage/sets/vintagemasters/MarchesaTheBlackRose.java index ad1d7340d19..d8b586092a9 100644 --- a/Mage.Sets/src/mage/sets/vintagemasters/MarchesaTheBlackRose.java +++ b/Mage.Sets/src/mage/sets/vintagemasters/MarchesaTheBlackRose.java @@ -73,7 +73,7 @@ public class MarchesaTheBlackRose extends CardImpl { // Dethrone this.addAbility(new DethroneAbility()); - + // Other creatures you control have dethrone. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(new DethroneAbility(), Duration.WhileOnBattlefield, new FilterCreaturePermanent(), true))); @@ -118,11 +118,11 @@ class MarchesaTheBlackRoseTriggeredAbility extends TriggeredAbilityImpl { if (((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD && ((ZoneChangeEvent) event).getFromZone() == Zone.BATTLEFIELD) { Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); - if (permanent != null && - permanent.getControllerId().equals(this.getControllerId()) + if (permanent != null + && permanent.getControllerId().equals(this.getControllerId()) && permanent.getCardType().contains(CardType.CREATURE) && permanent.getCounters().getCount(CounterType.P1P1) > 0) { - for (Effect effect: this.getEffects()) { + for (Effect effect : this.getEffects()) { effect.setTargetPointer(new FixedTarget(permanent.getId())); } return true; @@ -155,7 +155,7 @@ class MarchesaTheBlackRoseEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Card card = game.getCard(this.getTargetPointer().getFirst(game, source)); + Card card = game.getCard(getTargetPointer().getFirst(game, source)); if (card != null) { Effect effect = new ReturnToBattlefieldUnderYourControlTargetEffect(); effect.setText("return that card to the battlefield under your control at the beginning of the next end step"); @@ -163,7 +163,7 @@ class MarchesaTheBlackRoseEffect extends OneShotEffect { delayedAbility.setSourceId(source.getSourceId()); delayedAbility.setControllerId(source.getControllerId()); delayedAbility.setSourceObject(source.getSourceObject(game), game); - delayedAbility.getEffects().get(0).setTargetPointer(new FixedTarget(card.getId())); + delayedAbility.getEffects().get(0).setTargetPointer(getTargetPointer()); game.addDelayedTriggeredAbility(delayedAbility); return true; } diff --git a/Mage.Sets/src/mage/sets/vintagemasters/NorwoodPriestess.java b/Mage.Sets/src/mage/sets/vintagemasters/NorwoodPriestess.java index 0c0e924ea3d..423afe9b1c1 100644 --- a/Mage.Sets/src/mage/sets/vintagemasters/NorwoodPriestess.java +++ b/Mage.Sets/src/mage/sets/vintagemasters/NorwoodPriestess.java @@ -104,7 +104,7 @@ class NorwoodPriestessEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (player == null || !player.chooseUse(Outcome.PutCreatureInPlay, choiceText, game)) { + if (player == null || !player.chooseUse(Outcome.PutCreatureInPlay, choiceText, source, game)) { return false; } diff --git a/Mage.Sets/src/mage/sets/vintagemasters/PleaForPower.java b/Mage.Sets/src/mage/sets/vintagemasters/PleaForPower.java index 1561a1a2ffb..76d1b0032a0 100644 --- a/Mage.Sets/src/mage/sets/vintagemasters/PleaForPower.java +++ b/Mage.Sets/src/mage/sets/vintagemasters/PleaForPower.java @@ -87,7 +87,7 @@ class PleaForPowerEffect extends OneShotEffect { for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { - if (player.chooseUse(Outcome.ExtraTurn, "Choose time?", game)) { + if (player.chooseUse(Outcome.ExtraTurn, "Choose time?", source, game)) { timeCount++; game.informPlayers(player.getLogName() + " has chosen: time"); } else { diff --git a/Mage.Sets/src/mage/sets/visions/ElephantGrass.java b/Mage.Sets/src/mage/sets/visions/ElephantGrass.java index bbbe371753c..2c10185b733 100644 --- a/Mage.Sets/src/mage/sets/visions/ElephantGrass.java +++ b/Mage.Sets/src/mage/sets/visions/ElephantGrass.java @@ -126,7 +126,7 @@ class ElephantGrassReplacementEffect2 extends ReplacementEffectImpl { if ( player != null && event.getTargetId().equals(source.getControllerId())) { ManaCostsImpl attackCost = new ManaCostsImpl("{2}"); if ( attackCost.canPay(source, source.getSourceId(), event.getPlayerId(), game) && - player.chooseUse(Outcome.Benefit, "Pay {2} to attack player?", game) ) { + player.chooseUse(Outcome.Benefit, "Pay {2} to attack player?", source, game) ) { if (attackCost.payOrRollback(source, game, this.getId(), event.getPlayerId())) { return false; } diff --git a/Mage.Sets/src/mage/sets/visions/PhyrexianMarauder.java b/Mage.Sets/src/mage/sets/visions/PhyrexianMarauder.java index 0fa81436008..6d13d24901d 100644 --- a/Mage.Sets/src/mage/sets/visions/PhyrexianMarauder.java +++ b/Mage.Sets/src/mage/sets/visions/PhyrexianMarauder.java @@ -141,7 +141,7 @@ class PhyrexianMarauderPayEffect extends ReplacementEffectImpl { } ManaCostsImpl attackTax = new ManaCostsImpl<>("{" + xValue + "}"); if (attackTax.canPay(source, source.getSourceId(), event.getPlayerId(), game) - && player.chooseUse(Outcome.Neutral, chooseText, game)) { + && player.chooseUse(Outcome.Neutral, chooseText, source, game)) { if (attackTax.payOrRollback(source, game, source.getSourceId(), event.getPlayerId())) { return false; } diff --git a/Mage.Sets/src/mage/sets/visions/WandOfDenial.java b/Mage.Sets/src/mage/sets/visions/WandOfDenial.java index 1ccd7901d5f..d694a55cd6d 100644 --- a/Mage.Sets/src/mage/sets/visions/WandOfDenial.java +++ b/Mage.Sets/src/mage/sets/visions/WandOfDenial.java @@ -98,7 +98,7 @@ class WandOfDenialEffect extends OneShotEffect { if (!card.getCardType().contains(CardType.LAND) && controller.canPayLifeCost() && controller.getLife() >= 2 - && controller.chooseUse(Outcome.Neutral, "Pay 2 life to put " + card.getLogName() + " into graveyard?", game)) { + && controller.chooseUse(Outcome.Neutral, "Pay 2 life to put " + card.getLogName() + " into graveyard?", source, game)) { controller.loseLife(2, game); controller.moveCards(card, Zone.LIBRARY, Zone.GRAVEYARD, source, game); } diff --git a/Mage.Sets/src/mage/sets/weatherlight/LlanowarSentinel.java b/Mage.Sets/src/mage/sets/weatherlight/LlanowarSentinel.java index 840ab9ae1d3..bf5a00bb21f 100644 --- a/Mage.Sets/src/mage/sets/weatherlight/LlanowarSentinel.java +++ b/Mage.Sets/src/mage/sets/weatherlight/LlanowarSentinel.java @@ -92,7 +92,7 @@ class LlanowarSentinelEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if(player != null) { - if(player.chooseUse(Outcome.BoostCreature, "Do you want to to pay {1}{G}?", game)) { + if(player.chooseUse(Outcome.BoostCreature, "Do you want to to pay {1}{G}?", source, game)) { Cost cost = new ManaCostsImpl("{1}{G}"); if(cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { FilterCard filter = new FilterCard("card named Llanowar Sentinel"); diff --git a/Mage.Sets/src/mage/sets/weatherlight/SouthernPaladin.java b/Mage.Sets/src/mage/sets/weatherlight/SouthernPaladin.java new file mode 100644 index 00000000000..e8cbffcf3f2 --- /dev/null +++ b/Mage.Sets/src/mage/sets/weatherlight/SouthernPaladin.java @@ -0,0 +1,53 @@ +/* + * 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.weatherlight; + +import java.util.UUID; + +/** + * + * @author LoneFox + + */ +public class SouthernPaladin extends mage.sets.seventhedition.SouthernPaladin { + + public SouthernPaladin(UUID ownerId) { + super(ownerId); + this.cardNumber = 143; + this.expansionSetCode = "WTH"; + } + + public SouthernPaladin(final SouthernPaladin card) { + super(card); + } + + @Override + public SouthernPaladin copy() { + return new SouthernPaladin(this); + } +} diff --git a/Mage.Sets/src/mage/sets/weatherlight/Tariff.java b/Mage.Sets/src/mage/sets/weatherlight/Tariff.java index 5c9b1109489..f3ec4cd4178 100644 --- a/Mage.Sets/src/mage/sets/weatherlight/Tariff.java +++ b/Mage.Sets/src/mage/sets/weatherlight/Tariff.java @@ -117,7 +117,7 @@ class TariffEffect extends OneShotEffect { ManaCost manaCost = CardUtil.removeVariableManaCost(creatureToPayFor.getManaCost()); String message = new StringBuilder("Pay ").append(manaCost.getText()).append(" (otherwise sacrifice ") .append(creatureToPayFor.getName()).append(")?").toString(); - if (player.chooseUse(Outcome.Benefit, message, game)) { + if (player.chooseUse(Outcome.Benefit, message, source, game)) { if (manaCost.pay(source, game, source.getSourceId(), player.getId(), false)) { game.informPlayers(new StringBuilder(sourceObject != null ? sourceObject.getName() : "") .append(": ").append(player.getLogName()).append(" has paid").toString()); diff --git a/Mage.Sets/src/mage/sets/worldwake/JaceTheMindSculptor.java b/Mage.Sets/src/mage/sets/worldwake/JaceTheMindSculptor.java index a2d920cfae6..77ae649901b 100644 --- a/Mage.Sets/src/mage/sets/worldwake/JaceTheMindSculptor.java +++ b/Mage.Sets/src/mage/sets/worldwake/JaceTheMindSculptor.java @@ -122,7 +122,7 @@ class JaceTheMindSculptorEffect1 extends OneShotEffect { Cards cards = new CardsImpl(); cards.add(card); controller.lookAtCards("Jace, the Mind Sculptor", cards, game); - if (controller.chooseUse(outcome, "Do you wish to put card on the bottom of player's library?", game)) { + if (controller.chooseUse(outcome, "Do you wish to put card on the bottom of player's library?", source, game)) { controller.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.LIBRARY, false, false); } else { game.informPlayers(controller.getLogName() + " puts the card back on top of the library."); diff --git a/Mage.Sets/src/mage/sets/worldwake/QuestForUlasTemple.java b/Mage.Sets/src/mage/sets/worldwake/QuestForUlasTemple.java index 0a35620815e..d4ae627af11 100644 --- a/Mage.Sets/src/mage/sets/worldwake/QuestForUlasTemple.java +++ b/Mage.Sets/src/mage/sets/worldwake/QuestForUlasTemple.java @@ -105,7 +105,7 @@ class QuestForUlasTempleEffect extends OneShotEffect { Cards cards = new CardsImpl(card); controller.lookAtCards(sourcePermanent.getName(), cards, game); if (card.getCardType().contains(CardType.CREATURE)) { - if (controller.chooseUse(Outcome.DrawCard, "Do you wish to reveal the creature card at the top of the library?", game)) { + if (controller.chooseUse(Outcome.DrawCard, "Do you wish to reveal the creature card at the top of the library?", source, game)) { controller.revealCards(sourcePermanent.getName(), cards, game); Permanent questForUlasTemple = game.getPermanent(source.getSourceId()); if (questForUlasTemple != null) { @@ -178,7 +178,7 @@ class QuestForUlasTempleEffect2 extends OneShotEffect { if (controller != null) { TargetCardInHand target = new TargetCardInHand(filter); if (target.canChoose(source.getSourceId(), controller.getId(), game) - &&controller.chooseUse(Outcome.PutCreatureInPlay, query, game)) { + &&controller.chooseUse(Outcome.PutCreatureInPlay, query, source, game)) { if (controller.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/worldwake/StoneforgeMystic.java b/Mage.Sets/src/mage/sets/worldwake/StoneforgeMystic.java index 714e5b4a1f2..6d1f9a9bae8 100644 --- a/Mage.Sets/src/mage/sets/worldwake/StoneforgeMystic.java +++ b/Mage.Sets/src/mage/sets/worldwake/StoneforgeMystic.java @@ -126,7 +126,7 @@ class StoneforgeMysticEffect extends OneShotEffect { if (controller != null) { Target target = new TargetCardInHand(filter); if (target.canChoose(source.getSourceId(), source.getControllerId(), game) - && controller.chooseUse(outcome, "Put an Equipment from your hand to battlefield?", game) + && controller.chooseUse(outcome, "Put an Equipment from your hand to battlefield?", source, game) && controller.chooseTarget(outcome, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { diff --git a/Mage.Sets/src/mage/sets/worldwake/TalusPaladin.java b/Mage.Sets/src/mage/sets/worldwake/TalusPaladin.java index 792062bd19f..b8fa537cf49 100644 --- a/Mage.Sets/src/mage/sets/worldwake/TalusPaladin.java +++ b/Mage.Sets/src/mage/sets/worldwake/TalusPaladin.java @@ -145,7 +145,7 @@ class TalusPaladinEffect extends OneShotEffect { if (taluspPaladin != null) { StringBuilder sb = new StringBuilder(); sb.append("Put a +1/+1 counter on Talus Paladin?"); - if (!player.chooseUse(Outcome.Benefit, sb.toString(), game)) { + if (!player.chooseUse(Outcome.Benefit, sb.toString(), source, game)) { return false; } taluspPaladin.addCounters(CounterType.P1P1.createInstance(), game); diff --git a/Mage.Sets/src/mage/sets/zendikar/ArchmageAscension.java b/Mage.Sets/src/mage/sets/zendikar/ArchmageAscension.java index dab9c4578fc..01429447633 100644 --- a/Mage.Sets/src/mage/sets/zendikar/ArchmageAscension.java +++ b/Mage.Sets/src/mage/sets/zendikar/ArchmageAscension.java @@ -193,6 +193,6 @@ class ArchmageAscensionReplacementEffect extends ReplacementEffectImpl { && archmage != null && archmage.getCounters().getCount(CounterType.QUEST) >= 6 && you != null - && you.chooseUse(Outcome.Benefit, "Would you like to search your library instead of drawing a card?", game); + && you.chooseUse(Outcome.Benefit, "Would you like to search your library instead of drawing a card?", source, game); } } diff --git a/Mage.Sets/src/mage/sets/zendikar/ChandraAblaze.java b/Mage.Sets/src/mage/sets/zendikar/ChandraAblaze.java index e7451fd3a29..9ccf7a83cff 100644 --- a/Mage.Sets/src/mage/sets/zendikar/ChandraAblaze.java +++ b/Mage.Sets/src/mage/sets/zendikar/ChandraAblaze.java @@ -208,7 +208,7 @@ class ChandraAblazeEffect5 extends OneShotEffect { String message = "Play red instant or sorcery card from your graveyard without paying its mana cost?"; Set cards = player.getGraveyard().getCards(filter, game); TargetCardInGraveyard target = new TargetCardInGraveyard(filter); - while (!cards.isEmpty() && player.chooseUse(outcome, message, game)) { + while (!cards.isEmpty() && player.chooseUse(outcome, message, source, game)) { target.clearChosen(); if (player.choose(outcome, target, source.getSourceId(), game)) { Card card = game.getCard(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/sets/zendikar/Electropotence.java b/Mage.Sets/src/mage/sets/zendikar/Electropotence.java index dd00e4e9215..ce2b9795af4 100644 --- a/Mage.Sets/src/mage/sets/zendikar/Electropotence.java +++ b/Mage.Sets/src/mage/sets/zendikar/Electropotence.java @@ -130,7 +130,7 @@ class ElectropotenceEffect extends OneShotEffect { Permanent creature = game.getPermanentOrLKIBattlefield(creatureId); Player controller = game.getPlayer(source.getControllerId()); if (creature != null && controller != null) { - if (controller.chooseUse(Outcome.Damage, "Pay {2}{R} to do the damage?", game)) { + if (controller.chooseUse(Outcome.Damage, "Pay {2}{R} to do the damage?", source, game)) { // if (controller.chooseUse(Outcome.Damage, "Pay {2}{R}? If you do, " + creature.getName() + " deals damage equal to its power to target creature or player.", game)) { ManaCosts manaCosts = new ManaCostsImpl("{2}{R}"); if (manaCosts.pay(source, game, source.getSourceId(), controller.getId(), false)) { diff --git a/Mage.Sets/src/mage/sets/zendikar/ExplorersScope.java b/Mage.Sets/src/mage/sets/zendikar/ExplorersScope.java index f4733ff67b5..7ced325384c 100644 --- a/Mage.Sets/src/mage/sets/zendikar/ExplorersScope.java +++ b/Mage.Sets/src/mage/sets/zendikar/ExplorersScope.java @@ -104,7 +104,7 @@ class ExplorersScopeEffect extends OneShotEffect { controller.lookAtCards(sourceObject.getIdName(), cards, game); if (card.getCardType().contains(CardType.LAND)) { String message = "Put " + card.getLogName() + " onto the battlefield tapped?"; - if (controller.chooseUse(Outcome.PutLandInPlay, message, game)) { + if (controller.chooseUse(Outcome.PutLandInPlay, message, source, game)) { card.putOntoBattlefield(game, Zone.LIBRARY, source.getSourceId(), source.getControllerId(), true); } } diff --git a/Mage.Sets/src/mage/sets/zendikar/HellkiteCharger.java b/Mage.Sets/src/mage/sets/zendikar/HellkiteCharger.java index 503f7f9ab36..9586ec1a36c 100644 --- a/Mage.Sets/src/mage/sets/zendikar/HellkiteCharger.java +++ b/Mage.Sets/src/mage/sets/zendikar/HellkiteCharger.java @@ -97,7 +97,7 @@ class HellkiteChargerEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); if (player != null) { ManaCosts cost = new ManaCostsImpl("{5}{R}{R}"); - if (player.chooseUse(Outcome.Damage, "Pay " + cost.getText() + "?", game)) { + if (player.chooseUse(Outcome.Damage, "Pay " + cost.getText() + "?", source, game)) { cost.clearPaid(); if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { new UntapAllControllerEffect(new FilterAttackingCreature(),"").apply(game, source); diff --git a/Mage.Sets/src/mage/sets/zendikar/LorthosTheTidemaker.java b/Mage.Sets/src/mage/sets/zendikar/LorthosTheTidemaker.java index 8fa56dd5e0a..d6f4e02af71 100644 --- a/Mage.Sets/src/mage/sets/zendikar/LorthosTheTidemaker.java +++ b/Mage.Sets/src/mage/sets/zendikar/LorthosTheTidemaker.java @@ -102,7 +102,7 @@ class LorthosTheTideMakerEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); if (player != null) { Cost cost = new ManaCostsImpl("{8}"); - if (player.chooseUse(Outcome.Tap, "Pay " + cost.getText() + " and " + staticText, game)) { + if (player.chooseUse(Outcome.Tap, "Pay " + cost.getText() + " and " + staticText, source, game)) { cost.clearPaid(); if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { for (UUID target : this.targetPointer.getTargets(game, source)) { diff --git a/Mage.Tests/src/test/java/org/mage/test/AI/basic/CastAlternateCastingCostsTest.java b/Mage.Tests/src/test/java/org/mage/test/AI/basic/CastAlternateCastingCostsTest.java new file mode 100644 index 00000000000..8a2f551765e --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/AI/basic/CastAlternateCastingCostsTest.java @@ -0,0 +1,62 @@ +/* + * 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 org.mage.test.AI.basic; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Ignore; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBaseAI; + +/** + * + * @author LevelX2 + */ +public class CastAlternateCastingCostsTest extends CardTestPlayerBaseAI { + + /** + * Tests that if a spell has alternate casting costs, this option is also calculated + */ + @Test + @Ignore // AI only gets the cast ability yet, but does always say yes to use evoke + // TODO: Get the AI both options to calculate + public void testEvoke() { + // Flying + // When Mulldrifter enters the battlefield, draw two cards. + // Evoke (You may cast this spell for its evoke cost. If you do, it's sacrificed when it enters the battlefield.) + addCard(Zone.HAND, playerA, "Mulldrifter"); + addCard(Zone.BATTLEFIELD, playerA, "Island", 5); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Mulldrifter", 1); + } + +} + diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/equipped/ScytheOfTheWretchedTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/equipped/ScytheOfTheWretchedTest.java index 06bc16cf28d..0c0140397e5 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/equipped/ScytheOfTheWretchedTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/equipped/ScytheOfTheWretchedTest.java @@ -38,22 +38,22 @@ import org.mage.test.serverside.base.CardTestPlayerBase; * * @author LevelX2 */ - public class ScytheOfTheWretchedTest extends CardTestPlayerBase { /** - * Test that the creature taht died returns to battlefield under your control - * if the previous equiped creature does not die + * Test that the creature that died returns to battlefield under your + * control if the previous equipped creature does not die */ @Test public void testEquipAlive() { - addCard(Zone.BATTLEFIELD, playerA, "Soulmender", 1); + // {T}: You gain 1 life. + addCard(Zone.BATTLEFIELD, playerA, "Soulmender", 1); // 1/1 addCard(Zone.BATTLEFIELD, playerB, "Plains", 4); - addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); // Equipped creature gets +2/+2. // Whenever a creature dealt damage by equipped creature this turn dies, return that card to the battlefield under your control. Attach Scythe of the Wretched to that creature. - // Equip {4} + // Equip {4} addCard(Zone.BATTLEFIELD, playerB, "Scythe of the Wretched"); activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Equip {4}", "Silvercoat Lion"); @@ -66,29 +66,31 @@ public class ScytheOfTheWretchedTest extends CardTestPlayerBase { assertLife(playerA, 20); assertLife(playerB, 20); - + assertPermanentCount(playerA, "Soulmender", 0); assertPermanentCount(playerB, "Soulmender", 1); assertPowerToughness(playerB, "Soulmender", 3, 3); - + assertPowerToughness(playerB, "Silvercoat Lion", 2, 2); Permanent silvercoatLion = getPermanent("Silvercoat Lion", playerB.getId()); Assert.assertTrue("Silvercoat Lion may not have any attachments", silvercoatLion.getAttachments().isEmpty()); } - /** - * Test that the creature that died returns to battlefield under your control - * if the previous equiped creature does die after equipment is removed + + /** + * Test that the creature that died returns to battlefield under your + * control if the previous equiped creature does die after equipment is + * removed */ @Test public void testEquipDied() { - addCard(Zone.BATTLEFIELD, playerA, "Oreskos Swiftclaw", 1); // 3/1 + addCard(Zone.BATTLEFIELD, playerA, "Oreskos Swiftclaw", 1); // 3/1 addCard(Zone.BATTLEFIELD, playerB, "Plains", 4); - addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); // Equipped creature gets +2/+2. // Whenever a creature dealt damage by equipped creature this turn dies, return that card to the battlefield under your control. Attach Scythe of the Wretched to that creature. - // Equip {4} + // Equip {4} addCard(Zone.BATTLEFIELD, playerB, "Scythe of the Wretched"); activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Equip {4}", "Silvercoat Lion"); @@ -101,27 +103,27 @@ public class ScytheOfTheWretchedTest extends CardTestPlayerBase { assertLife(playerA, 20); assertLife(playerB, 20); - + assertPermanentCount(playerA, "Oreskos Swiftclaw", 0); assertPermanentCount(playerB, "Oreskos Swiftclaw", 1); assertPowerToughness(playerB, "Oreskos Swiftclaw", 5, 3); - + assertGraveyardCount(playerB, "Silvercoat Lion", 1); } - - /** - * Test that the creature that died returns to battlefield under your control - * if the previous equiped creature does die already in combat + + /** + * Test that the creature that died returns to battlefield under your + * control if the previous equiped creature does die already in combat */ @Test public void testEquipDiedInCombat() { addCard(Zone.BATTLEFIELD, playerA, "Serra Angel", 1); // 4/4 addCard(Zone.BATTLEFIELD, playerB, "Plains", 4); - addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); // Equipped creature gets +2/+2. // Whenever a creature dealt damage by equipped creature this turn dies, return that card to the battlefield under your control. Attach Scythe of the Wretched to that creature. - // Equip {4} + // Equip {4} addCard(Zone.BATTLEFIELD, playerB, "Scythe of the Wretched"); activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Equip {4}", "Silvercoat Lion"); @@ -134,18 +136,18 @@ public class ScytheOfTheWretchedTest extends CardTestPlayerBase { assertLife(playerA, 20); assertLife(playerB, 20); - + assertPermanentCount(playerA, "Serra Angel", 0); assertPermanentCount(playerB, "Serra Angel", 1); assertPowerToughness(playerB, "Serra Angel", 6, 6); - + assertGraveyardCount(playerB, "Silvercoat Lion", 1); - } - - - /** - * Test that the creature that died returns to battlefield under your control - * if the previous equiped creature does die already in combat and the equipment was destroyed meanwhile + } + + /** + * Test that the creature that died returns to battlefield under your + * control if the previous equiped creature does die already in combat and + * the equipment was destroyed meanwhile */ @Test public void testEquipDiedInCombat2() { @@ -154,17 +156,17 @@ public class ScytheOfTheWretchedTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Disenchant", 1); addCard(Zone.BATTLEFIELD, playerB, "Plains", 4); - addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); // Equipped creature gets +2/+2. // Whenever a creature dealt damage by equipped creature this turn dies, return that card to the battlefield under your control. Attach Scythe of the Wretched to that creature. - // Equip {4} + // Equip {4} addCard(Zone.BATTLEFIELD, playerB, "Scythe of the Wretched"); activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Equip {4}", "Silvercoat Lion"); attack(2, playerB, "Silvercoat Lion"); block(2, playerA, "Serra Angel", "Silvercoat Lion"); - + castSpell(2, PhaseStep.COMBAT_DAMAGE, playerA, "Disenchant", "Scythe of the Wretched", "Whenever a creature dealt damage"); setStopAt(2, PhaseStep.POSTCOMBAT_MAIN); @@ -172,14 +174,14 @@ public class ScytheOfTheWretchedTest extends CardTestPlayerBase { assertLife(playerA, 20); assertLife(playerB, 20); - + assertGraveyardCount(playerA, "Disenchant", 1); assertGraveyardCount(playerB, "Scythe of the Wretched", 1); - + assertPermanentCount(playerA, "Serra Angel", 0); assertPermanentCount(playerB, "Serra Angel", 1); assertPowerToughness(playerB, "Serra Angel", 4, 4); - + assertGraveyardCount(playerB, "Silvercoat Lion", 1); - } -} \ No newline at end of file + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ModularTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ModularTest.java index 61609e10486..ac13369a565 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ModularTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ModularTest.java @@ -25,11 +25,11 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package org.mage.test.cards.abilities.keywords; import mage.constants.PhaseStep; import mage.constants.Zone; +import mage.counters.CounterType; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -40,32 +40,27 @@ import org.mage.test.serverside.base.CardTestPlayerBase; public class ModularTest extends CardTestPlayerBase { /** - * 702.42. Modular - * 702.42a Modular represents both a static ability and a triggered ability. “Modular N” means “This - * permanent enters the battlefield with N +1/+1 counters on it” and “When this permanent is put - * into a graveyard from the battlefield, you may put a +1/+1 counter on target artifact creature for - * each +1/+1 counter on this permanent.” - * 702.42b If a creature has multiple instances of modular, each one works separately. - * - */ - - /** - * Arcbound Bruiser - * Artifact Creature — Golem 0/0, 5 (5) - * Modular 3 (This enters the battlefield with three +1/+1 counters on it. - * When it dies, you may put its +1/+1 counters on target artifact creature.) + * 702.42. Modular 702.42a Modular represents both a static ability and a + * triggered ability. “Modular N” means “This permanent enters the + * battlefield with N +1/+1 counters on it” and “When this permanent is put + * into a graveyard from the battlefield, you may put a +1/+1 counter on + * target artifact creature for each +1/+1 counter on this permanent.” + * 702.42b If a creature has multiple instances of modular, each one works + * separately. * */ - /** - * Arcbound Hybrid - * Artifact Creature — Beast 0/0, 4 (4) - * Haste - * Modular 2 (This enters the battlefield with two +1/+1 counters on it. - * When it dies, you may put its +1/+1 counters on target artifact creature.) - * + * Arcbound Bruiser Artifact Creature — Golem 0/0, 5 (5) Modular 3 (This + * enters the battlefield with three +1/+1 counters on it. When it dies, you + * may put its +1/+1 counters on target artifact creature.) + * + */ + /** + * Arcbound Hybrid Artifact Creature — Beast 0/0, 4 (4) Haste Modular 2 + * (This enters the battlefield with two +1/+1 counters on it. When it dies, + * you may put its +1/+1 counters on target artifact creature.) + * */ - @Test public void testModularEnters() { addCard(Zone.BATTLEFIELD, playerA, "Forest", 5); @@ -85,7 +80,7 @@ public class ModularTest extends CardTestPlayerBase { assertPowerToughness(playerA, "Arcbound Hybrid", 2, 2); } - + @Test public void testModularLeaves() { addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4); @@ -108,4 +103,32 @@ public class ModularTest extends CardTestPlayerBase { } + /** + * My Inkmoth Nexus was in creature "form". My Arcbound Ravager died. I + * could not transfer his counters on my Inkmoth "creature". + */ + @Test + public void testInkmothNexus() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); + addCard(Zone.BATTLEFIELD, playerA, "Inkmoth Nexus"); + addCard(Zone.HAND, playerA, "Arcbound Ravager"); + + addCard(Zone.HAND, playerB, "Lightning Bolt"); + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Arcbound Ravager"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}: {this} becomes"); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Lightning Bolt", "Arcbound Ravager"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertGraveyardCount(playerA, "Arcbound Ravager", 1); + assertGraveyardCount(playerB, "Lightning Bolt", 1); + + assertCounterCount("Inkmoth Nexus", CounterType.P1P1, 1); + + } + } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/damage/SpitefulShadowsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/damage/SpitefulShadowsTest.java index fd45afbe5d6..42628bca6c2 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/damage/SpitefulShadowsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/damage/SpitefulShadowsTest.java @@ -8,18 +8,21 @@ import org.mage.test.serverside.base.CardTestPlayerBase; /** * - * also tests regenerate and - * tests that permanents with protection can be sacrificed - * + * also tests regenerate and tests that permanents with protection can be + * sacrificed + * * @author BetaSteward */ public class SpitefulShadowsTest extends CardTestPlayerBase { @Test public void testCard() { + // Infect (This creature deals damage to creatures in the form of -1/-1 counters and to players in the form of poison counters.) addCard(Zone.BATTLEFIELD, playerA, "Glistener Elf"); addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); + // Enchant creature + // Whenever enchanted creature is dealt damage, it deals that much damage to its controller. addCard(Zone.HAND, playerA, "Spiteful Shadows"); addCard(Zone.HAND, playerA, "Lightning Bolt"); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CleverImpersonatorTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CleverImpersonatorTest.java new file mode 100644 index 00000000000..c045c0998af --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CleverImpersonatorTest.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 org.mage.test.cards.copy; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class CleverImpersonatorTest extends CardTestPlayerBase { + + /** + * Clever Impersonator Copy Gilded Drake. Gilded drake does not trigger to + * exchange creature. + */ + @Test + public void testCopyGildedDrake() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); + // Flying + // When Gilded Drake enters the battlefield, exchange control of Gilded Drake and up to one target creature an opponent controls. If you don't make an exchange, sacrifice Gilded Drake. This ability can't be countered except by spells and abilities. + addCard(Zone.HAND, playerA, "Gilded Drake", 1); + addCard(Zone.BATTLEFIELD, playerA, "Pillarfield Ox", 1); + + // You may have Clever Impersonator enter the battlefield as a copy of any nonland permanent on the battlefield. + addCard(Zone.HAND, playerB, "Clever Impersonator", 1); + + addCard(Zone.BATTLEFIELD, playerB, "Island", 4); + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Gilded Drake"); + addTarget(playerA, "Silvercoat Lion"); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Clever Impersonator"); + setChoice(playerB, "Gilded Drake"); // copy the drake + addTarget(playerB, "Pillarfield Ox"); // exchange control with Ox + + setStopAt(2, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Gilded Drake", 1); + assertPermanentCount(playerA, "Silvercoat Lion", 1); + + assertPermanentCount(playerB, "Gilded Drake", 1); + assertPermanentCount(playerB, "Pillarfield Ox", 1); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/mana/EmptyOnlyOnTurnsEndManaTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/mana/EmptyOnlyOnTurnsEndManaTest.java new file mode 100644 index 00000000000..55a0612ad73 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/mana/EmptyOnlyOnTurnsEndManaTest.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 org.mage.test.cards.mana; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Assert; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class EmptyOnlyOnTurnsEndManaTest extends CardTestPlayerBase { + + @Test + public void testDaxosOfMeletis() { + // At the beginning of each player's upkeep, that player adds {G}{G}{G} to his or her mana pool. Until end of turn, this mana doesn't empty from that player's mana pool as steps and phases end. + addCard(Zone.BATTLEFIELD, playerA, "Shizuko, Caller of Autumn", 1); + addCard(Zone.HAND, playerA, "Birds of Paradise", 1); + + addCard(Zone.HAND, playerB, "Birds of Paradise", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Birds of Paradise"); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Birds of Paradise"); + + setStopAt(2, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertPermanentCount(playerA, "Birds of Paradise", 1); + assertPermanentCount(playerB, "Birds of Paradise", 1); + + Assert.assertEquals("2 {G} have to be still im Mana Pool", "{G}{G}", playerB.getManaPool().getMana().toString()); + + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/rtr/JaceArchitectOfThoughtTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/rtr/JaceArchitectOfThoughtTest.java index 313bf1db091..2c8a300bece 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/rtr/JaceArchitectOfThoughtTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/rtr/JaceArchitectOfThoughtTest.java @@ -25,7 +25,6 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package org.mage.test.cards.single.rtr; import mage.constants.PhaseStep; @@ -35,36 +34,32 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * Jace, Architect of Thought {2}{U}{U} - * Planeswalker — Jace - * Loyalty 4 - * +1: Until your next turn, whenever a creature an opponent controls attacks, it gets - * -1/-0 until end of turn. - * -2: Reveal the top three cards of your library. An opponent separates those cards into - * two piles. Put one pile into your hand and the other on the bottom of your library - * in any order. - * -8: For each player, search that player's library for a nonland card and exile it, then - * that player shuffles his or her library. You may cast those cards without paying - * their mana costs. - * + * Jace, Architect of Thought {2}{U}{U} Planeswalker — Jace Loyalty 4 +1: Until + * your next turn, whenever a creature an opponent controls attacks, it gets + * -1/-0 until end of turn. -2: Reveal the top three cards of your library. An + * opponent separates those cards into two piles. Put one pile into your hand + * and the other on the bottom of your library in any order. -8: For each + * player, search that player's library for a nonland card and exile it, then + * that player shuffles his or her library. You may cast those cards without + * paying their mana costs. + * * @author LevelX2 */ - public class JaceArchitectOfThoughtTest extends CardTestPlayerBase { @Test public void testAbility1normal() { addCard(Zone.BATTLEFIELD, playerA, "Jace, Architect of Thought"); - + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1); - + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: Until your next turn, whenever a creature an opponent controls attacks, it gets -1/-0 until end of turn."); attack(2, playerB, "Silvercoat Lion"); - + setStopAt(2, PhaseStep.END_COMBAT); execute(); - + assertCounterCount("Jace, Architect of Thought", CounterType.LOYALTY, 5); assertPowerToughness(playerB, "Silvercoat Lion", 1, 2); @@ -72,53 +67,56 @@ public class JaceArchitectOfThoughtTest extends CardTestPlayerBase { assertLife(playerB, 20); } + @Test public void testAbilit1lastOnlyUntilNextTurn() { addCard(Zone.BATTLEFIELD, playerA, "Jace, Architect of Thought"); - + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1); - + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: Until your next turn, whenever a creature an opponent controls attacks, it gets -1/-0 until end of turn."); attack(2, playerB, "Silvercoat Lion"); attack(4, playerB, "Silvercoat Lion"); - + setStopAt(4, PhaseStep.END_COMBAT); execute(); - + assertCounterCount("Jace, Architect of Thought", CounterType.LOYALTY, 5); assertPowerToughness(playerB, "Silvercoat Lion", 2, 2); assertLife(playerA, 17); assertLife(playerB, 20); - } + } /* - Ability 1 has still to trigger next turn if used also if Jace left the battlefield. - */ + Ability 1 has still to trigger next turn if used also if Jace left the battlefield. + */ + @Test public void testAbility1AfterJacesWasExiled() { addCard(Zone.BATTLEFIELD, playerA, "Jace, Architect of Thought"); - + // Sorcery {R}{B} // Destroy target creature or planeswalker. addCard(Zone.HAND, playerB, "Dreadbore"); addCard(Zone.BATTLEFIELD, playerB, "Mountain"); addCard(Zone.BATTLEFIELD, playerB, "Swamp"); addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1); - - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: Until your next turn, whenever a creature an opponent controls attacks, it gets -1/-0 until end of turn."); - + + // +1: Until your next turn, whenever a creature an opponent controls attacks, it gets -1/-0 until end of turn. + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: Until your next turn"); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Dreadbore", "Jace, Architect of Thought"); attack(2, playerB, "Silvercoat Lion"); - + setStopAt(2, PhaseStep.END_COMBAT); execute(); assertLife(playerA, 19); assertLife(playerB, 20); - - assertPermanentCount(playerB, "Jace, Architect of Thought", 0); + + assertPermanentCount(playerA, "Jace, Architect of Thought", 0); assertPowerToughness(playerB, "Silvercoat Lion", 1, 2); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/GolemsHeartTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/GolemsHeartTest.java new file mode 100644 index 00000000000..cf23eaf261e --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/GolemsHeartTest.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 org.mage.test.cards.triggers; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class GolemsHeartTest extends CardTestPlayerBase { + + /* + My opponent and I were both playing artifact decks. + He had Golem's Heart out. + He wasn't gaining life when I or he was casting spells. + */ + @Test + public void testFirstTriggeredAbility() { + // Whenever a player casts an artifact spell, you may gain 1 life. + addCard(Zone.BATTLEFIELD, playerA, "Golem's Heart", 1); + + addCard(Zone.HAND, playerA, "Expedition Map"); // {1} + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); + + addCard(Zone.HAND, playerB, "Darksteel Axe"); // {1} + addCard(Zone.BATTLEFIELD, playerB, "Swamp", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Expedition Map"); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Darksteel Axe"); + + setStopAt(2, PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 22); + assertLife(playerB, 20); + + assertPermanentCount(playerA, "Expedition Map", 1); + assertPermanentCount(playerB, "Darksteel Axe", 1); + + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/ReturnToBattlefieldEffectsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/ReturnToBattlefieldEffectsTest.java index dc6b5f32a59..b2848c96634 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/ReturnToBattlefieldEffectsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/ReturnToBattlefieldEffectsTest.java @@ -36,7 +36,6 @@ import org.mage.test.serverside.base.CardTestPlayerBase; * * @author LevelX2 */ - public class ReturnToBattlefieldEffectsTest extends CardTestPlayerBase { @Test @@ -82,9 +81,10 @@ public class ReturnToBattlefieldEffectsTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Lightning Bolt", 1); assertPermanentCount(playerA, "Arcbound Worker", 1); } + /** - * That that the creature with a +1/+1 counter does not return - * if the card was removed from graveyard meanwhile + * Test that the creature with a +1/+1 counter does not return if the card + * was removed from graveyard meanwhile by Relic of Progenitus */ @Test public void testMarchesatheBlackRoseAfterExile() { @@ -100,10 +100,10 @@ public class ReturnToBattlefieldEffectsTest extends CardTestPlayerBase { // {T}: Target player exiles a card from his or her graveyard. // {1}, Exile Relic of Progenitus: Exile all cards from all graveyards. Draw a card. addCard(Zone.BATTLEFIELD, playerB, "Relic of Progenitus", 1); - + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Arcbound Worker"); castSpell(1, PhaseStep.END_COMBAT, playerB, "Lightning Bolt", "Arcbound Worker"); - + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "{T}: Target player exiles", playerA); setStopAt(1, PhaseStep.END_TURN); @@ -113,13 +113,15 @@ public class ReturnToBattlefieldEffectsTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Arcbound Worker", 0); assertExileCount("Arcbound Worker", 1); - + } + /** - * With my opponent's Deathmist Raptor return-to-battlefield trigger on the stack, - * I exiled the Deathmist Raptor with Pharika, God of Affliction. However, the Deathmist Raptor - * returned to the battlefield from exile, though it should not have because it had - * changed zones so was a different object. + * With my opponent's Deathmist Raptor return-to-battlefield trigger on the + * stack, I exiled the Deathmist Raptor with Pharika, God of Affliction. + * However, the Deathmist Raptor returned to the battlefield from exile, + * though it should not have because it had changed zones so was a different + * object. */ @Test public void testDeathmistRaptor() { @@ -129,20 +131,20 @@ public class ReturnToBattlefieldEffectsTest extends CardTestPlayerBase { addCard(Zone.GRAVEYARD, playerA, "Deathmist Raptor"); addCard(Zone.HAND, playerA, "Pine Walker"); addCard(Zone.BATTLEFIELD, playerA, "Forest", 5); - + addCard(Zone.BATTLEFIELD, playerB, "Forest", 1); addCard(Zone.BATTLEFIELD, playerB, "Swamp", 1); - // {B}{G}: Exile target creature card from a graveyard. It's owner puts a 1/1 black and green Snake enchantment creature token with deathtouch onto the battlefield. + // {B}{G}: Exile target creature card from a graveyard. It's owner puts a 1/1 black and green Snake enchantment creature token with deathtouch onto the battlefield. addCard(Zone.BATTLEFIELD, playerB, "Pharika, God of Affliction", 1); - + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pine Walker"); setChoice(playerA, "Yes"); // cast it face down as 2/2 creature - activateAbility(3, PhaseStep.POSTCOMBAT_MAIN, playerA, "{4}{G}: Turn this face-down permanent face up."); - activateAbility(3, PhaseStep.POSTCOMBAT_MAIN, playerB, "{B}{G}: Exile target creature card from a graveyard", + activateAbility(3, PhaseStep.POSTCOMBAT_MAIN, playerA, "{4}{G}: Turn this face-down permanent face up."); + activateAbility(3, PhaseStep.POSTCOMBAT_MAIN, playerB, "{B}{G}: Exile target creature card from a graveyard", "Deathmist Raptor", "Whenever a permanent you control is turned face up"); - - setStopAt(3, PhaseStep.END_TURN); + + setStopAt(3, PhaseStep.END_TURN); execute(); assertPermanentCount(playerB, "Pharika, God of Affliction", 1); @@ -150,6 +152,37 @@ public class ReturnToBattlefieldEffectsTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Pine Walker", 1); assertExileCount("Deathmist Raptor", 1); - - } -} \ No newline at end of file + + } + + /** + * Reassembling Skeleton is blocked by Necroskitter, and dies. Necroskitter + * triggers. With the trigger on the stack, activate Skeleton and return it + * to play. Expected result: trigger can't find Skeleton since it changed + * zones. Actual result: trigger steals control of Skeleton when it's + * already on the battlefield. + */ + @Test + public void testNecroskitter1() { + // Wither (This deals damage to creatures in the form of -1/-1 counters.) + // Whenever a creature an opponent controls with a -1/-1 counter on it dies, you may return that card to the battlefield under your control. + addCard(Zone.BATTLEFIELD, playerA, "Necroskitter", 1); // 1/4 + + // {1}{B}: Return Reassembling Skeleton from your graveyard to the battlefield tapped. + addCard(Zone.BATTLEFIELD, playerB, "Reassembling Skeleton"); + addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2); + + attack(2, playerB, "Reassembling Skeleton"); + block(2, playerA, "Necroskitter", "Reassembling Skeleton"); + + activateAbility(2, PhaseStep.COMBAT_DAMAGE, playerB, "{1}{B}: Return", NO_TARGET, "Whenever a creature"); + + setStopAt(2, PhaseStep.POSTCOMBAT_MAIN); + + execute(); + + assertLife(playerA, 20); + assertPermanentCount(playerB, "Reassembling Skeleton", 1); + + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/player/RandomPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/RandomPlayer.java index 148c3c34979..5cfb1bafde2 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/RandomPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/RandomPlayer.java @@ -346,7 +346,7 @@ public class RandomPlayer extends ComputerPlayer { } @Override - public boolean chooseUse(Outcome outcome, String message, Game game) { + public boolean chooseUse(Outcome outcome, String message, Ability source, Game game) { return rnd.nextBoolean(); } diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index 9fe14c7e861..b0904aeb2cf 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -99,8 +99,6 @@ import mage.target.common.TargetCreaturePermanentAmount; import mage.target.common.TargetPermanentOrPlayer; import org.junit.Ignore; - - /** * * @author BetaSteward_at_googlemail.com @@ -119,7 +117,6 @@ public class TestPlayer implements Player { private final ComputerPlayer computerPlayer; - public TestPlayer(ComputerPlayer computerPlayer) { this.computerPlayer = computerPlayer; AIPlayer = false; @@ -156,13 +153,14 @@ public class TestPlayer implements Player { } /** - * - * @param maxCallsWithoutAction max number of priority passes a player may have for this test (default = 100) - */ + * + * @param maxCallsWithoutAction max number of priority passes a player may + * have for this test (default = 100) + */ public void setMaxCallsWithoutAction(int maxCallsWithoutAction) { this.maxCallsWithoutAction = maxCallsWithoutAction; } - + protected Permanent findPermanent(FilterPermanent filter, UUID controllerId, Game game) { List permanents = game.getBattlefield().getAllActivePermanents(filter, controllerId, game); if (permanents.size() > 0) { @@ -427,7 +425,7 @@ public class TestPlayer implements Player { if (numberOfActions == actions.size()) { foundNoAction++; if (foundNoAction > maxCallsWithoutAction) { - throw new AssertionError("More priority calls to " +getName() + " and doing no action than allowed (" + maxCallsWithoutAction +")"); + throw new AssertionError("More priority calls to " + getName() + " and doing no action than allowed (" + maxCallsWithoutAction + ")"); } } else { foundNoAction = 0; @@ -609,13 +607,13 @@ public class TestPlayer implements Player { if (target instanceof TargetCardInGraveyard) { TargetCardInGraveyard targetCardInGraveyard = ((TargetCardInGraveyard) target); Set possibleTargets = new HashSet<>(); - for(UUID playerId: this.getInRange()) { + for (UUID playerId : this.getInRange()) { Player player = game.getPlayer(playerId); if (player != null) { possibleTargets.addAll(player.getGraveyard()); } } - + for (String choose2 : choices) { String[] targetList = choose2.split("\\^"); boolean targetFound = false; @@ -643,7 +641,7 @@ public class TestPlayer implements Player { } } } - } + } if (target instanceof TargetSource) { Set possibleTargets; TargetSource t = ((TargetSource) target); @@ -795,7 +793,7 @@ public class TestPlayer implements Player { } @Override - public boolean chooseUse(Outcome outcome, String message, Game game) { + public boolean chooseUse(Outcome outcome, String message, Ability source, Game game) { if (!choices.isEmpty()) { if (choices.get(0).equals("No")) { choices.remove(0); @@ -812,7 +810,7 @@ public class TestPlayer implements Player { @Override public int announceXMana(int min, int max, String message, Game game, Ability ability) { if (!choices.isEmpty()) { - for(String choice: choices) { + for (String choice : choices) { if (choice.startsWith("X=")) { int xValue = Integer.parseInt(choice.substring(2)); choices.remove(choice); @@ -1131,12 +1129,12 @@ public class TestPlayer implements Player { public void lookAtCards(String name, Cards cards, Game game) { computerPlayer.lookAtCards(name, cards, game); } - + @Override public void lookAtCards(String name, Card card, Game game) { computerPlayer.lookAtCards(name, card, game); } - + @Override public void phasing(Game game) { computerPlayer.phasing(game); diff --git a/Mage/src/mage/MageObjectImpl.java b/Mage/src/mage/MageObjectImpl.java index 1d0c6400bcb..f9402ad3df4 100644 --- a/Mage/src/mage/MageObjectImpl.java +++ b/Mage/src/mage/MageObjectImpl.java @@ -104,7 +104,7 @@ public abstract class MageObjectImpl implements MageObject { @Override public String getLogName() { - return GameLog.getColoredObjectName(this); + return GameLog.getColoredObjectIdName(this); } @Override diff --git a/Mage/src/mage/abilities/AbilityImpl.java b/Mage/src/mage/abilities/AbilityImpl.java index ad2bf78df83..a255e8a0c4b 100644 --- a/Mage/src/mage/abilities/AbilityImpl.java +++ b/Mage/src/mage/abilities/AbilityImpl.java @@ -346,7 +346,7 @@ public abstract class AbilityImpl implements Ability { for (Cost cost : optionalCosts) { if (cost instanceof ManaCost) { cost.clearPaid(); - if (controller.chooseUse(Outcome.Benefit, "Pay optional cost " + cost.getText() + "?", game)) { + if (controller.chooseUse(Outcome.Benefit, "Pay optional cost " + cost.getText() + "?", this, game)) { manaCostsToPay.add((ManaCost) cost); } } @@ -576,7 +576,7 @@ public abstract class AbilityImpl implements Ability { protected boolean useAlternativeCost(Game game) { for (AlternativeCost cost : alternativeCosts) { if (cost.isAvailable(game, this)) { - if (game.getPlayer(this.controllerId).chooseUse(Outcome.Neutral, "Use alternative cost " + cost.getName(), game)) { + if (game.getPlayer(this.controllerId).chooseUse(Outcome.Neutral, "Use alternative cost " + cost.getName(), this, game)) { return cost.pay(this, game, sourceId, controllerId, false); } } @@ -1013,9 +1013,9 @@ public abstract class AbilityImpl implements Ability { if (object instanceof StackAbility) { Card card = game.getCard(((StackAbility) object).getSourceId()); if (card != null) { - sb.append(GameLog.getColoredObjectName(card)); + sb.append(GameLog.getColoredObjectIdName(card)); } else { - sb.append(GameLog.getColoredObjectName(object)); + sb.append(GameLog.getColoredObjectIdName(object)); } } else { if (object instanceof Spell) { @@ -1027,7 +1027,7 @@ public abstract class AbilityImpl implements Ability { } sb.append(getOptionalTextSuffix(game, spell)); } else { - sb.append(GameLog.getColoredObjectName(object)); + sb.append(GameLog.getColoredObjectIdName(object)); } } } else { diff --git a/Mage/src/mage/abilities/TriggeredAbilityImpl.java b/Mage/src/mage/abilities/TriggeredAbilityImpl.java index c07195414b8..78745f0f5cd 100644 --- a/Mage/src/mage/abilities/TriggeredAbilityImpl.java +++ b/Mage/src/mage/abilities/TriggeredAbilityImpl.java @@ -1,31 +1,30 @@ /* -* 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. -*/ - + * 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; import java.util.UUID; @@ -80,24 +79,19 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge // TODO: Implement for all TriggeredAbilities so this default method can be removed /*@Override - public boolean checkEventType(GameEvent event, Game game) { - return true; - }*/ - + public boolean checkEventType(GameEvent event, Game game) { + return true; + }*/ @Override public boolean resolve(Game game) { - MageObject object = game.getObject(sourceId); if (optional) { + MageObject object = game.getObject(getSourceId()); Player player = game.getPlayer(this.getControllerId()); - StringBuilder sb = new StringBuilder(); - if (object != null) { - sb.append("Use the following ability from ").append(object.getLogName()).append("? "); - sb.append(this.getRule(object.getLogName())); - } - else { - sb.append("Use the following ability? ").append(this.getRule()); - } - if (!player.chooseUse(getEffects().get(0).getOutcome(), sb.toString(), game)) { + if (player != null) { + if (!player.chooseUse(getEffects().get(0).getOutcome(), (object != null ? this.getRule(object.getLogName()) : this.getRule()), this, game)) { + return false; + } + } else { return false; } } @@ -116,11 +110,11 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge sb.append("Ability triggers: ").append(object.getLogName()).append(" - ").append(this.getRule(object.getLogName())); } else { sb.append("Ability triggers: ").append(this.getRule()); - } + } String targetText = getTargetDescriptionForLog(getTargets(), game); if (!targetText.isEmpty()) { sb.append(" - ").append(targetText); - } + } return sb.toString(); } @@ -162,18 +156,22 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge @Override public boolean isInUseableZone(Game game, MageObject source, GameEvent event) { - + /** - * 603.6. Trigger events that involve objects changing zones are called “zone-change triggers.” - * Many abilities with zone-change triggers attempt to do something to that object after it - * changes zones. During resolution, these abilities look for the object in the zone that - * it moved to. If the object is unable to be found in the zone it went to, the part of the - * ability attempting to do something to the object will fail to do anything. The ability could - * be unable to find the object because the object never entered the specified zone, because it - * left the zone before the ability resolved, or because it is in a zone that is hidden from - * a player, such as a library or an opponent’s hand. (This rule applies even if the object - * leaves the zone and returns again before the ability resolves.) The most common zone-change - * triggers are enters-the-battlefield triggers and leaves-the-battlefield triggers. + * 603.6. Trigger events that involve objects changing zones are called + * “zone-change triggers.” Many abilities with zone-change triggers + * attempt to do something to that object after it changes zones. During + * resolution, these abilities look for the object in the zone that it + * moved to. If the object is unable to be found in the zone it went to, + * the part of the ability attempting to do something to the object will + * fail to do anything. The ability could be unable to find the object + * because the object never entered the specified zone, because it left + * the zone before the ability resolved, or because it is in a zone that + * is hidden from a player, such as a library or an opponent’s hand. + * (This rule applies even if the object leaves the zone and returns + * again before the ability resolves.) The most common zone-change + * triggers are enters-the-battlefield triggers and + * leaves-the-battlefield triggers. */ if (event != null && event.getTargetId() != null && event.getTargetId().equals(getSourceId())) { switch (event.getType()) { @@ -182,18 +180,18 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge if (event.getType().equals(EventType.DESTROYED_PERMANENT)) { source = game.getLastKnownInformation(getSourceId(), Zone.BATTLEFIELD); } else { - if (((ZoneChangeEvent)event).getTarget() != null) { - source = ((ZoneChangeEvent)event).getTarget(); - } else { - source = game.getLastKnownInformation(getSourceId(), ((ZoneChangeEvent)event).getZone()); + if (((ZoneChangeEvent) event).getTarget() != null) { + source = ((ZoneChangeEvent) event).getTarget(); + } else { + source = game.getLastKnownInformation(getSourceId(), ((ZoneChangeEvent) event).getZone()); } } - + case PHASED_OUT: case PHASED_IN: - if (this.zone == Zone.ALL || game.getLastKnownInformation(getSourceId(), zone) != null) { - return this.hasSourceObjectAbility(game, source, event); - } + if (this.zone == Zone.ALL || game.getLastKnownInformation(getSourceId(), zone) != null) { + return this.hasSourceObjectAbility(game, source, event); + } } } return super.isInUseableZone(game, source, event); diff --git a/Mage/src/mage/abilities/abilityword/KinshipAbility.java b/Mage/src/mage/abilities/abilityword/KinshipAbility.java index d0403232251..82716be27db 100644 --- a/Mage/src/mage/abilities/abilityword/KinshipAbility.java +++ b/Mage/src/mage/abilities/abilityword/KinshipAbility.java @@ -127,7 +127,7 @@ class KinshipBaseEffect extends OneShotEffect { Cards cards = new CardsImpl(card); controller.lookAtCards(sourcePermanent.getName(), cards, game); if (CardUtil.shareSubtypes(sourcePermanent, card)) { - if (controller.chooseUse(outcome,new StringBuilder("Kinship - Reveal ").append(card.getLogName()).append("?").toString(), game)) { + if (controller.chooseUse(outcome,new StringBuilder("Kinship - Reveal ").append(card.getLogName()).append("?").toString(), source, game)) { controller.revealCards(sourcePermanent.getName(), cards, game); for (Effect effect: kinshipEffects) { effect.setTargetPointer(new FixedTarget(card.getId())); diff --git a/Mage/src/mage/abilities/common/PutIntoGraveFromAnywhereSourceAbility.java b/Mage/src/mage/abilities/common/PutIntoGraveFromAnywhereSourceAbility.java index f0f56848cb8..625a5e13640 100644 --- a/Mage/src/mage/abilities/common/PutIntoGraveFromAnywhereSourceAbility.java +++ b/Mage/src/mage/abilities/common/PutIntoGraveFromAnywhereSourceAbility.java @@ -148,7 +148,7 @@ class PutIntoGraveFromAnywhereEffect extends ReplacementEffectImpl { if (controller == null || object == null) { return false; } - if (!controller.chooseUse(outcome, new StringBuilder("Use effect of ").append(object.getLogName()).append("?").toString(), game)) { + if (!controller.chooseUse(outcome, new StringBuilder("Use effect of ").append(object.getLogName()).append("?").toString(), source, game)) { return false; } } diff --git a/Mage/src/mage/abilities/common/delayed/PactDelayedTriggeredAbility.java b/Mage/src/mage/abilities/common/delayed/PactDelayedTriggeredAbility.java index e6564c2cc00..e922c99382e 100644 --- a/Mage/src/mage/abilities/common/delayed/PactDelayedTriggeredAbility.java +++ b/Mage/src/mage/abilities/common/delayed/PactDelayedTriggeredAbility.java @@ -98,7 +98,7 @@ class PactEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - if (player.chooseUse(Outcome.Benefit, "Pay " + cost.getText() + "?", game)) { + if (player.chooseUse(Outcome.Benefit, "Pay " + cost.getText() + "?", source, game)) { cost.clearPaid(); if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)){ return true; diff --git a/Mage/src/mage/abilities/costs/AlternativeCostSourceAbility.java b/Mage/src/mage/abilities/costs/AlternativeCostSourceAbility.java index a041c5cec2f..adad581065c 100644 --- a/Mage/src/mage/abilities/costs/AlternativeCostSourceAbility.java +++ b/Mage/src/mage/abilities/costs/AlternativeCostSourceAbility.java @@ -70,12 +70,14 @@ public class AlternativeCostSourceAbility extends StaticAbility implements Alter } /** - * + * * @param cost alternate cost to pay - * @param condition only if the condition is true it's possible to use the alternate costs + * @param condition only if the condition is true it's possible to use the + * alternate costs * @param rule if != null used as rule text * @param filter filters the cards this alternate cost can be applied to - * @param onlyMana if true only the mana costs are replaced by this costs, other costs stay untouched + * @param onlyMana if true only the mana costs are replaced by this costs, + * other costs stay untouched */ public AlternativeCostSourceAbility(Cost cost, Condition condition, String rule, FilterCard filter, boolean onlyMana) { super(Zone.ALL, null); @@ -86,7 +88,7 @@ public class AlternativeCostSourceAbility extends StaticAbility implements Alter this.filter = filter; this.onlyMana = onlyMana; } - + public AlternativeCostSourceAbility(Condition condition, String rule, FilterCard filter, boolean onlyMana, DynamicCost dynamicCost) { super(Zone.ALL, null); this.setRuleAtTheTop(true); @@ -109,14 +111,14 @@ public class AlternativeCostSourceAbility extends StaticAbility implements Alter @Override public void addCost(Cost cost) { - AlternativeCost2 alternativeCost = convertToAlternativeCost(cost); - if(alternativeCost != null) { - this.alternateCosts.add(alternativeCost); - } + AlternativeCost2 alternativeCost = convertToAlternativeCost(cost); + if (alternativeCost != null) { + this.alternateCosts.add(alternativeCost); + } } private AlternativeCost2 convertToAlternativeCost(Cost cost) { - return cost != null ? new AlternativeCost2Impl(null, cost.getText(), cost) : null; + return cost != null ? new AlternativeCost2Impl(null, cost.getText(), cost) : null; } @Override @@ -143,26 +145,25 @@ public class AlternativeCostSourceAbility extends StaticAbility implements Alter } Player player = game.getPlayer(ability.getControllerId()); if (player != null) { - Costs alternativeCosts; - if(dynamicCost != null) { - alternativeCosts = new CostsImpl<>(); - alternativeCosts.add(convertToAlternativeCost(dynamicCost.getCost(ability, game))); - } else { - alternativeCosts = this.alternateCosts; - } - - String costChoiceText; - if(dynamicCost != null) { - costChoiceText = dynamicCost.getText(ability, game); - } else { - costChoiceText = alternativeCosts.isEmpty() ? "Cast without paying its mana cost?" : "Pay alternative costs? (" + alternativeCosts.getText() +")"; - } - - - if (alternativeCosts.canPay(ability, ability.getSourceId(), ability.getControllerId(), game) && - player.chooseUse(Outcome.Benefit, costChoiceText, game)) { + Costs alternativeCosts; + if (dynamicCost != null) { + alternativeCosts = new CostsImpl<>(); + alternativeCosts.add(convertToAlternativeCost(dynamicCost.getCost(ability, game))); + } else { + alternativeCosts = this.alternateCosts; + } + + String costChoiceText; + if (dynamicCost != null) { + costChoiceText = dynamicCost.getText(ability, game); + } else { + costChoiceText = alternativeCosts.isEmpty() ? "Cast without paying its mana cost?" : "Pay alternative costs? (" + alternativeCosts.getText() + ")"; + } + + if (alternativeCosts.canPay(ability, ability.getSourceId(), ability.getControllerId(), game) + && player.chooseUse(Outcome.Benefit, costChoiceText, this, game)) { ability.getManaCostsToPay().clear(); - if(!onlyMana) { + if (!onlyMana) { ability.getCosts().clear(); } for (Cost cost : alternativeCosts) { @@ -189,13 +190,13 @@ public class AlternativeCostSourceAbility extends StaticAbility implements Alter @Override public boolean isActivated(Ability source, Game game) { - Costs alternativeCosts; - if(dynamicCost != null) { - alternativeCosts = new CostsImpl<>(); - alternativeCosts.add(convertToAlternativeCost(dynamicCost.getCost(source, game))); - } else { - alternativeCosts = this.alternateCosts; - } + Costs alternativeCosts; + if (dynamicCost != null) { + alternativeCosts = new CostsImpl<>(); + alternativeCosts.add(convertToAlternativeCost(dynamicCost.getCost(source, game))); + } else { + alternativeCosts = this.alternateCosts; + } for (AlternativeCost2 cost : alternativeCosts) { if (cost.isActivated(game)) { return true; @@ -206,7 +207,7 @@ public class AlternativeCostSourceAbility extends StaticAbility implements Alter @Override public String getCastMessageSuffix(Game game) { - return alternateCosts.isEmpty() ? " without paying it's mana costs":" using alternative casting costs"; + return alternateCosts.isEmpty() ? " without paying it's mana costs" : " using alternative casting costs"; } @Override @@ -227,7 +228,7 @@ public class AlternativeCostSourceAbility extends StaticAbility implements Alter } int numberCosts = 0; String remarkText = ""; - for (AlternativeCost2 alternativeCost : alternateCosts) { + for (AlternativeCost2 alternativeCost : alternateCosts) { if (numberCosts == 0) { if (alternativeCost.getCost() instanceof ManaCost) { sb.append("pay "); @@ -261,5 +262,5 @@ public class AlternativeCostSourceAbility extends StaticAbility implements Alter alterCosts.addAll(alternateCosts); return alterCosts; } - + } diff --git a/Mage/src/mage/abilities/costs/OrCost.java b/Mage/src/mage/abilities/costs/OrCost.java index 92d3499887c..2c5a7740e7c 100644 --- a/Mage/src/mage/abilities/costs/OrCost.java +++ b/Mage/src/mage/abilities/costs/OrCost.java @@ -1,35 +1,33 @@ /* -* 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. -*/ - + * 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.costs; import java.util.UUID; - import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCost; import mage.constants.Outcome; @@ -37,13 +35,8 @@ import mage.game.Game; import mage.players.Player; import mage.target.Targets; -/** - * - * @author LevelX2 - */ - - public class OrCost implements Cost { + private Cost firstCost; private Cost secondCost; private String description; @@ -92,12 +85,12 @@ public class OrCost implements Cost { if (selectedCost == null) { Player controller = game.getPlayer(controllerId); if (controller != null) { - StringBuilder sb = new StringBuilder(); + StringBuilder sb = new StringBuilder(); if (firstCost instanceof ManaCost) { sb.append("Pay "); } sb.append(firstCost.getText()).append("?"); - if (controller.chooseUse(Outcome.Detriment, sb.toString(), game)) { + if (controller.chooseUse(Outcome.Detriment, sb.toString(), ability, game)) { selectedCost = firstCost; } else { selectedCost = secondCost; diff --git a/Mage/src/mage/abilities/costs/common/RevealTargetFromHandCost.java b/Mage/src/mage/abilities/costs/common/RevealTargetFromHandCost.java index 23c0fd4333d..492a07fff12 100644 --- a/Mage/src/mage/abilities/costs/common/RevealTargetFromHandCost.java +++ b/Mage/src/mage/abilities/costs/common/RevealTargetFromHandCost.java @@ -29,12 +29,13 @@ package mage.abilities.costs.common; import java.util.UUID; -import mage.constants.Outcome; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.costs.CostImpl; import mage.cards.Card; import mage.cards.Cards; import mage.cards.CardsImpl; +import mage.constants.Outcome; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInHand; @@ -46,7 +47,7 @@ public class RevealTargetFromHandCost extends CostImpl { public RevealTargetFromHandCost(TargetCardInHand target) { this.addTarget(target); - this.text = (target.getNumberOfTargets() == 0 ?"you may ":"") + "reveal " + target.getTargetName(); + this.text = (target.getNumberOfTargets() == 0 ? "you may " : "") + "reveal " + target.getTargetName(); } public RevealTargetFromHandCost(final RevealTargetFromHandCost cost) { @@ -70,8 +71,9 @@ public class RevealTargetFromHandCost extends CostImpl { cards.add(card); } } - if (numberCardsRevealed > 0 ) { - player.revealCards("card cost", cards, game); + if (numberCardsRevealed > 0) { + MageObject baseObject = game.getBaseObject(sourceId); + player.revealCards(baseObject == null ? "card cost" : baseObject.getIdName(), cards, game); } if (targets.get(0).getNumberOfTargets() <= numberCardsRevealed) { paid = true; // e.g. for optional additional costs. example: Dragonlord's Prerogative also true if 0 cards shown diff --git a/Mage/src/mage/abilities/decorator/ConditionalRestrictionEffect.java b/Mage/src/mage/abilities/decorator/ConditionalRestrictionEffect.java index d829e3a85b4..20ae54c777d 100644 --- a/Mage/src/mage/abilities/decorator/ConditionalRestrictionEffect.java +++ b/Mage/src/mage/abilities/decorator/ConditionalRestrictionEffect.java @@ -25,7 +25,6 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.decorator; import mage.abilities.Ability; @@ -42,8 +41,7 @@ import mage.game.permanent.Permanent; * * @author LevelX2 */ - -public class ConditionalRestrictionEffect extends RestrictionEffect { +public class ConditionalRestrictionEffect extends RestrictionEffect { protected RestrictionEffect effect; protected RestrictionEffect otherwiseEffect; @@ -55,7 +53,7 @@ public class ConditionalRestrictionEffect extends RestrictionEffect { public ConditionalRestrictionEffect(RestrictionEffect effect, Condition condition) { this(Duration.WhileOnBattlefield, effect, condition, null); } - + public ConditionalRestrictionEffect(Duration duration, RestrictionEffect effect, Condition condition, RestrictionEffect otherwiseEffect) { super(duration); this.effectType = EffectType.RESTRICTION; @@ -93,7 +91,6 @@ public class ConditionalRestrictionEffect extends RestrictionEffect { initDone = true; } - @Override public boolean applies(Permanent permanent, Ability source, Game game) { if (!initDone) { // if simpleStaticAbility, init won't be called @@ -102,7 +99,7 @@ public class ConditionalRestrictionEffect extends RestrictionEffect { conditionState = condition.apply(game, source); if (conditionState) { effect.setTargetPointer(this.targetPointer); - return effect.applies(permanent, source,game); + return effect.applies(permanent, source, game); } else if (otherwiseEffect != null) { otherwiseEffect.setTargetPointer(this.targetPointer); return otherwiseEffect.applies(permanent, source, game); @@ -147,11 +144,11 @@ public class ConditionalRestrictionEffect extends RestrictionEffect { } @Override - public boolean canBeUntapped(Permanent permanent, Game game) { + public boolean canBeUntapped(Permanent permanent, Ability source, Game game) { if (conditionState) { - return effect.canBeUntapped(permanent, game); + return effect.canBeUntapped(permanent, source, game); } else if (otherwiseEffect != null) { - return otherwiseEffect.canBeUntapped(permanent, game); + return otherwiseEffect.canBeUntapped(permanent, source, game); } return true; } diff --git a/Mage/src/mage/abilities/dynamicvalue/common/PermanentsTargetOpponentControlsCount.java b/Mage/src/mage/abilities/dynamicvalue/common/PermanentsTargetOpponentControlsCount.java new file mode 100644 index 00000000000..f1f7ef9b874 --- /dev/null +++ b/Mage/src/mage/abilities/dynamicvalue/common/PermanentsTargetOpponentControlsCount.java @@ -0,0 +1,67 @@ +package mage.abilities.dynamicvalue.common; + +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.filter.FilterPermanent; +import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.game.Game; + +/** + * + * @author LoneFox + */ + +public class PermanentsTargetOpponentControlsCount implements DynamicValue { + + private FilterPermanent filter; + private Integer multiplier; + + public PermanentsTargetOpponentControlsCount() { + this(new FilterPermanent(), 1); + } + + public PermanentsTargetOpponentControlsCount(FilterPermanent filter) { + this(filter, 1); + } + + public PermanentsTargetOpponentControlsCount(FilterPermanent filter, Integer multiplier) { + this.filter = filter; + this.multiplier = multiplier; + } + + public PermanentsTargetOpponentControlsCount(final PermanentsTargetOpponentControlsCount dynamicValue) { + this.filter = dynamicValue.filter; + this.multiplier = dynamicValue.multiplier; + } + + @Override + public DynamicValue copy() { + return new PermanentsTargetOpponentControlsCount(this); + } + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + if(sourceAbility.getFirstTarget() != null) { + filter.add(new ControllerIdPredicate(sourceAbility.getFirstTarget())); + int value = game.getBattlefield().count(filter, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game); + return multiplier * value; + } + else { + return 0; + } + } + + @Override + public String toString() { + if(multiplier != null) { + return multiplier.toString(); + } + return "X"; + } + + @Override + public String getMessage() { + return filter.getMessage() + " target opponent controls"; + } +} diff --git a/Mage/src/mage/abilities/effects/AsTurnedFaceUpEffect.java b/Mage/src/mage/abilities/effects/AsTurnedFaceUpEffect.java index 9df6bf2eefa..3709ad2fa28 100644 --- a/Mage/src/mage/abilities/effects/AsTurnedFaceUpEffect.java +++ b/Mage/src/mage/abilities/effects/AsTurnedFaceUpEffect.java @@ -85,7 +85,7 @@ public class AsTurnedFaceUpEffect extends ReplacementEffectImpl { if (controller == null || object == null) { return false; } - if (!controller.chooseUse(outcome, new StringBuilder("Use effect of ").append(object.getLogName()).append("?").toString(), game)) { + if (!controller.chooseUse(outcome, new StringBuilder("Use effect of ").append(object.getLogName()).append("?").toString(), source, game)) { return false; } } diff --git a/Mage/src/mage/abilities/effects/ContinuousEffects.java b/Mage/src/mage/abilities/effects/ContinuousEffects.java index 333e964da87..b19c4420926 100644 --- a/Mage/src/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/mage/abilities/effects/ContinuousEffects.java @@ -628,7 +628,7 @@ public class ContinuousEffects implements Serializable { if (spliceAbilities.size() > 0) { Player controller = game.getPlayer(abilityToModify.getControllerId()); - if (controller.chooseUse(Outcome.Benefit, "Splice a card?", game)) { + if (controller.chooseUse(Outcome.Benefit, "Splice a card?", abilityToModify, game)) { Cards cardsToReveal = new CardsImpl(); do { FilterCard filter = new FilterCard("a card to splice"); @@ -655,7 +655,7 @@ public class ContinuousEffects implements Serializable { spliceAbilities.remove(selectedAbility); } } - } while (!spliceAbilities.isEmpty() && controller.chooseUse(Outcome.Benefit, "Splice another card?", game)); + } while (!spliceAbilities.isEmpty() && controller.chooseUse(Outcome.Benefit, "Splice another card?", abilityToModify, game)); controller.revealCards("Spliced cards", cardsToReveal, game); } } diff --git a/Mage/src/mage/abilities/effects/EntersBattlefieldEffect.java b/Mage/src/mage/abilities/effects/EntersBattlefieldEffect.java index 92dbfa7aa0d..90bdfaf14c3 100644 --- a/Mage/src/mage/abilities/effects/EntersBattlefieldEffect.java +++ b/Mage/src/mage/abilities/effects/EntersBattlefieldEffect.java @@ -111,7 +111,7 @@ public class EntersBattlefieldEffect extends ReplacementEffectImpl { if (controller == null || object == null) { return false; } - if (!controller.chooseUse(outcome, new StringBuilder("Use effect of ").append(object.getLogName()).append("?").toString(), game)) { + if (!controller.chooseUse(outcome, new StringBuilder("Use effect of ").append(object.getLogName()).append("?").toString(), source, game)) { return false; } } diff --git a/Mage/src/mage/abilities/effects/PlaneswalkerRedirectionEffect.java b/Mage/src/mage/abilities/effects/PlaneswalkerRedirectionEffect.java index 3e4aad2d6e4..7f2ee3c504d 100644 --- a/Mage/src/mage/abilities/effects/PlaneswalkerRedirectionEffect.java +++ b/Mage/src/mage/abilities/effects/PlaneswalkerRedirectionEffect.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,14 +20,14 @@ * 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 java.util.List; import java.util.UUID; import mage.abilities.Ability; import mage.constants.Duration; @@ -42,7 +42,6 @@ import mage.game.stack.StackObject; import mage.players.Player; import mage.target.TargetPermanent; - /** * * @author BetaSteward_at_googlemail.com @@ -68,22 +67,24 @@ public class PlaneswalkerRedirectionEffect extends RedirectionEffect { public boolean checksEventType(GameEvent event, Game game) { return event.getType() == EventType.DAMAGE_PLAYER; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { - DamageEvent damageEvent = (DamageEvent)event; + DamageEvent damageEvent = (DamageEvent) event; UUID playerId = getSourceControllerId(event.getSourceId(), game); if (!damageEvent.isCombatDamage() && game.getOpponents(event.getTargetId()).contains(playerId)) { Player target = game.getPlayer(event.getTargetId()); Player player = game.getPlayer(playerId); if (target != null && player != null) { int numPlaneswalkers = game.getBattlefield().countAll(filter, target.getId(), game); - if (numPlaneswalkers > 0 && player.chooseUse(outcome, "Redirect damage to planeswalker?", game)) { + if (numPlaneswalkers > 0 && player.chooseUse(outcome, "Redirect damage to planeswalker?", source, game)) { redirectTarget = new TargetPermanent(filter); if (numPlaneswalkers == 1) { - redirectTarget.add(game.getBattlefield().getAllActivePermanents(filter, target.getId(), game).get(0).getId(), game); - } - else { + List planeswalker = game.getBattlefield().getAllActivePermanents(filter, target.getId(), game); + if (!planeswalker.isEmpty()) { + redirectTarget.add(planeswalker.get(0).getId(), game); + } + } else { player.choose(Outcome.Damage, redirectTarget, null, game); } if (!game.isSimulation()) { diff --git a/Mage/src/mage/abilities/effects/RestrictionEffect.java b/Mage/src/mage/abilities/effects/RestrictionEffect.java index 87df553a361..47f89ec6021 100644 --- a/Mage/src/mage/abilities/effects/RestrictionEffect.java +++ b/Mage/src/mage/abilities/effects/RestrictionEffect.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,12 +20,11 @@ * 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 java.util.UUID; @@ -48,7 +47,7 @@ public abstract class RestrictionEffect extends ContinuousEffectImpl { public RestrictionEffect(Duration duration, Outcome outcome) { super(duration, outcome); - this.effectType = EffectType.RESTRICTION; + this.effectType = EffectType.RESTRICTION; } public RestrictionEffect(final RestrictionEffect effect) { @@ -65,7 +64,7 @@ public abstract class RestrictionEffect extends ContinuousEffectImpl { public boolean canAttack(Game game) { return true; } - + public boolean canAttack(UUID defenderId, Ability source, Game game) { return true; } @@ -80,22 +79,23 @@ public abstract class RestrictionEffect extends ContinuousEffectImpl { /** * Called for all attackers after all blocking decisions are made - * + * * @param attacker * @param source * @param game - * @return true = block is ok false = block is not valid (human: back to defining blockers, AI: remove blocker) + * @return true = block is ok false = block is not valid (human: back to + * defining blockers, AI: remove blocker) */ public boolean canBeBlockedCheckAfter(Permanent attacker, Ability source, Game game) { return true; } - - public boolean canBeUntapped(Permanent permanent, Game game) { + + public boolean canBeUntapped(Permanent permanent, Ability source, Game game) { return true; } public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game) { return true; } - + } diff --git a/Mage/src/mage/abilities/effects/common/AmplifyEffect.java b/Mage/src/mage/abilities/effects/common/AmplifyEffect.java index 2cfb394c77a..a06e008ad7a 100644 --- a/Mage/src/mage/abilities/effects/common/AmplifyEffect.java +++ b/Mage/src/mage/abilities/effects/common/AmplifyEffect.java @@ -109,7 +109,7 @@ public class AmplifyEffect extends ReplacementEffectImpl { filter.add(filterSubtypes.get(0)); } if (controller.getHand().count(filter, source.getSourceId(), source.getControllerId(), game) > 0){ - if (controller.chooseUse(outcome, "Reveal cards to Amplify?", game)) { + if (controller.chooseUse(outcome, "Reveal cards to Amplify?", source, game)) { TargetCardInHand target = new TargetCardInHand(0, Integer.MAX_VALUE, filter); if (controller.chooseTarget(outcome, target, source, game) && !target.getTargets().isEmpty()) { Cards cards = new CardsImpl(); diff --git a/Mage/src/mage/abilities/effects/common/AttachEffect.java b/Mage/src/mage/abilities/effects/common/AttachEffect.java index 4e5c446712a..2fe23522239 100644 --- a/Mage/src/mage/abilities/effects/common/AttachEffect.java +++ b/Mage/src/mage/abilities/effects/common/AttachEffect.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,18 +20,16 @@ * 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.common; -import mage.MageObject; -import mage.constants.Outcome; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -69,8 +67,7 @@ public class AttachEffect extends OneShotEffect { Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); if (permanent != null) { return permanent.addAttachment(source.getSourceId(), game); - } - else { + } else { Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); if (player != null) { return player.addAttachment(source.getSourceId(), game); diff --git a/Mage/src/mage/abilities/effects/common/CastCardFromOutsideTheGameEffect.java b/Mage/src/mage/abilities/effects/common/CastCardFromOutsideTheGameEffect.java index 8498cc29c00..5dbef2a742b 100644 --- a/Mage/src/mage/abilities/effects/common/CastCardFromOutsideTheGameEffect.java +++ b/Mage/src/mage/abilities/effects/common/CastCardFromOutsideTheGameEffect.java @@ -73,7 +73,7 @@ public class CastCardFromOutsideTheGameEffect extends OneShotEffect { return false; } - while (player.chooseUse(Outcome.Benefit, choiceText, game)) { + while (player.chooseUse(Outcome.Benefit, choiceText, source, game)) { Cards cards = player.getSideboard(); if (cards.isEmpty()) { if (!game.isSimulation()) diff --git a/Mage/src/mage/abilities/effects/common/CipherEffect.java b/Mage/src/mage/abilities/effects/common/CipherEffect.java index 8bdc853a650..d4bbdb20a20 100644 --- a/Mage/src/mage/abilities/effects/common/CipherEffect.java +++ b/Mage/src/mage/abilities/effects/common/CipherEffect.java @@ -89,7 +89,7 @@ public class CipherEffect extends OneShotEffect { TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent(); if (controller != null) { if (target.canChoose(source.getControllerId(), game) - && controller.chooseUse(outcome, "Cipher this spell to a creature?", game)) { + && controller.chooseUse(outcome, "Cipher this spell to a creature?", source, game)) { controller.chooseTarget(outcome, target, source, game); Card sourceCard = game.getCard(source.getSourceId()); Permanent targetCreature = game.getPermanent(target.getFirstTarget()); diff --git a/Mage/src/mage/abilities/effects/common/ClashEffect.java b/Mage/src/mage/abilities/effects/common/ClashEffect.java index 145faf5175e..71b22bfa968 100644 --- a/Mage/src/mage/abilities/effects/common/ClashEffect.java +++ b/Mage/src/mage/abilities/effects/common/ClashEffect.java @@ -25,10 +25,10 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.effects.common; import java.io.ObjectStreamException; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.MageSingleton; import mage.abilities.effects.Effect; @@ -47,54 +47,72 @@ import mage.target.Target; import mage.target.common.TargetOpponent; /** - 1. The controller of the spell or ability chooses an opponent. (This doesn't target the opponent.) - 2. Each player involved in the clash reveals the top card of his or her library. - 3. The converted mana costs of the revealed cards are noted. - 4. In turn order, each player involved in the clash chooses to put his or her revealed card on either the top or bottom of his or her library. (Note that the player whose turn it is does this first, not necessarily the controller of the clash spell or ability.) When the second player makes this decision, he or she will know what the first player chose. Then all cards are moved at the same time. - 5. The clash is over. If one player in the clash revealed a card with a higher converted mana cost than all other cards revealed in the clash, that player wins the clash. - 6. If any abilities trigger when a player clashes, they trigger and wait to be put on the stack. - 7. The clash spell or ability finishes resolving. That usually involves a bonus gained by the controller of the clash spell or ability if he or she won the clash. - 8. Abilities that triggered during the clash are put on the stack. - - There are no draws or losses in a clash. Either you win it or you don't. - Each spell or ability with clash says what happens if you (the controller of that spell or ability) win the clash. Typically, if you don't win the clash, nothing happens. - If no one reveals a card with a higher converted mana cost (for example, each player reveals a card with converted mana cost 2), no one wins the clash. - An X in a revealed card's mana cost is treated as 0. - A card without a mana cost (such as a land) has a converted mana cost of 0. - If one or more of the clashing players reveals a split card, each of the split card's converted mana costs is considered individually. In this way, it's possible for multiple players to win a clash. For example, if Player A reveals a split card with converted mana costs 1 and 3, and Player B reveals a card with converted mana cost 2, they'll both win. (Player A's card has a higher converted mana cost than Player B's card, since 3 is greater than 2. Player B's card has a higher converted mana cost than Player A's card, since 2 is greater than 1.) - + * 1. The controller of the spell or ability chooses an opponent. (This doesn't + * target the opponent.) 2. Each player involved in the clash reveals the top + * card of his or her library. 3. The converted mana costs of the revealed cards + * are noted. 4. In turn order, each player involved in the clash chooses to put + * his or her revealed card on either the top or bottom of his or her library. + * (Note that the player whose turn it is does this first, not necessarily the + * controller of the clash spell or ability.) When the second player makes this + * decision, he or she will know what the first player chose. Then all cards are + * moved at the same time. 5. The clash is over. If one player in the clash + * revealed a card with a higher converted mana cost than all other cards + * revealed in the clash, that player wins the clash. 6. If any abilities + * trigger when a player clashes, they trigger and wait to be put on the stack. + * 7. The clash spell or ability finishes resolving. That usually involves a + * bonus gained by the controller of the clash spell or ability if he or she won + * the clash. 8. Abilities that triggered during the clash are put on the stack. + * + * There are no draws or losses in a clash. Either you win it or you don't. Each + * spell or ability with clash says what happens if you (the controller of that + * spell or ability) win the clash. Typically, if you don't win the clash, + * nothing happens. If no one reveals a card with a higher converted mana cost + * (for example, each player reveals a card with converted mana cost 2), no one + * wins the clash. An X in a revealed card's mana cost is treated as 0. A card + * without a mana cost (such as a land) has a converted mana cost of 0. If one + * or more of the clashing players reveals a split card, each of the split + * card's converted mana costs is considered individually. In this way, it's + * possible for multiple players to win a clash. For example, if Player A + * reveals a split card with converted mana costs 1 and 3, and Player B reveals + * a card with converted mana cost 2, they'll both win. (Player A's card has a + * higher converted mana cost than Player B's card, since 3 is greater than 2. + * Player B's card has a higher converted mana cost than Player A's card, since + * 2 is greater than 1.) + * * @author LevelX2 */ - public class ClashEffect extends OneShotEffect implements MageSingleton { - - private static final ClashEffect fINSTANCE = new ClashEffect(); + + private static final ClashEffect fINSTANCE = new ClashEffect(); private Object readResolve() throws ObjectStreamException { return fINSTANCE; - } - + } + private ClashEffect() { super(Outcome.Benefit); this.staticText = "Clash with an opponent"; } - + public static ClashEffect getInstance() { return fINSTANCE; - } + } + public ClashEffect(final ClashEffect effect) { super(effect); } - + @Override public ClashEffect copy() { return new ClashEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null && !game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.CLASH, controller.getId(), controller.getId()))) { + MageObject sourceObject = source.getSourceObject(game); + if (controller != null && sourceObject != null + && !game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.CLASH, controller.getId(), controller.getId()))) { // choose opponent Target target = new TargetOpponent(true); target.setTargetName("an opponent to clash with"); @@ -110,11 +128,11 @@ public class ClashEffect extends OneShotEffect implements MageSingleton { // Reveal top cards of involved players StringBuilder message = new StringBuilder("Clash: "); message.append(controller.getLogName()); - if (controller.getLibrary().size() > 0) { + if (controller.getLibrary().size() > 0) { Cards cards = new CardsImpl(); cardController = controller.getLibrary().getFromTop(game); cards.add(cardController); - controller.revealCards("for clash by " + controller.getLogName(), cards, game); + controller.revealCards(sourceObject.getIdName() + ": Clash card of " + controller.getName(), cards, game); cmcController = cardController.getManaCost().convertedManaCost(); message.append(" (").append(cmcController).append(")"); } else { @@ -125,7 +143,7 @@ public class ClashEffect extends OneShotEffect implements MageSingleton { Cards cards = new CardsImpl(); cardOpponent = opponent.getLibrary().getFromTop(game); cards.add(cardOpponent); - opponent.revealCards("for clash by " + opponent.getLogName(), cards, game); + opponent.revealCards(sourceObject.getIdName() + ": Clash card of " + opponent.getName(), cards, game); cmcOpponent = cardOpponent.getManaCost().convertedManaCost(); message.append(" (").append(cmcOpponent).append(")"); } else { @@ -141,37 +159,37 @@ public class ClashEffect extends OneShotEffect implements MageSingleton { game.informPlayer(controller, opponent.getLogName() + " won the clash!"); } else { message.append(" no winner "); - } + } game.informPlayers(message.toString()); - } + } // decide to put the cards on top or on the buttom of library in turn order beginning with the active player in turn order PlayerList playerList = game.getPlayerList().copy(); playerList.setCurrent(game.getActivePlayerId()); do { Player current = playerList.getCurrent(game); if (cardController != null && current.getId().equals(controller.getId())) { - topController = current.chooseUse(Outcome.Detriment, "Put " + cardController.getLogName() + " back on top of your library? (otherwise it goes to bottom)" , game); - } + topController = current.chooseUse(Outcome.Detriment, "Put " + cardController.getLogName() + " back on top of your library? (otherwise it goes to bottom)", source, game); + } if (cardOpponent != null && current.getId().equals(opponent.getId())) { - topOpponent = current.chooseUse(Outcome.Detriment, "Put " + cardOpponent.getLogName() + " back on top of your library? (otherwise it goes to bottom)" , game); - } + topOpponent = current.chooseUse(Outcome.Detriment, "Put " + cardOpponent.getLogName() + " back on top of your library? (otherwise it goes to bottom)", source, game); + } } while (!playerList.getNext(game).getId().equals(game.getActivePlayerId())); // put the cards back to library - if (cardController != null) { + if (cardController != null) { controller.moveCardToLibraryWithInfo(cardController, source.getSourceId(), game, Zone.LIBRARY, topController, true); } - if (cardOpponent != null) { + if (cardOpponent != null) { opponent.moveCardToLibraryWithInfo(cardOpponent, source.getSourceId(), game, Zone.LIBRARY, topOpponent, true); } game.fireEvent(new GameEvent(EventType.CLASHED, opponent.getId(), source.getSourceId(), controller.getId(), 0, cmcController > cmcOpponent)); // set opponent to DoIfClashWonEffect - for (Effect effect :source.getEffects()) { + for (Effect effect : source.getEffects()) { if (effect instanceof DoIfClashWonEffect) { effect.setValue("clashOpponent", opponent); - } - } + } + } return cmcController > cmcOpponent; - } + } } } return false; diff --git a/Mage/src/mage/abilities/effects/common/CounterUnlessPaysEffect.java b/Mage/src/mage/abilities/effects/common/CounterUnlessPaysEffect.java index 947eae394c7..be63142eb3e 100644 --- a/Mage/src/mage/abilities/effects/common/CounterUnlessPaysEffect.java +++ b/Mage/src/mage/abilities/effects/common/CounterUnlessPaysEffect.java @@ -93,7 +93,7 @@ public class CounterUnlessPaysEffect extends OneShotEffect { message = costToPay.getText() + " to prevent counter effect?"; } costToPay.clearPaid(); - if (!(player.chooseUse(Outcome.Benefit, message, game) && costToPay.pay(source, game, spell.getSourceId(), spell.getControllerId(), false))) { + if (!(player.chooseUse(Outcome.Benefit, message, source, game) && costToPay.pay(source, game, spell.getSourceId(), spell.getControllerId(), false))) { return game.getStack().counter(spell.getId(), source.getSourceId(), game); } return true; diff --git a/Mage/src/mage/abilities/effects/common/DevourEffect.java b/Mage/src/mage/abilities/effects/common/DevourEffect.java index 0820df25799..1d02ab1733d 100644 --- a/Mage/src/mage/abilities/effects/common/DevourEffect.java +++ b/Mage/src/mage/abilities/effects/common/DevourEffect.java @@ -136,7 +136,7 @@ public class DevourEffect extends ReplacementEffectImpl { if (!target.canChoose(source.getSourceId(), source.getControllerId(), game)) { return false; } - if (controller.chooseUse(Outcome.Detriment, "Devour creatures?", game)) { + if (controller.chooseUse(Outcome.Detriment, "Devour creatures?", source, game)) { controller.chooseTarget(Outcome.Detriment, target, source, game); if (target.getTargets().size() > 0) { List> cardSubtypes = new ArrayList<>(); diff --git a/Mage/src/mage/abilities/effects/common/DoIfClashWonEffect.java b/Mage/src/mage/abilities/effects/common/DoIfClashWonEffect.java index e33f58311df..356692e44f7 100644 --- a/Mage/src/mage/abilities/effects/common/DoIfClashWonEffect.java +++ b/Mage/src/mage/abilities/effects/common/DoIfClashWonEffect.java @@ -79,7 +79,7 @@ public class DoIfClashWonEffect extends OneShotEffect { message = CardUtil.replaceSourceName(message, mageObject.getLogName()); } - if (chooseUseText == null || player.chooseUse(executingEffect.getOutcome(), message, game)) { + if (chooseUseText == null || player.chooseUse(executingEffect.getOutcome(), message, source, game)) { if (ClashEffect.getInstance().apply(game, source)) { if (setTargetPointerToClashedOpponent) { Object opponent = getValue("clashOpponent"); diff --git a/Mage/src/mage/abilities/effects/common/DoIfCostPaid.java b/Mage/src/mage/abilities/effects/common/DoIfCostPaid.java index 344e6aadc6d..000ee2e2753 100644 --- a/Mage/src/mage/abilities/effects/common/DoIfCostPaid.java +++ b/Mage/src/mage/abilities/effects/common/DoIfCostPaid.java @@ -14,6 +14,7 @@ import mage.players.Player; import mage.util.CardUtil; public class DoIfCostPaid extends OneShotEffect { + protected Effects executingEffects = new Effects(); private final Cost cost; private String chooseUseText; @@ -39,7 +40,7 @@ public class DoIfCostPaid extends OneShotEffect { public void addEffect(Effect effect) { executingEffects.add(effect); } - + @Override public boolean apply(Game game, Ability source) { Player player = getPayingPlayer(game, source); @@ -48,28 +49,27 @@ public class DoIfCostPaid extends OneShotEffect { String message; if (chooseUseText == null) { String effectText = executingEffects.getText(source.getModes().getMode()); - if (effectText.length() > 0 && effectText.charAt(effectText.length()-1)=='.') { - effectText = effectText.substring(0, effectText.length()-1); + if (effectText.length() > 0 && effectText.charAt(effectText.length() - 1) == '.') { + effectText = effectText.substring(0, effectText.length() - 1); } - message = getCostText() +" and " + effectText + "?"; + message = getCostText() + " and " + effectText + "?"; } else { message = chooseUseText; } message = CardUtil.replaceSourceName(message, mageObject.getLogName()); boolean result = true; - if (cost.canPay(source, source.getSourceId(), player.getId(), game) && player.chooseUse(executingEffects.get(0).getOutcome(), message, game)) { + if (cost.canPay(source, source.getSourceId(), player.getId(), game) && player.chooseUse(executingEffects.get(0).getOutcome(), message, source, game)) { cost.clearPaid(); if (cost.pay(source, game, source.getSourceId(), player.getId(), false)) { - - for(Effect effect: executingEffects) { + for (Effect effect : executingEffects) { effect.setTargetPointer(this.targetPointer); if (effect instanceof OneShotEffect) { result &= effect.apply(game, source); - } - else { + } else { game.addEffect((ContinuousEffect) effect, source); } } + player.resetStoredBookmark(game); // otherwise you can undo card drawn with Mentor of the Meek } } return result; @@ -108,4 +108,3 @@ public class DoIfCostPaid extends OneShotEffect { return new DoIfCostPaid(this); } } - diff --git a/Mage/src/mage/abilities/effects/common/DoUnlessAnyPlayerPaysEffect.java b/Mage/src/mage/abilities/effects/common/DoUnlessAnyPlayerPaysEffect.java index 5cea6d57822..c7e8ab933dc 100644 --- a/Mage/src/mage/abilities/effects/common/DoUnlessAnyPlayerPaysEffect.java +++ b/Mage/src/mage/abilities/effects/common/DoUnlessAnyPlayerPaysEffect.java @@ -91,7 +91,7 @@ public class DoUnlessAnyPlayerPaysEffect extends OneShotEffect { // check if any player is willing to pay for (UUID playerId: controller.getInRange()) { Player player = game.getPlayer(playerId); - if (player != null && cost.canPay(source, source.getSourceId(), player.getId(), game) && player.chooseUse(Outcome.Detriment, message, game)) { + if (player != null && cost.canPay(source, source.getSourceId(), player.getId(), game) && player.chooseUse(Outcome.Detriment, message, source, game)) { cost.clearPaid(); if (cost.pay(source, game, source.getSourceId(), player.getId(), false)) { if (!game.isSimulation()) diff --git a/Mage/src/mage/abilities/effects/common/DrawCardTargetEffect.java b/Mage/src/mage/abilities/effects/common/DrawCardTargetEffect.java index d6cb79f40c4..6443cc2efbc 100644 --- a/Mage/src/mage/abilities/effects/common/DrawCardTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/DrawCardTargetEffect.java @@ -90,7 +90,7 @@ public class DrawCardTargetEffect extends OneShotEffect { if (upTo) { cardsToDraw = player.getAmount(0, cardsToDraw, "Draw how many cards?", game); } - if (!optional || player.chooseUse(outcome, "Use draw effect?", game)) { + if (!optional || player.chooseUse(outcome, "Use draw effect?", source, game)) { player.drawCards(cardsToDraw, game); } return true; diff --git a/Mage/src/mage/abilities/effects/common/DrawDiscardControllerEffect.java b/Mage/src/mage/abilities/effects/common/DrawDiscardControllerEffect.java index 73e05f62eb4..20f1d46d6ed 100644 --- a/Mage/src/mage/abilities/effects/common/DrawDiscardControllerEffect.java +++ b/Mage/src/mage/abilities/effects/common/DrawDiscardControllerEffect.java @@ -82,7 +82,7 @@ public class DrawDiscardControllerEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - if (!optional || player.chooseUse(outcome, "Use draw, then discard effect?", game)) { + if (!optional || player.chooseUse(outcome, "Use draw, then discard effect?", source, game)) { player.drawCards(cardsToDraw, game); player.discard(cardsToDiscard, false, source, game); } diff --git a/Mage/src/mage/abilities/effects/common/EnterBattlefieldPayCostOrPutGraveyardEffect.java b/Mage/src/mage/abilities/effects/common/EnterBattlefieldPayCostOrPutGraveyardEffect.java index b3f4001b7b2..f485ee25c02 100644 --- a/Mage/src/mage/abilities/effects/common/EnterBattlefieldPayCostOrPutGraveyardEffect.java +++ b/Mage/src/mage/abilities/effects/common/EnterBattlefieldPayCostOrPutGraveyardEffect.java @@ -78,7 +78,7 @@ public class EnterBattlefieldPayCostOrPutGraveyardEffect extends ReplacementEffe if (player != null && cost != null && sourceObject != null){ boolean replace = true; if (cost.canPay(source, source.getSourceId(), player.getId(), game)) { - if (player.chooseUse(outcome, cost.getText() + "? (otherwise " + sourceObject.getLogName() + " is put into graveyard)", game)) { + if (player.chooseUse(outcome, cost.getText() + "? (otherwise " + sourceObject.getLogName() + " is put into graveyard)", source, game)) { cost.clearPaid(); replace = !cost.pay(source, game, source.getSourceId(), source.getControllerId(), false); } diff --git a/Mage/src/mage/abilities/effects/common/HideawayPlayEffect.java b/Mage/src/mage/abilities/effects/common/HideawayPlayEffect.java index 63358fb60ca..15ba5f0aa33 100644 --- a/Mage/src/mage/abilities/effects/common/HideawayPlayEffect.java +++ b/Mage/src/mage/abilities/effects/common/HideawayPlayEffect.java @@ -70,7 +70,7 @@ public class HideawayPlayEffect extends OneShotEffect { if (card.getCardType().contains(CardType.LAND)) { // If the revealed card is a land, you can play it only if it's your turn and you haven't yet played a land this turn. if (game.getActivePlayerId().equals(source.getControllerId()) && controller.canPlayLand()) { - if (controller.chooseUse(Outcome.Benefit, "Play " + card.getLogName() + " from Exile?", game)) { + if (controller.chooseUse(Outcome.Benefit, "Play " + card.getLogName() + " from Exile?", source, game)) { card.setFaceDown(false, game); return controller.playLand(card, game); } @@ -82,7 +82,7 @@ public class HideawayPlayEffect extends OneShotEffect { // The land's last ability allows you to play the removed card as part of the resolution of that ability. // Timing restrictions based on the card's type are ignored (for instance, if it's a creature or sorcery). // Other play restrictions are not (such as "Play [this card] only during combat"). - if (controller.chooseUse(Outcome.Benefit, "Cast "+ card.getLogName() + " without paying it's mana cost?", game)) { + if (controller.chooseUse(Outcome.Benefit, "Cast "+ card.getLogName() + " without paying it's mana cost?", source, game)) { card.setFaceDown(false, game); return controller.cast(card.getSpellAbility(), game, true); } diff --git a/Mage/src/mage/abilities/effects/common/LookLibraryAndPickControllerEffect.java b/Mage/src/mage/abilities/effects/common/LookLibraryAndPickControllerEffect.java index eb80a1b122c..88121480466 100644 --- a/Mage/src/mage/abilities/effects/common/LookLibraryAndPickControllerEffect.java +++ b/Mage/src/mage/abilities/effects/common/LookLibraryAndPickControllerEffect.java @@ -127,7 +127,7 @@ public class LookLibraryAndPickControllerEffect extends LookLibraryControllerEff protected void actionWithSelectedCards(Cards cards, Game game, Ability source, String windowName) { Player player = game.getPlayer(source.getControllerId()); if (player != null && foundCardsToPick > 0) { - if (!optional || player.chooseUse(Outcome.DrawCard, getMayText(), game)) { + if (!optional || player.chooseUse(Outcome.DrawCard, getMayText(), source, game)) { FilterCard pickFilter = filter.copy(); pickFilter.setMessage(getPickText()); TargetCard target = new TargetCard((upTo ? 0:numberToPick.calculate(game, source, this)),numberToPick.calculate(game, source, this), Zone.PICK, pickFilter); diff --git a/Mage/src/mage/abilities/effects/common/LookLibraryControllerEffect.java b/Mage/src/mage/abilities/effects/common/LookLibraryControllerEffect.java index 517179592e5..c32ff30e18d 100644 --- a/Mage/src/mage/abilities/effects/common/LookLibraryControllerEffect.java +++ b/Mage/src/mage/abilities/effects/common/LookLibraryControllerEffect.java @@ -27,8 +27,6 @@ */ package mage.abilities.effects.common; -import mage.constants.Outcome; -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.SpellAbility; @@ -38,6 +36,8 @@ import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.Cards; import mage.cards.CardsImpl; +import mage.constants.Outcome; +import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -142,7 +142,7 @@ public class LookLibraryControllerEffect extends OneShotEffect { player.setTopCardRevealed(topCardRevealed); - this.mayShuffle(player, game); + this.mayShuffle(player, source, game); return true; } @@ -162,19 +162,19 @@ public class LookLibraryControllerEffect extends OneShotEffect { * @param game */ protected void putCardsBack(Ability source, Player player, Cards cards, Game game) { - switch(targetZoneLookedCards) { - case LIBRARY: + switch (targetZoneLookedCards) { + case LIBRARY: if (putOnTop) { player.putCardsOnTopOfLibrary(cards, game, source, true); } else { player.putCardsOnBottomOfLibrary(cards, game, source, true); } break; - case GRAVEYARD: + case GRAVEYARD: player.moveCards(cards, Zone.LIBRARY, Zone.GRAVEYARD, source, game); break; default: - // not supported yet + // not supported yet } } @@ -184,8 +184,8 @@ public class LookLibraryControllerEffect extends OneShotEffect { * @param player * @param game */ - protected void mayShuffle(Player player, Game game) { - if (this.mayShuffleAfter && player.chooseUse(Outcome.Benefit, "Shuffle your library?", game)) { + protected void mayShuffle(Player player, Ability source, Game game) { + if (this.mayShuffleAfter && player.chooseUse(Outcome.Benefit, "Shuffle your library?", source, game)) { player.shuffleLibrary(game); } } @@ -226,7 +226,6 @@ public class LookLibraryControllerEffect extends OneShotEffect { sb.append(", where {X} is the number of cards ").append(numberOfCards.getMessage()); } - if (!middleText.isEmpty()) { sb.append(middleText); } else if (numberLook > 1) { diff --git a/Mage/src/mage/abilities/effects/common/LookLibraryMayPutToBottomEffect.java b/Mage/src/mage/abilities/effects/common/LookLibraryMayPutToBottomEffect.java index b352e9042de..3b4ea2dad6c 100644 --- a/Mage/src/mage/abilities/effects/common/LookLibraryMayPutToBottomEffect.java +++ b/Mage/src/mage/abilities/effects/common/LookLibraryMayPutToBottomEffect.java @@ -45,7 +45,7 @@ public class LookLibraryMayPutToBottomEffect extends OneShotEffect { return false; } controller.lookAtCards(sourceObject.getName(), new CardsImpl(card), game); - boolean toBottom = controller.chooseUse(outcome, "Put card on the bottom of your library?", game); + boolean toBottom = controller.chooseUse(outcome, "Put card on the bottom of your library?", source, game); return controller.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.LIBRARY, !toBottom, false); } return true; diff --git a/Mage/src/mage/abilities/effects/common/MayTapOrUntapTargetEffect.java b/Mage/src/mage/abilities/effects/common/MayTapOrUntapTargetEffect.java index 5b20678ab0c..9e2c9523a66 100644 --- a/Mage/src/mage/abilities/effects/common/MayTapOrUntapTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/MayTapOrUntapTargetEffect.java @@ -26,11 +26,11 @@ public class MayTapOrUntapTargetEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); if (target != null && player != null) { if (target.isTapped()) { - if (player.chooseUse(Outcome.Untap, "Untap that permanent?", game)) { + if (player.chooseUse(Outcome.Untap, "Untap that permanent?", source, game)) { target.untap(game); } } else { - if (player.chooseUse(Outcome.Tap, "Tap that permanent?", game)) { + if (player.chooseUse(Outcome.Tap, "Tap that permanent?", source, game)) { target.tap(game); } } diff --git a/Mage/src/mage/abilities/effects/common/PutCreatureOnBattlefieldEffect.java b/Mage/src/mage/abilities/effects/common/PutCreatureOnBattlefieldEffect.java index 14f106c56bc..9d5d1572fdd 100644 --- a/Mage/src/mage/abilities/effects/common/PutCreatureOnBattlefieldEffect.java +++ b/Mage/src/mage/abilities/effects/common/PutCreatureOnBattlefieldEffect.java @@ -34,7 +34,7 @@ public class PutCreatureOnBattlefieldEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (player == null || !player.chooseUse(Outcome.PutCreatureInPlay, choiceText, game)) { + if (player == null || !player.chooseUse(Outcome.PutCreatureInPlay, choiceText, source, game)) { return false; } diff --git a/Mage/src/mage/abilities/effects/common/PutLandFromHandOntoBattlefieldEffect.java b/Mage/src/mage/abilities/effects/common/PutLandFromHandOntoBattlefieldEffect.java index a2c3ad8e11d..8d819291cc3 100644 --- a/Mage/src/mage/abilities/effects/common/PutLandFromHandOntoBattlefieldEffect.java +++ b/Mage/src/mage/abilities/effects/common/PutLandFromHandOntoBattlefieldEffect.java @@ -67,7 +67,7 @@ public class PutLandFromHandOntoBattlefieldEffect extends OneShotEffect { if (controller != null) { Target target = new TargetCardInHand(new FilterLandCard("land card")); if (target.canChoose(source.getSourceId(), source.getControllerId(), game) && - controller.chooseUse(outcome, "Put land onto battlefield?", game) && + controller.chooseUse(outcome, "Put land onto battlefield?", source, game) && controller.choose(outcome, target, source.getSourceId(), game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { diff --git a/Mage/src/mage/abilities/effects/common/PutOntoBattlefieldTargetEffect.java b/Mage/src/mage/abilities/effects/common/PutOntoBattlefieldTargetEffect.java index f08e1853097..bebb9cee5ea 100644 --- a/Mage/src/mage/abilities/effects/common/PutOntoBattlefieldTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/PutOntoBattlefieldTargetEffect.java @@ -75,7 +75,7 @@ public class PutOntoBattlefieldTargetEffect extends OneShotEffect { if (controller == null || !controller.chooseUse(Outcome.PutCreatureInPlay, new StringBuilder("Put ") .append(source.getTargets() != null ? source.getTargets().get(0).getTargetName() : "target") - .append(" onto the battlefield?").toString(), game)) { + .append(" onto the battlefield?").toString(), source, game)) { return false; } } diff --git a/Mage/src/mage/abilities/effects/common/ReturnToBattlefieldUnderYourControlTargetEffect.java b/Mage/src/mage/abilities/effects/common/ReturnToBattlefieldUnderYourControlTargetEffect.java index 9989b06b275..d386e7d944f 100644 --- a/Mage/src/mage/abilities/effects/common/ReturnToBattlefieldUnderYourControlTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/ReturnToBattlefieldUnderYourControlTargetEffect.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,26 +20,22 @@ * 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.common; import java.util.UUID; - -import mage.constants.Outcome; -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; +import mage.constants.Outcome; +import mage.constants.Zone; import mage.game.ExileZone; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; /** @@ -49,14 +45,15 @@ import mage.util.CardUtil; public class ReturnToBattlefieldUnderYourControlTargetEffect extends OneShotEffect { private boolean fromExileZone; - + public ReturnToBattlefieldUnderYourControlTargetEffect() { this(false); } - + /** - * - * @param fromExileZone - the card will only be returned if it's still in the source object specific exile zone + * + * @param fromExileZone - the card will only be returned if it's still in + * the source object specific exile zone */ public ReturnToBattlefieldUnderYourControlTargetEffect(boolean fromExileZone) { super(Outcome.Benefit); @@ -77,29 +74,18 @@ public class ReturnToBattlefieldUnderYourControlTargetEffect extends OneShotEffe @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Card card = null; + if (controller != null) { + Card card = null; if (fromExileZone) { UUID exilZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); if (exilZoneId != null) { ExileZone exileZone = game.getExile().getExileZone(exilZoneId); if (exileZone != null && getTargetPointer().getFirst(game, source) != null) { card = exileZone.get(getTargetPointer().getFirst(game, source), game); - } + } } } else { - UUID cardId = targetPointer.getFirst(game, source); - if(targetPointer instanceof FixedTarget) { - UUID fixedTargetCardId = ((FixedTarget) targetPointer).getTarget(); - //Moved zones from battlefield to graveyard - if(fixedTargetCardId != null && cardId == null) { - Permanent permanent = game.getPermanentOrLKIBattlefield(fixedTargetCardId); - if(permanent != null) { - cardId = fixedTargetCardId; - } - } - } - card = game.getCard(cardId); + card = game.getCard(getTargetPointer().getFirst(game, source)); } if (card != null) { Zone currentZone = game.getState().getZone(card.getId()); diff --git a/Mage/src/mage/abilities/effects/common/SacrificeSourceUnlessPaysEffect.java b/Mage/src/mage/abilities/effects/common/SacrificeSourceUnlessPaysEffect.java index 8b82bdbf890..e9f188f41e5 100644 --- a/Mage/src/mage/abilities/effects/common/SacrificeSourceUnlessPaysEffect.java +++ b/Mage/src/mage/abilities/effects/common/SacrificeSourceUnlessPaysEffect.java @@ -42,7 +42,7 @@ public class SacrificeSourceUnlessPaysEffect extends OneShotEffect { } String message = CardUtil.replaceSourceName(sb.toString(), sourceObject.getLogName()); message = Character.toUpperCase(message.charAt(0)) + message.substring(1); - if (player.chooseUse(Outcome.Benefit, message, game)) { + if (player.chooseUse(Outcome.Benefit, message, source, game)) { cost.clearPaid(); if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { return true; diff --git a/Mage/src/mage/abilities/effects/common/SkipUntapOptionalSourceEffect.java b/Mage/src/mage/abilities/effects/common/SkipUntapOptionalSourceEffect.java index a251a0cba78..9db9a0de61b 100644 --- a/Mage/src/mage/abilities/effects/common/SkipUntapOptionalSourceEffect.java +++ b/Mage/src/mage/abilities/effects/common/SkipUntapOptionalSourceEffect.java @@ -39,8 +39,6 @@ import mage.players.Player; * * @author LevelX2 */ - - public class SkipUntapOptionalSourceEffect extends RestrictionEffect { public SkipUntapOptionalSourceEffect() { @@ -54,15 +52,15 @@ public class SkipUntapOptionalSourceEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - return permanent.getId().equals(source.getSourceId()) && - permanent.getControllerId().equals(game.getActivePlayerId()) && // your untap step + return permanent.getId().equals(source.getSourceId()) + && permanent.getControllerId().equals(game.getActivePlayerId()) && // your untap step permanent.isTapped(); } @Override - public boolean canBeUntapped(Permanent permanent, Game game) { + public boolean canBeUntapped(Permanent permanent, Ability source, Game game) { Player player = game.getPlayer(permanent.getControllerId()); - return player != null && player.chooseUse(Outcome.Benefit, "Untap " + permanent.getLogName() + "?", game); + return player != null && player.chooseUse(Outcome.Benefit, "Untap " + permanent.getLogName() + "?", source, game); } @Override diff --git a/Mage/src/mage/abilities/effects/common/TapSourceUnlessPaysEffect.java b/Mage/src/mage/abilities/effects/common/TapSourceUnlessPaysEffect.java index 0cec8d13365..55bc3ad99ed 100644 --- a/Mage/src/mage/abilities/effects/common/TapSourceUnlessPaysEffect.java +++ b/Mage/src/mage/abilities/effects/common/TapSourceUnlessPaysEffect.java @@ -61,7 +61,7 @@ public class TapSourceUnlessPaysEffect extends OneShotEffect { Permanent permanent = game.getPermanent(source.getSourceId()); if (player != null && permanent != null) { if (cost.canPay(source, source.getSourceId(), source.getControllerId(), game) - && player.chooseUse(Outcome.Benefit, cost.getText() + "? (otherwise " + permanent.getName() + " becomes tapped)", game)) { + && player.chooseUse(Outcome.Benefit, cost.getText() + "? (otherwise " + permanent.getName() + " becomes tapped)", source, game)) { cost.clearPaid(); if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { return true; diff --git a/Mage/src/mage/abilities/effects/common/continuous/BecomesColorOrColorsTargetEffect.java b/Mage/src/mage/abilities/effects/common/continuous/BecomesColorOrColorsTargetEffect.java index 8aac40950b4..87393154748 100644 --- a/Mage/src/mage/abilities/effects/common/continuous/BecomesColorOrColorsTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/continuous/BecomesColorOrColorsTargetEffect.java @@ -73,7 +73,7 @@ public class BecomesColorOrColorsTargetEffect extends OneShotEffect { if (controller != null && target != null) { for (int i = 0; i < 5; i++) { - if (!controller.chooseUse(Outcome.Neutral, "Do you wish to choose another color?", game)) { + if (!controller.chooseUse(Outcome.Neutral, "Do you wish to choose another color?", source, game)) { break; } ChoiceColor choiceColor = new ChoiceColor(); diff --git a/Mage/src/mage/abilities/effects/common/continuous/BoostControlledEffect.java b/Mage/src/mage/abilities/effects/common/continuous/BoostControlledEffect.java index b06cd3440a7..197e1b040d0 100644 --- a/Mage/src/mage/abilities/effects/common/continuous/BoostControlledEffect.java +++ b/Mage/src/mage/abilities/effects/common/continuous/BoostControlledEffect.java @@ -1,31 +1,30 @@ /* -* 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. -*/ - + * 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.common.continuous; import java.util.Iterator; @@ -83,7 +82,8 @@ public class BoostControlledEffect extends ContinuousEffectImpl { * @param toughness * @param duration * @param filter - * @param lockedIn if true, power and toughness will be calculated only once, when the ability resolves + * @param lockedIn if true, power and toughness will be calculated only + * once, when the ability resolves * @param excludeSource */ public BoostControlledEffect(DynamicValue power, DynamicValue toughness, Duration duration, FilterCreaturePermanent filter, boolean excludeSource, boolean lockedIn) { @@ -129,7 +129,7 @@ public class BoostControlledEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { if (this.affectedObjectsSet) { - for (Iterator it = affectedObjectList.iterator(); it.hasNext();) { + for (Iterator it = affectedObjectList.iterator(); it.hasNext();) { Permanent permanent = it.next().getPermanent(game); if (permanent != null) { permanent.addPower(power.calculate(game, source, this)); @@ -154,19 +154,19 @@ public class BoostControlledEffect extends ContinuousEffectImpl { String message = null; StringBuilder sb = new StringBuilder(); if (excludeSource) { - sb.append("Other "); + sb.append("other "); } sb.append(filter.getMessage()); sb.append(" you control get "); String p = power.toString(); - if(!p.startsWith("-")) { + if (!p.startsWith("-")) { sb.append("+"); } sb.append(p).append("/"); String t = toughness.toString(); - if(!t.startsWith("-")){ - if(p.startsWith("-")) { + if (!t.startsWith("-")) { + if (p.startsWith("-")) { sb.append("-"); } else { sb.append("+"); @@ -174,7 +174,7 @@ public class BoostControlledEffect extends ContinuousEffectImpl { } sb.append(t); - sb.append((duration==Duration.EndOfTurn?" until end of turn":"")); + sb.append((duration == Duration.EndOfTurn ? " until end of turn" : "")); if (t.equals("X")) { message = toughness.getMessage(); } else if (p.equals("X")) { diff --git a/Mage/src/mage/abilities/effects/common/continuous/CommanderReplacementEffect.java b/Mage/src/mage/abilities/effects/common/continuous/CommanderReplacementEffect.java index 7d0a1fc6b2e..daa86a6abea 100644 --- a/Mage/src/mage/abilities/effects/common/continuous/CommanderReplacementEffect.java +++ b/Mage/src/mage/abilities/effects/common/continuous/CommanderReplacementEffect.java @@ -132,7 +132,7 @@ public class CommanderReplacementEffect extends ReplacementEffectImpl { Permanent permanent = ((ZoneChangeEvent)event).getTarget(); if (permanent != null) { Player player = game.getPlayer(permanent.getOwnerId()); - if (player != null && player.chooseUse(Outcome.Benefit, "Move commander to command zone?", game)){ + if (player != null && player.chooseUse(Outcome.Benefit, "Move commander to command zone?", source, game)){ boolean result = permanent.moveToZone(Zone.COMMAND, source.getSourceId(), game, false); if (!game.isSimulation()) game.informPlayers(player.getLogName() + " has moved his or her commander to the command zone"); @@ -152,7 +152,7 @@ public class CommanderReplacementEffect extends ReplacementEffectImpl { } if (card != null) { Player player = game.getPlayer(card.getOwnerId()); - if (player != null && player.chooseUse(Outcome.Benefit, "Move commander to command zone?", game)){ + if (player != null && player.chooseUse(Outcome.Benefit, "Move commander to command zone?", source, game)){ boolean result = card.moveToZone(Zone.COMMAND, source.getSourceId(), game, false); if (!game.isSimulation()) game.informPlayers(player.getLogName() + " has moved his or her commander to the command zone"); diff --git a/Mage/src/mage/abilities/effects/common/continuous/UntapAllDuringEachOtherPlayersUntapStepEffect.java b/Mage/src/mage/abilities/effects/common/continuous/UntapAllDuringEachOtherPlayersUntapStepEffect.java index 806001cd79b..2513b9a9f5e 100644 --- a/Mage/src/mage/abilities/effects/common/continuous/UntapAllDuringEachOtherPlayersUntapStepEffect.java +++ b/Mage/src/mage/abilities/effects/common/continuous/UntapAllDuringEachOtherPlayersUntapStepEffect.java @@ -25,7 +25,6 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.abilities.effects.common.continuous; import mage.abilities.Ability; @@ -73,10 +72,10 @@ public class UntapAllDuringEachOtherPlayersUntapStepEffect extends ContinuousEff if (!applied && layer.equals(Layer.RulesEffects)) { if (!game.getActivePlayerId().equals(source.getControllerId()) && game.getStep().getType() == PhaseStep.UNTAP) { game.getState().setValue(source.getSourceId() + "applied", true); - for (Permanent permanent: game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { boolean untap = true; - for (RestrictionEffect effect: game.getContinuousEffects().getApplicableRestrictionEffects(permanent, game).keySet()) { - untap &= effect.canBeUntapped(permanent, game); + for (RestrictionEffect effect : game.getContinuousEffects().getApplicableRestrictionEffects(permanent, game).keySet()) { + untap &= effect.canBeUntapped(permanent, source, game); } if (untap) { permanent.untap(game); diff --git a/Mage/src/mage/abilities/keyword/BuybackAbility.java b/Mage/src/mage/abilities/keyword/BuybackAbility.java index 827aed84ffc..321a7de0a80 100644 --- a/Mage/src/mage/abilities/keyword/BuybackAbility.java +++ b/Mage/src/mage/abilities/keyword/BuybackAbility.java @@ -28,8 +28,6 @@ package mage.abilities.keyword; import java.util.Iterator; - -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.StaticAbility; @@ -43,6 +41,7 @@ import mage.abilities.effects.ReplacementEffectImpl; import mage.cards.Card; import mage.constants.Duration; import mage.constants.Outcome; +import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; @@ -51,16 +50,16 @@ import mage.players.Player; /** * 702.25. Buyback * - * 702.25a Buyback appears on some instants and sorceries. It represents two static - * abilities that function while the spell is on the stack. "Buyback [cost]" means - * "You may pay an additional [cost] as you cast this spell" and "If the buyback - * cost was paid, put this spell into its owner's hand instead of into that player's - * graveyard as it resolves." Paying a spell's buyback cost follows the rules for - * paying additional costs in rules 601.2b and 601.2e-g. + * 702.25a Buyback appears on some instants and sorceries. It represents two + * static abilities that function while the spell is on the stack. "Buyback + * [cost]" means "You may pay an additional [cost] as you cast this spell" and + * "If the buyback cost was paid, put this spell into its owner's hand instead + * of into that player's graveyard as it resolves." Paying a spell's buyback + * cost follows the rules for paying additional costs in rules 601.2b and + * 601.2e-g. * * @author LevelX2 */ - public class BuybackAbility extends StaticAbility implements OptionalAdditionalSourceCosts { private static final String keywordText = "Buyback"; @@ -69,25 +68,25 @@ public class BuybackAbility extends StaticAbility implements OptionalAdditionalS protected OptionalAdditionalCost buybackCost; public BuybackAbility(String manaString) { - super(Zone.STACK, new BuybackEffect()); - this.buybackCost = new OptionalAdditionalCostImpl(keywordText, reminderTextMana, new ManaCostsImpl(manaString)); - setRuleAtTheTop(true); + super(Zone.STACK, new BuybackEffect()); + this.buybackCost = new OptionalAdditionalCostImpl(keywordText, reminderTextMana, new ManaCostsImpl(manaString)); + setRuleAtTheTop(true); } - + public BuybackAbility(Cost cost) { - super(Zone.STACK, new BuybackEffect()); - this.buybackCost = new OptionalAdditionalCostImpl(keywordText, "-", reminderTextCost, cost); - setRuleAtTheTop(true); + super(Zone.STACK, new BuybackEffect()); + this.buybackCost = new OptionalAdditionalCostImpl(keywordText, "-", reminderTextCost, cost); + setRuleAtTheTop(true); } public BuybackAbility(final BuybackAbility ability) { - super(ability); - buybackCost = ability.buybackCost; + super(ability); + buybackCost = ability.buybackCost; } @Override public BuybackAbility copy() { - return new BuybackAbility(this); + return new BuybackAbility(this); } @Override @@ -117,7 +116,7 @@ public class BuybackAbility extends StaticAbility implements OptionalAdditionalS if (player != null) { this.resetBuyback(); if (buybackCost != null) { - if (player.chooseUse(Outcome.Benefit,new StringBuilder("Pay ").append(buybackCost.getText(false)).append(" ?").toString(), game)) { + if (player.chooseUse(Outcome.Benefit, new StringBuilder("Pay ").append(buybackCost.getText(false)).append(" ?").toString(), ability, game)) { buybackCost.activate(); for (Iterator it = ((Costs) buybackCost).iterator(); it.hasNext();) { Cost cost = (Cost) it.next(); @@ -133,7 +132,6 @@ public class BuybackAbility extends StaticAbility implements OptionalAdditionalS } } - @Override public String getRule() { StringBuilder sb = new StringBuilder(); @@ -186,8 +184,8 @@ class BuybackEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { if (event.getTargetId().equals(source.getSourceId())) { - ZoneChangeEvent zEvent = (ZoneChangeEvent)event; - if (zEvent.getFromZone() == Zone.STACK ) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (zEvent.getFromZone() == Zone.STACK) { return true; } } @@ -210,4 +208,4 @@ class BuybackEffect extends ReplacementEffectImpl { return false; } -} \ No newline at end of file +} diff --git a/Mage/src/mage/abilities/keyword/CascadeAbility.java b/Mage/src/mage/abilities/keyword/CascadeAbility.java index 1274da1a3f1..c4b6318f83b 100644 --- a/Mage/src/mage/abilities/keyword/CascadeAbility.java +++ b/Mage/src/mage/abilities/keyword/CascadeAbility.java @@ -114,7 +114,7 @@ public class CascadeAbility extends TriggeredAbilityImpl { player.getLibrary().reset(); if (card != null) { - if (player.chooseUse(outcome, "Use cascade effect on " + card.getName() + "?", game)) { + if (player.chooseUse(outcome, "Use cascade effect on " + card.getName() + "?", source, game)) { if(player.cast(card.getSpellAbility(), game, true)){ exile.remove(card.getId()); } diff --git a/Mage/src/mage/abilities/keyword/ConspireAbility.java b/Mage/src/mage/abilities/keyword/ConspireAbility.java index 311b6597090..fe470c425fd 100644 --- a/Mage/src/mage/abilities/keyword/ConspireAbility.java +++ b/Mage/src/mage/abilities/keyword/ConspireAbility.java @@ -126,7 +126,7 @@ public class ConspireAbility extends StaticAbility implements OptionalAdditional Player player = game.getPlayer(controllerId); if (player != null) { this.resetConspire(); - if (player.chooseUse(Outcome.Benefit, new StringBuilder("Pay ").append(conspireCost.getText(false)).append(" ?").toString(), game)) { + if (player.chooseUse(Outcome.Benefit, new StringBuilder("Pay ").append(conspireCost.getText(false)).append(" ?").toString(), ability, game)) { conspireCost.activate(); for (Iterator it = ((Costs) conspireCost).iterator(); it.hasNext();) { Cost cost = (Cost) it.next(); @@ -245,8 +245,9 @@ class ConspireEffect extends OneShotEffect { copy.setCopiedSpell(true); game.getStack().push(copy); copy.chooseNewTargets(game, source.getControllerId()); - if (!game.isSimulation()) + if (!game.isSimulation()) { game.informPlayers(new StringBuilder(controller.getLogName()).append(copy.getActivatedMessage(game)).toString()); + } return true; } } diff --git a/Mage/src/mage/abilities/keyword/CumulativeUpkeepAbility.java b/Mage/src/mage/abilities/keyword/CumulativeUpkeepAbility.java index 196daf5aceb..199c8536108 100644 --- a/Mage/src/mage/abilities/keyword/CumulativeUpkeepAbility.java +++ b/Mage/src/mage/abilities/keyword/CumulativeUpkeepAbility.java @@ -107,7 +107,7 @@ class CumulativeUpkeepEffect extends OneShotEffect { for(int i = 0 ; i < ageCounter; i++){ totalCost.add((ManaCost) cumulativeCost.copy()); } - if (player.chooseUse(Outcome.Benefit, "Pay " + totalCost.getText() + "?", game)) { + if (player.chooseUse(Outcome.Benefit, "Pay " + totalCost.getText() + "?", source, game)) { totalCost.clearPaid(); if (totalCost.payOrRollback(source, game, source.getSourceId(), source.getControllerId())){ return true; @@ -121,7 +121,7 @@ class CumulativeUpkeepEffect extends OneShotEffect { for(int i = 0 ; i < ageCounter; i++){ totalCost.add(cumulativeCost.copy()); } - if (player.chooseUse(Outcome.Benefit, totalCost.getText() + "?", game)) { + if (player.chooseUse(Outcome.Benefit, totalCost.getText() + "?", source, game)) { totalCost.clearPaid(); int bookmark = game.bookmarkState(); if (totalCost.pay(source, game, source.getSourceId(), source.getControllerId(), false)){ diff --git a/Mage/src/mage/abilities/keyword/DashAbility.java b/Mage/src/mage/abilities/keyword/DashAbility.java index a80b5f50796..4072e1a8563 100644 --- a/Mage/src/mage/abilities/keyword/DashAbility.java +++ b/Mage/src/mage/abilities/keyword/DashAbility.java @@ -67,7 +67,7 @@ public class DashAbility extends StaticAbility implements AlternativeSourceCosts protected List alternativeSourceCosts = new LinkedList<>(); // needed to check activation status, if card changes zone after casting it - private int zoneChangeCounter = 0; + private int zoneChangeCounter = 0; public DashAbility(Card card, String manaString) { super(Zone.ALL, null); @@ -75,7 +75,7 @@ public class DashAbility extends StaticAbility implements AlternativeSourceCosts this.addDashCost(manaString); Ability ability = new EntersBattlefieldAbility( new GainAbilitySourceEffect(HasteAbility.getInstance(), Duration.Custom, false), - DashedCondition.getInstance(), false, "",""); + DashedCondition.getInstance(), false, "", ""); Effect effect = new ReturnToHandTargetEffect(); effect.setText("return the dashed creature from the battlefield to its owner's hand"); effect.setTargetPointer(new FixedTarget(card.getId())); @@ -85,24 +85,24 @@ public class DashAbility extends StaticAbility implements AlternativeSourceCosts } public DashAbility(final DashAbility ability) { - super(ability); - this.alternativeSourceCosts.addAll(ability.alternativeSourceCosts); - this.zoneChangeCounter = ability.zoneChangeCounter; + super(ability); + this.alternativeSourceCosts.addAll(ability.alternativeSourceCosts); + this.zoneChangeCounter = ability.zoneChangeCounter; } @Override public DashAbility copy() { - return new DashAbility(this); + return new DashAbility(this); } public final AlternativeCost2 addDashCost(String manaString) { - AlternativeCost2 evokeCost = new AlternativeCost2Impl(KEYWORD, REMINDER_TEXT, new ManaCostsImpl(manaString)); - alternativeSourceCosts.add(evokeCost); - return evokeCost; + AlternativeCost2 evokeCost = new AlternativeCost2Impl(KEYWORD, REMINDER_TEXT, new ManaCostsImpl(manaString)); + alternativeSourceCosts.add(evokeCost); + return evokeCost; } public void resetDash() { - for (AlternativeCost2 cost: alternativeSourceCosts) { + for (AlternativeCost2 cost : alternativeSourceCosts) { cost.reset(); } zoneChangeCounter = 0; @@ -111,9 +111,9 @@ public class DashAbility extends StaticAbility implements AlternativeSourceCosts @Override public boolean isActivated(Ability ability, Game game) { Card card = game.getCard(sourceId); - if (card != null && card.getZoneChangeCounter(game) <= zoneChangeCounter +1) { - for (AlternativeCost2 cost: alternativeSourceCosts) { - if(cost.isActivated(game)) { + if (card != null && card.getZoneChangeCounter(game) <= zoneChangeCounter + 1) { + for (AlternativeCost2 cost : alternativeSourceCosts) { + if (cost.isActivated(game)) { return true; } } @@ -132,9 +132,9 @@ public class DashAbility extends StaticAbility implements AlternativeSourceCosts Player player = game.getPlayer(controllerId); if (player != null) { this.resetDash(); - for (AlternativeCost2 dashCost: alternativeSourceCosts) { - if (dashCost.canPay(ability, sourceId, controllerId, game) && - player.chooseUse(Outcome.Benefit, new StringBuilder(KEYWORD).append(" the creature for ").append(dashCost.getText(true)).append(" ?").toString(), game)) { + for (AlternativeCost2 dashCost : alternativeSourceCosts) { + if (dashCost.canPay(ability, sourceId, controllerId, game) + && player.chooseUse(Outcome.Benefit, new StringBuilder(KEYWORD).append(" the creature for ").append(dashCost.getText(true)).append(" ?").toString(), ability, game)) { activateDash(dashCost, game); ability.getManaCostsToPay().clear(); ability.getCosts().clear(); @@ -168,23 +168,23 @@ public class DashAbility extends StaticAbility implements AlternativeSourceCosts @Override public String getRule() { - StringBuilder sb = new StringBuilder(); - int numberCosts = 0; - String remarkText = ""; - for (AlternativeCost2 dashCost: alternativeSourceCosts) { - if (numberCosts == 0) { - sb.append(dashCost.getText(false)); - remarkText = dashCost.getReminderText(); - } else { - sb.append(" and/or ").append(dashCost.getText(true)); - } - ++numberCosts; - } - if (numberCosts == 1) { + StringBuilder sb = new StringBuilder(); + int numberCosts = 0; + String remarkText = ""; + for (AlternativeCost2 dashCost : alternativeSourceCosts) { + if (numberCosts == 0) { + sb.append(dashCost.getText(false)); + remarkText = dashCost.getReminderText(); + } else { + sb.append(" and/or ").append(dashCost.getText(true)); + } + ++numberCosts; + } + if (numberCosts == 1) { sb.append(" ").append(remarkText); - } + } - return sb.toString(); + return sb.toString(); } @Override @@ -203,7 +203,7 @@ public class DashAbility extends StaticAbility implements AlternativeSourceCosts @Override public Costs getCosts() { Costs alterCosts = new CostsImpl<>(); - for (AlternativeCost2 aCost: alternativeSourceCosts) { + for (AlternativeCost2 aCost : alternativeSourceCosts) { alterCosts.add(aCost.getCost()); } return alterCosts; diff --git a/Mage/src/mage/abilities/keyword/DredgeAbility.java b/Mage/src/mage/abilities/keyword/DredgeAbility.java index 62f77f3ada2..afed19ef46b 100644 --- a/Mage/src/mage/abilities/keyword/DredgeAbility.java +++ b/Mage/src/mage/abilities/keyword/DredgeAbility.java @@ -98,7 +98,7 @@ class DredgeEffect extends ReplacementEffectImpl { Player player = game.getPlayer(source.getControllerId()); if (player != null && player.getLibrary().size() >= amount && player.chooseUse(outcome, new StringBuilder("Dredge ").append(sourceCard.getLogName()). - append("? (").append(amount).append(" cards go from top of library to graveyard)").toString(), game)) { + append("? (").append(amount).append(" cards go from top of library to graveyard)").toString(), source, game)) { if (!game.isSimulation()) { game.informPlayers(new StringBuilder(player.getLogName()).append(" dreges ").append(sourceCard.getLogName()).toString()); } diff --git a/Mage/src/mage/abilities/keyword/EchoAbility.java b/Mage/src/mage/abilities/keyword/EchoAbility.java index 6b1d318678c..6b8a129a809 100644 --- a/Mage/src/mage/abilities/keyword/EchoAbility.java +++ b/Mage/src/mage/abilities/keyword/EchoAbility.java @@ -145,7 +145,7 @@ class EchoEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null && source.getSourceObjectIfItStillExists(game) != null) { - if (controller.chooseUse(Outcome.Benefit, "Pay " + cost.getText() /* + " or sacrifice " + permanent.getName() */ + "?", game)) { + if (controller.chooseUse(Outcome.Benefit, "Pay " + cost.getText() /* + " or sacrifice " + permanent.getName() */ + "?", source, game)) { cost.clearPaid(); if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false)) { return true; diff --git a/Mage/src/mage/abilities/keyword/EntwineAbility.java b/Mage/src/mage/abilities/keyword/EntwineAbility.java index 475324cae6a..141fd25162b 100644 --- a/Mage/src/mage/abilities/keyword/EntwineAbility.java +++ b/Mage/src/mage/abilities/keyword/EntwineAbility.java @@ -28,8 +28,6 @@ package mage.abilities.keyword; import java.util.Iterator; - -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.StaticAbility; @@ -40,24 +38,24 @@ import mage.abilities.costs.OptionalAdditionalCostImpl; import mage.abilities.costs.OptionalAdditionalModeSourceCosts; import mage.abilities.costs.mana.ManaCostsImpl; import mage.constants.Outcome; +import mage.constants.Zone; import mage.game.Game; import mage.players.Player; /** * 702.40. Entwine * - * 702.40a Entwine is a static ability of modal spells (see rule 700.2) that functions - * while the spell is on the stack. "Entwine [cost]" means "You may choose all modes - * of this spell instead of just one. If you do, you pay an additional [cost]." Using - * the entwine ability follows the rules for choosing modes and paying additional costs - * in rules 601.2b and 601.2e-g. + * 702.40a Entwine is a static ability of modal spells (see rule 700.2) that + * functions while the spell is on the stack. "Entwine [cost]" means "You may + * choose all modes of this spell instead of just one. If you do, you pay an + * additional [cost]." Using the entwine ability follows the rules for choosing + * modes and paying additional costs in rules 601.2b and 601.2e-g. * - * 702.40b If the entwine cost was paid, follow the text of each of the modes in the order - * written on the card when the spell resolves. + * 702.40b If the entwine cost was paid, follow the text of each of the modes in + * the order written on the card when the spell resolves. * * @author LevelX2 */ - public class EntwineAbility extends StaticAbility implements OptionalAdditionalModeSourceCosts { private static final String keywordText = "Entwine"; @@ -65,24 +63,24 @@ public class EntwineAbility extends StaticAbility implements OptionalAdditionalM protected OptionalAdditionalCost additionalCost; public EntwineAbility(String manaString) { - super(Zone.STACK, null); - this.additionalCost = new OptionalAdditionalCostImpl(keywordText, reminderText, new ManaCostsImpl(manaString)); + super(Zone.STACK, null); + this.additionalCost = new OptionalAdditionalCostImpl(keywordText, reminderText, new ManaCostsImpl(manaString)); } public EntwineAbility(Cost cost) { - super(Zone.STACK, null); - this.additionalCost = new OptionalAdditionalCostImpl(keywordText, "-", reminderText, cost); - setRuleAtTheTop(true); + super(Zone.STACK, null); + this.additionalCost = new OptionalAdditionalCostImpl(keywordText, "-", reminderText, cost); + setRuleAtTheTop(true); } public EntwineAbility(final EntwineAbility ability) { - super(ability); - additionalCost = ability.additionalCost; + super(ability); + additionalCost = ability.additionalCost; } @Override public EntwineAbility copy() { - return new EntwineAbility(this); + return new EntwineAbility(this); } @Override @@ -112,7 +110,7 @@ public class EntwineAbility extends StaticAbility implements OptionalAdditionalM if (player != null) { this.resetCosts(); if (additionalCost != null) { - if (player.chooseUse(Outcome.Benefit,new StringBuilder("Pay ").append(additionalCost.getText(false)).append(" ?").toString(), game)) { + if (player.chooseUse(Outcome.Benefit, new StringBuilder("Pay ").append(additionalCost.getText(false)).append(" ?").toString(), ability, game)) { additionalCost.activate(); for (Iterator it = ((Costs) additionalCost).iterator(); it.hasNext();) { Cost cost = (Cost) it.next(); @@ -130,7 +128,6 @@ public class EntwineAbility extends StaticAbility implements OptionalAdditionalM } } - @Override public String getRule() { StringBuilder sb = new StringBuilder(); diff --git a/Mage/src/mage/abilities/keyword/EvokeAbility.java b/Mage/src/mage/abilities/keyword/EvokeAbility.java index 7be2dbeec5f..4141a987c21 100644 --- a/Mage/src/mage/abilities/keyword/EvokeAbility.java +++ b/Mage/src/mage/abilities/keyword/EvokeAbility.java @@ -1,31 +1,30 @@ /* -* 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. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities.keyword; import java.util.Iterator; @@ -55,7 +54,6 @@ import mage.players.Player; * * @author LevelX2 */ - public class EvokeAbility extends StaticAbility implements AlternativeSourceCosts { protected static final String EVOKE_KEYWORD = "Evoke"; @@ -64,7 +62,7 @@ public class EvokeAbility extends StaticAbility implements AlternativeSourceCost protected List evokeCosts = new LinkedList<>(); // needed to check activation status, if card changes zone after casting it - private int zoneChangeCounter = 0; + private int zoneChangeCounter = 0; public EvokeAbility(Card card, String manaString) { super(Zone.ALL, null); @@ -77,24 +75,24 @@ public class EvokeAbility extends StaticAbility implements AlternativeSourceCost } public EvokeAbility(final EvokeAbility ability) { - super(ability); - this.evokeCosts.addAll(ability.evokeCosts); - this.zoneChangeCounter = ability.zoneChangeCounter; + super(ability); + this.evokeCosts.addAll(ability.evokeCosts); + this.zoneChangeCounter = ability.zoneChangeCounter; } @Override public EvokeAbility copy() { - return new EvokeAbility(this); + return new EvokeAbility(this); } - + public final AlternativeCost2 addEvokeCost(String manaString) { - AlternativeCost2 evokeCost = new AlternativeCost2Impl(EVOKE_KEYWORD, REMINDER_TEXT, new ManaCostsImpl(manaString)); - evokeCosts.add(evokeCost); - return evokeCost; + AlternativeCost2 evokeCost = new AlternativeCost2Impl(EVOKE_KEYWORD, REMINDER_TEXT, new ManaCostsImpl(manaString)); + evokeCosts.add(evokeCost); + return evokeCost; } public void resetEvoke() { - for (AlternativeCost2 cost: evokeCosts) { + for (AlternativeCost2 cost : evokeCosts) { cost.reset(); } zoneChangeCounter = 0; @@ -103,30 +101,30 @@ public class EvokeAbility extends StaticAbility implements AlternativeSourceCost @Override public boolean isActivated(Ability ability, Game game) { Card card = game.getCard(sourceId); - if (card != null && card.getZoneChangeCounter(game) <= zoneChangeCounter +1) { - for (AlternativeCost2 cost: evokeCosts) { - if(cost.isActivated(game)) { + if (card != null && card.getZoneChangeCounter(game) <= zoneChangeCounter + 1) { + for (AlternativeCost2 cost : evokeCosts) { + if (cost.isActivated(game)) { return true; } } } return false; } - + @Override public boolean isAvailable(Ability source, Game game) { return true; } - + @Override public boolean askToActivateAlternativeCosts(Ability ability, Game game) { if (ability instanceof SpellAbility) { Player player = game.getPlayer(controllerId); if (player != null) { this.resetEvoke(); - for (AlternativeCost2 evokeCost: evokeCosts) { - if (evokeCost.canPay(ability, sourceId, controllerId, game) && - player.chooseUse(Outcome.Benefit, new StringBuilder(EVOKE_KEYWORD).append(" the creature for ").append(evokeCost.getText(true)).append(" ?").toString(), game)) { + for (AlternativeCost2 evokeCost : evokeCosts) { + if (evokeCost.canPay(ability, sourceId, controllerId, game) + && player.chooseUse(Outcome.Benefit, new StringBuilder(EVOKE_KEYWORD).append(" the creature for ").append(evokeCost.getText(true)).append(" ?").toString(), ability, game)) { activateEvoke(evokeCost, game); ability.getManaCostsToPay().clear(); ability.getCosts().clear(); @@ -160,23 +158,23 @@ public class EvokeAbility extends StaticAbility implements AlternativeSourceCost @Override public String getRule() { - StringBuilder sb = new StringBuilder(); - int numberCosts = 0; - String remarkText = ""; - for (AlternativeCost2 evokeCost: evokeCosts) { - if (numberCosts == 0) { - sb.append(evokeCost.getText(false)); - remarkText = evokeCost.getReminderText(); - } else { - sb.append(" and/or ").append(evokeCost.getText(true)); - } - ++numberCosts; - } - if (numberCosts == 1) { + StringBuilder sb = new StringBuilder(); + int numberCosts = 0; + String remarkText = ""; + for (AlternativeCost2 evokeCost : evokeCosts) { + if (numberCosts == 0) { + sb.append(evokeCost.getText(false)); + remarkText = evokeCost.getReminderText(); + } else { + sb.append(" and/or ").append(evokeCost.getText(true)); + } + ++numberCosts; + } + if (numberCosts == 1) { sb.append(" ").append(remarkText); - } + } - return sb.toString(); + return sb.toString(); } @Override @@ -191,13 +189,13 @@ public class EvokeAbility extends StaticAbility implements AlternativeSourceCost } return sb.toString(); } - + @Override public Costs getCosts() { Costs alterCosts = new CostsImpl<>(); - for (AlternativeCost2 aCost: evokeCosts) { + for (AlternativeCost2 aCost : evokeCosts) { alterCosts.add(aCost.getCost()); } return alterCosts; - } + } } diff --git a/Mage/src/mage/abilities/keyword/ExtortAbility.java b/Mage/src/mage/abilities/keyword/ExtortAbility.java index 1a910c230f5..d700e557387 100644 --- a/Mage/src/mage/abilities/keyword/ExtortAbility.java +++ b/Mage/src/mage/abilities/keyword/ExtortAbility.java @@ -101,7 +101,7 @@ class ExtortEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(source.getSourceId()); if (player != null && permanent != null) { - if (player.chooseUse(Outcome.Damage, new StringBuilder("Extort opponents? (").append(permanent.getName()).append(")").toString(), game)) { + if (player.chooseUse(Outcome.Damage, new StringBuilder("Extort opponents? (").append(permanent.getName()).append(")").toString(), source, game)) { Cost cost = new ManaCostsImpl("{W/B}"); if (cost.pay(source, game, source.getSourceId(), player.getId(), false)) { int loseLife = 0; diff --git a/Mage/src/mage/abilities/keyword/KickerAbility.java b/Mage/src/mage/abilities/keyword/KickerAbility.java index ada8a8248fc..5ff7303443f 100644 --- a/Mage/src/mage/abilities/keyword/KickerAbility.java +++ b/Mage/src/mage/abilities/keyword/KickerAbility.java @@ -1,31 +1,30 @@ /* -* 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. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities.keyword; import java.util.HashMap; @@ -52,33 +51,31 @@ import mage.players.Player; /** * - * 20121001 702.31. Kicker - * 702.31a Kicker is a static ability that functions while the spell with kicker - * is on the stack. "Kicker [cost]" means "You may pay an additional [cost] - * as you cast this spell." Paying a spell's kicker cost(s) follows the - * rules for paying additional costs in rules 601.2b and 601.2e-g. - * 702.31b The phrase "Kicker [cost 1] and/or [cost 2]" means the same thing as - * "Kicker [cost 1], kicker [cost 2]." - * 702.31c Multikicker is a variant of the kicker ability. "Multikicker [cost]" - * means "You may pay an additional [cost] any number of times as you cast - * this spell." A multikicker cost is a kicker cost. - * 702.31d If a spell's controller declares the intention to pay any of that spell's - * kicker costs, that spell has been "kicked." If a spell has two kicker - * costs or has multikicker, it may be kicked multiple times. See rule 601.2b. - * 702.31e Objects with kicker or multikicker have additional abilities that specify - * what happens if they are kicked. These abilities are linked to the kicker - * or multikicker abilities printed on that object: they can refer only to - * those specific kicker or multikicker abilities. See rule 607, - * "Linked Abilities." - * 702.31f Objects with more than one kicker cost have abilities that each correspond - * to a specific kicker cost. They contain the phrases "if it was kicked with - * its [A] kicker" and "if it was kicked with its [B] kicker," where A and B - * are the first and second kicker costs listed on the card, respectively. Each - * of those abilities is linked to the appropriate kicker ability. - * 702.31g If part of a spell's ability has its effect only if that spell was kicked, - * and that part of the ability includes any targets, the spell's controller - * chooses those targets only if that spell was kicked. Otherwise, the spell is - * cast as if it did not have those targets. See rule 601.2c. + * 20121001 702.31. Kicker 702.31a Kicker is a static ability that functions + * while the spell with kicker is on the stack. "Kicker [cost]" means "You may + * pay an additional [cost] as you cast this spell." Paying a spell's kicker + * cost(s) follows the rules for paying additional costs in rules 601.2b and + * 601.2e-g. 702.31b The phrase "Kicker [cost 1] and/or [cost 2]" means the same + * thing as "Kicker [cost 1], kicker [cost 2]." 702.31c Multikicker is a variant + * of the kicker ability. "Multikicker [cost]" means "You may pay an additional + * [cost] any number of times as you cast this spell." A multikicker cost is a + * kicker cost. 702.31d If a spell's controller declares the intention to pay + * any of that spell's kicker costs, that spell has been "kicked." If a spell + * has two kicker costs or has multikicker, it may be kicked multiple times. See + * rule 601.2b. 702.31e Objects with kicker or multikicker have additional + * abilities that specify what happens if they are kicked. These abilities are + * linked to the kicker or multikicker abilities printed on that object: they + * can refer only to those specific kicker or multikicker abilities. See rule + * 607, "Linked Abilities." 702.31f Objects with more than one kicker cost have + * abilities that each correspond to a specific kicker cost. They contain the + * phrases "if it was kicked with its [A] kicker" and "if it was kicked with its + * [B] kicker," where A and B are the first and second kicker costs listed on + * the card, respectively. Each of those abilities is linked to the appropriate + * kicker ability. 702.31g If part of a spell's ability has its effect only if + * that spell was kicked, and that part of the ability includes any targets, the + * spell's controller chooses those targets only if that spell was kicked. + * Otherwise, the spell is cast as if it did not have those targets. See rule + * 601.2c. * * @author LevelX2 * @@ -90,61 +87,61 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo protected static final String KICKER_REMINDER_COST = "(You may {cost} in addition to any other costs as you cast this spell.)"; protected Map activations = new HashMap<>(); // zoneChangeCounter, activations - + protected String keywordText; protected String reminderText; protected List kickerCosts = new LinkedList<>(); - private int xManaValue = 0; + private int xManaValue = 0; public KickerAbility(String manaString) { - this(KICKER_KEYWORD, KICKER_REMINDER_MANA); - this.addKickerCost(manaString); + this(KICKER_KEYWORD, KICKER_REMINDER_MANA); + this.addKickerCost(manaString); } public KickerAbility(Cost cost) { - this(KICKER_KEYWORD, KICKER_REMINDER_COST); - this.addKickerCost(cost); + this(KICKER_KEYWORD, KICKER_REMINDER_COST); + this.addKickerCost(cost); } public KickerAbility(String keywordText, String reminderText) { - super(Zone.STACK, null); - name = keywordText; - this.keywordText = keywordText; - this.reminderText = reminderText; - setRuleAtTheTop(true); + super(Zone.STACK, null); + name = keywordText; + this.keywordText = keywordText; + this.reminderText = reminderText; + setRuleAtTheTop(true); } public KickerAbility(final KickerAbility ability) { - super(ability); - this.kickerCosts.addAll(ability.kickerCosts); - this.keywordText = ability.keywordText; - this.reminderText = ability.reminderText; - this.xManaValue = ability.xManaValue; - this.activations.putAll(ability.activations); + super(ability); + this.kickerCosts.addAll(ability.kickerCosts); + this.keywordText = ability.keywordText; + this.reminderText = ability.reminderText; + this.xManaValue = ability.xManaValue; + this.activations.putAll(ability.activations); } @Override public KickerAbility copy() { - return new KickerAbility(this); + return new KickerAbility(this); } public final OptionalAdditionalCost addKickerCost(String manaString) { - OptionalAdditionalCost kickerCost = new OptionalAdditionalCostImpl(keywordText, reminderText, new ManaCostsImpl(manaString)); - kickerCosts.add(kickerCost); - return kickerCost; + OptionalAdditionalCost kickerCost = new OptionalAdditionalCostImpl(keywordText, reminderText, new ManaCostsImpl(manaString)); + kickerCosts.add(kickerCost); + return kickerCost; } public final OptionalAdditionalCost addKickerCost(Cost cost) { - OptionalAdditionalCost kickerCost = new OptionalAdditionalCostImpl(keywordText, "-", reminderText, cost); - kickerCosts.add(kickerCost); - return kickerCost; + OptionalAdditionalCost kickerCost = new OptionalAdditionalCostImpl(keywordText, "-", reminderText, cost); + kickerCosts.add(kickerCost); + return kickerCost; } public void resetKicker(Game game, Ability source) { String key = getActivationKey(source, "", game); - activations.remove(key); - for (OptionalAdditionalCost cost: kickerCosts) { + activations.remove(key); + for (OptionalAdditionalCost cost : kickerCosts) { cost.reset(); } } @@ -152,7 +149,7 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo public int getXManaValue() { return xManaValue; } - + public int getKickedCounter(Game game, Ability source) { String key = getActivationKey(source, "", game); if (activations.containsKey(key)) { @@ -169,7 +166,7 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo return false; } - public List getKickerCosts () { + public List getKickerCosts() { return kickerCosts; } @@ -186,50 +183,50 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo int zcc = source.getSourceObjectZoneChangeCounter(); if (source.getSourceObjectZoneChangeCounter() == 0) { zcc = game.getState().getZoneChangeCounter(source.getSourceId()); - } + } if (zcc > 0 && (source.getAbilityType().equals(AbilityType.TRIGGERED) || source.getAbilityType().equals(AbilityType.STATIC))) { --zcc; } - return String.valueOf(zcc) + ((kickerCosts.size() > 1) ? costText :""); + return String.valueOf(zcc) + ((kickerCosts.size() > 1) ? costText : ""); } - + @Override public void addOptionalAdditionalCosts(Ability ability, Game game) { if (ability instanceof SpellAbility) { Player player = game.getPlayer(controllerId); if (player != null) { this.resetKicker(game, ability); - for (OptionalAdditionalCost kickerCost: kickerCosts) { + for (OptionalAdditionalCost kickerCost : kickerCosts) { boolean again = true; while (player.isInGame() && again) { String times = ""; if (kickerCost.isRepeatable()) { int activatedCount = getKickedCounter(game, ability); - times = Integer.toString(activatedCount + 1) + (activatedCount == 0 ? " time ":" times "); + times = Integer.toString(activatedCount + 1) + (activatedCount == 0 ? " time " : " times "); } - if (kickerCost.canPay(ability, sourceId, controllerId, game) && - player.chooseUse(Outcome.Benefit, "Pay " + times + kickerCost.getText(false) + " ?", game)) { + if (kickerCost.canPay(ability, sourceId, controllerId, game) + && player.chooseUse(Outcome.Benefit, "Pay " + times + kickerCost.getText(false) + " ?", ability, game)) { this.activateKicker(kickerCost, ability, game); for (Iterator it = ((Costs) kickerCost).iterator(); it.hasNext();) { Cost cost = (Cost) it.next(); if (cost instanceof ManaCostsImpl) { - List varCosts = ((ManaCostsImpl)cost).getVariableCosts(); + List varCosts = ((ManaCostsImpl) cost).getVariableCosts(); if (!varCosts.isEmpty()) { // use only first variable cost xManaValue = game.getPlayer(this.controllerId).announceXMana(varCosts.get(0).getMinX(), Integer.MAX_VALUE, "Announce kicker value for " + varCosts.get(0).getText(), game, this); // kicker variable X costs handled internally as multikicker with {1} cost (no multikicker on card) if (!game.isSimulation()) { - game.informPlayers(game.getPlayer(this.controllerId).getLogName() + " announced a value of " + xManaValue +" for " + " kicker X "); + game.informPlayers(game.getPlayer(this.controllerId).getLogName() + " announced a value of " + xManaValue + " for " + " kicker X "); } ability.getManaCostsToPay().add(new GenericManaCost(xManaValue)); } else { - ability.getManaCostsToPay().add((ManaCostsImpl) cost.copy()); + ability.getManaCostsToPay().add((ManaCostsImpl) cost.copy()); } } else { ability.getCosts().add(cost.copy()); } } - + again = kickerCost.isRepeatable(); } else { again = false; @@ -240,26 +237,25 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo } } - @Override public String getRule() { - StringBuilder sb = new StringBuilder(); - int numberKicker = 0; - String remarkText = ""; - for (OptionalAdditionalCost kickerCost: kickerCosts) { - if (numberKicker == 0) { - sb.append(kickerCost.getText(false)); - remarkText = kickerCost.getReminderText(); - } else { - sb.append(" and/or ").append(kickerCost.getText(true)); - } - ++numberKicker; - } - if (numberKicker == 1) { + StringBuilder sb = new StringBuilder(); + int numberKicker = 0; + String remarkText = ""; + for (OptionalAdditionalCost kickerCost : kickerCosts) { + if (numberKicker == 0) { + sb.append(kickerCost.getText(false)); + remarkText = kickerCost.getReminderText(); + } else { + sb.append(" and/or ").append(kickerCost.getText(true)); + } + ++numberKicker; + } + if (numberKicker == 1) { sb.append(" ").append(remarkText); - } + } - return sb.toString(); + return sb.toString(); } @Override diff --git a/Mage/src/mage/abilities/keyword/MadnessAbility.java b/Mage/src/mage/abilities/keyword/MadnessAbility.java index f8e1ff0f5cc..b7ceb209ca3 100644 --- a/Mage/src/mage/abilities/keyword/MadnessAbility.java +++ b/Mage/src/mage/abilities/keyword/MadnessAbility.java @@ -88,7 +88,7 @@ class MadnessReplacementEffect extends ReplacementEffectImpl { if (controller != null) { Card card = game.getCard(event.getTargetId()); if (card != null) { - if (controller.chooseUse(outcome, "Move " + card.getLogName() + " to exile to cast it by Madness?", game)) { + if (controller.chooseUse(outcome, "Move " + card.getLogName() + " to exile to cast it by Madness?", source, game)) { controller.moveCardToExileWithInfo(card, source.getSourceId(), "Madness", source.getSourceId(), game, ((ZoneChangeEvent) event).getFromZone(), true); game.fireEvent(GameEvent.getEvent(GameEvent.EventType.MADNESS_CARD_EXILED, card.getId(), card.getId(),controller.getId())); return true; diff --git a/Mage/src/mage/abilities/keyword/MorphAbility.java b/Mage/src/mage/abilities/keyword/MorphAbility.java index 362be6c6191..cba284786e6 100644 --- a/Mage/src/mage/abilities/keyword/MorphAbility.java +++ b/Mage/src/mage/abilities/keyword/MorphAbility.java @@ -1,31 +1,30 @@ /* -* 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. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities.keyword; import java.util.Iterator; @@ -58,42 +57,44 @@ import mage.players.Player; /** * 702.36. Morph * - * 702.36a Morph is a static ability that functions in any zone from which you could play - * the card it’s on, and the morph effect works any time the card is face down. - * "Morph [cost]" means "You may cast this card as a 2/2 face-down creature, with no text, - * no name, no subtypes, and no mana cost by paying {3} rather than paying its mana cost." - * (See rule 707, "Face-Down Spells and Permanents.") + * 702.36a Morph is a static ability that functions in any zone from which you + * could play the card it’s on, and the morph effect works any time the card is + * face down. "Morph [cost]" means "You may cast this card as a 2/2 face-down + * creature, with no text, no name, no subtypes, and no mana cost by paying {3} + * rather than paying its mana cost." (See rule 707, "Face-Down Spells and + * Permanents.") * - * 702.36b To cast a card using its morph ability, turn it face down. It becomes a 2/2 - * face-down creature card, with no text, no name, no subtypes, and no mana cost. Any - * effects or prohibitions that would apply to casting a card with these characteristics - * (and not the face-up card’s characteristics) are applied to casting this card. These - * values are the copiable values of that object’s characteristics. (See rule 613, - * "Interaction of Continuous Effects," and rule 706, "Copying Objects.") Put it onto the - * stack (as a face-down spell with the same characteristics), and pay {3} rather than pay - * its mana cost. This follows the rules for paying alternative costs. You can use morph - * to cast a card from any zone from which you could normally play it. When the spell - * resolves, it enters the battlefield with the same characteristics the spell had. The - * morph effect applies to the face-down object wherever it is, and it ends when the - * permanent is turned face up. # + * 702.36b To cast a card using its morph ability, turn it face down. It becomes + * a 2/2 face-down creature card, with no text, no name, no subtypes, and no + * mana cost. Any effects or prohibitions that would apply to casting a card + * with these characteristics (and not the face-up card’s characteristics) are + * applied to casting this card. These values are the copiable values of that + * object’s characteristics. (See rule 613, "Interaction of Continuous Effects," + * and rule 706, "Copying Objects.") Put it onto the stack (as a face-down spell + * with the same characteristics), and pay {3} rather than pay its mana cost. + * This follows the rules for paying alternative costs. You can use morph to + * cast a card from any zone from which you could normally play it. When the + * spell resolves, it enters the battlefield with the same characteristics the + * spell had. The morph effect applies to the face-down object wherever it is, + * and it ends when the permanent is turned face up. # * - * 702.36c You can’t cast a card face down if it doesn’t have morph. + * 702.36c You can’t cast a card face down if it doesn’t have morph. * - * 702.36d If you have priority, you may turn a face-down permanent you control face up. - * This is a special action; it doesn’t use the stack (see rule 115). To do this, show - * all players what the permanent’s morph cost would be if it were face up, pay that cost, - * then turn the permanent face up. (If the permanent wouldn’t have a morph cost if it - * were face up, it can’t be turned face up this way.) The morph effect on it ends, and - * it regains its normal characteristics. Any abilities relating to the permanent entering - * the battlefield don’t trigger when it’s turned face up and don’t have any effect, because - * the permanent has already entered the battlefield. + * 702.36d If you have priority, you may turn a face-down permanent you control + * face up. This is a special action; it doesn’t use the stack (see rule 115). + * To do this, show all players what the permanent’s morph cost would be if it + * were face up, pay that cost, then turn the permanent face up. (If the + * permanent wouldn’t have a morph cost if it were face up, it can’t be turned + * face up this way.) The morph effect on it ends, and it regains its normal + * characteristics. Any abilities relating to the permanent entering the + * battlefield don’t trigger when it’s turned face up and don’t have any effect, + * because the permanent has already entered the battlefield. * - * 702.36e See rule 707, "Face-Down Spells and Permanents," for more information on how to - * cast cards with morph. + * 702.36e See rule 707, "Face-Down Spells and Permanents," for more information + * on how to cast cards with morph. * * @author LevelX2 */ - public class MorphAbility extends StaticAbility implements AlternativeSourceCosts { protected static final String ABILITY_KEYWORD = "Morph"; @@ -104,9 +105,9 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost protected AlternativeCost2Impl alternateCosts = new AlternativeCost2Impl(ABILITY_KEYWORD, REMINDER_TEXT, new GenericManaCost(3)); protected Costs morphCosts; // needed to check activation status, if card changes zone after casting it - private int zoneChangeCounter = 0; - private boolean megamorph; - + private int zoneChangeCounter = 0; + private boolean megamorph; + public MorphAbility(Card card, Cost morphCost) { this(card, createCosts(morphCost)); } @@ -118,7 +119,7 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost public MorphAbility(Card card, Costs morphCosts) { this(card, morphCosts, false); } - + public MorphAbility(Card card, Costs morphCosts, boolean megamorph) { super(Zone.HAND, null); this.morphCosts = morphCosts; @@ -129,9 +130,9 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost sb.append(ABILITY_KEYWORD_MEGA).append(" "); } else { sb.append(ABILITY_KEYWORD).append(" "); - } - name = ABILITY_KEYWORD; - for (Cost cost :morphCosts) { + } + name = ABILITY_KEYWORD; + for (Cost cost : morphCosts) { if (!(cost instanceof ManaCosts)) { sb.append("- "); break; @@ -143,10 +144,10 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost } else { sb.append(REMINDER_TEXT); } - + ruleText = sb.toString(); - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BecomesFaceDownCreatureEffect(morphCosts, (megamorph ? FaceDownType.MEGAMORPHED :FaceDownType.MORPHED))); + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BecomesFaceDownCreatureEffect(morphCosts, (megamorph ? FaceDownType.MEGAMORPHED : FaceDownType.MORPHED))); ability.setWorksFaceDown(true); ability.setRuleVisible(false); addSubAbility(ability); @@ -154,12 +155,12 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost } public MorphAbility(final MorphAbility ability) { - super(ability); - this.zoneChangeCounter = ability.zoneChangeCounter; - this.ruleText = ability.ruleText; - this.alternateCosts = ability.alternateCosts.copy(); - this.morphCosts = ability.morphCosts; // can't be changed - this.megamorph = ability.megamorph; + super(ability); + this.zoneChangeCounter = ability.zoneChangeCounter; + this.ruleText = ability.ruleText; + this.alternateCosts = ability.alternateCosts.copy(); + this.morphCosts = ability.morphCosts; // can't be changed + this.megamorph = ability.megamorph; } private static Costs createCosts(Cost cost) { @@ -170,11 +171,11 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost @Override public MorphAbility copy() { - return new MorphAbility(this); + return new MorphAbility(this); } public void resetMorph() { - alternateCosts.reset(); + alternateCosts.reset(); zoneChangeCounter = 0; } @@ -185,7 +186,7 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost @Override public boolean isActivated(Ability ability, Game game) { Card card = game.getCard(sourceId); - if (card != null && card.getZoneChangeCounter(game) <= zoneChangeCounter +1) { + if (card != null && card.getZoneChangeCounter(game) <= zoneChangeCounter + 1) { return alternateCosts.isActivated(game); } return false; @@ -205,7 +206,7 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost this.resetMorph(); spell.setFaceDown(true, game); // so only the back is visible if (alternateCosts.canPay(ability, sourceId, controllerId, game)) { - if (player.chooseUse(Outcome.Benefit, new StringBuilder("Cast this card as a 2/2 face-down creature for ").append(getCosts().getText()).append(" ?").toString(), game)) { + if (player.chooseUse(Outcome.Benefit, "Cast this card as a 2/2 face-down creature for " + getCosts().getText() + " ?", ability, game)) { activateMorph(game); // change mana costs ability.getManaCostsToPay().clear(); @@ -213,7 +214,7 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost for (Iterator it = this.alternateCosts.iterator(); it.hasNext();) { Cost cost = (Cost) it.next(); if (cost instanceof ManaCost) { - ability.getManaCostsToPay().add((ManaCost)cost.copy()); + ability.getManaCostsToPay().add((ManaCost) cost.copy()); } else { ability.getCosts().add(cost.copy()); } @@ -231,12 +232,12 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost } } } - if (ability.getAbilityType().equals(AbilityType.PLAY_LAND)) { + if (ability.getAbilityType().equals(AbilityType.PLAY_LAND)) { Player player = game.getPlayer(controllerId); if (player != null) { this.resetMorph(); if (alternateCosts.canPay(ability, sourceId, controllerId, game)) { - if (player.chooseUse(Outcome.Benefit, new StringBuilder("Cast this card as a 2/2 face-down creature for ").append(getCosts().getText()).append(" ?").toString(), game)) { + if (player.chooseUse(Outcome.Benefit, new StringBuilder("Cast this card as a 2/2 face-down creature for ").append(getCosts().getText()).append(" ?").toString(), ability, game)) { activateMorph(game); // change mana costs ability.getManaCostsToPay().clear(); @@ -244,7 +245,7 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost for (Iterator it = this.alternateCosts.iterator(); it.hasNext();) { Cost cost = (Cost) it.next(); if (cost instanceof ManaCost) { - ability.getManaCostsToPay().add((ManaCost)cost.copy()); + ability.getManaCostsToPay().add((ManaCost) cost.copy()); } else { ability.getCosts().add(cost.copy()); } @@ -292,7 +293,7 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost public Costs getCosts() { return alternateCosts; } - + public static void setPermanentToFaceDownCreature(MageObject mageObject) { mageObject.getPower().initValue(2); mageObject.getToughness().initValue(2); @@ -305,13 +306,9 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost mageObject.getSupertype().clear(); mageObject.getManaCost().clear(); if (mageObject instanceof Permanent) { - ((Permanent)mageObject).setExpansionSetCode(""); - ((Permanent)mageObject).setRarity(Rarity.NA); + ((Permanent) mageObject).setExpansionSetCode(""); + ((Permanent) mageObject).setRarity(Rarity.NA); } - + } } - - - - diff --git a/Mage/src/mage/abilities/keyword/OfferingAbility.java b/Mage/src/mage/abilities/keyword/OfferingAbility.java index 0ecb7ec5ec2..97f737e4cf1 100644 --- a/Mage/src/mage/abilities/keyword/OfferingAbility.java +++ b/Mage/src/mage/abilities/keyword/OfferingAbility.java @@ -159,7 +159,7 @@ class OfferingAsThoughEffect extends AsThoughEffectImpl { Card spellToCast = game.getCard(source.getSourceId()); Player player = game.getPlayer(source.getControllerId()); if (player != null && !CardUtil.isCheckPlayableMode(affectedAbility) && - player.chooseUse(Outcome.Benefit, "Offer a " + filter.getMessage() + " to cast " + spellToCast.getName() + "?", game)) { + player.chooseUse(Outcome.Benefit, "Offer a " + filter.getMessage() + " to cast " + spellToCast.getName() + "?", source, game)) { Target target = new TargetControlledCreaturePermanent(1,1,filter,true); player.chooseTarget(Outcome.Sacrifice, target, source, game); if (!target.isChosen()) { diff --git a/Mage/src/mage/abilities/keyword/ProwlAbility.java b/Mage/src/mage/abilities/keyword/ProwlAbility.java index fb752f990b5..1f0d53f630f 100644 --- a/Mage/src/mage/abilities/keyword/ProwlAbility.java +++ b/Mage/src/mage/abilities/keyword/ProwlAbility.java @@ -1,31 +1,30 @@ /* -* 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. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities.keyword; import java.util.Iterator; @@ -50,16 +49,16 @@ import mage.watchers.common.ProwlWatcher; /** * 702.74. Prowl # - * - * 702.74a Prowl is a static ability that functions on the stack. "Prowl [cost]" means - * "You may pay [cost] rather than pay this spell's mana cost if a player was dealt combat - * damage this turn by a source that, at the time it dealt that damage, was under your - * control and had any of this spell's creature types." Paying a spell's prowl cost follows - * the rules for paying alternative costs in rules 601.2b and 601.2e-g + * + * 702.74a Prowl is a static ability that functions on the stack. "Prowl [cost]" + * means "You may pay [cost] rather than pay this spell's mana cost if a player + * was dealt combat damage this turn by a source that, at the time it dealt that + * damage, was under your control and had any of this spell's creature types." + * Paying a spell's prowl cost follows the rules for paying alternative costs in + * rules 601.2b and 601.2e-g * * @author LevelX2 */ - public class ProwlAbility extends StaticAbility implements AlternativeSourceCosts { private static final String PROWL_KEYWORD = "Prowl"; @@ -77,43 +76,43 @@ public class ProwlAbility extends StaticAbility implements AlternativeSourceCost } public ProwlAbility(final ProwlAbility ability) { - super(ability); - this.prowlCosts.addAll(ability.prowlCosts); - this.reminderText = ability.reminderText; + super(ability); + this.prowlCosts.addAll(ability.prowlCosts); + this.reminderText = ability.reminderText; } @Override public ProwlAbility copy() { - return new ProwlAbility(this); + return new ProwlAbility(this); } public final AlternativeCost2 addProwlCost(String manaString) { - AlternativeCost2 prowlCost = new AlternativeCost2Impl(PROWL_KEYWORD, reminderText, new ManaCostsImpl(manaString)); - prowlCosts.add(prowlCost); - return prowlCost; + AlternativeCost2 prowlCost = new AlternativeCost2Impl(PROWL_KEYWORD, reminderText, new ManaCostsImpl(manaString)); + prowlCosts.add(prowlCost); + return prowlCost; } public void resetProwl() { - for (AlternativeCost2 cost: prowlCosts) { + for (AlternativeCost2 cost : prowlCosts) { cost.reset(); } } @Override public boolean isActivated(Ability ability, Game game) { - for (AlternativeCost2 cost: prowlCosts) { - if(cost.isActivated(game)) { + for (AlternativeCost2 cost : prowlCosts) { + if (cost.isActivated(game)) { return true; } } return false; } - + @Override public boolean isAvailable(Ability source, Game game) { return true; } - + @Override public boolean askToActivateAlternativeCosts(Ability ability, Game game) { if (ability instanceof SpellAbility) { @@ -124,7 +123,7 @@ public class ProwlAbility extends StaticAbility implements AlternativeSourceCost throw new IllegalArgumentException("Params can't be null"); } boolean canProwl = false; - for (String subtype: card.getSubtype()) { + for (String subtype : card.getSubtype()) { if (prowlWatcher.hasSubtypeMadeCombatDamage(ability.getControllerId(), subtype)) { canProwl = true; break; @@ -132,9 +131,9 @@ public class ProwlAbility extends StaticAbility implements AlternativeSourceCost } if (canProwl) { this.resetProwl(); - for (AlternativeCost2 prowlCost: prowlCosts) { - if (prowlCost.canPay(ability, sourceId, controllerId, game) && - player.chooseUse(Outcome.Benefit, new StringBuilder("Cast for ").append(PROWL_KEYWORD).append(" cost ").append(prowlCost.getText(true)).append(" ?").toString(), game)) { + for (AlternativeCost2 prowlCost : prowlCosts) { + if (prowlCost.canPay(ability, sourceId, controllerId, game) + && player.chooseUse(Outcome.Benefit, new StringBuilder("Cast for ").append(PROWL_KEYWORD).append(" cost ").append(prowlCost.getText(true)).append(" ?").toString(), ability, game)) { prowlCost.activate(); ability.getManaCostsToPay().clear(); ability.getCosts().clear(); @@ -155,23 +154,23 @@ public class ProwlAbility extends StaticAbility implements AlternativeSourceCost @Override public String getRule() { - StringBuilder sb = new StringBuilder(); - int numberCosts = 0; - String remarkText = ""; - for (AlternativeCost2 prowlCost: prowlCosts) { - if (numberCosts == 0) { - sb.append(prowlCost.getText(false)); - remarkText = prowlCost.getReminderText(); - } else { - sb.append(" and/or ").append(prowlCost.getText(true)); - } - ++numberCosts; - } - if (numberCosts == 1) { + StringBuilder sb = new StringBuilder(); + int numberCosts = 0; + String remarkText = ""; + for (AlternativeCost2 prowlCost : prowlCosts) { + if (numberCosts == 0) { + sb.append(prowlCost.getText(false)); + remarkText = prowlCost.getReminderText(); + } else { + sb.append(" and/or ").append(prowlCost.getText(true)); + } + ++numberCosts; + } + if (numberCosts == 1) { sb.append(" ").append(remarkText); - } + } - return sb.toString(); + return sb.toString(); } @Override @@ -190,12 +189,12 @@ public class ProwlAbility extends StaticAbility implements AlternativeSourceCost private void setReminderText(Card card) { StringBuilder sb = new StringBuilder("(You may cast this for its prowl cost if you dealt combat damage to a player this turn with a "); int i = 0; - for (String subtype: card.getSubtype()) { + for (String subtype : card.getSubtype()) { i++; sb.append(subtype); if (card.getSubtype().size() > 1 && i < card.getSubtype().size()) { sb.append(" or "); - } + } } sb.append(".)"); @@ -205,7 +204,7 @@ public class ProwlAbility extends StaticAbility implements AlternativeSourceCost @Override public Costs getCosts() { Costs alterCosts = new CostsImpl<>(); - for (AlternativeCost2 aCost: prowlCosts) { + for (AlternativeCost2 aCost : prowlCosts) { alterCosts.add(aCost.getCost()); } return alterCosts; diff --git a/Mage/src/mage/abilities/keyword/ReplicateAbility.java b/Mage/src/mage/abilities/keyword/ReplicateAbility.java index c78f0790444..4607b39af1d 100644 --- a/Mage/src/mage/abilities/keyword/ReplicateAbility.java +++ b/Mage/src/mage/abilities/keyword/ReplicateAbility.java @@ -1,31 +1,30 @@ /* -* 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. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.abilities.keyword; import java.util.Iterator; @@ -54,7 +53,6 @@ import mage.players.Player; * * @author LevelX2 */ - public class ReplicateAbility extends StaticAbility implements OptionalAdditionalSourceCosts { private static final String keywordText = "Replicate"; @@ -62,21 +60,21 @@ public class ReplicateAbility extends StaticAbility implements OptionalAdditiona protected OptionalAdditionalCost additionalCost; public ReplicateAbility(Card card, String manaString) { - super(Zone.STACK, null); - this.additionalCost = new OptionalAdditionalCostImpl(keywordText, reminderTextMana, new ManaCostsImpl(manaString)); - this.additionalCost.setRepeatable(true); - setRuleAtTheTop(true); - addSubAbility(new ReplicateTriggeredAbility()); + super(Zone.STACK, null); + this.additionalCost = new OptionalAdditionalCostImpl(keywordText, reminderTextMana, new ManaCostsImpl(manaString)); + this.additionalCost.setRepeatable(true); + setRuleAtTheTop(true); + addSubAbility(new ReplicateTriggeredAbility()); } public ReplicateAbility(final ReplicateAbility ability) { - super(ability); - additionalCost = ability.additionalCost; + super(ability); + additionalCost = ability.additionalCost; } @Override public ReplicateAbility copy() { - return new ReplicateAbility(this); + return new ReplicateAbility(this); } @Override @@ -119,10 +117,10 @@ public class ReplicateAbility extends StaticAbility implements OptionalAdditiona String times = ""; if (additionalCost.isRepeatable()) { int numActivations = additionalCost.getActivateCount(); - times = Integer.toString(numActivations + 1) + (numActivations == 0 ? " time ":" times "); + times = Integer.toString(numActivations + 1) + (numActivations == 0 ? " time " : " times "); } - if (additionalCost.canPay(ability, sourceId, controllerId, game) && - player.chooseUse(Outcome.Benefit, new StringBuilder("Pay ").append(times).append(additionalCost.getText(false)).append(" ?").toString(), game)) { + if (additionalCost.canPay(ability, sourceId, controllerId, game) + && player.chooseUse(Outcome.Benefit, new StringBuilder("Pay ").append(times).append(additionalCost.getText(false)).append(" ?").toString(), ability, game)) { additionalCost.activate(); for (Iterator it = ((Costs) additionalCost).iterator(); it.hasNext();) { Cost cost = (Cost) it.next(); @@ -140,7 +138,6 @@ public class ReplicateAbility extends StaticAbility implements OptionalAdditiona } } - @Override public String getRule() { StringBuilder sb = new StringBuilder(); @@ -179,6 +176,7 @@ class ReplicateTriggeredAbility extends TriggeredAbilityImpl { private ReplicateTriggeredAbility(final ReplicateTriggeredAbility ability) { super(ability); } + @Override public ReplicateTriggeredAbility copy() { return new ReplicateTriggeredAbility(this); @@ -196,7 +194,7 @@ class ReplicateTriggeredAbility extends TriggeredAbilityImpl { if (spell instanceof Spell) { Card card = game.getCard(spell.getSourceId()); if (card != null) { - for (Ability ability: card.getAbilities()) { + for (Ability ability : card.getAbilities()) { if (ability instanceof ReplicateAbility) { if (((ReplicateAbility) ability).isActivated()) { for (Effect effect : this.getEffects()) { @@ -215,7 +213,7 @@ class ReplicateTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Replicate (When you cast this spell, copy it for each time you paid its replicate cost. You may choose new targets for the copies.)" ; + return "Replicate (When you cast this spell, copy it for each time you paid its replicate cost. You may choose new targets for the copies.)"; } } @@ -239,7 +237,7 @@ class ReplicateCopyEffect extends OneShotEffect { // reset replicate now so the copies don't report x times Replicate Card card = game.getCard(spell.getSourceId()); if (card != null) { - for (Ability ability: card.getAbilities()) { + for (Ability ability : card.getAbilities()) { if (ability instanceof ReplicateAbility) { if (((ReplicateAbility) ability).isActivated()) { ((ReplicateAbility) ability).resetReplicate(); @@ -254,8 +252,9 @@ class ReplicateCopyEffect extends OneShotEffect { copy.setCopiedSpell(true); game.getStack().push(copy); copy.chooseNewTargets(game, source.getControllerId()); - if (!game.isSimulation()) + if (!game.isSimulation()) { game.informPlayers(new StringBuilder(controller.getLogName()).append(copy.getActivatedMessage(game)).toString()); + } } return true; } diff --git a/Mage/src/mage/abilities/keyword/TributeAbility.java b/Mage/src/mage/abilities/keyword/TributeAbility.java index 5c31ca8ab3f..ad5ad5b6b7b 100644 --- a/Mage/src/mage/abilities/keyword/TributeAbility.java +++ b/Mage/src/mage/abilities/keyword/TributeAbility.java @@ -118,7 +118,7 @@ class TributeEffect extends OneShotEffect { sb.append(sourcePermanent.getName()); sb.append(" (add ").append(CardUtil.numberToText(tributeValue)).append(" +1/+1 counter"); sb.append(tributeValue > 1 ? "s":"").append(" to it)?"); - if (opponent.chooseUse(outcome, sb.toString(), game)) { + if (opponent.chooseUse(outcome, sb.toString(), source, game)) { if (!game.isSimulation()) game.informPlayers(opponent.getLogName() + " pays tribute to " + sourcePermanent.getLogName()); game.getState().setValue("tributeValue" + source.getSourceId(), "yes"); diff --git a/Mage/src/mage/abilities/keyword/UnleashAbility.java b/Mage/src/mage/abilities/keyword/UnleashAbility.java index 023b276fa1e..45112f075b2 100644 --- a/Mage/src/mage/abilities/keyword/UnleashAbility.java +++ b/Mage/src/mage/abilities/keyword/UnleashAbility.java @@ -111,7 +111,7 @@ class UnleashReplacementEffect extends ReplacementEffectImpl { Permanent creature = game.getPermanent(event.getTargetId()); Player controller = game.getPlayer(source.getControllerId()); if (creature != null && controller != null) { - if (controller.chooseUse(outcome, "Unleash "+ creature.getName() +"?", game)) { + if (controller.chooseUse(outcome, "Unleash "+ creature.getName() +"?", source, game)) { if (!game.isSimulation()) game.informPlayers(controller.getLogName() + " unleashes " + creature.getName()); creature.addCounters(CounterType.P1P1.createInstance(), game); diff --git a/Mage/src/mage/cards/CardImpl.java b/Mage/src/mage/cards/CardImpl.java index 8f9f4ee18a6..e36d8fa0b2b 100644 --- a/Mage/src/mage/cards/CardImpl.java +++ b/Mage/src/mage/cards/CardImpl.java @@ -753,7 +753,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card { if (name.isEmpty()) { return GameLog.getNeutralColoredText("face down card"); } else { - return GameLog.getColoredObjectName(this); + return GameLog.getColoredObjectIdName(this); } } diff --git a/Mage/src/mage/cards/decks/Deck.java b/Mage/src/mage/cards/decks/Deck.java index 74ea98b86f9..7d2dff0e14a 100644 --- a/Mage/src/mage/cards/decks/Deck.java +++ b/Mage/src/mage/cards/decks/Deck.java @@ -1,36 +1,33 @@ /* -* 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. -*/ - + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ package mage.cards.decks; import java.io.Serializable; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashSet; @@ -61,7 +58,7 @@ public class Deck implements Serializable { Deck deck = new Deck(); deck.setName(deckCardLists.getName()); List deckCardNames = new ArrayList<>(); - for (DeckCardInfo deckCardInfo: deckCardLists.getCards()) { + for (DeckCardInfo deckCardInfo : deckCardLists.getCards()) { Card card = createCard(deckCardInfo, mockCards); if (card != null) { deck.cards.add(card); @@ -71,7 +68,7 @@ public class Deck implements Serializable { } } List sbCardNames = new ArrayList<>(); - for (DeckCardInfo deckCardInfo: deckCardLists.getSideboard()) { + for (DeckCardInfo deckCardInfo : deckCardLists.getSideboard()) { Card card = createCard(deckCardInfo, mockCards); if (card != null) { deck.sideboard.add(card); @@ -97,9 +94,9 @@ public class Deck implements Serializable { } private static GameException createCardNotFoundGameException(DeckCardInfo deckCardInfo, String deckName) { - return new GameException("Card not found - " + deckCardInfo.getCardName() + " - " + deckCardInfo.getSetCode() + " for deck - " + deckName + "\n" + - "Possible reason is, that you use cards in your deck, that are only supported in newer versions of the server.\n" + - "So it can help to use the same card from another set, that's already supported from this server." ); + return new GameException("Card not found - " + deckCardInfo.getCardName() + " - " + deckCardInfo.getSetCode() + " for deck - " + deckName + "\n" + + "Possible reason is, that you use cards in your deck, that are only supported in newer versions of the server.\n" + + "So it can help to use the same card from another set, that's already supported from this server."); } private static Card createCard(DeckCardInfo deckCardInfo, boolean mockCards) { @@ -119,11 +116,11 @@ public class Deck implements Serializable { DeckCardLists deckCardLists = new DeckCardLists(); deckCardLists.setName(name); - for (Card card: cards) { + for (Card card : cards) { deckCardLists.getCards().add(new DeckCardInfo(card.getName(), card.getCardNumber(), card.getExpansionSetCode())); } - for (Card card: sideboard) { + for (Card card : sideboard) { deckCardLists.getSideboard().add(new DeckCardInfo(card.getName(), card.getCardNumber(), card.getExpansionSetCode())); } diff --git a/Mage/src/mage/game/Game.java b/Mage/src/mage/game/Game.java index 40c78f0512f..e3b00cd8b44 100644 --- a/Mage/src/mage/game/Game.java +++ b/Mage/src/mage/game/Game.java @@ -1,33 +1,40 @@ /* -* 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. -*/ - + * 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 java.io.Serializable; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; import mage.MageItem; import mage.MageObject; import mage.abilities.Ability; @@ -44,6 +51,7 @@ import mage.cards.decks.Deck; import mage.choices.Choice; import mage.constants.Duration; import mage.constants.MultiplayerAttackOption; +import mage.constants.PlayerAction; import mage.constants.RangeOfInfluence; import mage.constants.Zone; import mage.game.combat.Combat; @@ -66,176 +74,281 @@ import mage.players.PlayerList; import mage.players.Players; import mage.util.functions.ApplyToPermanent; -import java.io.Serializable; -import java.util.*; -import mage.constants.PlayerAction; - public interface Game extends MageItem, Serializable { MatchType getGameType(); + int getNumPlayers(); + int getLife(); + RangeOfInfluence getRangeOfInfluence(); + MultiplayerAttackOption getAttackOption(); //game data methods void loadCards(Set cards, UUID ownerId); + Collection getCards(); + Object getCustomData(); + void setCustomData(Object data); + GameOptions getOptions(); + MageObject getObject(UUID objectId); + + MageObject getBaseObject(UUID objectId); + MageObject getEmblem(UUID objectId); + UUID getControllerId(UUID objectId); + Permanent getPermanent(UUID permanentId); + Permanent getPermanentOrLKIBattlefield(UUID permanentId); - Map> getLKI(); + + Map> getLKI(); + Card getCard(UUID cardId); + Ability getAbility(UUID abilityId, UUID sourceId); + void setZone(UUID objectId, Zone zone); + void addPlayer(Player player, Deck deck) throws GameException; + Player getPlayer(UUID playerId); + Players getPlayers(); + PlayerList getPlayerList(); - + /** * Returns a Set of opponents in range for the given playerId - * + * * @param playerId - * @return + * @return */ Set getOpponents(UUID playerId); - + /** * Checks if the given playerToCheckId is an opponent of player - * - * @param player + * + * @param player * @param playerToCheckId - * @return + * @return */ boolean isOpponent(Player player, UUID playerToCheckId); - + Turn getTurn(); + Phase getPhase(); + Step getStep(); + int getTurnNum(); + boolean isMainPhase(); + boolean canPlaySorcery(UUID playerId); + UUID getActivePlayerId(); + UUID getPriorityPlayerId(); + boolean gameOver(UUID playerId); + boolean hasEnded(); + Battlefield getBattlefield(); + SpellStack getStack(); + Exile getExile(); + Combat getCombat(); + GameState getState(); + String getWinner(); + void setDraw(UUID playerId); + boolean isADraw(); + ContinuousEffects getContinuousEffects(); + GameStates getGameStates(); + void loadGameStates(GameStates states); + Game copy(); + boolean isSimulation(); + void setSimulation(boolean simulation); + MageObject getLastKnownInformation(UUID objectId, Zone zone); + MageObject getLastKnownInformation(UUID objectId, Zone zone, int zoneChangeCounter); + boolean getShortLivingLKI(UUID objectId, Zone zone); + void rememberLKI(UUID objectId, Zone zone, MageObject object); + void resetLKI(); + void resetShortLivingLKI(); + void setLosingPlayer(Player player); + Player getLosingPlayer(); + void setStateCheckRequired(); + boolean getStateCheckRequired(); //client event methods void addTableEventListener(Listener listener); + void addPlayerQueryEventListener(Listener listener); + void fireAskPlayerEvent(UUID playerId, String message); + void fireChooseChoiceEvent(UUID playerId, Choice choice); + void fireSelectTargetEvent(UUID playerId, String message, Set targets, boolean required, Map options); + void fireSelectTargetEvent(UUID playerId, String message, Cards cards, boolean required, Map options); + void fireSelectTargetEvent(UUID playerId, String message, List abilities); + void fireSelectTargetEvent(UUID playerId, String message, List perms, boolean required); + void fireSelectEvent(UUID playerId, String message); + void fireSelectEvent(UUID playerId, String message, Map options); + void firePriorityEvent(UUID playerId); + void firePlayManaEvent(UUID playerId, String message); + void firePlayXManaEvent(UUID playerId, String message); + void fireGetChoiceEvent(UUID playerId, String message, MageObject object, List choices); + void fireGetModeEvent(UUID playerId, String message, Map modes); + void fireGetAmountEvent(UUID playerId, String message, int min, int max); + void fireChoosePileEvent(UUID playerId, String message, List pile1, List pile2); + void fireInformEvent(String message); + void fireStatusEvent(String message, boolean withTime); + void fireUpdatePlayersEvent(); + void informPlayers(String message); + void informPlayer(Player player, String message); + void debugMessage(String message); + void fireErrorEvent(String message, Exception ex); + void fireGameEndInfo(); //game event methods void fireEvent(GameEvent event); + /** - * The events are stored until the resolution of the current effect ends - * and fired then all together (e.g. X lands enter the battlefield from Scapeshift) + * The events are stored until the resolution of the current effect ends and + * fired then all together (e.g. X lands enter the battlefield from + * Scapeshift) + * * @param event */ void addSimultaneousEvent(GameEvent event); + boolean replaceEvent(GameEvent event); /** * Creates and fires an damage prevention event * - * @param damageEvent damage event that will be replaced (instanceof check will be done) + * @param damageEvent damage event that will be replaced (instanceof check + * will be done) * @param source ability that's the source of the prevention effect * @param game * @param amountToPrevent max preventable amount * @return true prevention was successfull / false prevention was replaced */ PreventionEffectData preventDamage(GameEvent damageEvent, Ability source, Game game, int amountToPrevent); + /** * Creates and fires an damage prevention event * - * @param event damage event that will be replaced (instanceof check will be done) + * @param event damage event that will be replaced (instanceof check will be + * done) * @param source ability that's the source of the prevention effect * @param game - * @param preventAllDamage true if there is no limit to the damage that can be prevented + * @param preventAllDamage true if there is no limit to the damage that can + * be prevented * @return true prevention was successfull / false prevention was replaced */ PreventionEffectData preventDamage(GameEvent event, Ability source, Game game, boolean preventAllDamage); void start(UUID choosingPlayerId); + void resume(); + void pause(); + boolean isPaused(); + void end(); + void cleanUp(); /* * Gives back the number of cards the player has after the next mulligan */ + int mulliganDownTo(UUID playerId); + void mulligan(UUID playerId); + void endMulligan(UUID playerId); + // void quit(UUID playerId); + void timerTimeout(UUID playerId); + void idleTimeout(UUID playerId); + void concede(UUID playerId); + void setManaPaymentMode(UUID playerId, boolean autoPayment); + void setManaPaymentModeRestricted(UUID playerId, boolean autoPaymentRestricted); + void undo(UUID playerId); + void emptyManaPools(); + void addEffect(ContinuousEffect continuousEffect, Ability source); + void addEmblem(Emblem emblem, Ability source); + void addEmblem(Emblem emblem, Ability source, UUID toPlayerId); + void addCommander(Commander commander); + void addPermanent(Permanent permanent); // priority method - void sendPlayerAction(PlayerAction playerAction, UUID playerId); + void sendPlayerAction(PlayerAction playerAction, UUID playerId); /** * This version supports copying of copies of any depth. @@ -249,53 +362,74 @@ public interface Game extends MageItem, Serializable { Permanent copyPermanent(Permanent copyFromPermanent, Permanent copyToPermanent, Ability source, ApplyToPermanent applier); Permanent copyPermanent(Duration duration, Permanent copyFromPermanent, Permanent copyToPermanent, Ability source, ApplyToPermanent applier); - + Card copyCard(Card cardToCopy, Ability source, UUID newController); void addTriggeredAbility(TriggeredAbility ability); + UUID addDelayedTriggeredAbility(DelayedTriggeredAbility delayedAbility); + void applyEffects(); + boolean checkStateAndTriggered(); + void playPriority(UUID activePlayerId, boolean resuming); + boolean endTurn(); int doAction(MageAction action); //game transaction methods void saveState(boolean bookmark); + int bookmarkState(); + void restoreState(int bookmark, String context); + void removeBookmark(int bookmark); + int getSavedStateSize(); + boolean isSaveGame(); + void setSaveGame(boolean saveGame); - + // game options void setGameOptions(GameOptions options); // game times Date getStartTime(); + Date getEndTime(); // game cheats (for tests only) void cheat(UUID ownerId, Map commands); + void cheat(UUID ownerId, List library, List hand, List battlefield, List graveyard); // controlling the behaviour of replacement effects void setScopeRelevant(boolean scopeRelevant); + public boolean getScopeRelevant(); // players' timers void initTimer(UUID playerId); - void resumeTimer(UUID playerId); - void pauseTimer(UUID playerId); - int getPriorityTime(); - void setPriorityTime(int priorityTime); - UUID getStartingPlayerId(); - - void saveRollBackGameState(); - boolean canRollbackTurns(int turnsToRollback); - void rollbackTurns(int turnsToRollback); - boolean executingRollback(); -} + void resumeTimer(UUID playerId); + + void pauseTimer(UUID playerId); + + int getPriorityTime(); + + void setPriorityTime(int priorityTime); + + UUID getStartingPlayerId(); + + void saveRollBackGameState(); + + boolean canRollbackTurns(int turnsToRollback); + + void rollbackTurns(int turnsToRollback); + + boolean executingRollback(); +} diff --git a/Mage/src/mage/game/GameCommanderImpl.java b/Mage/src/mage/game/GameCommanderImpl.java index 92fbac34254..f6a47aad006 100644 --- a/Mage/src/mage/game/GameCommanderImpl.java +++ b/Mage/src/mage/game/GameCommanderImpl.java @@ -1,31 +1,30 @@ /* -* 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. -*/ - + * 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 java.util.HashMap; @@ -57,10 +56,10 @@ import mage.watchers.common.CommanderInfoWatcher; public abstract class GameCommanderImpl extends GameImpl { static boolean CHECK_COMMANDER_DAMAGE = true; - + private final Map mulliganedCards = new HashMap<>(); // private final Set commanderCombatWatcher = new HashSet<>(); - + protected boolean alsoHand; // replace commander going to hand protected boolean alsoLibrary; // replace commander going to library protected boolean startingPlayerSkipsDraw = true; @@ -80,12 +79,12 @@ public abstract class GameCommanderImpl extends GameImpl { protected void init(UUID choosingPlayerId) { Ability ability = new SimpleStaticAbility(Zone.COMMAND, new InfoEffect("Commander effects")); //Move commander to command zone - for (UUID playerId: state.getPlayerList(startingPlayerId)) { + for (UUID playerId : state.getPlayerList(startingPlayerId)) { Player player = getPlayer(playerId); - if (player != null){ - if (player.getSideboard().size() > 0){ - Card commander = getCard((UUID)player.getSideboard().toArray()[0]); - if (commander != null) { + if (player != null) { + if (player.getSideboard().size() > 0) { + Card commander = getCard((UUID) player.getSideboard().toArray()[0]); + if (commander != null) { player.setCommanderId(commander.getId()); commander.moveToZone(Zone.COMMAND, null, this, true); commander.getAbilities().setControllerId(player.getId()); @@ -107,7 +106,6 @@ public abstract class GameCommanderImpl extends GameImpl { state.getTurnMods().add(new TurnMod(startingPlayerId, PhaseStep.DRAW)); } } - //20130711 /*903.8. The Commander variant uses an alternate mulligan rule. @@ -123,12 +121,12 @@ public abstract class GameCommanderImpl extends GameImpl { TargetCardInHand target = new TargetCardInHand(1, player.getHand().size(), new FilterCard("card to mulligan")); target.setNotTarget(true); target.setRequired(false); - if (player.choose(Outcome.Exile, player.getHand(), target, this)){ + if (player.choose(Outcome.Exile, player.getHand(), target, this)) { int numCards = target.getTargets().size(); - for(UUID uuid : target.getTargets()){ + for (UUID uuid : target.getTargets()) { Card card = player.getHand().get(uuid, this); - if(card != null){ - if(!mulliganedCards.containsKey(playerId)){ + if (card != null) { + if (!mulliganedCards.containsKey(playerId)) { mulliganedCards.put(playerId, new CardsImpl()); } card.moveToExile(null, "", null, this); @@ -140,14 +138,15 @@ public abstract class GameCommanderImpl extends GameImpl { if (freeMulligans > 0) { if (usedFreeMulligans != null && usedFreeMulligans.containsKey(player.getId())) { int used = usedFreeMulligans.get(player.getId()); - if (used < freeMulligans ) { + if (used < freeMulligans) { deduction = 0; - usedFreeMulligans.put(player.getId(), used+1); + usedFreeMulligans.put(player.getId(), used + 1); } } else { - deduction = 0;{ + deduction = 0; + { - } + } usedFreeMulligans.put(player.getId(), 1); } } @@ -155,25 +154,25 @@ public abstract class GameCommanderImpl extends GameImpl { fireInformEvent(new StringBuilder(player.getLogName()) .append(" mulligans ") .append(numCards) - .append(numCards == 1? " card":" cards") - .append(deduction == 0 ? " for free and draws ":" down to ") + .append(numCards == 1 ? " card" : " cards") + .append(deduction == 0 ? " for free and draws " : " down to ") .append(Integer.toString(player.getHand().size())) - .append(player.getHand().size() <= 1? " card":" cards").toString()); + .append(player.getHand().size() <= 1 ? " card" : " cards").toString()); } } @Override - public void endMulligan(UUID playerId){ + public void endMulligan(UUID playerId) { //return cards to Player player = getPlayer(playerId); - if(player != null && mulliganedCards.containsKey(playerId)){ - for(Card card : mulliganedCards.get(playerId).getCards(this)){ - if(card != null){ + if (player != null && mulliganedCards.containsKey(playerId)) { + for (Card card : mulliganedCards.get(playerId).getCards(this)) { + if (card != null) { card.moveToZone(Zone.LIBRARY, null, this, false); card.setFaceDown(false, this); } } - if(mulliganedCards.get(playerId).size() > 0){ + if (mulliganedCards.get(playerId).size() > 0) { player.shuffleLibrary(this); } } @@ -186,12 +185,15 @@ public abstract class GameCommanderImpl extends GameImpl { */ @Override protected boolean checkStateBasedActions() { - for (Player player: getPlayers().values()) { + for (Player player : getPlayers().values()) { CommanderInfoWatcher damageWatcher = (CommanderInfoWatcher) getState().getWatchers().get("CommanderCombatDamageWatcher", player.getCommanderId()); - for(Map.Entry entrySet : damageWatcher.getDamageToPlayer().entrySet()){ + if (damageWatcher == null) { + continue; + } + for (Map.Entry entrySet : damageWatcher.getDamageToPlayer().entrySet()) { if (entrySet.getValue() > 20) { Player opponent = getPlayer(entrySet.getKey()); - if (opponent != null && player.isInGame()){ + if (opponent != null && player.isInGame()) { opponent.lost(this); } } @@ -203,7 +205,7 @@ public abstract class GameCommanderImpl extends GameImpl { @Override public Set getOpponents(UUID playerId) { Set opponents = new HashSet<>(); - for (UUID opponentId: this.getPlayer(playerId).getInRange()) { + for (UUID opponentId : this.getPlayer(playerId).getInRange()) { if (!opponentId.equals(playerId)) { opponents.add(opponentId); } @@ -213,7 +215,7 @@ public abstract class GameCommanderImpl extends GameImpl { @Override public boolean isOpponent(Player player, UUID playerToCheck) { - return !player.getId().equals(playerToCheck); + return !player.getId().equals(playerToCheck); } public void setAlsoHand(boolean alsoHand) { diff --git a/Mage/src/mage/game/GameImpl.java b/Mage/src/mage/game/GameImpl.java index f9a2930de5f..1479a6a4429 100644 --- a/Mage/src/mage/game/GameImpl.java +++ b/Mage/src/mage/game/GameImpl.java @@ -1,31 +1,30 @@ /* -* 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. -*/ - + * 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 java.io.IOException; @@ -132,7 +131,7 @@ import org.apache.log4j.Logger; public abstract class GameImpl implements Game, Serializable { private static final int ROLLBACK_TURNS_MAX = 4; - + private static final transient Logger logger = Logger.getLogger(GameImpl.class); private static final FilterPermanent filterAura = new FilterPermanent(); @@ -155,19 +154,18 @@ public abstract class GameImpl implements Game, Serializable { private static Random rnd = new Random(); - private transient Object customData; protected boolean simulation = false; - protected final UUID id; - + protected final UUID id; + protected boolean ready; protected transient TableEventSource tableEventSource = new TableEventSource(); protected transient PlayerQueryEventSource playerQueryEventSource = new PlayerQueryEventSource(); protected Map gameCards = new HashMap<>(); - - protected Map> lki = new EnumMap<>(Zone.class); + + protected Map> lki = new EnumMap<>(Zone.class); protected Map> lkiExtended = new HashMap<>(); // Used to check if an object was moved by the current effect in resolution (so Wrath like effect can be handled correctly) protected Map> shortLivingLKI = new EnumMap<>(Zone.class); @@ -283,19 +281,19 @@ public abstract class GameImpl implements Game, Serializable { @Override public void loadCards(Set cards, UUID ownerId) { - for (Card card: cards) { + for (Card card : cards) { if (card instanceof PermanentCard) { - card = ((PermanentCard)card).getCard(); + card = ((PermanentCard) card).getCard(); } card.setOwnerId(ownerId); gameCards.put(card.getId(), card); state.addCard(card); if (card.isSplitCard()) { - Card leftCard = ((SplitCard)card).getLeftHalfCard(); + Card leftCard = ((SplitCard) card).getLeftHalfCard(); leftCard.setOwnerId(ownerId); gameCards.put(leftCard.getId(), leftCard); state.addCard(leftCard); - Card rightCard = ((SplitCard)card).getRightHalfCard(); + Card rightCard = ((SplitCard) card).getRightHalfCard(); rightCard.setOwnerId(ownerId); gameCards.put(rightCard.getId(), rightCard); state.addCard(rightCard); @@ -332,7 +330,7 @@ public abstract class GameImpl implements Game, Serializable { return state.getPlayer(playerId); } - @Override + @Override public MageObject getObject(UUID objectId) { if (objectId == null) { return null; @@ -343,7 +341,7 @@ public abstract class GameImpl implements Game, Serializable { state.setZone(objectId, Zone.BATTLEFIELD); return object; } - for (StackObject item: state.getStack()) { + for (StackObject item : state.getStack()) { if (item.getId().equals(objectId)) { state.setZone(objectId, Zone.STACK); return item; @@ -374,6 +372,40 @@ public abstract class GameImpl implements Game, Serializable { return object; } + /** + * Get permanent, card or command object (not spell or ability on the stack) + * + * @param objectId + * @return + */ + @Override + public MageObject getBaseObject(UUID objectId) { + if (objectId == null) { + return null; + } + MageObject object; + if (state.getBattlefield().containsPermanent(objectId)) { + object = state.getBattlefield().getPermanent(objectId); + return object; + } + for (CommandObject commandObject : state.getCommand()) { + if (commandObject instanceof Commander && commandObject.getId().equals(objectId)) { + return commandObject; + } + } + object = getCard(objectId); + if (object == null) { + for (CommandObject commandObject : state.getCommand()) { + if (commandObject.getId().equals(objectId)) { + return commandObject; + } + } + // can be an ability of a sacrificed Token trying to get it's source object + object = getLastKnownInformation(objectId, Zone.BATTLEFIELD); + } + return object; + } + @Override public MageObject getEmblem(UUID objectId) { if (objectId == null) { @@ -395,24 +427,24 @@ public abstract class GameImpl implements Game, Serializable { MageObject object = getObject(objectId); if (object != null) { if (object instanceof StackObject) { - return ((StackObject)object).getControllerId(); + return ((StackObject) object).getControllerId(); } else if (object instanceof Permanent) { - return ((Permanent)object).getControllerId(); + return ((Permanent) object).getControllerId(); } else if (object instanceof CommandObject) { - return ((CommandObject)object).getControllerId(); - } + return ((CommandObject) object).getControllerId(); + } UUID controllerId = getContinuousEffects().getControllerOfSourceId(objectId); if (controllerId != null) { return controllerId; } // TODO: When is a player the damage source itself? If not possible remove this Player player = getPlayer(objectId); - if (player != null){ + if (player != null) { return player.getId(); } // No object with controller found so return owner if possible if (object instanceof Card) { - return ((Card)object).getOwnerId(); + return ((Card) object).getOwnerId(); } } return null; @@ -457,7 +489,6 @@ public abstract class GameImpl implements Game, Serializable { // public Zone getZone(UUID objectId) { // return state.getZone(objectId); // } - @Override public void setZone(UUID objectId, Zone zone) { state.setZone(objectId, zone); @@ -483,8 +514,8 @@ public abstract class GameImpl implements Game, Serializable { } /** - * Starts check if game is over or - * if playerId is given let the player concede. + * Starts check if game is over or if playerId is given let the player + * concede. * * @param playerId * @return @@ -494,21 +525,20 @@ public abstract class GameImpl implements Game, Serializable { if (playerId == null) { boolean result = checkIfGameIsOver(); return result; - } else { + } else { logger.debug("Game over for player Id: " + playerId + " gameId " + getId()); leave(playerId); return true; } } - private boolean checkIfGameIsOver() { if (state.isGameOver()) { return true; } int remainingPlayers = 0; int numLosers = 0; - for (Player player: state.getPlayers().values()) { + for (Player player : state.getPlayers().values()) { if (!player.hasLeft()) { remainingPlayers++; } @@ -520,11 +550,11 @@ public abstract class GameImpl implements Game, Serializable { end(); if (remainingPlayers == 0 && logger.isDebugEnabled()) { logger.debug("DRAW for gameId: " + getId()); - for (Player player: state.getPlayers().values()) { - logger.debug("-- " + player.getName() + " left: " + (player.hasLeft() ? "Y":"N") + " lost: " + (player.hasLost()? "Y":"N")); - } + for (Player player : state.getPlayers().values()) { + logger.debug("-- " + player.getName() + " left: " + (player.hasLeft() ? "Y" : "N") + " lost: " + (player.hasLost() ? "Y" : "N")); + } } - for (Player player: state.getPlayers().values()) { + for (Player player : state.getPlayers().values()) { if (!player.hasLeft() && !player.hasLost()) { logger.debug(new StringBuilder("Player ").append(player.getName()).append(" has won gameId: ").append(this.getId())); player.won(this); @@ -550,7 +580,7 @@ public abstract class GameImpl implements Game, Serializable { if (winnerId == null) { return "Game is a draw"; } - return "Player "+ state.getPlayer(winnerId).getName() + " is the winner"; + return "Player " + state.getPlayer(winnerId).getName() + " is the winner"; } @Override @@ -576,7 +606,7 @@ public abstract class GameImpl implements Game, Serializable { if (!simulation && !this.hasEnded()) { // if player left or game is over no undo is possible - this could lead to wrong winner if (bookmark != 0) { if (!savedStates.contains(bookmark - 1)) { - throw new UnsupportedOperationException("It was not possible to do the requested undo operation (bookmark " + (bookmark -1) + " does not exist) context: " + context); + throw new UnsupportedOperationException("It was not possible to do the requested undo operation (bookmark " + (bookmark - 1) + " does not exist) context: " + context); } int stateNum = savedStates.get(bookmark - 1); removeBookmark(bookmark); @@ -677,16 +707,16 @@ public abstract class GameImpl implements Game, Serializable { winnerId = findWinnersAndLosers(); StringBuilder sb = new StringBuilder("GAME END gameId: ").append(this.getId()).append(" "); int count = 0; - for (Player player: this.getState().getPlayers().values()) { + for (Player player : this.getState().getPlayers().values()) { if (count > 0) { sb.append(" - "); } sb.append("[").append(player.getName()).append(" => "); - sb.append(player.hasWon() ? "W":""); - sb.append(player.hasLost()? "L":""); - sb.append(player.hasQuit() ? "Q":""); - sb.append(player.hasIdleTimeout() ? "I":""); - sb.append(player.hasTimerTimeout() ? "T":""); + sb.append(player.hasWon() ? "W" : ""); + sb.append(player.hasLost() ? "L" : ""); + sb.append(player.hasQuit() ? "Q" : ""); + sb.append(player.hasIdleTimeout() ? "I" : ""); + sb.append(player.hasTimerTimeout() ? "T" : ""); sb.append("]"); count++; } @@ -715,12 +745,12 @@ public abstract class GameImpl implements Game, Serializable { } state.setTurnId(null); state.setExtraTurn(false); - + } - + private TurnMod getNextExtraTurn() { boolean checkForExtraTurn = true; - while(checkForExtraTurn) { + while (checkForExtraTurn) { TurnMod extraTurn = getState().getTurnMods().getNextExtraTurn(); if (extraTurn != null) { GameEvent event = new GameEvent(GameEvent.EventType.EXTRA_TURN, extraTurn.getId(), null, extraTurn.getPlayerId()); @@ -733,20 +763,20 @@ public abstract class GameImpl implements Game, Serializable { } return null; } - + private boolean playTurn(Player player) { do { if (executingRollback) { executingRollback = false; player = getPlayer(state.getActivePlayerId()); - for (Player playerObject: getPlayers().values()) { + for (Player playerObject : getPlayers().values()) { if (playerObject.isInGame()) { playerObject.abortReset(); } } } else { state.setActivePlayerId(player.getId()); - saveRollBackGameState(); + saveRollBackGameState(); } this.logStartOfTurn(player); if (checkStopOnTurnOption()) { @@ -754,7 +784,7 @@ public abstract class GameImpl implements Game, Serializable { } state.getTurn().play(this, player); } while (executingRollback); - + if (isPaused() || gameOver(null)) { return false; } @@ -763,7 +793,6 @@ public abstract class GameImpl implements Game, Serializable { return true; } - private void logStartOfTurn(Player player) { StringBuilder sb = new StringBuilder("Turn ").append(state.getTurnNum()).append(" "); sb.append(player.getLogName()); @@ -796,7 +825,7 @@ public abstract class GameImpl implements Game, Serializable { } protected void init(UUID choosingPlayerId) { - for (Player player: state.getPlayers().values()) { + for (Player player : state.getPlayers().values()) { player.beginTurn(this); // init only if match is with timer (>0) and time left was not set yet (== MAX_VALUE). // otherwise the priorityTimeLeft is set in {@link MatchImpl.initGame) @@ -817,7 +846,7 @@ public abstract class GameImpl implements Game, Serializable { //20091005 - 103.1 if (!gameOptions.skipInitShuffling) { //don't shuffle in test mode for card injection on top of player's libraries - for (Player player: state.getPlayers().values()) { + for (Player player : state.getPlayers().values()) { player.shuffleLibrary(this); } } @@ -831,7 +860,7 @@ public abstract class GameImpl implements Game, Serializable { } if (choosingPlayer == null) { choosingPlayerId = pickChoosingPlayer(); - choosingPlayer = getPlayer(choosingPlayerId); + choosingPlayer = getPlayer(choosingPlayerId); } getState().setChoosingPlayerId(choosingPlayerId); // needed to start/stop the timer if active if (choosingPlayer != null && choosingPlayer.choose(Outcome.Benefit, targetPlayer, null, this)) { @@ -845,15 +874,14 @@ public abstract class GameImpl implements Game, Serializable { } message.append(" takes the first turn"); - this.informPlayers(message.toString()); + this.informPlayers(message.toString()); } else { // not possible to choose starting player, stop here return; } - //20091005 - 103.3 - for (UUID playerId: state.getPlayerList(startingPlayerId)) { + for (UUID playerId : state.getPlayerList(startingPlayerId)) { Player player = getPlayer(playerId); if (!gameOptions.testMode || player.getLife() == 0) { player.initLife(this.getLife()); @@ -903,7 +931,7 @@ public abstract class GameImpl implements Game, Serializable { } while (!mulliganPlayers.isEmpty()); getState().setChoosingPlayerId(null); Watchers watchers = state.getWatchers(); - // add default watchers + // add default watchers for (UUID playerId : state.getPlayerList(startingPlayerId)) { watchers.add(new PlayerDamagedBySourceWatcher(playerId)); watchers.add(new BloodthirstWatcher(playerId)); @@ -916,18 +944,18 @@ public abstract class GameImpl implements Game, Serializable { watchers.add(new DamageDoneWatcher()); //20100716 - 103.5 - for (UUID playerId: state.getPlayerList(startingPlayerId)) { + for (UUID playerId : state.getPlayerList(startingPlayerId)) { Player player = getPlayer(playerId); - for (Card card: player.getHand().getCards(this)) { + for (Card card : player.getHand().getCards(this)) { if (player.getHand().contains(card.getId())) { if (card.getAbilities().containsKey(LeylineAbility.getInstance().getId())) { - if (player.chooseUse(Outcome.PutCardInPlay, "Do you wish to put " + card.getName() + " on the battlefield?", this)) { + if (player.chooseUse(Outcome.PutCardInPlay, "Do you wish to put " + card.getName() + " on the battlefield?", null, this)) { card.putOntoBattlefield(this, Zone.HAND, null, player.getId()); } } - for (Ability ability: card.getAbilities()) { + for (Ability ability : card.getAbilities()) { if (ability instanceof ChancellorAbility) { - if (player.chooseUse(Outcome.PutCardInPlay, "Do you wish to reveal " + card.getName() + "?", this)) { + if (player.chooseUse(Outcome.PutCardInPlay, "Do you wish to reveal " + card.getName() + "?", ability, this)) { Cards cards = new CardsImpl(); cards.add(card); player.revealCards("Revealed", cards, this); @@ -936,7 +964,7 @@ public abstract class GameImpl implements Game, Serializable { } if (ability instanceof GemstoneCavernsAbility) { if (!playerId.equals(startingPlayerId)) { - if (player.chooseUse(Outcome.PutCardInPlay, "Do you wish to put " + card.getName() + " into play?", this)) { + if (player.chooseUse(Outcome.PutCardInPlay, "Do you wish to put " + card.getName() + " into play?", ability, this)) { Cards cards = new CardsImpl(); cards.add(card); player.revealCards("Revealed", cards, this); @@ -952,7 +980,7 @@ public abstract class GameImpl implements Game, Serializable { protected UUID findWinnersAndLosers() { UUID winnerIdFound = null; - for (Player player: state.getPlayers().values()) { + for (Player player : state.getPlayers().values()) { if (player.hasWon()) { logger.debug(player.getName() + " has won gameId: " + getId()); winnerIdFound = player.getId(); @@ -965,7 +993,7 @@ public abstract class GameImpl implements Game, Serializable { break; } } - for (Player player: state.getPlayers().values()) { + for (Player player : state.getPlayers().values()) { if (winnerIdFound != null && !player.getId().equals(winnerIdFound) && !player.hasLost()) { player.lost(this); } @@ -974,7 +1002,7 @@ public abstract class GameImpl implements Game, Serializable { } protected void endOfTurn() { - for (Player player: getPlayers().values()) { + for (Player player : getPlayers().values()) { player.endOfTurn(this); } state.getWatchers().reset(); @@ -1003,7 +1031,7 @@ public abstract class GameImpl implements Game, Serializable { logger.debug("END of gameId: " + this.getId()); endTime = new Date(); state.endGame(); - for (Player player: state.getPlayers().values()) { + for (Player player : state.getPlayers().values()) { player.abort(); } } @@ -1021,7 +1049,7 @@ public abstract class GameImpl implements Game, Serializable { if (freeMulligans > 0) { if (usedFreeMulligans != null && usedFreeMulligans.containsKey(player.getId())) { int used = usedFreeMulligans.get(player.getId()); - if (used < freeMulligans ) { + if (used < freeMulligans) { deduction = 0; } } else { @@ -1032,7 +1060,7 @@ public abstract class GameImpl implements Game, Serializable { } @Override - public void endMulligan(UUID playerId){ + public void endMulligan(UUID playerId) { } @Override @@ -1046,9 +1074,9 @@ public abstract class GameImpl implements Game, Serializable { if (freeMulligans > 0) { if (usedFreeMulligans != null && usedFreeMulligans.containsKey(player.getId())) { int used = usedFreeMulligans.get(player.getId()); - if (used < freeMulligans ) { + if (used < freeMulligans) { deduction = 0; - usedFreeMulligans.put(player.getId(), used+1); + usedFreeMulligans.put(player.getId(), used + 1); } } else { deduction = 0; @@ -1057,9 +1085,9 @@ public abstract class GameImpl implements Game, Serializable { } fireInformEvent(new StringBuilder(player.getLogName()) .append(" mulligans") - .append(deduction == 0 ? " for free and draws ":" down to ") + .append(deduction == 0 ? " for free and draws " : " down to ") .append(Integer.toString(numCards - deduction)) - .append(numCards - deduction == 1? " card":" cards").toString()); + .append(numCards - deduction == 1 ? " card" : " cards").toString()); player.drawCards(numCards - deduction, this); } @@ -1072,7 +1100,6 @@ public abstract class GameImpl implements Game, Serializable { // } // } // } - @Override public synchronized void timerTimeout(UUID playerId) { Player player = state.getPlayer(playerId); @@ -1115,15 +1142,14 @@ public abstract class GameImpl implements Game, Serializable { } } } - + @Override public void sendPlayerAction(PlayerAction playerAction, UUID playerId) { Player player = state.getPlayer(playerId); if (player != null) { player.sendPlayerAction(playerAction, this); - } + } } - @Override public synchronized void setManaPaymentMode(UUID playerId, boolean autoPayment) { @@ -1132,27 +1158,26 @@ public abstract class GameImpl implements Game, Serializable { player.getManaPool().setAutoPayment(autoPayment); } } - + @Override public synchronized void setManaPaymentModeRestricted(UUID playerId, boolean autoPaymentRestricted) { Player player = state.getPlayer(playerId); if (player != null) { player.getManaPool().setAutoPaymentRestricted(autoPaymentRestricted); } - } + } @Override public void playPriority(UUID activePlayerId, boolean resuming) { int bookmark = 0; clearAllBookmarks(); try { - applyEffects(); + applyEffects(); while (!isPaused() && !gameOver(null) && !this.getTurn().isEndTurnRequested()) { if (!resuming) { state.getPlayers().resetPassed(); state.getPlayerList().setCurrent(activePlayerId); - } - else { + } else { state.getPlayerList().setCurrent(this.getPriorityPlayerId()); } fireUpdatePlayersEvent(); @@ -1171,14 +1196,14 @@ public abstract class GameImpl implements Game, Serializable { applyEffects(); if (state.getStack().isEmpty()) { resetLKI(); - } + } saveState(false); if (isPaused() || gameOver(null)) { return; } // resetPassed should be called if player performs any action if (player.priority(this)) { - if(executingRollback()) { + if (executingRollback()) { return; } applyEffects(); @@ -1201,15 +1226,14 @@ public abstract class GameImpl implements Game, Serializable { applyEffects(); state.getPlayers().resetPassed(); fireUpdatePlayersEvent(); - resetShortLivingLKI(); + resetShortLivingLKI(); break; } else { resetLKI(); return; } } - } - catch (Exception ex) { + } catch (Exception ex) { logger.fatal("Game exception gameId: " + getId(), ex); ex.printStackTrace(); this.fireErrorEvent("Game exception occurred: ", ex); @@ -1237,19 +1261,19 @@ public abstract class GameImpl implements Game, Serializable { top.resolve(this); } finally { if (top != null) { - state.getStack().remove(top); // seems partly redundant because move card from stack to grave is already done and the stack removed + state.getStack().remove(top); // seems partly redundant because move card from stack to grave is already done and the stack removed rememberLKI(top.getSourceId(), Zone.STACK, top); if (!getTurn().isEndTurnRequested()) { while (state.hasSimultaneousEvents()) { state.handleSimultaneousEvent(this); } - } + } } } } protected boolean allPassed() { - for (Player player: state.getPlayers().values()) { + for (Player player : state.getPlayers().values()) { if (!player.isPassed() && player.isInGame()) { return false; } @@ -1259,7 +1283,7 @@ public abstract class GameImpl implements Game, Serializable { @Override public void emptyManaPools() { - for (Player player: getPlayers().values()) { + for (Player player : getPlayers().values()) { player.getManaPool().emptyPool(this); } } @@ -1302,9 +1326,8 @@ public abstract class GameImpl implements Game, Serializable { state.addCommandObject(newEmblem); } - @Override - public void addCommander(Commander commander){ + public void addCommander(Commander commander) { state.addCommandObject(commander); } @@ -1331,14 +1354,14 @@ public abstract class GameImpl implements Game, Serializable { MageObject oldBluePrint = ((CopyEffect) effect).getTarget(); if (oldBluePrint instanceof Permanent) { // copy it and apply the applier if any - newBluePrint = ((Permanent)oldBluePrint).copy(); + newBluePrint = ((Permanent) oldBluePrint).copy(); } } } } // if it was no copy of copy take the target itself if (newBluePrint == null) { - newBluePrint = copyFromPermanent.copy(); + newBluePrint = copyFromPermanent.copy(); newBluePrint.reset(this); //getState().addCard(permanent); if (copyFromPermanent.isMorphed() || copyFromPermanent.isManifested()) { @@ -1347,7 +1370,7 @@ public abstract class GameImpl implements Game, Serializable { newBluePrint.assignNewId(); if (copyFromPermanent.isTransformed()) { TransformAbility.transform(newBluePrint, copyFromPermanent.getSecondCardFace(), this); - } + } } if (applier != null) { applier.apply(this, newBluePrint); @@ -1358,7 +1381,6 @@ public abstract class GameImpl implements Game, Serializable { newEffect.setApplier(applier); Ability newAbility = source.copy(); newEffect.init(newAbility, this); - state.addEffect(newEffect, newAbility); return newBluePrint; @@ -1376,10 +1398,12 @@ public abstract class GameImpl implements Game, Serializable { Ability manaAbiltiy = ability.copy(); manaAbiltiy.activate(this, false); manaAbiltiy.resolve(this); - } - else { + } else { TriggeredAbility newAbility = ability.copy(); newAbility.newId(); + for (Effect effect : newAbility.getEffects()) { + effect.getTargetPointer().init(this, newAbility); + } state.addTriggeredAbility(newAbility); } } @@ -1388,32 +1412,36 @@ public abstract class GameImpl implements Game, Serializable { public UUID addDelayedTriggeredAbility(DelayedTriggeredAbility delayedAbility) { DelayedTriggeredAbility newAbility = delayedAbility.copy(); newAbility.newId(); - newAbility.init(this); + // ability.init is called as the ability triggeres not now. + // If a FixedTarget pointer is already set from the effect setting up this delayed ability + // it has to be already initialized so it won't be overwitten as the ability triggers state.addDelayedTriggeredAbility(newAbility); return newAbility.getId(); } /** - * 116.5. Each time a player would get priority, the game first performs all applicable state-based actions as a single event (see rule 704, - * “State-Based Actions”), then repeats this process until no state-based actions are performed. Then triggered abilities are put on the stack - * (see rule 603, “Handling Triggered Abilities”). These steps repeat in order until no further state-based actions are performed and no abilities - * trigger. Then the player who would have received priority does so. - * - * @return - */ - + * 116.5. Each time a player would get priority, the game first performs all + * applicable state-based actions as a single event (see rule 704, + * “State-Based Actions”), then repeats this process until no state-based + * actions are performed. Then triggered abilities are put on the stack (see + * rule 603, “Handling Triggered Abilities”). These steps repeat in order + * until no further state-based actions are performed and no abilities + * trigger. Then the player who would have received priority does so. + * + * @return + */ @Override public boolean checkStateAndTriggered() { boolean trigger = !getTurn().isEndTurnRequested(); boolean somethingHappened = false; //20091005 - 115.5 while (!isPaused() && !gameOver(null)) { - if (!checkStateBasedActions() ) { + if (!checkStateBasedActions()) { // nothing happened so check triggers if (trigger) { state.handleSimultaneousEvent(this); } - if (isPaused() || gameOver(null) || !trigger || !checkTriggered()) { + if (isPaused() || gameOver(null) || !trigger || !checkTriggered()) { break; } } @@ -1422,15 +1450,16 @@ public abstract class GameImpl implements Game, Serializable { } return somethingHappened; } + /** - * Sets the waiting triggered abilities (if there are any) - * to the stack in the choosen order by player + * Sets the waiting triggered abilities (if there are any) to the stack in + * the choosen order by player * * @return */ public boolean checkTriggered() { boolean played = false; - for (UUID playerId: state.getPlayerList(state.getActivePlayerId())) { + for (UUID playerId : state.getPlayerList(state.getActivePlayerId())) { Player player = getPlayer(playerId); while (player.isInGame()) { // player can die or win caused by triggered abilities or leave the game List abilities = state.getTriggered(player.getId()); @@ -1452,8 +1481,7 @@ public abstract class GameImpl implements Game, Serializable { if (abilities.size() == 1) { state.removeTriggeredAbility(abilities.get(0)); played |= player.triggerAbility(abilities.get(0), this); - } - else { + } else { TriggeredAbility ability = player.chooseTriggeredAbility(abilities, this); if (ability != null) { state.removeTriggeredAbility(ability); @@ -1466,17 +1494,21 @@ public abstract class GameImpl implements Game, Serializable { } /** - * 116.5. Each time a player would get priority, the game first performs all applicable state-based actions as a single event (see rule 704, - * “State-Based Actions”), then repeats this process until no state-based actions are performed. Then triggered abilities are put on the stack - * (see rule 603, “Handling Triggered Abilities”). These steps repeat in order until no further state-based actions are performed and no abilities - * trigger. Then the player who would have received priority does so. - * @return + * 116.5. Each time a player would get priority, the game first performs all + * applicable state-based actions as a single event (see rule 704, + * “State-Based Actions”), then repeats this process until no state-based + * actions are performed. Then triggered abilities are put on the stack (see + * rule 603, “Handling Triggered Abilities”). These steps repeat in order + * until no further state-based actions are performed and no abilities + * trigger. Then the player who would have received priority does so. + * + * @return */ protected boolean checkStateBasedActions() { boolean somethingHappened = false; //20091005 - 704.5a/704.5b/704.5c - for (Player player: state.getPlayers().values()) { + for (Player player : state.getPlayers().values()) { if (!player.hasLost() && ((player.getLife() <= 0 && player.canLoseByZeroOrLessLife()) || player.isEmptyDraw() @@ -1494,7 +1526,7 @@ public abstract class GameImpl implements Game, Serializable { if (zone != Zone.BATTLEFIELD && zone != Zone.STACK) { switch (zone) { case GRAVEYARD: - for(Player player: getPlayers().values()) { + for (Player player : getPlayers().values()) { if (player.getGraveyard().contains(card.getId())) { player.getGraveyard().remove(card); break; @@ -1502,7 +1534,7 @@ public abstract class GameImpl implements Game, Serializable { } break; case HAND: - for(Player player: getPlayers().values()) { + for (Player player : getPlayers().values()) { if (player.getHand().contains(card.getId())) { player.getHand().remove(card); break; @@ -1510,7 +1542,7 @@ public abstract class GameImpl implements Game, Serializable { } break; case LIBRARY: - for(Player player: getPlayers().values()) { + for (Player player : getPlayers().values()) { if (player.getLibrary().getCard(card.getId(), this) != null) { player.getLibrary().remove(card.getId(), this); break; @@ -1524,11 +1556,11 @@ public abstract class GameImpl implements Game, Serializable { copiedCards.remove(); } } - + List planeswalkers = new ArrayList<>(); List legendary = new ArrayList<>(); List worldEnchantment = new ArrayList<>(); - for (Permanent perm: getBattlefield().getAllActivePermanents()) { + for (Permanent perm : getBattlefield().getAllActivePermanents()) { if (perm.getCardType().contains(CardType.CREATURE)) { //20091005 - 704.5f if (perm.getToughness().getValue() <= 0) { @@ -1536,8 +1568,7 @@ public abstract class GameImpl implements Game, Serializable { somethingHappened = true; continue; } - } - //20091005 - 704.5g/704.5h + } //20091005 - 704.5g/704.5h else if (perm.getToughness().getValue() <= perm.getDamage() || perm.isDeathtouched()) { if (perm.destroy(null, this, false)) { somethingHappened = true; @@ -1587,8 +1618,7 @@ public abstract class GameImpl implements Game, Serializable { somethingHappened = true; } } - } - else { + } else { if (perm.getSpellAbility().getTargets().isEmpty()) { Permanent enchanted = this.getPermanent(perm.getAttachedTo()); logger.error("Aura without target: " + perm.getName() + " attached to " + (enchanted == null ? " null" : enchanted.getName())); @@ -1608,11 +1638,10 @@ public abstract class GameImpl implements Game, Serializable { somethingHappened = true; } } - } - else { + } else { Filter auraFilter = perm.getSpellAbility().getTargets().get(0).getFilter(); if (auraFilter instanceof FilterControlledCreaturePermanent) { - if (!((FilterControlledCreaturePermanent)auraFilter).match(attachedTo, perm.getId(), perm.getControllerId(), this) + if (!((FilterControlledCreaturePermanent) auraFilter).match(attachedTo, perm.getId(), perm.getControllerId(), this) || attachedTo.cantBeEnchantedBy(perm, this)) { if (movePermanentToGraveyardWithInfo(perm)) { somethingHappened = true; @@ -1634,15 +1663,13 @@ public abstract class GameImpl implements Game, Serializable { } } } - } - else if (target instanceof TargetPlayer) { + } else if (target instanceof TargetPlayer) { Player attachedToPlayer = getPlayer(perm.getAttachedTo()); if (attachedToPlayer == null) { if (movePermanentToGraveyardWithInfo(perm)) { somethingHappened = true; } - } - else { + } else { Filter auraFilter = perm.getSpellAbility().getTargets().get(0).getFilter(); if (!auraFilter.match(attachedToPlayer, this) || attachedToPlayer.hasProtectionFrom(perm, this)) { if (movePermanentToGraveyardWithInfo(perm)) { @@ -1677,8 +1704,7 @@ public abstract class GameImpl implements Game, Serializable { Permanent land = getPermanent(perm.getAttachedTo()); if (land == null || !land.getAttachments().contains(perm.getId())) { perm.attachTo(null, this); - } - else if (!land.getCardType().contains(CardType.LAND) || land.hasProtectionFrom(perm, this)) { + } else if (!land.getCardType().contains(CardType.LAND) || land.hasProtectionFrom(perm, this)) { if (land.removeAttachment(perm.getId(), this)) { somethingHappened = true; } @@ -1691,11 +1717,11 @@ public abstract class GameImpl implements Game, Serializable { if (perm.getAttachments().size() > 0) { for (UUID attachmentId : perm.getAttachments()) { Permanent attachment = getPermanent(attachmentId); - if (attachment != null && - (attachment.getCardType().contains(CardType.CREATURE) || - !(attachment.getSubtype().contains("Aura") - || attachment.getSubtype().contains("Equipment") - || attachment.getSubtype().contains("Fortification")))) { + if (attachment != null + && (attachment.getCardType().contains(CardType.CREATURE) + || !(attachment.getSubtype().contains("Aura") + || attachment.getSubtype().contains("Equipment") + || attachment.getSubtype().contains("Fortification")))) { if (perm.removeAttachment(attachment.getId(), this)) { somethingHappened = true; break; @@ -1719,8 +1745,8 @@ public abstract class GameImpl implements Game, Serializable { // chooses one of them, and the rest are put into their owners' graveyards. // This is called the "planeswalker uniqueness rule." if (planeswalkers.size() > 1) { //don't bother checking if less than 2 planeswalkers in play - for (Permanent planeswalker: planeswalkers) { - for (String planeswalkertype: planeswalker.getSubtype()) { + for (Permanent planeswalker : planeswalkers) { + for (String planeswalkertype : planeswalker.getSubtype()) { FilterPlaneswalkerPermanent filterPlaneswalker = new FilterPlaneswalkerPermanent(); filterPlaneswalker.add(new SubtypePredicate(planeswalkertype)); filterPlaneswalker.add(new ControllerIdPredicate(planeswalker.getControllerId())); @@ -1730,7 +1756,7 @@ public abstract class GameImpl implements Game, Serializable { Target targetPlaneswalkerToKeep = new TargetPermanent(filterPlaneswalker); targetPlaneswalkerToKeep.setTargetName(new StringBuilder(planeswalker.getName()).append(" to keep?").toString()); controller.chooseTarget(Outcome.Benefit, targetPlaneswalkerToKeep, null, this); - for (Permanent dupPlaneswalker: this.getBattlefield().getActivePermanents(filterPlaneswalker, planeswalker.getControllerId(), this)) { + for (Permanent dupPlaneswalker : this.getBattlefield().getActivePermanents(filterPlaneswalker, planeswalker.getControllerId(), this)) { if (!targetPlaneswalkerToKeep.getTargets().contains(dupPlaneswalker.getId())) { movePermanentToGraveyardWithInfo(dupPlaneswalker); } @@ -1747,7 +1773,7 @@ public abstract class GameImpl implements Game, Serializable { // This is called the "legend rule." if (legendary.size() > 1) { //don't bother checking if less than 2 legends in play - for (Permanent legend: legendary) { + for (Permanent legend : legendary) { FilterPermanent filterLegendName = new FilterPermanent(); filterLegendName.add(new SupertypePredicate("Legendary")); filterLegendName.add(new NamePredicate(legend.getName())); @@ -1758,7 +1784,7 @@ public abstract class GameImpl implements Game, Serializable { Target targetLegendaryToKeep = new TargetPermanent(filterLegendName); targetLegendaryToKeep.setTargetName(new StringBuilder(legend.getName()).append(" to keep (Legendary Rule)?").toString()); controller.chooseTarget(Outcome.Benefit, targetLegendaryToKeep, null, this); - for (Permanent dupLegend: getBattlefield().getActivePermanents(filterLegendName, legend.getControllerId(), this)) { + for (Permanent dupLegend : getBattlefield().getActivePermanents(filterLegendName, legend.getControllerId(), this)) { if (!targetLegendaryToKeep.getTargets().contains(dupLegend.getId())) { movePermanentToGraveyardWithInfo(dupLegend); } @@ -1769,21 +1795,21 @@ public abstract class GameImpl implements Game, Serializable { } } //704.5m - World Enchantments - if (worldEnchantment.size() > 1) { + if (worldEnchantment.size() > 1) { int newestCard = -1; Permanent newestPermanent = null; - for (Permanent permanent :worldEnchantment) { + for (Permanent permanent : worldEnchantment) { if (newestCard == -1) { newestCard = permanent.getCreateOrder(); newestPermanent = permanent; } else if (newestCard < permanent.getCreateOrder()) { newestCard = permanent.getCreateOrder(); newestPermanent = permanent; - } else if(newestCard == permanent.getCreateOrder()) { + } else if (newestCard == permanent.getCreateOrder()) { newestPermanent = null; } } - for (Permanent permanent :worldEnchantment) { + for (Permanent permanent : worldEnchantment) { if (newestPermanent != permanent) { movePermanentToGraveyardWithInfo(permanent); somethingHappened = true; @@ -1819,9 +1845,8 @@ public abstract class GameImpl implements Game, Serializable { String message; if (this.canPlaySorcery(playerId)) { message = "Play spells and abilities."; - } - else { - message = "Play instants and activated abilities."; + } else { + message = "Play instants and activated abilities."; } playerQueryEventSource.select(playerId, message); } @@ -1834,7 +1859,6 @@ public abstract class GameImpl implements Game, Serializable { playerQueryEventSource.select(playerId, message); } - @Override public synchronized void fireSelectEvent(UUID playerId, String message, Map options) { if (simulation) { @@ -1979,7 +2003,7 @@ public abstract class GameImpl implements Game, Serializable { } logger.trace("fireUpdatePlayersEvent"); tableEventSource.fireTableEvent(EventType.UPDATE, null, this); - getState().clearLookedAt(); + getState().clearLookedAt(); getState().clearRevealed(); } @@ -2058,22 +2082,23 @@ public abstract class GameImpl implements Game, Serializable { } /** - * 800.4a When a player leaves the game, all objects (see rule 109) owned by that player leave - * the game and any effects which give that player control of any objects or players end. Then, - * if that player controlled any objects on the stack not represented by cards, those objects - * cease to exist. Then, if there are any objects still controlled by that player, those objects - * are exiled. This is not a state-based action. It happens as soon as the player leaves the game. - * If the player who left the game had priority at the time he or she left, priority passes to - * the next player in turn order who's still in the game. # + * 800.4a When a player leaves the game, all objects (see rule 109) owned by + * that player leave the game and any effects which give that player control + * of any objects or players end. Then, if that player controlled any + * objects on the stack not represented by cards, those objects cease to + * exist. Then, if there are any objects still controlled by that player, + * those objects are exiled. This is not a state-based action. It happens as + * soon as the player leaves the game. If the player who left the game had + * priority at the time he or she left, priority passes to the next player + * in turn order who's still in the game. # * * @param playerId */ - protected void leave(UUID playerId) { Player player = getPlayer(playerId); if (player == null || player.hasLeft()) { - logger.debug("Player already left " + (player != null ? player.getName():playerId)); + logger.debug("Player already left " + (player != null ? player.getName() : playerId)); return; } logger.debug("Start leave game: " + player.getName()); @@ -2114,12 +2139,12 @@ public abstract class GameImpl implements Game, Serializable { } // Then, if there are any objects still controlled by that player, those objects are exiled. List permanents = this.getBattlefield().getAllActivePermanents(playerId); - for(Permanent permanent : permanents) { + for (Permanent permanent : permanents) { permanent.moveToExile(null, "", null, this); } // Remove cards from the player in all exile zones - for (ExileZone exile: this.getExile().getExileZones()) { + for (ExileZone exile : this.getExile().getExileZones()) { for (Iterator it = exile.iterator(); it.hasNext();) { Card card = this.getCard(it.next()); if (card != null && card.getOwnerId().equals(playerId)) { @@ -2129,8 +2154,8 @@ public abstract class GameImpl implements Game, Serializable { } Iterator it = gameCards.entrySet().iterator(); - while(it.hasNext()) { - Entry entry = (Entry) it.next(); + while (it.hasNext()) { + Entry entry = (Entry) it.next(); Card card = entry.getValue(); if (card.getOwnerId().equals(playerId)) { it.remove(); @@ -2139,7 +2164,6 @@ public abstract class GameImpl implements Game, Serializable { // 801.2c The particular players within each player‘s range of influence are determined as each turn begins. // So no update of range if influence yet - } @Override @@ -2229,7 +2253,6 @@ public abstract class GameImpl implements Game, Serializable { } - protected void removeCreaturesFromCombat() { //20091005 - 511.3 getCombat().endCombat(this); @@ -2250,8 +2273,9 @@ public abstract class GameImpl implements Game, Serializable { } /** - * Gets last known information about object in the zone. - * At the moment doesn't take into account zone (it is expected that it doesn't really matter, if not, then Map> should be used instead). + * Gets last known information about object in the zone. At the moment + * doesn't take into account zone (it is expected that it doesn't really + * matter, if not, then Map> should be used instead). * * Can return null. * @@ -2262,17 +2286,17 @@ public abstract class GameImpl implements Game, Serializable { @Override public MageObject getLastKnownInformation(UUID objectId, Zone zone) { /*if (!lki.containsKey(objectId)) { - return getCard(objectId); - }*/ + return getCard(objectId); + }*/ Map lkiMap = lki.get(zone); if (lkiMap != null) { MageObject object = lkiMap.get(objectId); if (object != null) { return object.copy(); } - for (MageObject mageObject:lkiMap.values()) { + for (MageObject mageObject : lkiMap.values()) { if (mageObject instanceof Spell) { - if (((Spell)mageObject).getCard().getId().equals(objectId)) { + if (((Spell) mageObject).getCard().getId().equals(objectId)) { return mageObject; } } @@ -2335,7 +2359,7 @@ public abstract class GameImpl implements Game, Serializable { idSet = new HashSet<>(); shortLivingLKI.put(zone, idSet); } - idSet.add(objectId); + idSet.add(objectId); if (object instanceof Permanent) { Map lkiExtendedMap = lkiExtended.get(objectId); if (lkiExtendedMap != null) { @@ -2393,7 +2417,6 @@ public abstract class GameImpl implements Game, Serializable { } } - } break; } @@ -2403,7 +2426,7 @@ public abstract class GameImpl implements Game, Serializable { } @Override - public Map> getLKI() { + public Map> getLKI() { return lki; } @@ -2433,7 +2456,7 @@ public abstract class GameImpl implements Game, Serializable { PermanentCard permanent = new PermanentCard(card.getCard(), ownerId, this); getBattlefield().addPermanent(permanent); permanent.entersBattlefield(permanent.getId(), this, Zone.OUTSIDE, false); - ((PermanentImpl)permanent).removeSummoningSickness(); + ((PermanentImpl) permanent).removeSummoningSickness(); if (card.isTapped()) { permanent.setTapped(true); } @@ -2541,7 +2564,6 @@ public abstract class GameImpl implements Game, Serializable { this.saveGame = saveGame; } - public void setStartMessage(String startMessage) { this.startMessage = startMessage; } @@ -2581,7 +2603,7 @@ public abstract class GameImpl implements Game, Serializable { public UUID getStartingPlayerId() { return startingPlayerId; } - + @Override public int getLife() { return startLife; @@ -2591,7 +2613,7 @@ public abstract class GameImpl implements Game, Serializable { public void setDraw(UUID playerId) { Player player = getPlayer(playerId); if (player != null) { - for (UUID playerToSetId :player.getInRange()) { + for (UUID playerToSetId : player.getInRange()) { Player playerToDraw = getPlayer(playerToSetId); playerToDraw.lostForced(this); } @@ -2601,7 +2623,7 @@ public abstract class GameImpl implements Game, Serializable { @Override public void saveRollBackGameState() { if (gameOptions.rollbackTurnsAllowed) { - int toDelete = getTurnNum()- ROLLBACK_TURNS_MAX; + int toDelete = getTurnNum() - ROLLBACK_TURNS_MAX; if (toDelete > 0 && gameStatesRollBack.containsKey(toDelete)) { gameStatesRollBack.remove(toDelete); } @@ -2620,12 +2642,12 @@ public abstract class GameImpl implements Game, Serializable { if (gameOptions.rollbackTurnsAllowed) { int turnToGoTo = getTurnNum() - turnsToRollback; if (turnToGoTo < 1 || !gameStatesRollBack.containsKey(turnToGoTo)) { - informPlayers(GameLog.getPlayerRequestColoredText("Player request: It's not possible to rollback " + turnsToRollback +" turn(s)")); + informPlayers(GameLog.getPlayerRequestColoredText("Player request: It's not possible to rollback " + turnsToRollback + " turn(s)")); } else { - GameState restore = gameStatesRollBack.get(turnToGoTo); + GameState restore = gameStatesRollBack.get(turnToGoTo); if (restore != null) { informPlayers(GameLog.getPlayerRequestColoredText("Player request: Rolling back to start of turn " + restore.getTurnNum())); - for (Player playerObject: getPlayers().values()) { + for (Player playerObject : getPlayers().values()) { if (playerObject.isHuman() && playerObject.isInGame()) { playerObject.abort(); } @@ -2639,7 +2661,7 @@ public abstract class GameImpl implements Game, Serializable { } } } - + @Override public boolean executingRollback() { return executingRollback; diff --git a/Mage/src/mage/game/combat/CombatGroup.java b/Mage/src/mage/game/combat/CombatGroup.java index 3a07906c561..1c50ff3d1b0 100644 --- a/Mage/src/mage/game/combat/CombatGroup.java +++ b/Mage/src/mage/game/combat/CombatGroup.java @@ -1,31 +1,30 @@ /* -* 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. -*/ - + * 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.combat; import java.io.Serializable; @@ -87,13 +86,13 @@ public class CombatGroup implements Serializable, Copyable { } public boolean hasFirstOrDoubleStrike(Game game) { - for (UUID permId: attackers) { + for (UUID permId : attackers) { Permanent attacker = game.getPermanent(permId); if (attacker != null && hasFirstOrDoubleStrike(attacker)) { return true; } } - for (UUID permId: blockers) { + for (UUID permId : blockers) { Permanent blocker = game.getPermanent(permId); if (blocker != null && hasFirstOrDoubleStrike(blocker)) { return true; @@ -138,20 +137,18 @@ public class CombatGroup implements Serializable, Copyable { if (attackers.size() > 0 && (!first || hasFirstOrDoubleStrike(game))) { if (blockers.isEmpty()) { unblockedDamage(first, game); - } - else { + } else { Permanent attacker = game.getPermanent(attackers.get(0)); if (attacker.getAbilities().containsKey(DamageAsThoughNotBlockedAbility.getInstance().getId())) { Player player = game.getPlayer(attacker.getControllerId()); - if (player.chooseUse(Outcome.Damage, "Do you wish to assign damage for " + attacker.getLogName() + " as though it weren't blocked?", game)) { + if (player.chooseUse(Outcome.Damage, "Do you wish to assign damage for " + attacker.getLogName() + " as though it weren't blocked?", null, game)) { blocked = false; unblockedDamage(first, game); } } if (blockers.size() == 1) { singleBlockerDamage(first, game); - } - else { + } else { multiBlockerDamage(first, game); } } @@ -162,8 +159,7 @@ public class CombatGroup implements Serializable, Copyable { if (blockers.size() > 0 && (!first || hasFirstOrDoubleStrike(game))) { if (attackers.size() == 1) { singleAttackerDamage(first, game); - } - else { + } else { multiAttackerDamage(first, game); } } @@ -185,7 +181,8 @@ public class CombatGroup implements Serializable, Copyable { } /** - * Determines if permanent can damage in current (First Strike or not) combat damage step + * Determines if permanent can damage in current (First Strike or not) + * combat damage step * * @param perm Permanent to check * @param first First strike or common combat damage step @@ -196,8 +193,7 @@ public class CombatGroup implements Serializable, Copyable { if (first) { // should have first strike or double strike return hasFirstOrDoubleStrike(perm); - } - // if now not first strike combat + } // if now not first strike combat else { if (hasFirstStrike(perm)) { // if it has first strike in non FS combat damage step @@ -211,7 +207,7 @@ public class CombatGroup implements Serializable, Copyable { } private void unblockedDamage(boolean first, Game game) { - for (UUID attackerId: attackers) { + for (UUID attackerId : attackers) { Permanent attacker = game.getPermanent(attackerId); if (canDamage(attacker, first)) { //20091005 - 510.1c, 702.17c @@ -222,8 +218,6 @@ public class CombatGroup implements Serializable, Copyable { } } - - private void singleBlockerDamage(boolean first, Game game) { //TODO: handle banding Permanent blocker = game.getPermanent(blockers.get(0)); @@ -241,8 +235,7 @@ public class CombatGroup implements Serializable, Copyable { } if (lethalDamage >= damage) { blocker.markDamage(damage, attacker.getId(), game, true, true); - } - else { + } else { Player player = game.getPlayer(attacker.getControllerId()); int damageAssigned = player.getAmount(lethalDamage, damage, "Assign damage to " + blocker.getName(), game); blocker.markDamage(damageAssigned, attacker.getId(), game, true, true); @@ -251,13 +244,12 @@ public class CombatGroup implements Serializable, Copyable { defenderDamage(attacker, damage, game); } } - } - else { + } else { blocker.markDamage(damage, attacker.getId(), game, true, true); } } if (canDamage(blocker, first)) { - if (blocker.getBlocking() == 1) { // blocking several creatures handled separately + if (blocker.getBlocking() == 1) { // blocking several creatures handled separately attacker.markDamage(blockerDamage, blocker.getId(), game, true, true); } } @@ -275,7 +267,7 @@ public class CombatGroup implements Serializable, Copyable { if (canDamage(attacker, first)) { // must be set before attacker damage marking because of effects like Test of Faith Map blockerPower = new HashMap<>(); - for (UUID blockerId: blockerOrder) { + for (UUID blockerId : blockerOrder) { Permanent blocker = game.getPermanent(blockerId); if (canDamage(blocker, first)) { if (blocker.getBlocking() == 1) { // blocking several creatures handled separately @@ -285,7 +277,7 @@ public class CombatGroup implements Serializable, Copyable { } Map assigned = new HashMap<>(); if (blocked) { - for (UUID blockerId: blockerOrder) { + for (UUID blockerId : blockerOrder) { Permanent blocker = game.getPermanent(blockerId); int lethalDamage; if (attacker.getAbilities().containsKey(DeathtouchAbility.getInstance().getId())) { @@ -309,7 +301,7 @@ public class CombatGroup implements Serializable, Copyable { assigned.put(blockerOrder.get(0), assigned.get(blockerOrder.get(0)) + damage); } } - for (UUID blockerId: blockerOrder) { + for (UUID blockerId : blockerOrder) { Integer power = blockerPower.get(blockerId); if (power != null) { attacker.markDamage(power, blockerId, game, true, true); @@ -320,7 +312,7 @@ public class CombatGroup implements Serializable, Copyable { blocker.markDamage(entry.getValue(), attacker.getId(), game, true, true); } } else { - for (UUID blockerId: blockerOrder) { + for (UUID blockerId : blockerOrder) { Permanent blocker = game.getPermanent(blockerId); if (canDamage(blocker, first)) { attacker.markDamage(getDamageValueFromPermanent(blocker, game), blocker.getId(), game, true, true); @@ -331,11 +323,12 @@ public class CombatGroup implements Serializable, Copyable { /** * Damages attacking creatures by a creature that blocked several ones - * Damages only attackers as blocker was damage in {@link #singleBlockerDamage}. + * Damages only attackers as blocker was damage in + * {@link #singleBlockerDamage}. * * Handles abilities like "{this} an block any number of creatures.". * - * @param first + * @param first * @param game */ private void singleAttackerDamage(boolean first, Game game) { @@ -351,7 +344,8 @@ public class CombatGroup implements Serializable, Copyable { /** * Damages attacking creatures by a creature that blocked several ones - * Damages only attackers as blocker was damage in either {@link #singleBlockerDamage} or {@link #multiBlockerDamage}. + * Damages only attackers as blocker was damage in either + * {@link #singleBlockerDamage} or {@link #multiBlockerDamage}. * * Handles abilities like "{this} an block any number of creatures.". * @@ -368,7 +362,7 @@ public class CombatGroup implements Serializable, Copyable { if (canDamage(blocker, first)) { Map assigned = new HashMap<>(); - for (UUID attackerId: attackerOrder) { + for (UUID attackerId : attackerOrder) { Permanent attacker = game.getPermanent(attackerId); int lethalDamage; if (blocker.getAbilities().containsKey(DeathtouchAbility.getInstance().getId())) { @@ -398,8 +392,7 @@ public class CombatGroup implements Serializable, Copyable { if (defender != null) { defender.markDamage(amount, attacker.getId(), game, true, true); } - } - else { + } else { Player defender = game.getPlayer(defenderId); defender.damage(amount, attacker.getId(), game, true, true); } @@ -407,10 +400,10 @@ public class CombatGroup implements Serializable, Copyable { public boolean canBlock(Permanent blocker, Game game) { // player can't block if another player is attacked - if (!defendingPlayerId.equals(blocker.getControllerId()) ) { + if (!defendingPlayerId.equals(blocker.getControllerId())) { return false; } - for (UUID attackerId: attackers) { + for (UUID attackerId : attackers) { if (!blocker.canBlock(attackerId, game)) { return false; } @@ -419,7 +412,7 @@ public class CombatGroup implements Serializable, Copyable { } public void addBlocker(UUID blockerId, UUID playerId, Game game) { - for (UUID attackerId: attackers) { + for (UUID attackerId : attackers) { if (game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DECLARE_BLOCKER, attackerId, blockerId, playerId))) { return; } @@ -445,10 +438,9 @@ public class CombatGroup implements Serializable, Copyable { if (blockerList.size() == 1) { blockerOrder.add(blockerList.get(0)); break; - } - else { + } else { List blockerPerms = new ArrayList<>(); - for (UUID blockerId: blockerList) { + for (UUID blockerId : blockerList) { blockerPerms.add(game.getPermanent(blockerId)); } UUID blockerId = player.chooseBlockerOrder(blockerPerms, this, blockerOrder, game); @@ -469,10 +461,9 @@ public class CombatGroup implements Serializable, Copyable { if (attackerList.size() == 1) { attackerOrder.add(attackerList.get(0)); break; - } - else { + } else { List attackerPerms = new ArrayList<>(); - for (UUID attackerId: attackerList) { + for (UUID attackerId : attackerList) { attackerPerms.add(game.getPermanent(attackerId)); } UUID attackerId = player.chooseAttackerOrder(attackerPerms, game); @@ -484,7 +475,7 @@ public class CombatGroup implements Serializable, Copyable { public int totalAttackerDamage(Game game) { int total = 0; - for (UUID attackerId: attackers) { + for (UUID attackerId : attackers) { total += getDamageValueFromPermanent(game.getPermanent(attackerId), game); } return total; @@ -517,13 +508,13 @@ public class CombatGroup implements Serializable, Copyable { return; } for (UUID blockerId : blockers) { - for (UUID attackerId: attackers) { + for (UUID attackerId : attackers) { game.fireEvent(GameEvent.getEvent(GameEvent.EventType.BLOCKER_DECLARED, attackerId, blockerId, players.get(blockerId))); } } - - if(!blockers.isEmpty()) { - for (UUID attackerId: attackers) { + + if (!blockers.isEmpty()) { + for (UUID attackerId : attackers) { game.fireEvent(GameEvent.getEvent(GameEvent.EventType.CREATURE_BLOCKED, attackerId, null)); } } @@ -536,12 +527,13 @@ public class CombatGroup implements Serializable, Copyable { } if (blockersCount == 1) { List toBeRemoved = new ArrayList<>(); - for (UUID blockerId: getBlockers()) { + for (UUID blockerId : getBlockers()) { Permanent blocker = game.getPermanent(blockerId); if (blocker != null && blocker.getAbilities().containsKey(CantBlockAloneAbility.getInstance().getId())) { blockWasLegal = false; - if (!game.isSimulation()) + if (!game.isSimulation()) { game.informPlayers(blocker.getLogName() + " can't block alone. Removing it from combat."); + } toBeRemoved.add(blockerId); } } @@ -567,8 +559,9 @@ public class CombatGroup implements Serializable, Copyable { blockers.clear(); blockerOrder.clear(); this.blocked = false; - if (!game.isSimulation()) + if (!game.isSimulation()) { game.informPlayers(attacker.getLogName() + " can't be blocked except by " + attacker.getMinBlockedBy() + " or more creatures. Blockers discarded."); + } blockWasLegal = false; } // Check if there are to many blockers (maxBlockedBy = 0 means no restrictions) @@ -582,20 +575,23 @@ public class CombatGroup implements Serializable, Copyable { blockers.clear(); blockerOrder.clear(); this.blocked = false; - if (!game.isSimulation()) + if (!game.isSimulation()) { game.informPlayers(new StringBuilder(attacker.getLogName()) - .append(" can't be blocked by more than ").append(attacker.getMaxBlockedBy()) - .append(attacker.getMaxBlockedBy()==1?" creature.":" creatures.") - .append(" Blockers discarded.").toString()); + .append(" can't be blocked by more than ").append(attacker.getMaxBlockedBy()) + .append(attacker.getMaxBlockedBy() == 1 ? " creature." : " creatures.") + .append(" Blockers discarded.").toString()); + } blockWasLegal = false; } } return blockWasLegal; } + /** - * There are effects that let creatures assigns combat damage equal to its toughness rather than its power. - * So this method takes this into account to get the value of damage a creature will assign + * There are effects that let creatures assigns combat damage equal to its + * toughness rather than its power. So this method takes this into account + * to get the value of damage a creature will assign * * @param permanent * @param game @@ -610,14 +606,15 @@ public class CombatGroup implements Serializable, Copyable { } /** - * There are effects, that set an attacker to be blcoked. - * Therefore this setter can be used. - * @param blocked + * There are effects, that set an attacker to be blcoked. Therefore this + * setter can be used. + * + * @param blocked */ public void setBlocked(boolean blocked) { this.blocked = blocked; } - + @Override public CombatGroup copy() { return new CombatGroup(this); diff --git a/Mage/src/mage/game/command/Commander.java b/Mage/src/mage/game/command/Commander.java index ff0a5565263..f3265532cfb 100644 --- a/Mage/src/mage/game/command/Commander.java +++ b/Mage/src/mage/game/command/Commander.java @@ -106,7 +106,7 @@ public class Commander implements CommandObject{ @Override public String getLogName() { - return GameLog.getColoredObjectName(this); + return GameLog.getColoredObjectIdName(this); } @Override diff --git a/Mage/src/mage/game/command/Emblem.java b/Mage/src/mage/game/command/Emblem.java index 79d74ca8885..3321f3ead71 100644 --- a/Mage/src/mage/game/command/Emblem.java +++ b/Mage/src/mage/game/command/Emblem.java @@ -106,7 +106,7 @@ public class Emblem implements CommandObject { @Override public String getLogName() { - return GameLog.getColoredObjectName(this); + return GameLog.getColoredObjectIdName(this); } @Override diff --git a/Mage/src/mage/game/permanent/PermanentImpl.java b/Mage/src/mage/game/permanent/PermanentImpl.java index 51eea8e9cc2..c44b666bff4 100644 --- a/Mage/src/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/mage/game/permanent/PermanentImpl.java @@ -1300,7 +1300,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { return GameLog.getNeutralColoredText("a creature without name"); } } - return GameLog.getColoredObjectName(this); + return GameLog.getColoredObjectIdName(this); } @Override diff --git a/Mage/src/mage/game/stack/Spell.java b/Mage/src/mage/game/stack/Spell.java index 2ae5dd56c79..6674065cafc 100644 --- a/Mage/src/mage/game/stack/Spell.java +++ b/Mage/src/mage/game/stack/Spell.java @@ -354,7 +354,7 @@ public class Spell extends StackObjImpl implements Card { @Override public String getLogName() { - return GameLog.getColoredObjectName(card); + return GameLog.getColoredObjectIdName(card); } @Override diff --git a/Mage/src/mage/game/stack/StackAbility.java b/Mage/src/mage/game/stack/StackAbility.java index 021ac659dbe..0ab2eeb7bae 100644 --- a/Mage/src/mage/game/stack/StackAbility.java +++ b/Mage/src/mage/game/stack/StackAbility.java @@ -132,7 +132,7 @@ public class StackAbility extends StackObjImpl implements Ability { @Override public String getLogName() { - return GameLog.getColoredObjectName(this); + return GameLog.getColoredObjectIdName(this); } @Override diff --git a/Mage/src/mage/game/stack/StackObjImpl.java b/Mage/src/mage/game/stack/StackObjImpl.java index c4889dc1c90..c2a725153ad 100644 --- a/Mage/src/mage/game/stack/StackObjImpl.java +++ b/Mage/src/mage/game/stack/StackObjImpl.java @@ -37,38 +37,38 @@ public abstract class StackObjImpl implements StackObject { public boolean chooseNewTargets(Game game, UUID playerId) { return chooseNewTargets(game, playerId, false, false, null); } - + /** * 114.6. Some effects allow a player to change the target(s) of a spell or * ability, and other effects allow a player to choose new targets for a - * spell or ability. - * - * 114.6a If an effect allows a player to "change the - * target(s)" of a spell or ability, each target can be changed only to - * another legal target. If a target can't be changed to another legal - * target, the original target is unchanged, even if the original target is - * itself illegal by then. If all the targets aren't changed to other legal - * targets, none of them are changed. - * - * 114.6b If an effect allows a player to "change a target" of a - * spell or ability, the process described in rule 114.6a - * is followed, except that only one of those targets may be changed - * (rather than all of them or none of them). - * - * 114.6c If an effect allows a - * player to "change any targets" of a spell or ability, the process - * described in rule 114.6a is followed, except that any number of those - * targets may be changed (rather than all of them or none of them). - * - * 114.6d If an effect allows a player to "choose new targets" for a spell or - * ability, the player may leave any number of the targets unchanged, even - * if those targets would be illegal. If the player chooses to change some - * or all of the targets, the new targets must be legal and must not cause - * any unchanged targets to become illegal. - * - * 114.6e When changing targets or - * choosing new targets for a spell or ability, only the final set of - * targets is evaluated to determine whether the change is legal. + * spell or ability. + * + * 114.6a If an effect allows a player to "change the target(s)" of a spell + * or ability, each target can be changed only to another legal target. If a + * target can't be changed to another legal target, the original target is + * unchanged, even if the original target is itself illegal by then. If all + * the targets aren't changed to other legal targets, none of them are + * changed. + * + * 114.6b If an effect allows a player to "change a target" of a spell or + * ability, the process described in rule 114.6a is followed, except that + * only one of those targets may be changed (rather than all of them or none + * of them). + * + * 114.6c If an effect allows a player to "change any targets" of a spell or + * ability, the process described in rule 114.6a is followed, except that + * any number of those targets may be changed (rather than all of them or + * none of them). + * + * 114.6d If an effect allows a player to "choose new targets" for a spell + * or ability, the player may leave any number of the targets unchanged, + * even if those targets would be illegal. If the player chooses to change + * some or all of the targets, the new targets must be legal and must not + * cause any unchanged targets to become illegal. + * + * 114.6e When changing targets or choosing new targets for a spell or + * ability, only the final set of targets is evaluated to determine whether + * the change is legal. * * Example: Arc Trail is a sorcery that reads "Arc Trail deals 2 damage to * target creature or player and 1 damage to another target creature or @@ -92,10 +92,14 @@ public abstract class StackObjImpl implements StackObject { * targets will be, the copy is put onto the stack with those targets. * * @param game - * @param targetControllerId - player that can/has to change the target of the spell - * @param forceChange - does only work for targets with maximum of one targetId - * @param onlyOneTarget - 114.6b one target must be changed to another target - * @param filterNewTarget restriction for the new target, if null nothing is cheched + * @param targetControllerId - player that can/has to change the target of + * the spell + * @param forceChange - does only work for targets with maximum of one + * targetId + * @param onlyOneTarget - 114.6b one target must be changed to another + * target + * @param filterNewTarget restriction for the new target, if null nothing is + * cheched * @return */ @Override @@ -105,8 +109,8 @@ public abstract class StackObjImpl implements StackObject { StringBuilder newTargetDescription = new StringBuilder(); // Fused split spells or spells where "Splice on Arcane" was used can have more than one ability Abilities objectAbilities = new AbilitiesImpl<>(); - if (this instanceof Spell) { - objectAbilities.addAll(((Spell)this).getSpellAbilities()); + if (this instanceof Spell) { + objectAbilities.addAll(((Spell) this).getSpellAbilities()); } else { objectAbilities.addAll(getAbilities()); } @@ -119,7 +123,7 @@ public abstract class StackObjImpl implements StackObject { // clear the old target and copy all targets from new target target.clearChosen(); for (UUID targetId : newTarget.getTargets()) { - target.addTarget(targetId, newTarget.getTargetAmount(targetId), ability, game, false); + target.addTarget(targetId, newTarget.getTargetAmount(targetId), ability, game, false); } } @@ -137,30 +141,30 @@ public abstract class StackObjImpl implements StackObject { /** * Handles the change of one target instance of a mode - * + * * @param targetController - player that can choose the new target * @param ability * @param mode * @param target * @param forceChange * @param game - * @return + * @return */ private Target chooseNewTarget(Player targetController, Ability ability, Mode mode, Target target, boolean forceChange, FilterPermanent filterNewTarget, Game game) { Target newTarget = target.copy(); if (!targetController.getId().equals(getControllerId())) { newTarget.setTargetController(targetController.getId()); // target controller for the change is different from spell controller newTarget.setAbilityController(getControllerId()); - } + } newTarget.clearChosen(); for (UUID targetId : target.getTargets()) { String targetNames = getNamesOftargets(targetId, game); // change the target? if (targetNames != null - && (forceChange || targetController.chooseUse(mode.getEffects().get(0).getOutcome(), "Change this target: " + targetNames + "?", game))) { + && (forceChange || targetController.chooseUse(mode.getEffects().get(0).getOutcome(), "Change this target: " + targetNames + "?", ability, game))) { Set possibleTargets = target.possibleTargets(this.getSourceId(), getControllerId(), game); // choose exactly one other target - already targeted objects are not counted - if (forceChange && possibleTargets != null && possibleTargets.size() > 1) { // controller of spell must be used (e.g. TargetOpponent) + if (forceChange && possibleTargets != null && possibleTargets.size() > 1) { // controller of spell must be used (e.g. TargetOpponent) int iteration = 0; do { if (iteration > 0 && !game.isSimulation()) { @@ -168,36 +172,36 @@ public abstract class StackObjImpl implements StackObject { } iteration++; newTarget.clearChosen(); - - newTarget.chooseTarget(mode.getEffects().get(0).getOutcome(), getControllerId(), ability, game); - // check target restriction + + newTarget.chooseTarget(mode.getEffects().get(0).getOutcome(), getControllerId(), ability, game); + // check target restriction if (newTarget.getFirstTarget() != null && filterNewTarget != null) { Permanent newTargetPermanent = game.getPermanent(newTarget.getFirstTarget()); if (newTargetPermanent == null || !filterNewTarget.match(newTargetPermanent, game)) { - game.informPlayer(targetController, "Target does not fullfil the target requirements (" + filterNewTarget.getMessage() +")"); + game.informPlayer(targetController, "Target does not fullfil the target requirements (" + filterNewTarget.getMessage() + ")"); newTarget.clearChosen(); } - } + } } while (targetController.isInGame() && (targetId.equals(newTarget.getFirstTarget()) || newTarget.getTargets().size() != 1)); - // choose a new target + // choose a new target } else { // build a target definition with exactly one possible target to select that replaces old target Target tempTarget = target.copy(); if (target instanceof TargetAmount) { - ((TargetAmount)tempTarget).setAmountDefinition(new StaticValue(target.getTargetAmount(targetId))); + ((TargetAmount) tempTarget).setAmountDefinition(new StaticValue(target.getTargetAmount(targetId))); } tempTarget.setMinNumberOfTargets(1); tempTarget.setMaxNumberOfTargets(1); if (!targetController.getId().equals(getControllerId())) { tempTarget.setTargetController(targetController.getId()); - tempTarget.setAbilityController(getControllerId()); + tempTarget.setAbilityController(getControllerId()); } boolean again; do { again = false; tempTarget.clearChosen(); if (!tempTarget.chooseTarget(mode.getEffects().get(0).getOutcome(), getControllerId(), ability, game)) { - if (targetController.chooseUse(Outcome.Benefit, "No target object selected. Reset to original target?", game)) { + if (targetController.chooseUse(Outcome.Benefit, "No target object selected. Reset to original target?", ability, game)) { // use previous target no target was selected newTarget.addTarget(targetId, target.getTargetAmount(targetId), ability, game, false); } else { @@ -206,43 +210,41 @@ public abstract class StackObjImpl implements StackObject { } else { // if possible add the alternate Target - it may not be included in the old definition nor in the already selected targets of the new definition if (newTarget.getTargets().contains(tempTarget.getFirstTarget()) || target.getTargets().contains(tempTarget.getFirstTarget())) { - if(targetController.isHuman()) { + if (targetController.isHuman()) { game.informPlayer(targetController, "This target was already selected from origin spell. You can only keep this target!"); again = true; } else { newTarget.addTarget(targetId, target.getTargetAmount(targetId), ability, game, false); } } else if (!target.canTarget(getControllerId(), tempTarget.getFirstTarget(), ability, game)) { - if(targetController.isHuman()) { + if (targetController.isHuman()) { game.informPlayer(targetController, "This target is not valid!"); again = true; } else { // keep the old newTarget.addTarget(targetId, target.getTargetAmount(targetId), ability, game, false); - } + } } else if (newTarget.getFirstTarget() != null && filterNewTarget != null) { Permanent newTargetPermanent = game.getPermanent(newTarget.getFirstTarget()); if (newTargetPermanent == null || !filterNewTarget.match(newTargetPermanent, game)) { - game.informPlayer(targetController, "This target does not fullfil the target requirements (" + filterNewTarget.getMessage() +")"); + game.informPlayer(targetController, "This target does not fullfil the target requirements (" + filterNewTarget.getMessage() + ")"); again = true; - } + } } else { // valid target was selected, add it to the new target definition newTarget.addTarget(tempTarget.getFirstTarget(), target.getTargetAmount(targetId), ability, game, false); } } } while (again && targetController.isInGame()); - } - } - // keep the target - else { + } + } // keep the target + else { newTarget.addTarget(targetId, target.getTargetAmount(targetId), ability, game, false); } - } + } return newTarget; } - - + private String getNamesOftargets(UUID targetId, Game game) { MageObject object = game.getObject(targetId); String name = null; @@ -256,5 +258,5 @@ public abstract class StackObjImpl implements StackObject { } return name; } - + } diff --git a/Mage/src/mage/players/Player.java b/Mage/src/mage/players/Player.java index c369e8f045e..d9b3a914f70 100644 --- a/Mage/src/mage/players/Player.java +++ b/Mage/src/mage/players/Player.java @@ -1,31 +1,30 @@ /* -* 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. -*/ - + * 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.players; import java.io.Serializable; @@ -35,7 +34,6 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; - import mage.MageItem; import mage.MageObject; import mage.abilities.Abilities; @@ -84,104 +82,170 @@ import mage.util.Copyable; public interface Player extends MageItem, Copyable { boolean isHuman(); + String getName(); + String getLogName(); + RangeOfInfluence getRange(); + Library getLibrary(); + Cards getSideboard(); + Graveyard getGraveyard(); + Abilities getAbilities(); + void addAbility(Ability ability); + Counters getCounters(); + int getLife(); + void initLife(int life); + void setLife(int life, Game game); + int loseLife(int amount, Game game); + int gainLife(int amount, Game game); + int damage(int damage, UUID sourceId, Game game, boolean combatDamage, boolean preventable); + int damage(int damage, UUID sourceId, Game game, boolean combatDamage, boolean preventable, ArrayList appliedEffects); - + // to handle rule changing effects (613.10) boolean isCanLoseLife(); - void setCanLoseLife(boolean canLoseLife); + + void setCanLoseLife(boolean canLoseLife); + void setCanGainLife(boolean canGainLife); + boolean isCanGainLife(); + void setCanPayLifeCost(boolean canPayLifeCost); + boolean canPayLifeCost(); - void setCanPaySacrificeCost(boolean canPaySacrificeCost); + + void setCanPaySacrificeCost(boolean canPaySacrificeCost); + boolean canPaySacrificeCost(); + void setLifeTotalCanChange(boolean lifeTotalCanChange); - boolean isLifeTotalCanChange(); + + boolean isLifeTotalCanChange(); + void setLoseByZeroOrLessLife(boolean loseByZeroOrLessLife); + boolean canLoseByZeroOrLessLife(); + void setPlayCardsFromGraveyard(boolean playCardsFromGraveyard); + boolean canPlayCardsFromGraveyard(); /** * Returns alternative casting costs a player can cast spells for - * - * @return + * + * @return */ List getAlternativeSourceCosts(); - - + Cards getHand(); + int getLandsPlayed(); + int getLandsPerTurn(); + void setLandsPerTurn(int landsPerTurn); + int getLoyaltyUsePerTurn(); + void setLoyaltyUsePerTurn(int loyaltyUsePerTurn); + int getMaxHandSize(); + void setMaxHandSize(int maxHandSize); + int getMaxAttackedBy(); + void setMaxAttackedBy(int maxAttackedBy); + boolean isPassed(); + boolean isEmptyDraw(); + void pass(Game game); + void resetPassed(); boolean getPassedTurn(); + boolean getPassedUntilEndOfTurn(); + boolean getPassedUntilNextMain(); + boolean getPassedUntilStackResolved(); + boolean getPassedAllTurns(); boolean hasLost(); + boolean hasWon(); + boolean hasQuit(); + void quit(Game game); + boolean hasTimerTimeout(); + void timerTimeout(Game game); + boolean hasIdleTimeout(); + void idleTimeout(Game game); + boolean hasLeft(); + /** * Player is still active in game (has not left, lost or won the game). + * * @return */ boolean isInGame(); + /** * Called if other player left the game + * * @param game */ void otherPlayerLeftGame(Game game); - + ManaPool getManaPool(); + Set getInRange(); + boolean isTopCardRevealed(); + void setTopCardRevealed(boolean topCardRevealed); + /** - * Get data from the client Preferences (e.g. avatarId or showAbilityPickerForce) - * @return + * Get data from the client Preferences (e.g. avatarId or + * showAbilityPickerForce) + * + * @return */ UserData getUserData(); + void setUserData(UserData userData); + boolean canLose(Game game); + boolean autoLoseGame(); /** - * Returns a set of players which turns under you control. - * Doesn't include yourself. + * Returns a set of players which turns under you control. Doesn't include + * yourself. * * @return */ @@ -189,6 +253,7 @@ public interface Player extends MageItem, Copyable { /** * Defines player whose turn this player controls at the moment. + * * @param game * @param playerId */ @@ -211,7 +276,8 @@ public interface Player extends MageItem, Copyable { /** * Returns false in case player don't control the game. * - * Note: For effects like "You control target player during that player's next turn". + * Note: For effects like "You control target player during that player's + * next turn". * * @return */ @@ -220,103 +286,165 @@ public interface Player extends MageItem, Copyable { /** * Returns false in case you don't control the game. * - * Note: For effects like "You control target player during that player's next turn". + * Note: For effects like "You control target player during that player's + * next turn". * * @param value */ void setGameUnderYourControl(boolean value); boolean isTestMode(); + void setTestMode(boolean value); + void addAction(String action); + int getActionCount(); + void setAllowBadMoves(boolean allowBadMoves); void init(Game game); + void init(Game game, boolean testMode); + void useDeck(Deck deck, Game game); - + /** - * Called before each applyEffects, to rest all what can be applyed by continuous effects + * Called before each applyEffects, to rest all what can be applyed by + * continuous effects */ void reset(); - + void shuffleLibrary(Game game); + int drawCards(int num, Game game); + int drawCards(int num, Game game, ArrayList appliedEffects); + boolean cast(SpellAbility ability, Game game, boolean noMana); + SpellAbility chooseSpellAbilityForCast(SpellAbility ability, Game game, boolean noMana); + boolean putInHand(Card card, Game game); + boolean removeFromHand(Card card, Game game); + boolean removeFromBattlefield(Permanent permanent, Game game); + boolean putInGraveyard(Card card, Game game, boolean fromBattlefield); + boolean removeFromGraveyard(Card card, Game game); + boolean removeFromLibrary(Card card, Game game); + boolean searchLibrary(TargetCardInLibrary target, Game game); + /** - * - * @param target - * @param game - * @param targetPlayerId player whose library will be searched - * @return true if search was successful - */ + * + * @param target + * @param game + * @param targetPlayerId player whose library will be searched + * @return true if search was successful + */ boolean searchLibrary(TargetCardInLibrary target, Game game, UUID targetPlayerId); + boolean canPlayLand(); + boolean playLand(Card card, Game game); + boolean activateAbility(ActivatedAbility ability, Game game); + boolean triggerAbility(TriggeredAbility ability, Game game); + boolean canBeTargetedBy(MageObject source, UUID sourceControllerId, Game game); + boolean hasProtectionFrom(MageObject source, Game game); + boolean flipCoin(Game game); + boolean flipCoin(Game game, ArrayList appliedEffects); + @Deprecated void discard(int amount, Ability source, Game game); + Card discardOne(boolean random, Ability source, Game game); + Cards discard(int amount, boolean random, Ability source, Game game); + void discardToMax(Game game); + boolean discard(Card card, Ability source, Game game); + void lost(Game game); + void lostForced(Game game); + void won(Game game); + void leave(); + void concede(Game game); + void abort(); + void abortReset(); + void skip(); // priority, undo, ... void sendPlayerAction(PlayerAction passPriorityAction, Game game); - + int getStoredBookmark(); + void setStoredBookmark(int bookmark); + void resetStoredBookmark(Game game); void revealCards(String name, Cards cards, Game game); + void revealCards(String name, Cards cards, Game game, boolean postToLog); + void lookAtCards(String name, Card card, Game game); + void lookAtCards(String name, Cards cards, Game game); @Override Player copy(); + void restore(Player player); void setResponseString(String responseString); + void setResponseUUID(UUID responseUUID); + void setResponseBoolean(Boolean responseBoolean); + void setResponseInteger(Integer data); + void setResponseManaType(UUID manaTypePlayerId, ManaType responseManaType); boolean priority(Game game); + boolean choose(Outcome outcome, Target target, UUID sourceId, Game game); + boolean choose(Outcome outcome, Target target, UUID sourceId, Game game, Map options); + boolean choose(Outcome outcome, Cards cards, TargetCard target, Game game); + boolean chooseTarget(Outcome outcome, Target target, Ability source, Game game); + boolean chooseTarget(Outcome outcome, Cards cards, TargetCard target, Ability source, Game game); + boolean chooseTargetAmount(Outcome outcome, TargetAmount target, Ability source, Game game); + boolean chooseMulligan(Game game); - boolean chooseUse(Outcome outcome, String message, Game game); + + boolean chooseUse(Outcome outcome, String message, Ability source, Game game); + boolean choose(Outcome outcome, Choice choice, Game game); + boolean choosePile(Outcome outcome, String message, List pile1, List pile2, Game game); + boolean playMana(ManaCost unpaid, String promptText, Game game); /** @@ -348,13 +476,20 @@ public interface Player extends MageItem, Copyable { int announceXCost(int min, int max, String message, Game game, Ability ability, VariableCost variableCost); int chooseReplacementEffect(Map abilityMap, Game game); + TriggeredAbility chooseTriggeredAbility(List abilities, Game game); + Mode chooseMode(Modes modes, Ability source, Game game); + void selectAttackers(Game game, UUID attackingPlayerId); + void selectBlockers(Game game, UUID defendingPlayerId); + UUID chooseAttackerOrder(List attacker, Game game); + /** * Choose the order in which blockers get damage assigned to + * * @param blockers list of blockers where to choose the next one from * @param combatGroup the concerning combat group * @param blockerOrder the already set order of blockers @@ -362,35 +497,52 @@ public interface Player extends MageItem, Copyable { * @return blocker next to add to the blocker order */ UUID chooseBlockerOrder(List blockers, CombatGroup combatGroup, List blockerOrder, Game game); + void assignDamage(int damage, List targets, String singleTargetName, UUID sourceId, Game game); + int getAmount(int min, int max, String message, Game game); + void sideboard(Match match, Deck deck); + void construct(Tournament tournament, Deck deck); + void pickCard(List cards, Deck deck, Draft draft); void declareAttacker(UUID attackerId, UUID defenderId, Game game, boolean allowUndo); + void declareBlocker(UUID defenderId, UUID blockerId, UUID attackerId, Game game); + List getAvailableAttackers(Game game); + List getAvailableAttackers(UUID defenderId, Game game); + List getAvailableBlockers(Game game); void beginTurn(Game game); + void endOfTurn(Game game); + void phasing(Game game); + void untap(Game game); ManaOptions getManaAvailable(Game game); + List getPlayable(Game game, boolean hidden); + List getPlayableOptions(Ability ability, Game game); - Set getPlayableInHand(Game game); + LinkedHashMap getUseableActivatedAbilities(MageObject object, Zone zone, Game game); - + void addCounters(Counter counter, Game game); + List getAttachments(); + boolean addAttachment(UUID permanentId, Game game); - boolean removeAttachment(Permanent permanent, Game game); + + boolean removeAttachment(Permanent permanent, Game game); /** * Signals that the player becomes active player in this turn. @@ -422,10 +574,13 @@ public interface Player extends MageItem, Copyable { int getPriorityTimeLeft(); void setReachedNextTurnAfterLeaving(boolean reachedNextTurnAfterLeaving); + boolean hasReachedNextTurnAfterLeaving(); + /** - * Checks if a AI player is able to join a table - * i.e. Draft - bot can not enter a table with constructed format + * Checks if a AI player is able to join a table i.e. Draft - bot can not + * enter a table with constructed format + * * @param table * @return */ @@ -433,34 +588,38 @@ public interface Player extends MageItem, Copyable { /** * Set the commanderId of the player + * * @param commanderId */ void setCommanderId(UUID commanderId); /** * Get the commanderId of the player - * @return + * + * @return */ UUID getCommanderId(); /** - * Moves cards from one zone to another - * + * Moves cards from one zone to another + * * @param cards * @param fromZone * @param toZone * @param source * @param game - * @return + * @return */ boolean moveCards(Cards cards, Zone fromZone, Zone toZone, Ability source, Game game); + boolean moveCards(List cards, Zone fromZone, Zone toZone, Ability source, Game game); + boolean moveCards(Card card, Zone fromZone, Zone toZone, Ability source, Game game); - + /** * Uses card.moveToZone and posts a inform message about moving the card * into the game log - * + * * @param card * @param sourceId * @param game @@ -468,7 +627,7 @@ public interface Player extends MageItem, Copyable { * @return */ boolean moveCardToHandWithInfo(Card card, UUID sourceId, Game game, Zone fromZone); - + /** * @param card * @param sourceId @@ -476,12 +635,13 @@ public interface Player extends MageItem, Copyable { * @param withName show the card name in the log * @param fromZone * @return - * */ + * + */ boolean moveCardToHandWithInfo(Card card, UUID sourceId, Game game, Zone fromZone, boolean withName); /** - * Uses card.moveToExile and posts a inform message about moving the card to exile - * into the game log + * Uses card.moveToExile and posts a inform message about moving the card to + * exile into the game log * * @param card * @param exileId exile zone id (optional) @@ -495,8 +655,8 @@ public interface Player extends MageItem, Copyable { boolean moveCardToExileWithInfo(Card card, UUID exileId, String exileName, UUID sourceId, Game game, Zone fromZone, boolean withName); /** - * Uses card.moveToZone and posts a inform message about moving the card to graveyard - * into the game log + * Uses card.moveToZone and posts a inform message about moving the card to + * graveyard into the game log * * @param card * @param sourceId @@ -506,10 +666,8 @@ public interface Player extends MageItem, Copyable { */ boolean moveCardToGraveyardWithInfo(Card card, UUID sourceId, Game game, Zone fromZone); - /** - * Internal used to move cards - * Use commonly player.moveCards() + * Internal used to move cards Use commonly player.moveCards() * * @param cards * @param source @@ -520,8 +678,8 @@ public interface Player extends MageItem, Copyable { boolean moveCardsToGraveyardWithInfo(List cards, Ability source, Game game, Zone fromZone); /** - * Uses card.moveToZone and posts a inform message about moving the card to graveyard - * into the game log + * Uses card.moveToZone and posts a inform message about moving the card to + * graveyard into the game log * * @param card * @param sourceId @@ -533,9 +691,9 @@ public interface Player extends MageItem, Copyable { */ boolean moveCardToLibraryWithInfo(Card card, UUID sourceId, Game game, Zone fromZone, boolean toTop, boolean withName); - /** - * Uses putOntoBattlefield and posts also a info message about in the game log + * Uses putOntoBattlefield and posts also a info message about in the game + * log * * @param card * @param game @@ -544,9 +702,10 @@ public interface Player extends MageItem, Copyable { * @return */ boolean putOntoBattlefieldWithInfo(Card card, Game game, Zone fromZone, UUID sourceId); - + /** - * Uses putOntoBattlefield and posts also a info message about in the game log + * Uses putOntoBattlefield and posts also a info message about in the game + * log * * @param card * @param game @@ -558,7 +717,8 @@ public interface Player extends MageItem, Copyable { boolean putOntoBattlefieldWithInfo(Card card, Game game, Zone fromZone, UUID sourceId, boolean tapped); /** - * Uses putOntoBattlefield and posts also a info message about in the game log + * Uses putOntoBattlefield and posts also a info message about in the game + * log * * @param card * @param game @@ -569,10 +729,10 @@ public interface Player extends MageItem, Copyable { * @return */ boolean putOntoBattlefieldWithInfo(Card card, Game game, Zone fromZone, UUID sourceId, boolean tapped, boolean facedown); - + /** * Checks if the playerToCheckId is from an opponent in range - * + * * @param playerToCheckId * @param game * @return true if playerToCheckId belongs to an opponent @@ -580,30 +740,38 @@ public interface Player extends MageItem, Copyable { boolean hasOpponent(UUID playerToCheckId, Game game); /** - * Free resources on match end + * Free resources on match end */ void cleanUpOnMatchEnd(); /** - * If the next cast spell has the set sourceId, the spell will - * be cast without mana. + * If the next cast spell has the set sourceId, the spell will be cast + * without mana. * * @param sourceId the source that can be cast without mana - * @param manaCosts alternate ManaCost, null if it can be cast without mana cost + * @param manaCosts alternate ManaCost, null if it can be cast without mana + * cost */ void setCastSourceIdWithAlternateMana(UUID sourceId, ManaCosts manaCosts); + UUID getCastSourceIdWithAlternateMana(); + ManaCosts getCastSourceIdManaCosts(); // permission handling to show hand cards void addPermissionToShowHandCards(UUID watcherUserId); + boolean hasUserPermissionToSeeHand(UUID userId); + void revokePermissionToSeeHandCards(); + boolean isRequestToShowHandCardsAllowed(); + Set getUsersAllowedToSeeHandCards(); boolean isInPayManaMode(); void setMatchPlayer(MatchPlayer matchPlayer); + MatchPlayer getMatchPlayer(); } diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index d87e64e5401..4fcd9df58f0 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -227,6 +227,8 @@ public abstract class PlayerImpl implements Player, Serializable { protected UserData userData; protected MatchPlayer matchPlayer; + protected String flagName; + /** * During some steps we can't play anything */ @@ -571,7 +573,9 @@ public abstract class PlayerImpl implements Player, Serializable { } /** - * returns true if the player has the control itself - false if the player is controlled by another player + * returns true if the player has the control itself - false if the player + * is controlled by another player + * * @return */ @Override @@ -701,7 +705,7 @@ public abstract class PlayerImpl implements Player, Serializable { if (random) { for (int i = 0; i < amount; i++) { Card card = this.getHand().getRandom(game); - if(card != null) { + if (card != null) { discardedCards.add(card); discard(card, source, game); } @@ -917,7 +921,6 @@ public abstract class PlayerImpl implements Player, Serializable { return castSourceIdManaCosts; } - @Override public boolean isInPayManaMode() { return payManaMode; @@ -939,7 +942,7 @@ public abstract class PlayerImpl implements Player, Serializable { // some effects set sourceId to cast without paying mana costs if (ability.getSourceId().equals(getCastSourceIdWithAlternateMana())) { ManaCosts alternateCosts = getCastSourceIdManaCosts(); - Ability spellAbility = spell.getSpellAbility(); + Ability spellAbility = spell.getSpellAbility(); if (alternateCosts == null) { noMana = true; } else { @@ -1096,7 +1099,6 @@ public abstract class PlayerImpl implements Player, Serializable { } if (ability instanceof PlayLandAbility) { - Card card = game.getCard(ability.getSourceId()); result = playLand(card, game); } else { @@ -1324,7 +1326,7 @@ public abstract class PlayerImpl implements Player, Serializable { int current = 0, last = cards.size(); for (Card card : cards.getCards(game)) { current++; - sb.append(card.getLogName()); + sb.append(GameLog.getColoredObjectName(card)); if (current < last) { sb.append(", "); } @@ -1338,7 +1340,7 @@ public abstract class PlayerImpl implements Player, Serializable { game.getState().getLookedAt(this.playerId).add(name, card); game.fireUpdatePlayersEvent(); } - + @Override public void lookAtCards(String name, Cards cards, Game game) { game.getState().getLookedAt(this.playerId).add(name, cards); @@ -1371,7 +1373,7 @@ public abstract class PlayerImpl implements Player, Serializable { for (Permanent permanent : game.getBattlefield().getAllActivePermanents(playerId)) { boolean untap = true; for (RestrictionEffect effect : game.getContinuousEffects().getApplicableRestrictionEffects(permanent, game).keySet()) { - untap &= effect.canBeUntapped(permanent, game); + untap &= effect.canBeUntapped(permanent, null, game); } if (untap) { canBeUntapped.add(permanent); @@ -1480,7 +1482,7 @@ public abstract class PlayerImpl implements Player, Serializable { for (Permanent permanent : game.getBattlefield().getAllActivePermanents(playerId)) { boolean untap = true; for (RestrictionEffect effect : game.getContinuousEffects().getApplicableRestrictionEffects(permanent, game).keySet()) { - untap &= effect.canBeUntapped(permanent, game); + untap &= effect.canBeUntapped(permanent, null, game); } if (untap) { permanent.untap(game); @@ -1679,7 +1681,7 @@ public abstract class PlayerImpl implements Player, Serializable { } else if (source instanceof Card) { sourceAbilities = ((Card) source).getAbilities(game); sourceControllerId = ((Card) source).getOwnerId(); - } else if (source instanceof CommandObject){ + } else if (source instanceof CommandObject) { sourceControllerId = ((CommandObject) source).getControllerId(); sourceAbilities = ((CommandObject) source).getAbilities(); } @@ -2033,7 +2035,7 @@ public abstract class PlayerImpl implements Player, Serializable { } Permanent attacker = game.getPermanent(attackerId); if (attacker != null && attacker.canAttack(defenderId, game) && attacker.getControllerId().equals(playerId)) { - if(!game.getCombat().declareAttacker(attackerId, defenderId, playerId, game)) { + if (!game.getCombat().declareAttacker(attackerId, defenderId, playerId, game)) { game.undo(playerId); } } @@ -2285,64 +2287,64 @@ public abstract class PlayerImpl implements Player, Serializable { } protected boolean canPlayCardByAlternateCost(Card sourceObject, ManaOptions available, Ability ability, Game game) { - if (sourceObject != null && !(sourceObject instanceof Permanent)) { - for (Ability alternateSourceCostsAbility : sourceObject.getAbilities()) { - // if cast for noMana no Alternative costs are allowed - if (alternateSourceCostsAbility instanceof AlternativeSourceCosts) { - if (((AlternativeSourceCosts) alternateSourceCostsAbility).isAvailable(ability, game)) { - if (alternateSourceCostsAbility.getCosts().canPay(ability, playerId, playerId, game)) { - ManaCostsImpl manaCosts = new ManaCostsImpl(); - for (Cost cost : alternateSourceCostsAbility.getCosts()) { - if (cost instanceof ManaCost) { - manaCosts.add((ManaCost) cost); - } - } + if (sourceObject != null && !(sourceObject instanceof Permanent)) { + for (Ability alternateSourceCostsAbility : sourceObject.getAbilities()) { + // if cast for noMana no Alternative costs are allowed + if (alternateSourceCostsAbility instanceof AlternativeSourceCosts) { + if (((AlternativeSourceCosts) alternateSourceCostsAbility).isAvailable(ability, game)) { + if (alternateSourceCostsAbility.getCosts().canPay(ability, playerId, playerId, game)) { + ManaCostsImpl manaCosts = new ManaCostsImpl(); + for (Cost cost : alternateSourceCostsAbility.getCosts()) { + if (cost instanceof ManaCost) { + manaCosts.add((ManaCost) cost); + } + } - if (manaCosts.size() == 0) { - return true; - } else { - for (Mana mana : manaCosts.getOptions()) { - for (Mana avail : available) { - if (mana.enough(avail)) { - return true; - } - } - } - } - } - } - } - } + if (manaCosts.size() == 0) { + return true; + } else { + for (Mana mana : manaCosts.getOptions()) { + for (Mana avail : available) { + if (mana.enough(avail)) { + return true; + } + } + } + } + } + } + } + } - // controller specific alternate spell costs - for (AlternativeSourceCosts alternateSourceCosts: getAlternativeSourceCosts()) { - if (alternateSourceCosts instanceof Ability) { - if (alternateSourceCosts.isAvailable(ability, game)) { - if (((Ability) alternateSourceCosts).getCosts().canPay(ability, playerId, playerId, game)) { - ManaCostsImpl manaCosts = new ManaCostsImpl(); - for (Cost cost : ((Ability) alternateSourceCosts).getCosts()) { - if (cost instanceof ManaCost) { - manaCosts.add((ManaCost) cost); - } - } + // controller specific alternate spell costs + for (AlternativeSourceCosts alternateSourceCosts : getAlternativeSourceCosts()) { + if (alternateSourceCosts instanceof Ability) { + if (alternateSourceCosts.isAvailable(ability, game)) { + if (((Ability) alternateSourceCosts).getCosts().canPay(ability, playerId, playerId, game)) { + ManaCostsImpl manaCosts = new ManaCostsImpl(); + for (Cost cost : ((Ability) alternateSourceCosts).getCosts()) { + if (cost instanceof ManaCost) { + manaCosts.add((ManaCost) cost); + } + } - if (manaCosts.size() == 0) { - return true; - } else { - for (Mana mana : manaCosts.getOptions()) { - for (Mana avail : available) { - if (mana.enough(avail)) { - return true; - } - } - } - } - } - } - } - } - } - return false; + if (manaCosts.size() == 0) { + return true; + } else { + for (Mana mana : manaCosts.getOptions()) { + for (Mana avail : available) { + if (mana.enough(avail)) { + return true; + } + } + } + } + } + } + } + } + } + return false; } protected boolean canLandPlayAlternateSourceCostsAbility(Card sourceObject, ManaOptions available, Ability ability, Game game) { @@ -2847,7 +2849,7 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCards(Cards cards, Zone fromZone, Zone toZone, Ability source, Game game) { ArrayList cardList = new ArrayList<>(); - for (UUID cardId: cards) { + for (UUID cardId : cards) { if (fromZone.equals(Zone.BATTLEFIELD)) { Permanent permanent = game.getPermanent(cardId); if (permanent != null) { @@ -2857,7 +2859,7 @@ public abstract class PlayerImpl implements Player, Serializable { Card card = game.getCard(cardId); if (card != null) { cardList.add(card); - } + } } } return moveCards(cardList, fromZone, toZone, source, game); @@ -2878,10 +2880,10 @@ public abstract class PlayerImpl implements Player, Serializable { return true; } game.fireEvent(new ZoneChangeGroupEvent(cards, source == null ? null : source.getSourceId(), this.getId(), fromZone, toZone)); - switch(toZone) { + switch (toZone) { case EXILED: boolean result = false; - for(Card card: cards) { + for (Card card : cards) { result |= moveCardToExileWithInfo(card, null, "", source == null ? null : source.getSourceId(), game, fromZone, true); } return result; @@ -2889,7 +2891,7 @@ public abstract class PlayerImpl implements Player, Serializable { return moveCardsToGraveyardWithInfo(cards, source, game, fromZone); case HAND: result = false; - for(Card card: cards) { + for (Card card : cards) { result |= moveCardToHandWithInfo(card, source == null ? null : source.getSourceId(), game, fromZone); } return result; @@ -2912,7 +2914,7 @@ public abstract class PlayerImpl implements Player, Serializable { } if (!game.isSimulation()) { StringBuilder sb = new StringBuilder(this.getLogName()).append(" puts ").append(withName ? card.getLogName() : "a face down card"); - switch(fromZone) { + switch (fromZone) { case EXILED: sb.append(" from exile zone "); break; @@ -2958,7 +2960,7 @@ public abstract class PlayerImpl implements Player, Serializable { boolean chooseOrder = false; if (userData.askMoveToGraveOrder()) { if (cards.size() > 3) { - chooseOrder = choosingPlayer.chooseUse(Outcome.Neutral, "Would you like to choose the order the cards go to graveyard?", game); + chooseOrder = choosingPlayer.chooseUse(Outcome.Neutral, "Would you like to choose the order the cards go to graveyard?", source, game); } } if (chooseOrder) { @@ -3051,8 +3053,8 @@ public abstract class PlayerImpl implements Player, Serializable { if (card instanceof PermanentCard) { card = game.getCard(card.getId()); } - game.informPlayers(this.getLogName() + " moves " + (withName ? card.getLogName() : "a card face down") + " " + - (fromZone != null ? "from " + fromZone.toString().toLowerCase(Locale.ENGLISH) + " " : "") + "to the exile zone"); + game.informPlayers(this.getLogName() + " moves " + (withName ? card.getLogName() : "a card face down") + " " + + (fromZone != null ? "from " + fromZone.toString().toLowerCase(Locale.ENGLISH) + " " : "") + "to the exile zone"); } result = true; } @@ -3075,7 +3077,7 @@ public abstract class PlayerImpl implements Player, Serializable { if (card.putOntoBattlefield(game, fromZone, sourceId, this.getId(), tapped, facedown)) { if (!game.isSimulation()) { game.informPlayers(new StringBuilder(this.getLogName()) - .append(" puts ").append(facedown ? "a card face down ":card.getLogName()) + .append(" puts ").append(facedown ? "a card face down " : card.getLogName()) .append(" from ").append(fromZone.toString().toLowerCase(Locale.ENGLISH)).append(" ") .append("onto the Battlefield").toString()); } @@ -3129,7 +3131,6 @@ public abstract class PlayerImpl implements Player, Serializable { usersAllowedToSeeHandCards.add(watcherUserId); } - @Override public boolean isRequestToShowHandCardsAllowed() { return userData.isAllowRequestShowHandCards(); diff --git a/Mage/src/mage/players/net/UserData.java b/Mage/src/mage/players/net/UserData.java index 101325ec660..ca11e192381 100644 --- a/Mage/src/mage/players/net/UserData.java +++ b/Mage/src/mage/players/net/UserData.java @@ -18,7 +18,7 @@ public class UserData implements Serializable { protected String flagName; protected boolean askMoveToGraveOrder; - public UserData(UserGroup userGroup, int avatarId, boolean showAbilityPickerForced, + public UserData(UserGroup userGroup, int avatarId, boolean showAbilityPickerForced, boolean allowRequestShowHandCards, boolean confirmEmptyManaPool, UserSkipPrioritySteps userSkipPrioritySteps, String flagName, boolean askMoveToGraveOrder) { this.groupId = userGroup.getGroupId(); @@ -31,6 +31,21 @@ public class UserData implements Serializable { this.askMoveToGraveOrder = askMoveToGraveOrder; } + public void update(UserData userData) { + this.groupId = userData.groupId; + this.avatarId = userData.avatarId; + this.showAbilityPickerForced = userData.showAbilityPickerForced; + this.allowRequestShowHandCards = userData.allowRequestShowHandCards; + this.userSkipPrioritySteps = userData.userSkipPrioritySteps; + this.confirmEmptyManaPool = userData.confirmEmptyManaPool; + this.flagName = userData.flagName; + this.askMoveToGraveOrder = userData.askMoveToGraveOrder; + } + + public static UserData getDefaultUserDataView() { + return new UserData(UserGroup.DEFAULT, 0, false, false, true, null, "world.png", false); + } + public void setGroupId(int groupId) { this.groupId = groupId; } @@ -90,5 +105,5 @@ public class UserData implements Serializable { public void setAskMoveToGraveOrder(boolean askMoveToGraveOrder) { this.askMoveToGraveOrder = askMoveToGraveOrder; } - + } diff --git a/Mage/src/mage/players/net/UserGroup.java b/Mage/src/mage/players/net/UserGroup.java index 97a39da1513..58a61d3dff4 100644 --- a/Mage/src/mage/players/net/UserGroup.java +++ b/Mage/src/mage/players/net/UserGroup.java @@ -7,6 +7,7 @@ public enum UserGroup { COMPUTER(0), PLAYER(1), + DEFAULT(2), MAGE(3), ADMIN(7), OWNER(15); diff --git a/Mage/src/mage/target/targetpointer/FixedTarget.java b/Mage/src/mage/target/targetpointer/FixedTarget.java index 3e82b76f26e..5a8f3c68d4d 100644 --- a/Mage/src/mage/target/targetpointer/FixedTarget.java +++ b/Mage/src/mage/target/targetpointer/FixedTarget.java @@ -1,31 +1,52 @@ package mage.target.targetpointer; -import mage.abilities.Ability; -import mage.cards.Card; -import mage.game.Game; - import java.util.ArrayList; import java.util.List; import java.util.UUID; +import mage.abilities.Ability; +import mage.cards.Card; +import mage.game.Game; public class FixedTarget implements TargetPointer { - private final UUID target; + + private final UUID targetId; private int zoneChangeCounter; + private boolean initialized; public FixedTarget(UUID target) { - this.target = target; + this.targetId = target; + this.initialized = false; + } + + /** + * Use this if you already want to fix the target object to the known zone + * now (otherwise the zone will be set if the ability triggers or not at + * all) If not initialized, the object of the current zone then will be + * used. + * + * @param targetId + * @param zoneChangeCounter + */ + public FixedTarget(UUID targetId, int zoneChangeCounter) { + this.targetId = targetId; + this.initialized = true; + this.zoneChangeCounter = zoneChangeCounter; } public FixedTarget(final FixedTarget fixedTarget) { - this.target = fixedTarget.target; + this.targetId = fixedTarget.targetId; this.zoneChangeCounter = fixedTarget.zoneChangeCounter; + this.initialized = fixedTarget.initialized; } @Override public void init(Game game, Ability source) { - Card card = game.getCard(target); - if (card != null) { - this.zoneChangeCounter = card.getZoneChangeCounter(game); + if (!initialized) { + initialized = true; + Card card = game.getCard(targetId); + if (card != null) { + this.zoneChangeCounter = card.getZoneChangeCounter(game); + } } } @@ -33,14 +54,14 @@ public class FixedTarget implements TargetPointer { public List getTargets(Game game, Ability source) { // check target not changed zone if (this.zoneChangeCounter > 0) { // will be zero if not defined in init - Card card = game.getCard(target); + Card card = game.getCard(targetId); if (card != null && card.getZoneChangeCounter(game) != this.zoneChangeCounter) { return new ArrayList<>(); // return empty } } ArrayList list = new ArrayList<>(1); - list.add(target); + list.add(targetId); return list; } @@ -48,26 +69,26 @@ public class FixedTarget implements TargetPointer { public UUID getFirst(Game game, Ability source) { // check target not changed zone if (this.zoneChangeCounter > 0) { // will be zero if not defined in init - Card card = game.getCard(target); + Card card = game.getCard(targetId); if (card != null && card.getZoneChangeCounter(game) != this.zoneChangeCounter) { return null; } } - return target; + return targetId; } @Override public TargetPointer copy() { return new FixedTarget(this); } - + public UUID getTarget() { - return target; + return targetId; } public int getZoneChangeCounter() { return zoneChangeCounter; } - + } diff --git a/Mage/src/mage/util/GameLog.java b/Mage/src/mage/util/GameLog.java index 082178a1168..544b0a2d359 100644 --- a/Mage/src/mage/util/GameLog.java +++ b/Mage/src/mage/util/GameLog.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,12 +20,11 @@ * 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.util; import mage.MageObject; @@ -36,64 +35,66 @@ import mage.ObjectColor; * @author LevelX2 */ public class GameLog { - - static final String LOG_COLOR_PLAYER = "#20B2AA"; // LightSeaGreen - static final String LOG_COLOR_PLAYER_REQUEST = "#D2691E"; // Chocolate - static final String LOG_COLOR_PLAYER_CONFIRM = "#D2691E"; // Chocolate + + static final String LOG_COLOR_PLAYER = "#20B2AA"; // LightSeaGreen + static final String LOG_COLOR_PLAYER_REQUEST = "#D2691E"; // Chocolate + static final String LOG_COLOR_PLAYER_CONFIRM = "#D2691E"; // Chocolate static final String LOG_COLOR_GREEN = "#90EE90"; // LightGreen - static final String LOG_COLOR_RED = "#FF6347"; // Tomato + static final String LOG_COLOR_RED = "#FF6347"; // Tomato static final String LOG_COLOR_BLUE = "#87CEFA"; // LightSkyBlue static final String LOG_COLOR_BLACK = "#696969"; // DimGray // "#5F9EA0"; // CadetBlue - static final String LOG_COLOR_WHITE = "#F0E68C"; // Khaki - static final String LOG_COLOR_MULTI = "#DAA520"; // GoldenRod - static final String LOG_COLOR_COLORLESS = "#B0C4DE"; // LightSteelBlue - static final String LOG_COLOR_NEUTRAL = "#F0F8FF"; // AliceBlue - - - + static final String LOG_COLOR_WHITE = "#F0E68C"; // Khaki + static final String LOG_COLOR_MULTI = "#DAA520"; // GoldenRod + static final String LOG_COLOR_COLORLESS = "#B0C4DE"; // LightSteelBlue + static final String LOG_COLOR_NEUTRAL = "#F0F8FF"; // AliceBlue + public static String replaceNameByColoredName(MageObject mageObject, String text) { - return text.replaceAll(mageObject.getName(), getColoredObjectName(mageObject)); + return text.replaceAll(mageObject.getName(), getColoredObjectIdName(mageObject)); } - public static String getColoredObjectName(MageObject mageObject) { - return "" + mageObject.getName() + " ["+mageObject.getId().toString().substring(0,3) + "]"; + public static String getColoredObjectName(MageObject mageObject) { + return "" + mageObject.getName() + ""; } - public static String getNeutralColoredText(String text) { + public static String getColoredObjectIdName(MageObject mageObject) { + return "" + mageObject.getName() + " [" + mageObject.getId().toString().substring(0, 3) + "]"; + } + + public static String getNeutralColoredText(String text) { return "" + text + ""; } - public static String getColoredPlayerName(String name) { + public static String getColoredPlayerName(String name) { return "" + name + ""; } - - public static String getPlayerRequestColoredText(String name) { + + public static String getPlayerRequestColoredText(String name) { return "" + name + ""; } - public static String getPlayerConfirmColoredText(String name) { + public static String getPlayerConfirmColoredText(String name) { return "" + name + ""; } - public static String getSmallSecondLineText(String text) { + public static String getSmallSecondLineText(String text) { return "
" + text + "
"; } private static String getColorName(ObjectColor objectColor) { if (objectColor.isMulticolored()) { return LOG_COLOR_MULTI; - } else if (objectColor.isColorless()){ + } else if (objectColor.isColorless()) { return LOG_COLOR_COLORLESS; - } else if (objectColor.isRed()){ + } else if (objectColor.isRed()) { return LOG_COLOR_RED; - } else if (objectColor.isGreen()){ + } else if (objectColor.isGreen()) { return LOG_COLOR_GREEN; - } else if (objectColor.isBlue()){ + } else if (objectColor.isBlue()) { return LOG_COLOR_BLUE; - } else if (objectColor.isWhite()){ + } else if (objectColor.isWhite()) { return LOG_COLOR_WHITE; } else { - return LOG_COLOR_BLACK; + return LOG_COLOR_BLACK; } } } diff --git a/Mage/src/mage/util/ManaUtil.java b/Mage/src/mage/util/ManaUtil.java index 7dd8627c7ba..6b8e0062926 100644 --- a/Mage/src/mage/util/ManaUtil.java +++ b/Mage/src/mage/util/ManaUtil.java @@ -1,18 +1,23 @@ package mage.util; -import mage.Mana; -import mage.ManaSymbol; -import mage.abilities.costs.mana.ManaCost; -import mage.abilities.costs.mana.ManaSymbols; -import mage.abilities.mana.*; - import java.util.HashSet; import java.util.LinkedHashMap; import java.util.Set; import java.util.UUID; import mage.MageObject; +import mage.Mana; +import mage.ManaSymbol; import mage.abilities.Ability; import mage.abilities.costs.mana.AlternateManaPaymentAbility; +import mage.abilities.costs.mana.ManaCost; +import mage.abilities.costs.mana.ManaSymbols; +import mage.abilities.mana.BasicManaAbility; +import mage.abilities.mana.BlackManaAbility; +import mage.abilities.mana.BlueManaAbility; +import mage.abilities.mana.GreenManaAbility; +import mage.abilities.mana.ManaAbility; +import mage.abilities.mana.RedManaAbility; +import mage.abilities.mana.WhiteManaAbility; import mage.cards.Card; import mage.game.Game; @@ -21,29 +26,32 @@ import mage.game.Game; */ public class ManaUtil { - private ManaUtil() {} + private ManaUtil() { + } /** - * In case the choice of mana to be produced is obvious, let's discard all other abilities. + * In case the choice of mana to be produced is obvious, let's discard all + * other abilities. * - * Example: - * Pay {W}{R} + * Example: Pay {W}{R} * - * Land produces {W} or {G}. + * Land produces {W} or {G}. * - * No need to ask what player wants to choose. - * {W} mana ability should be left only. + * No need to ask what player wants to choose. {W} mana ability should be + * left only. * * But we CAN do auto choice only in case we have basic mana abilities. - * Example: - * we should pay {1} and we have Cavern of Souls that can produce {1} or any mana of creature type choice. - * We can't simply auto choose {1} as the second mana ability also makes spell uncounterable. + * Example: we should pay {1} and we have Cavern of Souls that can produce + * {1} or any mana of creature type choice. We can't simply auto choose {1} + * as the second mana ability also makes spell uncounterable. * - * In case we can't auto choose we'll simply return the useableAbilities map back to caller without any modification. + * In case we can't auto choose we'll simply return the useableAbilities map + * back to caller without any modification. * * @param unpaid Mana we need to pay. Can be null (it is for X costs now). * @param useableAbilities List of mana abilities permanent may produce - * @return List of mana abilities permanent may produce and are reasonable for unpaid mana + * @return List of mana abilities permanent may produce and are reasonable + * for unpaid mana */ public static LinkedHashMap tryToAutoPay(ManaCost unpaid, LinkedHashMap useableAbilities) { @@ -55,8 +63,7 @@ public class ManaUtil { } } - - if (unpaid != null) { + if (unpaid != null) { ManaSymbols symbols = ManaSymbols.buildFromManaCost(unpaid); Mana unpaidMana = unpaid.getMana(); @@ -339,10 +346,10 @@ public class ManaUtil { return useableAbilities; } - + /** - * This activates the special button inthe feedback panel of the client - * if there exists special ways to pay the mana (e.g. Delve, Convoke) + * This activates the special button inthe feedback panel of the client if + * there exists special ways to pay the mana (e.g. Delve, Convoke) * * @param source ability the mana costs have to be paid for * @param game @@ -350,17 +357,26 @@ public class ManaUtil { * @return message to be shown in human players feedback area */ public static String addSpecialManaPayAbilities(Ability source, Game game, ManaCost unpaid) { + MageObject baseObject = game.getPermanent(source.getSourceId()); + if (baseObject == null) { + baseObject = game.getCard(source.getSourceId()); + } // check for special mana payment possibilities - MageObject mageObject = source.getSourceObject(game); - if (mageObject instanceof Card) { - for (Ability ability :((Card)mageObject).getAbilities(game)) { + MageObject mageObject = source.getSourceObject(game); + if (mageObject instanceof Card) { + for (Ability ability : ((Card) mageObject).getAbilities(game)) { if (ability instanceof AlternateManaPaymentAbility) { ((AlternateManaPaymentAbility) ability).addSpecialAction(source, game, unpaid); } } - return unpaid.getText() + "
" + mageObject.getLogName() + "
"; + if (baseObject == null) { + baseObject = mageObject; + } + } + if (baseObject != null) { + return unpaid.getText() + "
" + baseObject.getLogName() + "
"; } else { return unpaid.getText(); } - } + } } diff --git a/Mage/src/mage/watchers/common/CommanderInfoWatcher.java b/Mage/src/mage/watchers/common/CommanderInfoWatcher.java index a59f3eb8007..963fcaf374e 100644 --- a/Mage/src/mage/watchers/common/CommanderInfoWatcher.java +++ b/Mage/src/mage/watchers/common/CommanderInfoWatcher.java @@ -1,16 +1,16 @@ /* * Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,7 +20,7 @@ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. @@ -43,15 +43,14 @@ import mage.watchers.Watcher; /* 20130711 *903.14a A player that’s been dealt 21 or more combat damage by the same commander - * over the course of the game loses the game. (This is a state-based action. See rule 704.) + * over the course of the game loses the game. (This is a state-based action. See rule 704.) * * * @author Plopman */ - public class CommanderInfoWatcher extends Watcher { - public Map damageToPlayer = new HashMap<>(); + public final Map damageToPlayer = new HashMap<>(); public boolean checkCommanderDamage; public CommanderInfoWatcher(UUID commander, boolean checkCommanderDamage) { @@ -59,7 +58,6 @@ public class CommanderInfoWatcher extends Watcher { this.sourceId = commander; this.checkCommanderDamage = checkCommanderDamage; } - public CommanderInfoWatcher(final CommanderInfoWatcher watcher) { super(watcher); @@ -76,20 +74,21 @@ public class CommanderInfoWatcher extends Watcher { public void watch(GameEvent event, Game game) { if (checkCommanderDamage && event.getType() == EventType.DAMAGED_PLAYER && event instanceof DamagedPlayerEvent) { if (sourceId.equals(event.getSourceId())) { - DamagedPlayerEvent damageEvent = (DamagedPlayerEvent)event; + DamagedPlayerEvent damageEvent = (DamagedPlayerEvent) event; if (damageEvent.isCombatDamage()) { UUID playerUUID = event.getTargetId(); Integer damage = damageToPlayer.get(playerUUID); - if(damage == null){ + if (damage == null) { damage = 0; } damage += damageEvent.getAmount(); damageToPlayer.put(playerUUID, damage); Player player = game.getPlayer(playerUUID); MageObject commander = game.getObject(sourceId); - if (player != null && commander != null){ - if (!game.isSimulation()) + if (player != null && commander != null) { + if (!game.isSimulation()) { game.informPlayers(commander.getLogName() + " did " + damage + " combat damage to " + player.getLogName() + " during the game."); + } this.addCardInfoToCommander(game); } } @@ -109,18 +108,18 @@ public class CommanderInfoWatcher extends Watcher { if (object != null) { StringBuilder sb = new StringBuilder(); sb.append("Commander"); - Integer castCount = (Integer)game.getState().getValue(sourceId + "_castCount"); + Integer castCount = (Integer) game.getState().getValue(sourceId + "_castCount"); if (castCount != null) { - sb.append(" ").append(castCount).append(castCount == 1 ? " time":" times").append(" casted from the command zone."); + sb.append(" ").append(castCount).append(castCount == 1 ? " time" : " times").append(" casted from the command zone."); } - this.addInfo(object, "Commander",sb.toString(), game); - + this.addInfo(object, "Commander", sb.toString(), game); + if (checkCommanderDamage) { for (Map.Entry entry : damageToPlayer.entrySet()) { Player damagedPlayer = game.getPlayer(entry.getKey()); sb.setLength(0); sb.append("Commander did ").append(entry.getValue()).append(" combat damage to player ").append(damagedPlayer.getLogName()).append("."); - this.addInfo(object, new StringBuilder("Commander").append(entry.getKey()).toString(),sb.toString(), game); + this.addInfo(object, new StringBuilder("Commander").append(entry.getKey()).toString(), sb.toString(), game); } } } @@ -135,6 +134,6 @@ public class CommanderInfoWatcher extends Watcher { public Map getDamageToPlayer() { return damageToPlayer; - } + } } diff --git a/Mage/src/mage/watchers/common/MiracleWatcher.java b/Mage/src/mage/watchers/common/MiracleWatcher.java index 847be131931..d9816918777 100644 --- a/Mage/src/mage/watchers/common/MiracleWatcher.java +++ b/Mage/src/mage/watchers/common/MiracleWatcher.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,12 +20,11 @@ * 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.watchers.common; import java.util.HashMap; @@ -45,8 +44,8 @@ import mage.players.Player; import mage.watchers.Watcher; /** - * Counts amount of cards drawn this turn by players. - * Asks players about Miracle ability to be activated if it the first card drawn this turn. + * Counts amount of cards drawn this turn by players. Asks players about Miracle + * ability to be activated if it the first card drawn this turn. * * @author noxx */ @@ -99,9 +98,9 @@ public class MiracleWatcher extends Watcher { Cards cards = new CardsImpl(); cards.add(card); controller.lookAtCards("Miracle", cards, game); - if (controller.chooseUse(Outcome.Benefit, "Reveal " + card.getLogName() + " to be able to use Miracle?", game)) { + if (controller.chooseUse(Outcome.Benefit, "Reveal " + card.getLogName() + " to be able to use Miracle?", ability, game)) { controller.revealCards("Miracle", cards, game); - game.fireEvent(GameEvent.getEvent(GameEvent.EventType.MIRACLE_CARD_REVEALED, card.getId(), card.getId(),controller.getId())); + game.fireEvent(GameEvent.getEvent(GameEvent.EventType.MIRACLE_CARD_REVEALED, card.getId(), card.getId(), controller.getId())); break; } } @@ -110,7 +109,6 @@ public class MiracleWatcher extends Watcher { } } - @Override public void reset() { amountOfCardsDrawnThisTurn.clear(); diff --git a/Mage/src/mage/watchers/common/SoulbondWatcher.java b/Mage/src/mage/watchers/common/SoulbondWatcher.java index c86e9b8fe28..4806133c740 100644 --- a/Mage/src/mage/watchers/common/SoulbondWatcher.java +++ b/Mage/src/mage/watchers/common/SoulbondWatcher.java @@ -1,16 +1,16 @@ /* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: - * + * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR @@ -20,12 +20,11 @@ * 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.watchers.common; import mage.abilities.keyword.SoulbondAbility; @@ -34,7 +33,6 @@ import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.WatcherScope; -import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.Predicate; import mage.filter.predicate.Predicates; @@ -79,7 +77,7 @@ public class SoulbondWatcher extends Watcher { Cards cards = new CardsImpl(); cards.add(permanent); controller.lookAtCards("Soulbond", cards, game); - if (controller.chooseUse(Outcome.Benefit, "Use Soulbond?", game)) { + if (controller.chooseUse(Outcome.Benefit, "Use Soulbond?", null, game)) { TargetControlledPermanent target = new TargetControlledPermanent(filter); target.setNotTarget(true); if (target.canChoose(permanent.getId(), controller.getId(), game)) { @@ -88,8 +86,9 @@ public class SoulbondWatcher extends Watcher { if (chosen != null) { chosen.setPairedCard(permanent.getId()); permanent.setPairedCard(chosen.getId()); - if (!game.isSimulation()) + if (!game.isSimulation()) { game.informPlayers(new StringBuilder(controller.getLogName()).append(" souldbonds ").append(permanent.getLogName()).append(" with ").append(chosen.getName()).toString()); + } } } } @@ -110,11 +109,12 @@ public class SoulbondWatcher extends Watcher { Cards cards = new CardsImpl(); cards.add(chosen); controller.lookAtCards("Soulbond", cards, game); - if (controller.chooseUse(Outcome.Benefit, "Use Soulbond for recent " + permanent.getLogName() + "?", game)) { + if (controller.chooseUse(Outcome.Benefit, "Use Soulbond for recent " + permanent.getLogName() + "?", null, game)) { chosen.setPairedCard(permanent.getId()); permanent.setPairedCard(chosen.getId()); - if (!game.isSimulation()) + if (!game.isSimulation()) { game.informPlayers(new StringBuilder(controller.getLogName()).append(" souldbonds ").append(permanent.getLogName()).append(" with ").append(chosen.getName()).toString()); + } break; } }