Please test! Some changes to the display of user choices, showing also a longer text in tooltip window.

This commit is contained in:
LevelX2 2015-06-28 21:55:48 +02:00
parent cac04616f3
commit df3e6db569
352 changed files with 2277 additions and 2034 deletions

View file

@ -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;
}
}

View file

@ -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("<html><body style='font-family:Dialog;font-size:");
buffer.append(fontSize);
buffer.append(16);
buffer.append("pt;margin:3px 3px 3px 3px;color: #FFFFFF'><b><center>");
text = text.replaceAll("#([^#]+)#", "<i>$1</i>");
// Don't know what it does (easy italc?) but it bugs with multiple #HTML color codes (LevelX2)
//text = text.replaceAll("#([^#]+)#", "<i>$1</i>");
//text = text.replaceAll("\\s*//\\s*", "<hr width='50%'>");
text = text.replace("\r\n", "<div style='font-size:5pt'></div>");
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("</b></center></body></html>");
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'><p width='400'>")
// .replace("</body>", "</p></body>");
String tooltip = "<html><center><body style='font-family:Dialog;font-size:14;color: #FFFFFF'><p width='500'>" + basicText + "</p></body></html>";
MageTextArea.super.setToolTipText(tooltip);
} else {
MageTextArea.super.setToolTipText(null);
}
setCaretPosition(0);
}
});

View file

@ -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

View file

@ -1150,21 +1150,21 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jScrollPane1" alignment="0" pref="590" max="32767" attributes="0"/>
<Component id="avatarPane" alignment="0" pref="590" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jScrollPane1" alignment="0" pref="359" max="32767" attributes="0"/>
<Component id="avatarPane" alignment="0" pref="359" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
<Container class="javax.swing.JScrollPane" name="avatarPane">
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="jPanel9">
<Container class="javax.swing.JPanel" name="avatarPanel">
<Layout>
<DimensionLayout dim="0">
@ -1256,6 +1256,14 @@
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="jLabel12">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="11" style="1"/>
</Property>
<Property name="text" type="java.lang.String" value="Choose your avatar:"/>
</Properties>
</Component>
<Container class="javax.swing.JPanel" name="jPanel10">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
@ -1328,14 +1336,6 @@
</DimensionLayout>
</Layout>
</Container>
<Component class="javax.swing.JLabel" name="jLabel12">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="11" style="1"/>
</Property>
<Property name="text" type="java.lang.String" value="Choose your avatar:"/>
</Properties>
</Component>
<Container class="javax.swing.JPanel" name="jPanel12">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">

View file

@ -420,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();
@ -1190,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);
@ -1229,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);
@ -1352,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))
@ -1422,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);
@ -2423,7 +2423,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
public static UserData getUserData() {
return new UserData(UserGroup.PLAYER,
getSelectedAvatar(),
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"),
@ -2434,6 +2434,8 @@ public class PreferencesDialog extends javax.swing.JDialog {
}
// 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;
@ -2506,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;

View file

@ -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<String, Serializable> 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() {

View file

@ -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));
@ -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);
}
});
}
@ -220,17 +248,18 @@ public class HelperPanel extends JPanel {
}
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 "<div style='font-size:11pt'>" + text + "</div>";
}

View file

@ -328,8 +328,8 @@ public class PlayerPanelExt extends javax.swing.JPanel {
avatar.add(new JLabel());
avatar.add(new JLabel());
avatar.add(avatarFlag);
avatar.setAlignmentY(CENTER_ALIGNMENT);
avatarFlag.setHorizontalAlignment(JLabel.CENTER);
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");

View file

@ -1286,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

View file

@ -27,13 +27,24 @@
*/
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,9 +55,6 @@ import mage.target.TargetAmount;
import mage.target.TargetCard;
import org.apache.log4j.Logger;
import java.io.Serializable;
import java.util.*;
/**
*
* plays randomly
@ -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<Ability> 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<Ability> 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<Ability> 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<Permanent> 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<UUID> possibleTargets = target.possibleTargets(source==null?null:source.getSourceId(), playerId, game);
if (possibleTargets.isEmpty())
Set<UUID> 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<UUID> possibleTargets = target.possibleTargets(source==null?null:source.getSourceId(), playerId, game);
Set<UUID> 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);
}
}

View file

@ -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 += "<div style='font-size:11pt'>" + mageObject.getLogName() + "</div>";
}
}
return message;
}
@Override
public int chooseReplacementEffect(Map<String, String> 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,7 +262,7 @@ 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
@ -254,18 +286,18 @@ public class HumanPlayer extends PlayerImpl {
}
List<UUID> 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<UUID> possibleTargets = target.possibleTargets(source==null?null:source.getSourceId(), abilityControllerId, game);
Set<UUID> 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,7 +364,7 @@ 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;
}
}
@ -348,7 +381,7 @@ public class HumanPlayer extends PlayerImpl {
return false;
}
private Map<String, Serializable> getOptions(Target target, Map<String, Serializable> options ) {
private Map<String, Serializable> getOptions(Target target, Map<String, Serializable> 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<String, Serializable> options = getOptions(target, null);
List<UUID> chosen = target.getTargets();
options.put("chosen", (Serializable)chosen);
options.put("chosen", (Serializable) chosen);
List<UUID> choosable = new ArrayList<>();
for (UUID cardId : cards) {
if (target.canTarget(cardId, cards, game)) {
@ -432,7 +465,7 @@ public class HumanPlayer extends PlayerImpl {
}
Map<String, Serializable> options = getOptions(target, null);
List<UUID> chosen = target.getTargets();
options.put("chosen", (Serializable)chosen);
options.put("chosen", (Serializable) chosen);
List<UUID> choosable = new ArrayList<>();
for (UUID cardId : cards) {
if (target.canTarget(cardId, cards, game)) {
@ -442,7 +475,7 @@ 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
@ -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) {
@ -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<ManaCost> costs = (ManaCostsImpl<ManaCost>) 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;
}
@ -686,6 +717,7 @@ public class HumanPlayer extends PlayerImpl {
/**
* 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;
}
@ -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<String, Serializable> 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<UUID> possibleDefender = game.getCombat().getCreaturesForcedToAttack().get(creatureId);
@ -780,7 +812,7 @@ public class HumanPlayer extends PlayerImpl {
}
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) {
@ -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<Permanent> blockers, CombatGroup combatGroup, List<UUID> 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();
}
@ -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);
@ -1081,7 +1109,7 @@ public class HumanPlayer extends PlayerImpl {
@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<UUID, String> 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());
@ -1234,8 +1262,8 @@ public class HumanPlayer extends PlayerImpl {
}
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";
@ -1247,7 +1275,7 @@ public class HumanPlayer extends PlayerImpl {
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;
}

View file

@ -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);

View file

@ -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;

View file

@ -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)) {

View file

@ -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()) {

View file

@ -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;
}

View file

@ -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());

View file

@ -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.");

View file

@ -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;

View file

@ -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 {

View file

@ -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());

View file

@ -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);

View file

@ -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) {

View file

@ -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);

View file

@ -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);
}
}

View file

@ -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) {

View file

@ -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;

View file

@ -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)) {

View file

@ -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);

View file

@ -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()) {

View file

@ -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) {

View file

@ -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) {

View file

@ -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;

View file

@ -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;
}

View file

@ -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.");
}

View file

@ -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);
}

View file

@ -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());

View file

@ -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());

View file

@ -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);

View file

@ -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());

View file

@ -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);

View file

@ -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)) {

View file

@ -114,7 +114,7 @@ class VeteranExplorerEffect extends OneShotEffect {
}
private void chooseAndSearchLibrary(List<Player> 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)) {

View file

@ -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);

View file

@ -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());
}
}

View file

@ -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);
}

View file

@ -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);
}
}

View file

@ -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());

View file

@ -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 {

View file

@ -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);

View file

@ -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);
}
}

View file

@ -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)) {

View file

@ -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");

View file

@ -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) {

View file

@ -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 {

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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()));

View file

@ -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);

View file

@ -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;
}

View file

@ -124,7 +124,7 @@ class WaveOfVitriolEffect extends OneShotEffect {
}
game.getState().handleSimultaneousEvent(game);
for(Map.Entry<Player, Integer> 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()) {

View file

@ -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) {

View file

@ -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) {

View file

@ -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);

View file

@ -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");
}

View file

@ -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");
}

View file

@ -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)) {

View file

@ -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<Predicate<MageObject>> types = new ArrayList<Predicate<MageObject>>();
for (CardType type: stackObject.getCardType()) {

View file

@ -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);

View file

@ -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;
}

View file

@ -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);
}
}

View file

@ -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();

View file

@ -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:

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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;

View file

@ -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;

View file

@ -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)) {

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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);

View file

@ -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());

View file

@ -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;
}

View file

@ -116,7 +116,7 @@ class RiseOfTheHobgoblinsEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Player you = game.getPlayer(source.getControllerId());
ManaCosts<ManaCost> 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)) {

View file

@ -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()) {

View file

@ -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;

View file

@ -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) {

View file

@ -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";
}

View file

@ -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;

View file

@ -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) {

View file

@ -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);
}
}

View file

@ -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<UUID> cardsDrawnThisTurn = new HashSet<UUID>();
public CardsDrawnThisTurnWatcher() {
super("CardsDrawnThisTurnWatcher", WatcherScope.PLAYER);
}

View file

@ -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);
}

View file

@ -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.");

View file

@ -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()));

View file

@ -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);
}

View file

@ -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;

Some files were not shown because too many files have changed in this diff Show more