Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Count Andromalius 2018-03-17 10:56:50 -03:00
commit 17db6f5345
67 changed files with 1059 additions and 548 deletions

View file

@ -613,7 +613,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient {
} }
} }
private static MagePane getTopMost(MagePane exclude) { public static MagePane getTopMost(MagePane exclude) {
MagePane topmost = null; MagePane topmost = null;
int best = Integer.MAX_VALUE; int best = Integer.MAX_VALUE;
for (Component frame : desktopPane.getComponentsInLayer(JLayeredPane.DEFAULT_LAYER)) { for (Component frame : desktopPane.getComponentsInLayer(JLayeredPane.DEFAULT_LAYER)) {

View file

@ -3,6 +3,7 @@ package mage.client.components;
import java.awt.Color; import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Font; import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Image; import java.awt.Image;
@ -40,6 +41,7 @@ public class HoverButton extends JPanel implements MouseListener {
private String topText; private String topText;
private Image topTextImage; private Image topTextImage;
private Image topTextImageRight; private Image topTextImageRight;
private String centerText;
private boolean isHovered = false; private boolean isHovered = false;
private boolean isSelected = false; private boolean isSelected = false;
@ -49,12 +51,15 @@ public class HoverButton extends JPanel implements MouseListener {
private Command observer = null; private Command observer = null;
private Command onHover = null; private Command onHover = null;
private Color textColor = Color.white; private Color textColor = Color.white;
private final Rectangle centerTextArea = new Rectangle(5, 18, 75, 40);
private final Color centerTextColor = Color.YELLOW;
private final Color textBGColor = Color.black; private final Color textBGColor = Color.black;
static final Font textFont = new Font("Arial", Font.PLAIN, 12); static final Font textFont = new Font("Arial", Font.PLAIN, 12);
static final Font textFontMini = new Font("Arial", Font.PLAIN, 11); static final Font textFontMini = new Font("Arial", Font.PLAIN, 11);
static final Font textSetFontBoldMini = new Font("Arial", Font.BOLD, 12); static final Font textSetFontBoldMini = new Font("Arial", Font.BOLD, 12);
static final Font textSetFontBold = new Font("Arial", Font.BOLD, 14); static final Font textSetFontBold = new Font("Arial", Font.BOLD, 14);
private boolean useMiniFont = false; private boolean useMiniFont = false;
private boolean alignTextLeft = false; private boolean alignTextLeft = false;
@ -134,6 +139,21 @@ public class HoverButton extends JPanel implements MouseListener {
if (topTextImageRight != null) { if (topTextImageRight != null) {
g.drawImage(topTextImageRight, this.getWidth() - 20, 3, this); g.drawImage(topTextImageRight, this.getWidth() - 20, 3, this);
} }
if (centerText != null) {
g2d.setColor(centerTextColor);
int fontSize = 40;
int val = Integer.parseInt(centerText);
if (val > 9999) {
fontSize = 24;
} else if (val > 999) {
fontSize = 28;
} else if (val > 99) {
fontSize = 34;
}
drawCenteredString(g2d, centerText, centerTextArea, new Font("Arial", Font.BOLD, fontSize));
}
g2d.setColor(textColor);
if (overlayImage != null) { if (overlayImage != null) {
g.drawImage(overlayImage, (imageSize.width - overlayImageSize.width) / 2, 10, this); g.drawImage(overlayImage, (imageSize.width - overlayImageSize.width) / 2, 10, this);
} else if (set != null) { } else if (set != null) {
@ -298,13 +318,17 @@ public class HoverButton extends JPanel implements MouseListener {
public void setTopTextImage(Image topTextImage) { public void setTopTextImage(Image topTextImage) {
this.topTextImage = topTextImage; this.topTextImage = topTextImage;
this.textOffsetX = -1; // rest for new clculation this.textOffsetX = -1; // rest for new calculation
} }
public void setTopTextImageRight(Image topTextImage) { public void setTopTextImageRight(Image topTextImage) {
this.topTextImageRight = topTextImage; this.topTextImageRight = topTextImage;
} }
public void setCenterText(String centerText) {
this.centerText = centerText;
}
public void setTextAlwaysVisible(boolean textAlwaysVisible) { public void setTextAlwaysVisible(boolean textAlwaysVisible) {
this.textAlwaysVisible = textAlwaysVisible; this.textAlwaysVisible = textAlwaysVisible;
} }
@ -313,4 +337,24 @@ public class HoverButton extends JPanel implements MouseListener {
this.alignTextLeft = alignTextLeft; this.alignTextLeft = alignTextLeft;
} }
/**
* Draw a String centered in the middle of a Rectangle.
*
* @param g The Graphics instance.
* @param text The String to draw.
* @param rect The Rectangle to center the text in.
* @param font
*/
public void drawCenteredString(Graphics g, String text, Rectangle rect, Font font) {
// Get the FontMetrics
FontMetrics metrics = g.getFontMetrics(font);
// Determine the X coordinate for the text
int x = rect.x + (rect.width - metrics.stringWidth(text)) / 2;
// Determine the Y coordinate for the text (note we add the ascent, as in java 2d 0 is top of the screen)
int y = rect.y + ((rect.height - metrics.getHeight()) / 2) + metrics.getAscent();
// Set the font
g.setFont(font);
// Draw the String
g.drawString(text, x, y);
}
} }

View file

@ -7,6 +7,11 @@
<Property name="text" type="java.lang.String" value="jButton2"/> <Property name="text" type="java.lang.String" value="jButton2"/>
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.JLabel" name="jLabel1">
<Properties>
<Property name="text" type="java.lang.String" value="jLabel1"/>
</Properties>
</Component>
</NonVisualComponents> </NonVisualComponents>
<Properties> <Properties>
<Property name="title" type="java.lang.String" value="Add Land"/> <Property name="title" type="java.lang.String" value="Add Land"/>
@ -29,8 +34,9 @@
<Layout> <Layout>
<DimensionLayout dim="0"> <DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0"> <Group type="102" alignment="0" attributes="0">
<EmptySpace max="32767" attributes="0"/> <EmptySpace max="32767" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Component id="lblMountain" alignment="0" min="-2" max="-2" attributes="0"/> <Component id="lblMountain" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lblForest" alignment="1" min="-2" max="-2" attributes="0"/> <Component id="lblForest" alignment="1" min="-2" max="-2" attributes="0"/>
@ -39,30 +45,51 @@
<Component id="lblPains" alignment="1" min="-2" max="-2" attributes="0"/> <Component id="lblPains" alignment="1" min="-2" max="-2" attributes="0"/>
<Component id="lblSwamp" alignment="1" min="-2" max="-2" attributes="0"/> <Component id="lblSwamp" alignment="1" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<Component id="lblDeckSize" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="separate" max="-2" attributes="0"/> <EmptySpace type="separate" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Component id="ckbFullArtLands" min="-2" max="-2" attributes="0"/> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="1" attributes="0">
<Group type="103" groupAlignment="1" max="-2" attributes="0">
<Component id="btnAutoAdd" alignment="0" pref="85" max="32767" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Group type="103" alignment="0" groupAlignment="1" max="-2" attributes="0">
<Component id="spnMountain" alignment="0" pref="85" max="32767" attributes="0"/>
<Component id="spnIsland" alignment="0" pref="85" max="32767" attributes="0"/>
<Component id="spnForest" alignment="0" max="32767" attributes="0"/>
</Group>
<Group type="103" alignment="0" groupAlignment="1" max="-2" attributes="0">
<Component id="spnSwamp" alignment="0" pref="85" max="32767" attributes="0"/>
<Component id="spnPlains" alignment="0" max="32767" attributes="0"/>
</Group>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnAdd" min="-2" max="-2" attributes="0"/> <Component id="btnAdd" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="btnCancel" min="-2" max="-2" attributes="0"/> <Component id="btnCancel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
<Component id="ckbFullArtLands" min="-2" max="-2" attributes="0"/>
<Component id="panelSet" min="-2" pref="219" max="-2" attributes="0"/>
<Group type="102" attributes="0">
<Component id="spnForest" min="-2" pref="50" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="lblForestIcon" min="-2" pref="20" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Component id="spnIsland" min="-2" pref="50" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="lblIslandIcon" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Component id="spnMountain" min="-2" pref="50" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="lblMountainIcon" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Component id="spnSwamp" min="-2" pref="50" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="lblSwampIcon" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="spnDeckSize" min="-2" pref="50" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="btnAutoAdd" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="spnPlains" min="-2" pref="50" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="lblPlainsIcon" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="36" max="-2" attributes="0"/>
</Group> </Group>
<Component id="panelSet" max="32767" attributes="0"/>
</Group> </Group>
</Group> </Group>
</Group> </Group>
@ -79,35 +106,54 @@
<Group type="103" groupAlignment="3" attributes="0"> <Group type="103" groupAlignment="3" attributes="0">
<Component id="lblForest" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="lblForest" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="spnForest" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="spnForest" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="lblForestIcon" alignment="0" max="32767" attributes="0"/>
</Group> </Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="103" groupAlignment="3" attributes="0"> <Group type="103" groupAlignment="3" attributes="0">
<Component id="lblIsland" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="lblIsland" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="spnIsland" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="spnIsland" alignment="3" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<Component id="lblIslandIcon" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="103" groupAlignment="3" attributes="0"> <Group type="103" groupAlignment="3" attributes="0">
<Component id="lblMountain" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="lblMountain" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="spnMountain" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="spnMountain" alignment="3" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<Component id="lblMountainIcon" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="103" groupAlignment="3" attributes="0"> <Group type="103" groupAlignment="3" attributes="0">
<Component id="lblPains" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="lblPains" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="spnPlains" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="spnPlains" alignment="3" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<Component id="lblPlainsIcon" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="103" groupAlignment="3" attributes="0"> <Group type="103" groupAlignment="3" attributes="0">
<Component id="lblSwamp" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="lblSwamp" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="spnSwamp" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="spnSwamp" alignment="3" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<EmptySpace max="32767" attributes="0"/> <Component id="lblSwampIcon" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="ckbFullArtLands" min="-2" max="-2" attributes="0"/> <Component id="ckbFullArtLands" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="2" max="-2" attributes="0"/> <EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0"> <Group type="103" groupAlignment="3" attributes="0">
<Component id="btnAutoAdd" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="btnAutoAdd" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="lblDeckSize" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="spnDeckSize" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="btnAdd" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="btnAdd" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="btnCancel" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="btnCancel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<EmptySpace max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
@ -120,7 +166,7 @@
</Component> </Component>
<Component class="javax.swing.JLabel" name="lblForest"> <Component class="javax.swing.JLabel" name="lblForest">
<Properties> <Properties>
<Property name="text" type="java.lang.String" value="Forest"/> <Property name="text" type="java.lang.String" value="Forest:"/>
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.JSpinner" name="spnForest"> <Component class="javax.swing.JSpinner" name="spnForest">
@ -130,9 +176,23 @@
</Property> </Property>
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.JLabel" name="lblForestIcon">
<Properties>
<Property name="toolTipText" type="java.lang.String" value=""/>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[22, 20]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[22, 20]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[22, 20]"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lblIsland"> <Component class="javax.swing.JLabel" name="lblIsland">
<Properties> <Properties>
<Property name="text" type="java.lang.String" value="Island"/> <Property name="text" type="java.lang.String" value="Island:"/>
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.JSpinner" name="spnIsland"> <Component class="javax.swing.JSpinner" name="spnIsland">
@ -142,9 +202,22 @@
</Property> </Property>
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.JLabel" name="lblIslandIcon">
<Properties>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[22, 20]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[22, 20]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[22, 20]"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lblMountain"> <Component class="javax.swing.JLabel" name="lblMountain">
<Properties> <Properties>
<Property name="text" type="java.lang.String" value="Mountain"/> <Property name="text" type="java.lang.String" value="Mountain:"/>
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.JSpinner" name="spnMountain"> <Component class="javax.swing.JSpinner" name="spnMountain">
@ -154,9 +227,22 @@
</Property> </Property>
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.JLabel" name="lblMountainIcon">
<Properties>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[22, 20]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[22, 20]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[22, 20]"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lblPains"> <Component class="javax.swing.JLabel" name="lblPains">
<Properties> <Properties>
<Property name="text" type="java.lang.String" value="Plains"/> <Property name="text" type="java.lang.String" value="Plains:"/>
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.JSpinner" name="spnPlains"> <Component class="javax.swing.JSpinner" name="spnPlains">
@ -166,9 +252,22 @@
</Property> </Property>
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.JLabel" name="lblPlainsIcon">
<Properties>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[22, 20]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[22, 20]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[22, 20]"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lblSwamp"> <Component class="javax.swing.JLabel" name="lblSwamp">
<Properties> <Properties>
<Property name="text" type="java.lang.String" value="Swamp"/> <Property name="text" type="java.lang.String" value="Swamp:"/>
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.JSpinner" name="spnSwamp"> <Component class="javax.swing.JSpinner" name="spnSwamp">
@ -178,9 +277,44 @@
</Property> </Property>
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.JLabel" name="lblSwampIcon">
<Properties>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[22, 20]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[22, 20]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[22, 20]"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="lblDeckSize">
<Properties>
<Property name="text" type="java.lang.String" value="Deck size:"/>
</Properties>
</Component>
<Component class="javax.swing.JSpinner" name="spnDeckSize">
<Properties>
<Property name="model" type="javax.swing.SpinnerModel" editor="org.netbeans.modules.form.editors2.SpinnerModelEditor">
<SpinnerModel initial="0" minimum="0" numberType="java.lang.Integer" stepSize="1" type="number"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="btnAutoAdd">
<Properties>
<Property name="text" type="java.lang.String" value="Suggest"/>
<Property name="toolTipText" type="java.lang.String" value="&lt;HTML&gt;Propose related to the mana costs of the cards in the deck&lt;br&gt;&#xa;the number of lands to add to get to the set deck size."/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnAutoAddActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="btnAdd"> <Component class="javax.swing.JButton" name="btnAdd">
<Properties> <Properties>
<Property name="text" type="java.lang.String" value="Add"/> <Property name="text" type="java.lang.String" value="Add"/>
<Property name="toolTipText" type="java.lang.String" value="Add the selected number of basic lands to the deck."/>
</Properties> </Properties>
<Events> <Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnAddActionPerformed"/> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnAddActionPerformed"/>
@ -194,14 +328,6 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnCancelActionPerformed"/> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnCancelActionPerformed"/>
</Events> </Events>
</Component> </Component>
<Component class="javax.swing.JButton" name="btnAutoAdd">
<Properties>
<Property name="text" type="java.lang.String" value="Suggest"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnAutoAddActionPerformed"/>
</Events>
</Component>
<Container class="javax.swing.JPanel" name="panelSet"> <Container class="javax.swing.JPanel" name="panelSet">
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout"/> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout"/>

View file

@ -27,12 +27,13 @@
*/ */
package mage.client.dialog; package mage.client.dialog;
import java.util.HashSet; import java.awt.image.BufferedImage;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.SortedSet; import java.util.SortedSet;
import java.util.TreeSet; import java.util.TreeSet;
import javax.swing.DefaultComboBoxModel; import javax.swing.DefaultComboBoxModel;
import javax.swing.ImageIcon;
import javax.swing.JLayeredPane; import javax.swing.JLayeredPane;
import mage.Mana; import mage.Mana;
import mage.cards.Card; import mage.cards.Card;
@ -49,6 +50,7 @@ import mage.client.util.gui.FastSearchUtil;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.util.RandomUtil; import mage.util.RandomUtil;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.mage.card.arcane.ManaSymbols;
/** /**
* *
@ -59,7 +61,6 @@ public class AddLandDialog extends MageDialog {
private static final Logger logger = Logger.getLogger(MageDialog.class); private static final Logger logger = Logger.getLogger(MageDialog.class);
private Deck deck; private Deck deck;
private final Set<String> landSetCodes = new HashSet<>();
private static final int DEFAULT_SEALED_DECK_CARD_NUMBER = 40; private static final int DEFAULT_SEALED_DECK_CARD_NUMBER = 40;
@ -131,6 +132,27 @@ public class AddLandDialog extends MageDialog {
} else { } else {
MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER); MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER);
} }
spnDeckSize.setValue(DEFAULT_SEALED_DECK_CARD_NUMBER);
BufferedImage image = ManaSymbols.getSizedManaSymbol("G", 15);
if (image != null) {
lblForestIcon.setIcon(new ImageIcon(image));
}
image = ManaSymbols.getSizedManaSymbol("U", 15);
if (image != null) {
lblIslandIcon.setIcon(new ImageIcon(image));
}
image = ManaSymbols.getSizedManaSymbol("W", 15);
if (image != null) {
lblPlainsIcon.setIcon(new ImageIcon(image));
}
image = ManaSymbols.getSizedManaSymbol("R", 15);
if (image != null) {
lblMountainIcon.setIcon(new ImageIcon(image));
}
image = ManaSymbols.getSizedManaSymbol("B", 15);
if (image != null) {
lblSwampIcon.setIcon(new ImageIcon(image));
}
this.setVisible(true); this.setVisible(true);
} }
@ -139,9 +161,7 @@ public class AddLandDialog extends MageDialog {
String landSetName = (String) cbLandSet.getSelectedItem(); String landSetName = (String) cbLandSet.getSelectedItem();
CardCriteria criteria = new CardCriteria(); CardCriteria criteria = new CardCriteria();
if (landSetName.equals("<Random lands>")) { if (!landSetName.equals("<Random lands>")) {
criteria.setCodes(landSetCodes.toArray(new String[landSetCodes.size()]));
} else {
ExpansionInfo expansionInfo = ExpansionRepository.instance.getSetByName(landSetName); ExpansionInfo expansionInfo = ExpansionRepository.instance.getSetByName(landSetName);
if (expansionInfo == null) { if (expansionInfo == null) {
throw new IllegalArgumentException("Code of Set " + landSetName + " not found"); throw new IllegalArgumentException("Code of Set " + landSetName + " not found");
@ -193,20 +213,28 @@ public class AddLandDialog extends MageDialog {
private void initComponents() { private void initComponents() {
jButton2 = new javax.swing.JButton(); jButton2 = new javax.swing.JButton();
jLabel1 = new javax.swing.JLabel();
lblLandSet = new javax.swing.JLabel(); lblLandSet = new javax.swing.JLabel();
lblForest = new javax.swing.JLabel(); lblForest = new javax.swing.JLabel();
spnForest = new javax.swing.JSpinner(); spnForest = new javax.swing.JSpinner();
lblForestIcon = new javax.swing.JLabel();
lblIsland = new javax.swing.JLabel(); lblIsland = new javax.swing.JLabel();
spnIsland = new javax.swing.JSpinner(); spnIsland = new javax.swing.JSpinner();
lblIslandIcon = new javax.swing.JLabel();
lblMountain = new javax.swing.JLabel(); lblMountain = new javax.swing.JLabel();
spnMountain = new javax.swing.JSpinner(); spnMountain = new javax.swing.JSpinner();
lblMountainIcon = new javax.swing.JLabel();
lblPains = new javax.swing.JLabel(); lblPains = new javax.swing.JLabel();
spnPlains = new javax.swing.JSpinner(); spnPlains = new javax.swing.JSpinner();
lblPlainsIcon = new javax.swing.JLabel();
lblSwamp = new javax.swing.JLabel(); lblSwamp = new javax.swing.JLabel();
spnSwamp = new javax.swing.JSpinner(); spnSwamp = new javax.swing.JSpinner();
lblSwampIcon = new javax.swing.JLabel();
lblDeckSize = new javax.swing.JLabel();
spnDeckSize = new javax.swing.JSpinner();
btnAutoAdd = new javax.swing.JButton();
btnAdd = new javax.swing.JButton(); btnAdd = new javax.swing.JButton();
btnCancel = new javax.swing.JButton(); btnCancel = new javax.swing.JButton();
btnAutoAdd = new javax.swing.JButton();
panelSet = new javax.swing.JPanel(); panelSet = new javax.swing.JPanel();
cbLandSet = new javax.swing.JComboBox(); cbLandSet = new javax.swing.JComboBox();
btnSetFastSearch = new javax.swing.JButton(); btnSetFastSearch = new javax.swing.JButton();
@ -214,31 +242,67 @@ public class AddLandDialog extends MageDialog {
jButton2.setText("jButton2"); jButton2.setText("jButton2");
jLabel1.setText("jLabel1");
setTitle("Add Land"); setTitle("Add Land");
lblLandSet.setText("Set:"); lblLandSet.setText("Set:");
lblForest.setText("Forest"); lblForest.setText("Forest:");
spnForest.setModel(new javax.swing.SpinnerNumberModel(0, 0, null, 1)); spnForest.setModel(new javax.swing.SpinnerNumberModel(0, 0, null, 1));
lblIsland.setText("Island"); lblForestIcon.setToolTipText("");
lblForestIcon.setMaximumSize(new java.awt.Dimension(22, 20));
lblForestIcon.setMinimumSize(new java.awt.Dimension(22, 20));
lblForestIcon.setPreferredSize(new java.awt.Dimension(22, 20));
lblIsland.setText("Island:");
spnIsland.setModel(new javax.swing.SpinnerNumberModel(0, 0, null, 1)); spnIsland.setModel(new javax.swing.SpinnerNumberModel(0, 0, null, 1));
lblMountain.setText("Mountain"); lblIslandIcon.setMaximumSize(new java.awt.Dimension(22, 20));
lblIslandIcon.setMinimumSize(new java.awt.Dimension(22, 20));
lblIslandIcon.setPreferredSize(new java.awt.Dimension(22, 20));
lblMountain.setText("Mountain:");
spnMountain.setModel(new javax.swing.SpinnerNumberModel(0, 0, null, 1)); spnMountain.setModel(new javax.swing.SpinnerNumberModel(0, 0, null, 1));
lblPains.setText("Plains"); lblMountainIcon.setMaximumSize(new java.awt.Dimension(22, 20));
lblMountainIcon.setMinimumSize(new java.awt.Dimension(22, 20));
lblMountainIcon.setPreferredSize(new java.awt.Dimension(22, 20));
lblPains.setText("Plains:");
spnPlains.setModel(new javax.swing.SpinnerNumberModel(0, 0, null, 1)); spnPlains.setModel(new javax.swing.SpinnerNumberModel(0, 0, null, 1));
lblSwamp.setText("Swamp"); lblPlainsIcon.setMaximumSize(new java.awt.Dimension(22, 20));
lblPlainsIcon.setMinimumSize(new java.awt.Dimension(22, 20));
lblPlainsIcon.setPreferredSize(new java.awt.Dimension(22, 20));
lblSwamp.setText("Swamp:");
spnSwamp.setModel(new javax.swing.SpinnerNumberModel(0, 0, null, 1)); spnSwamp.setModel(new javax.swing.SpinnerNumberModel(0, 0, null, 1));
lblSwampIcon.setMaximumSize(new java.awt.Dimension(22, 20));
lblSwampIcon.setMinimumSize(new java.awt.Dimension(22, 20));
lblSwampIcon.setPreferredSize(new java.awt.Dimension(22, 20));
lblDeckSize.setText("Deck size:");
spnDeckSize.setModel(new javax.swing.SpinnerNumberModel(0, 0, null, 1));
btnAutoAdd.setText("Suggest");
btnAutoAdd.setToolTipText("<HTML>Propose related to the mana costs of the cards in the deck<br>\nthe number of lands to add to get to the set deck size.");
btnAutoAdd.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnAutoAddActionPerformed(evt);
}
});
btnAdd.setText("Add"); btnAdd.setText("Add");
btnAdd.setToolTipText("Add the selected number of basic lands to the deck.");
btnAdd.addActionListener(new java.awt.event.ActionListener() { btnAdd.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) { public void actionPerformed(java.awt.event.ActionEvent evt) {
btnAddActionPerformed(evt); btnAddActionPerformed(evt);
@ -252,13 +316,6 @@ public class AddLandDialog extends MageDialog {
} }
}); });
btnAutoAdd.setText("Suggest");
btnAutoAdd.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnAutoAddActionPerformed(evt);
}
});
panelSet.setLayout(new javax.swing.BoxLayout(panelSet, javax.swing.BoxLayout.LINE_AXIS)); panelSet.setLayout(new javax.swing.BoxLayout(panelSet, javax.swing.BoxLayout.LINE_AXIS));
cbLandSet.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" })); cbLandSet.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" }));
@ -285,6 +342,7 @@ public class AddLandDialog extends MageDialog {
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(lblMountain) .addComponent(lblMountain)
.addComponent(lblForest, javax.swing.GroupLayout.Alignment.TRAILING) .addComponent(lblForest, javax.swing.GroupLayout.Alignment.TRAILING)
@ -292,25 +350,42 @@ public class AddLandDialog extends MageDialog {
.addComponent(lblIsland, javax.swing.GroupLayout.Alignment.TRAILING) .addComponent(lblIsland, javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(lblPains, javax.swing.GroupLayout.Alignment.TRAILING) .addComponent(lblPains, javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(lblSwamp, javax.swing.GroupLayout.Alignment.TRAILING)) .addComponent(lblSwamp, javax.swing.GroupLayout.Alignment.TRAILING))
.addComponent(lblDeckSize))
.addGap(18, 18, 18) .addGap(18, 18, 18)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(ckbFullArtLands) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup() .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addComponent(btnAutoAdd, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 85, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addComponent(spnMountain, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 85, Short.MAX_VALUE)
.addComponent(spnIsland, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 85, Short.MAX_VALUE)
.addComponent(spnForest, javax.swing.GroupLayout.Alignment.LEADING))
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addComponent(spnSwamp, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 85, Short.MAX_VALUE)
.addComponent(spnPlains, javax.swing.GroupLayout.Alignment.LEADING))))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnAdd) .addComponent(btnAdd)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnCancel)) .addComponent(btnCancel)
.addComponent(panelSet, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) .addContainerGap())
.addComponent(ckbFullArtLands)
.addComponent(panelSet, javax.swing.GroupLayout.PREFERRED_SIZE, 219, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGroup(layout.createSequentialGroup()
.addComponent(spnForest, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lblForestIcon, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createSequentialGroup()
.addComponent(spnIsland, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lblIslandIcon, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createSequentialGroup()
.addComponent(spnMountain, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lblMountainIcon, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createSequentialGroup()
.addComponent(spnSwamp, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lblSwampIcon, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createSequentialGroup()
.addComponent(spnDeckSize, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(btnAutoAdd)))
.addGroup(layout.createSequentialGroup()
.addComponent(spnPlains, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(lblPlainsIcon, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(36, 36, 36))))
); );
layout.setVerticalGroup( layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -322,30 +397,44 @@ public class AddLandDialog extends MageDialog {
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lblForest) .addComponent(lblForest)
.addComponent(spnForest, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(spnForest, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(lblForestIcon, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lblIsland) .addComponent(lblIsland)
.addComponent(spnIsland, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(spnIsland, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(lblIslandIcon, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lblMountain) .addComponent(lblMountain)
.addComponent(spnMountain, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(spnMountain, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(lblMountainIcon, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lblPains) .addComponent(lblPains)
.addComponent(spnPlains, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(spnPlains, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(lblPlainsIcon, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(lblSwamp) .addComponent(lblSwamp)
.addComponent(spnSwamp, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(spnSwamp, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(lblSwampIcon, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(ckbFullArtLands) .addComponent(ckbFullArtLands)
.addGap(2, 2, 2) .addGap(2, 2, 2)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(btnAutoAdd) .addComponent(btnAutoAdd)
.addComponent(lblDeckSize)
.addComponent(spnDeckSize, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(18, 18, 18)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(btnAdd) .addComponent(btnAdd)
.addComponent(btnCancel))) .addComponent(btnCancel))
.addContainerGap())
); );
pack(); pack();
@ -386,7 +475,7 @@ public class AddLandDialog extends MageDialog {
int blue = 0; int blue = 0;
int white = 0; int white = 0;
Set<Card> cards = deck.getCards(); Set<Card> cards = deck.getCards();
int land_number = DEFAULT_SEALED_DECK_CARD_NUMBER - cards.size(); int land_number = ((Number) spnDeckSize.getValue()).intValue() - cards.size();
if (land_number < 0) { if (land_number < 0) {
land_number = 0; land_number = 0;
} }
@ -427,13 +516,21 @@ public class AddLandDialog extends MageDialog {
private javax.swing.JComboBox cbLandSet; private javax.swing.JComboBox cbLandSet;
private javax.swing.JCheckBox ckbFullArtLands; private javax.swing.JCheckBox ckbFullArtLands;
private javax.swing.JButton jButton2; private javax.swing.JButton jButton2;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel lblDeckSize;
private javax.swing.JLabel lblForest; private javax.swing.JLabel lblForest;
private javax.swing.JLabel lblForestIcon;
private javax.swing.JLabel lblIsland; private javax.swing.JLabel lblIsland;
private javax.swing.JLabel lblIslandIcon;
private javax.swing.JLabel lblLandSet; private javax.swing.JLabel lblLandSet;
private javax.swing.JLabel lblMountain; private javax.swing.JLabel lblMountain;
private javax.swing.JLabel lblMountainIcon;
private javax.swing.JLabel lblPains; private javax.swing.JLabel lblPains;
private javax.swing.JLabel lblPlainsIcon;
private javax.swing.JLabel lblSwamp; private javax.swing.JLabel lblSwamp;
private javax.swing.JLabel lblSwampIcon;
private javax.swing.JPanel panelSet; private javax.swing.JPanel panelSet;
private javax.swing.JSpinner spnDeckSize;
private javax.swing.JSpinner spnForest; private javax.swing.JSpinner spnForest;
private javax.swing.JSpinner spnIsland; private javax.swing.JSpinner spnIsland;
private javax.swing.JSpinner spnMountain; private javax.swing.JSpinner spnMountain;

View file

@ -27,6 +27,12 @@
*/ */
package mage.client.dialog; package mage.client.dialog;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import javax.swing.*;
import mage.cards.decks.importer.DeckImporterUtil; import mage.cards.decks.importer.DeckImporterUtil;
import mage.client.MageFrame; import mage.client.MageFrame;
import mage.client.SessionHandler; import mage.client.SessionHandler;
@ -45,13 +51,6 @@ import mage.view.GameTypeView;
import mage.view.TableView; import mage.view.TableView;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import javax.swing.*;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/** /**
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
*/ */
@ -623,17 +622,22 @@ public class NewTableDialog extends MageDialog {
* set the table settings from java prefs * set the table settings from java prefs
*/ */
int currentSettingVersion = 0; int currentSettingVersion = 0;
private void setGameSettingsFromPrefs(int version) { private void setGameSettingsFromPrefs(int version) {
currentSettingVersion = version; currentSettingVersion = version;
String versionStr = ""; String versionStr = "";
if (currentSettingVersion == 1) { switch (currentSettingVersion) {
case 1:
versionStr = "1"; versionStr = "1";
btnPreviousConfiguration1.requestFocus(); btnPreviousConfiguration1.requestFocus();
} else if (currentSettingVersion == 2) { break;
case 2:
versionStr = "2"; versionStr = "2";
btnPreviousConfiguration2.requestFocus(); btnPreviousConfiguration2.requestFocus();
} else { break;
default:
btnPreviousConfiguration2.getParent().requestFocus(); btnPreviousConfiguration2.getParent().requestFocus();
break;
} }
txtName.setText(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_NAME + versionStr, "Game")); txtName.setText(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_NAME + versionStr, "Game"));
txtPassword.setText(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_PASSWORD + versionStr, "")); txtPassword.setText(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_PASSWORD + versionStr, ""));
@ -724,6 +728,7 @@ public class NewTableDialog extends MageDialog {
PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_RANGE + versionStr, Integer.toString(options.getRange().getRange())); PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_RANGE + versionStr, Integer.toString(options.getRange().getRange()));
PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_ATTACK_OPTION + versionStr, options.getAttackOption().toString()); PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_ATTACK_OPTION + versionStr, options.getAttackOption().toString());
PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_SKILL_LEVEL + versionStr, options.getSkillLevel().toString()); PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_SKILL_LEVEL + versionStr, options.getSkillLevel().toString());
PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_SPECTATORS_ALLOWED + versionStr, options.isSpectatorsAllowed() ? "Yes" : "No");
PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_QUIT_RATIO + versionStr, Integer.toString(options.getQuitRatio())); PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_QUIT_RATIO + versionStr, Integer.toString(options.getQuitRatio()));
StringBuilder playerTypesString = new StringBuilder(); StringBuilder playerTypesString = new StringBuilder();
for (Object player : players) { for (Object player : players) {

View file

@ -35,11 +35,13 @@ package mage.client.dialog;
import java.awt.*; import java.awt.*;
import java.io.File; import java.io.File;
import java.util.*; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.UUID;
import javax.swing.*; import javax.swing.*;
import javax.swing.filechooser.FileFilter; import javax.swing.filechooser.FileFilter;
import mage.cards.decks.Deck; import mage.cards.decks.Deck;
import mage.cards.decks.importer.DeckImporterUtil; import mage.cards.decks.importer.DeckImporterUtil;
import mage.cards.repository.ExpansionInfo; import mage.cards.repository.ExpansionInfo;
@ -764,7 +766,6 @@ public class NewTournamentDialog extends MageDialog {
this.spnNumPlayers.setModel(new SpinnerNumberModel(numPlayers, tournamentType.getMinPlayers(), tournamentType.getMaxPlayers(), 1)); this.spnNumPlayers.setModel(new SpinnerNumberModel(numPlayers, tournamentType.getMinPlayers(), tournamentType.getMaxPlayers(), 1));
this.spnNumPlayers.setEnabled(tournamentType.getMinPlayers() != tournamentType.getMaxPlayers()); this.spnNumPlayers.setEnabled(tournamentType.getMinPlayers() != tournamentType.getMaxPlayers());
createPlayers((Integer) spnNumPlayers.getValue() - 1); createPlayers((Integer) spnNumPlayers.getValue() - 1);
this.spnNumSeats.setModel(new SpinnerNumberModel(2, 2, tournamentType.getMaxPlayers(), 1)); this.spnNumSeats.setModel(new SpinnerNumberModel(2, 2, tournamentType.getMaxPlayers(), 1));
if (tournamentType.isLimited()) { if (tournamentType.isLimited()) {

View file

@ -95,10 +95,10 @@
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="main_game" min="-2" max="-2" attributes="0"/> <Component id="main_game" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="main_gamelog" min="-2" pref="107" max="-2" attributes="0"/> <Component id="main_gamelog" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="main_battlefield" min="-2" max="-2" attributes="0"/> <Component id="main_battlefield" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="121" max="32767" attributes="0"/> <EmptySpace max="32767" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
@ -200,7 +200,7 @@
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/> <EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="103" alignment="0" groupAlignment="1" max="-2" attributes="0"> <Group type="103" alignment="0" groupAlignment="1" max="-2" attributes="0">
<Component id="tooltipDelayLabel" pref="308" max="32767" attributes="0"/> <Component id="tooltipDelayLabel" max="32767" attributes="0"/>
<Component id="tooltipDelay" alignment="1" max="32767" attributes="0"/> <Component id="tooltipDelay" alignment="1" max="32767" attributes="0"/>
</Group> </Group>
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0">
@ -295,6 +295,8 @@
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0"> <Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" max="-2" attributes="0"> <Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="showPlayerNamesPermanently" alignment="0" max="32767" attributes="0"/> <Component id="showPlayerNamesPermanently" alignment="0" max="32767" attributes="0"/>
<Component id="nonLandPermanentsInOnePile" alignment="0" max="32767" attributes="0"/> <Component id="nonLandPermanentsInOnePile" alignment="0" max="32767" attributes="0"/>
@ -304,7 +306,11 @@
<Component id="cbAskMoveToGraveOrder" alignment="0" max="32767" attributes="0"/> <Component id="cbAskMoveToGraveOrder" alignment="0" max="32767" attributes="0"/>
<Component id="showAbilityPickerForced" alignment="0" max="32767" attributes="0"/> <Component id="showAbilityPickerForced" alignment="0" max="32767" attributes="0"/>
</Group> </Group>
<EmptySpace pref="177" max="32767" attributes="0"/> <EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Component id="displayLifeOnAvatar" alignment="0" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
@ -315,6 +321,8 @@
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="showPlayerNamesPermanently" min="-2" max="-2" attributes="0"/> <Component id="showPlayerNamesPermanently" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="displayLifeOnAvatar" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="showAbilityPickerForced" min="-2" max="-2" attributes="0"/> <Component id="showAbilityPickerForced" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="cbAllowRequestToShowHandCards" min="-2" max="-2" attributes="0"/> <Component id="cbAllowRequestToShowHandCards" min="-2" max="-2" attributes="0"/>
@ -324,7 +332,6 @@
<Component id="cbConfirmEmptyManaPool" min="-2" max="-2" attributes="0"/> <Component id="cbConfirmEmptyManaPool" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="cbAskMoveToGraveOrder" min="-2" max="-2" attributes="0"/> <Component id="cbAskMoveToGraveOrder" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
@ -354,6 +361,17 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="showPlayerNamesPermanentlyActionPerformed"/> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="showPlayerNamesPermanentlyActionPerformed"/>
</Events> </Events>
</Component> </Component>
<Component class="javax.swing.JCheckBox" name="displayLifeOnAvatar">
<Properties>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" value="Display life on avatar image"/>
<Property name="toolTipText" type="java.lang.String" value="Display the player&apos;s life over its avatar image."/>
<Property name="horizontalAlignment" type="int" value="2"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="displayLifeOnAvatarActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="showAbilityPickerForced"> <Component class="javax.swing.JCheckBox" name="showAbilityPickerForced">
<Properties> <Properties>
<Property name="selected" type="boolean" value="true"/> <Property name="selected" type="boolean" value="true"/>
@ -4274,7 +4292,7 @@
<Component id="panelCardImages" min="-2" max="-2" attributes="0"/> <Component id="panelCardImages" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="panelBackgroundImages" min="-2" max="-2" attributes="0"/> <Component id="panelBackgroundImages" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="125" max="32767" attributes="0"/> <EmptySpace pref="133" max="32767" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
@ -4847,7 +4865,7 @@
<DimensionLayout dim="1"> <DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0">
<Component id="avatarPane" pref="584" max="32767" attributes="0"/> <Component id="avatarPane" pref="620" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>

View file

@ -96,6 +96,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
public static final String KEY_SHOW_FULL_IMAGE_PATH = "showFullImagePath"; public static final String KEY_SHOW_FULL_IMAGE_PATH = "showFullImagePath";
public static final String KEY_PERMANENTS_IN_ONE_PILE = "nonLandPermanentsInOnePile"; public static final String KEY_PERMANENTS_IN_ONE_PILE = "nonLandPermanentsInOnePile";
public static final String KEY_SHOW_PLAYER_NAMES_PERMANENTLY = "showPlayerNamesPermanently"; public static final String KEY_SHOW_PLAYER_NAMES_PERMANENTLY = "showPlayerNamesPermanently";
public static final String KEY_DISPLAY_LIVE_ON_AVATAR = "displayLiveOnAvatar";
public static final String KEY_SHOW_ABILITY_PICKER_FORCED = "showAbilityPicker"; public static final String KEY_SHOW_ABILITY_PICKER_FORCED = "showAbilityPicker";
public static final String KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS = "gameAllowRequestShowHandCards"; public static final String KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS = "gameAllowRequestShowHandCards";
public static final String KEY_GAME_SHOW_STORM_COUNTER = "gameShowStormCounter"; public static final String KEY_GAME_SHOW_STORM_COUNTER = "gameShowStormCounter";
@ -421,6 +422,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
main_game = new javax.swing.JPanel(); main_game = new javax.swing.JPanel();
nonLandPermanentsInOnePile = new javax.swing.JCheckBox(); nonLandPermanentsInOnePile = new javax.swing.JCheckBox();
showPlayerNamesPermanently = new javax.swing.JCheckBox(); showPlayerNamesPermanently = new javax.swing.JCheckBox();
displayLifeOnAvatar = new javax.swing.JCheckBox();
showAbilityPickerForced = new javax.swing.JCheckBox(); showAbilityPickerForced = new javax.swing.JCheckBox();
cbAllowRequestToShowHandCards = new javax.swing.JCheckBox(); cbAllowRequestToShowHandCards = new javax.swing.JCheckBox();
cbShowStormCounter = new javax.swing.JCheckBox(); cbShowStormCounter = new javax.swing.JCheckBox();
@ -700,7 +702,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
.add(6, 6, 6) .add(6, 6, 6)
.add(main_cardLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(main_cardLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(main_cardLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING, false) .add(main_cardLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING, false)
.add(tooltipDelayLabel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 308, Short.MAX_VALUE) .add(tooltipDelayLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.add(tooltipDelay, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .add(tooltipDelay, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.add(main_cardLayout.createSequentialGroup() .add(main_cardLayout.createSequentialGroup()
.add(showCardName) .add(showCardName)
@ -741,6 +743,16 @@ public class PreferencesDialog extends javax.swing.JDialog {
} }
}); });
displayLifeOnAvatar.setSelected(true);
displayLifeOnAvatar.setText("Display life on avatar image");
displayLifeOnAvatar.setToolTipText("Display the player's life over its avatar image.");
displayLifeOnAvatar.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
displayLifeOnAvatar.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
displayLifeOnAvatarActionPerformed(evt);
}
});
showAbilityPickerForced.setSelected(true); showAbilityPickerForced.setSelected(true);
showAbilityPickerForced.setText("Show ability picker for abilities or spells without costs"); showAbilityPickerForced.setText("Show ability picker for abilities or spells without costs");
showAbilityPickerForced.setToolTipText("This prevents you from accidently activating abilities without other costs than tapping or casting spells with 0 mana costs."); showAbilityPickerForced.setToolTipText("This prevents you from accidently activating abilities without other costs than tapping or casting spells with 0 mana costs.");
@ -797,6 +809,8 @@ public class PreferencesDialog extends javax.swing.JDialog {
main_gameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) main_gameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(main_gameLayout.createSequentialGroup() .add(main_gameLayout.createSequentialGroup()
.addContainerGap() .addContainerGap()
.add(main_gameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(main_gameLayout.createSequentialGroup()
.add(main_gameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false) .add(main_gameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false)
.add(showPlayerNamesPermanently, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .add(showPlayerNamesPermanently, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.add(nonLandPermanentsInOnePile, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .add(nonLandPermanentsInOnePile, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
@ -805,7 +819,9 @@ public class PreferencesDialog extends javax.swing.JDialog {
.add(cbShowStormCounter, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .add(cbShowStormCounter, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.add(cbAskMoveToGraveOrder, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .add(cbAskMoveToGraveOrder, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.add(showAbilityPickerForced, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .add(showAbilityPickerForced, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap(177, Short.MAX_VALUE)) .add(0, 0, Short.MAX_VALUE))
.add(displayLifeOnAvatar, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap())
); );
main_gameLayout.setVerticalGroup( main_gameLayout.setVerticalGroup(
main_gameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) main_gameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
@ -814,6 +830,8 @@ public class PreferencesDialog extends javax.swing.JDialog {
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(showPlayerNamesPermanently) .add(showPlayerNamesPermanently)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(displayLifeOnAvatar)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(showAbilityPickerForced) .add(showAbilityPickerForced)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(cbAllowRequestToShowHandCards) .add(cbAllowRequestToShowHandCards)
@ -822,8 +840,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(cbConfirmEmptyManaPool) .add(cbConfirmEmptyManaPool)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(cbAskMoveToGraveOrder) .add(cbAskMoveToGraveOrder))
.addContainerGap())
); );
nonLandPermanentsInOnePile.getAccessibleContext().setAccessibleName("nonLandPermanentsInOnePile"); nonLandPermanentsInOnePile.getAccessibleContext().setAccessibleName("nonLandPermanentsInOnePile");
@ -880,10 +897,10 @@ public class PreferencesDialog extends javax.swing.JDialog {
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(main_game, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .add(main_game, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(main_gamelog, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 107, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .add(main_gamelog, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(main_battlefield, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .add(main_battlefield, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addContainerGap(121, Short.MAX_VALUE)) .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
); );
main_card.getAccessibleContext().setAccessibleName("Game panel"); main_card.getAccessibleContext().setAccessibleName("Game panel");
@ -1797,7 +1814,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
.add(panelCardImages, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .add(panelCardImages, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(panelBackgroundImages, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .add(panelBackgroundImages, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addContainerGap(125, Short.MAX_VALUE)) .addContainerGap(133, Short.MAX_VALUE))
); );
tabsPanel.addTab("Images", tabImages); tabsPanel.addTab("Images", tabImages);
@ -2372,7 +2389,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
tabAvatarsLayout.setVerticalGroup( tabAvatarsLayout.setVerticalGroup(
tabAvatarsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) tabAvatarsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(tabAvatarsLayout.createSequentialGroup() .add(tabAvatarsLayout.createSequentialGroup()
.add(avatarPane, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 584, Short.MAX_VALUE) .add(avatarPane, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 620, Short.MAX_VALUE)
.addContainerGap()) .addContainerGap())
); );
@ -2762,6 +2779,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
save(prefs, dialog.showFullImagePath, KEY_SHOW_FULL_IMAGE_PATH, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.showFullImagePath, KEY_SHOW_FULL_IMAGE_PATH, "true", "false", UPDATE_CACHE_POLICY);
save(prefs, dialog.nonLandPermanentsInOnePile, KEY_PERMANENTS_IN_ONE_PILE, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.nonLandPermanentsInOnePile, KEY_PERMANENTS_IN_ONE_PILE, "true", "false", UPDATE_CACHE_POLICY);
save(prefs, dialog.showPlayerNamesPermanently, KEY_SHOW_PLAYER_NAMES_PERMANENTLY, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.showPlayerNamesPermanently, KEY_SHOW_PLAYER_NAMES_PERMANENTLY, "true", "false", UPDATE_CACHE_POLICY);
save(prefs, dialog.displayLifeOnAvatar, KEY_DISPLAY_LIVE_ON_AVATAR, "true", "false", UPDATE_CACHE_POLICY);
save(prefs, dialog.showAbilityPickerForced, KEY_SHOW_ABILITY_PICKER_FORCED, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.showAbilityPickerForced, KEY_SHOW_ABILITY_PICKER_FORCED, "true", "false", UPDATE_CACHE_POLICY);
save(prefs, dialog.cbAllowRequestToShowHandCards, KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.cbAllowRequestToShowHandCards, KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS, "true", "false", UPDATE_CACHE_POLICY);
save(prefs, dialog.cbShowStormCounter, KEY_GAME_SHOW_STORM_COUNTER, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.cbShowStormCounter, KEY_GAME_SHOW_STORM_COUNTER, "true", "false", UPDATE_CACHE_POLICY);
@ -3225,6 +3243,10 @@ public class PreferencesDialog extends javax.swing.JDialog {
} }
}//GEN-LAST:event_cbGameJsonLogAutoSaveActionPerformed }//GEN-LAST:event_cbGameJsonLogAutoSaveActionPerformed
private void displayLifeOnAvatarActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_displayLifeOnAvatarActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_displayLifeOnAvatarActionPerformed
private void showProxySettings() { private void showProxySettings() {
Connection.ProxyType proxyType = (Connection.ProxyType) cbProxyType.getSelectedItem(); Connection.ProxyType proxyType = (Connection.ProxyType) cbProxyType.getSelectedItem();
switch (proxyType) { switch (proxyType) {
@ -3331,6 +3353,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
load(prefs, dialog.showFullImagePath, KEY_SHOW_FULL_IMAGE_PATH, "true"); load(prefs, dialog.showFullImagePath, KEY_SHOW_FULL_IMAGE_PATH, "true");
load(prefs, dialog.nonLandPermanentsInOnePile, KEY_PERMANENTS_IN_ONE_PILE, "true"); load(prefs, dialog.nonLandPermanentsInOnePile, KEY_PERMANENTS_IN_ONE_PILE, "true");
load(prefs, dialog.showPlayerNamesPermanently, KEY_SHOW_PLAYER_NAMES_PERMANENTLY, "true"); load(prefs, dialog.showPlayerNamesPermanently, KEY_SHOW_PLAYER_NAMES_PERMANENTLY, "true");
load(prefs, dialog.displayLifeOnAvatar, KEY_DISPLAY_LIVE_ON_AVATAR, "true");
load(prefs, dialog.showAbilityPickerForced, KEY_SHOW_ABILITY_PICKER_FORCED, "true"); load(prefs, dialog.showAbilityPickerForced, KEY_SHOW_ABILITY_PICKER_FORCED, "true");
load(prefs, dialog.cbAllowRequestToShowHandCards, KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS, "true"); load(prefs, dialog.cbAllowRequestToShowHandCards, KEY_GAME_ALLOW_REQUEST_SHOW_HAND_CARDS, "true");
load(prefs, dialog.cbShowStormCounter, KEY_GAME_SHOW_STORM_COUNTER, "true"); load(prefs, dialog.cbShowStormCounter, KEY_GAME_SHOW_STORM_COUNTER, "true");
@ -3928,6 +3951,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
private javax.swing.JCheckBox checkBoxUpkeepYou; private javax.swing.JCheckBox checkBoxUpkeepYou;
private javax.swing.JPanel connection_servers; private javax.swing.JPanel connection_servers;
private javax.swing.JLabel controlsDescriptionLabel; private javax.swing.JLabel controlsDescriptionLabel;
private javax.swing.JCheckBox displayLifeOnAvatar;
private javax.swing.JButton exitButton; private javax.swing.JButton exitButton;
private javax.swing.JLabel fontSizeLabel; private javax.swing.JLabel fontSizeLabel;
private javax.swing.JPanel guiSizeBasic; private javax.swing.JPanel guiSizeBasic;

View file

@ -77,7 +77,6 @@ import mage.constants.ManaType;
import mage.counters.Counter; import mage.counters.Counter;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.designations.DesignationType; import mage.designations.DesignationType;
import mage.remote.Session;
import mage.utils.timer.PriorityTimer; import mage.utils.timer.PriorityTimer;
import mage.view.CardView; import mage.view.CardView;
import mage.view.ManaPoolView; import mage.view.ManaPoolView;
@ -93,13 +92,10 @@ public class PlayerPanelExt extends javax.swing.JPanel {
private UUID playerId; private UUID playerId;
private UUID gameId; private UUID gameId;
private Session session;
private PlayerView player; private PlayerView player;
private BigCard bigCard; private BigCard bigCard;
private static final int AVATAR_COUNT = 77;
private static final String DEFAULT_AVATAR_PATH = "/avatars/" + DEFAULT_AVATAR_ID + ".jpg"; private static final String DEFAULT_AVATAR_PATH = "/avatars/" + DEFAULT_AVATAR_ID + ".jpg";
private static final int PANEL_WIDTH = 94; private static final int PANEL_WIDTH = 94;
@ -179,8 +175,11 @@ public class PlayerPanelExt extends javax.swing.JPanel {
public void update(PlayerView player) { public void update(PlayerView player) {
this.player = player; this.player = player;
updateAvatar();
int playerLife = player.getLife(); int playerLife = player.getLife();
avatar.setCenterText("true".equals(MageFrame.getPreferences().get(PreferencesDialog.KEY_DISPLAY_LIVE_ON_AVATAR, "true"))
? String.valueOf(playerLife) : null);
updateAvatar();
if (playerLife > 99) { if (playerLife > 99) {
Font font = lifeLabel.getFont(); Font font = lifeLabel.getFont();
font = font.deriveFont(9f); font = font.deriveFont(9f);
@ -701,8 +700,6 @@ public class PlayerPanelExt extends javax.swing.JPanel {
.addComponent(btnPlayer, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(btnPlayer, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(timerLabel, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(timerLabel, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(avatar, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 80, Short.MAX_VALUE)) .addComponent(avatar, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 80, Short.MAX_VALUE))
// .addGroup(gl_panelBackground.createSequentialGroup()
// .addComponent(avatarFlag, GroupLayout.PREFERRED_SIZE, 16, GroupLayout.PREFERRED_SIZE))
.addGap(8)) .addGap(8))
.addGroup(gl_panelBackground.createSequentialGroup() .addGroup(gl_panelBackground.createSequentialGroup()
.addGap(6) .addGap(6)
@ -824,16 +821,12 @@ public class PlayerPanelExt extends javax.swing.JPanel {
protected void sizePlayerPanel(boolean smallMode) { protected void sizePlayerPanel(boolean smallMode) {
if (smallMode) { if (smallMode) {
avatar.setVisible(false); avatar.setVisible(false);
// avatarFlag.setVisible(false);
// monarchIcon.setVisible(false);
btnPlayer.setVisible(true); btnPlayer.setVisible(true);
timerLabel.setVisible(true); timerLabel.setVisible(true);
panelBackground.setPreferredSize(new Dimension(PANEL_WIDTH - 2, PANEL_HEIGHT_SMALL)); panelBackground.setPreferredSize(new Dimension(PANEL_WIDTH - 2, PANEL_HEIGHT_SMALL));
panelBackground.setBounds(0, 0, PANEL_WIDTH - 2, PANEL_HEIGHT_SMALL); panelBackground.setBounds(0, 0, PANEL_WIDTH - 2, PANEL_HEIGHT_SMALL);
} else { } else {
avatar.setVisible(true); avatar.setVisible(true);
// avatarFlag.setVisible(true);
// monarchIcon.setVisible(true);
btnPlayer.setVisible(false); btnPlayer.setVisible(false);
timerLabel.setVisible(false); timerLabel.setVisible(false);
panelBackground.setPreferredSize(new Dimension(PANEL_WIDTH - 2, PANEL_HEIGHT)); panelBackground.setPreferredSize(new Dimension(PANEL_WIDTH - 2, PANEL_HEIGHT));
@ -887,8 +880,6 @@ public class PlayerPanelExt extends javax.swing.JPanel {
} }
private HoverButton avatar; private HoverButton avatar;
// private JLabel avatarFlag;
// private JLabel monarchIcon;
private JButton btnPlayer; private JButton btnPlayer;
private ImagePanel life; private ImagePanel life;
private ImagePanel poison; private ImagePanel poison;
@ -918,7 +909,6 @@ public class PlayerPanelExt extends javax.swing.JPanel {
private JPanel energyExperiencePanel; private JPanel energyExperiencePanel;
private HoverButton exileZone; private HoverButton exileZone;
private HoverButton commandZone; private HoverButton commandZone;
private HoverButton enchantPlayerViewZone;
private final Map<String, JLabel> manaLabels = new HashMap<>(); private final Map<String, JLabel> manaLabels = new HashMap<>();
} }

View file

@ -26,10 +26,12 @@ import mage.cards.MageCard;
import mage.cards.action.ActionCallback; import mage.cards.action.ActionCallback;
import mage.cards.action.TransferData; import mage.cards.action.TransferData;
import mage.client.MageFrame; import mage.client.MageFrame;
import mage.client.MagePane;
import mage.client.SessionHandler; import mage.client.SessionHandler;
import mage.client.cards.BigCard; import mage.client.cards.BigCard;
import mage.client.components.MageComponents; import mage.client.components.MageComponents;
import mage.client.dialog.PreferencesDialog; import mage.client.dialog.PreferencesDialog;
import mage.client.game.GamePane;
import mage.client.plugins.impl.Plugins; import mage.client.plugins.impl.Plugins;
import mage.client.util.DefaultActionCallback; import mage.client.util.DefaultActionCallback;
import mage.client.util.gui.ArrowBuilder; import mage.client.util.gui.ArrowBuilder;
@ -367,6 +369,16 @@ public class MageActionCallback implements ActionCallback {
} }
private void handleOverNewView(TransferData data) { private void handleOverNewView(TransferData data) {
// Prevent to show tooltips from panes not in front
MagePane topPane = MageFrame.getTopMost(null);
if (topPane instanceof GamePane) {
if (!((GamePane) topPane).getGameId().equals(data.gameId)) {
return;
}
} else if (data.gameId != null) {
return;
}
hideTooltipPopup(); hideTooltipPopup();
cancelTimeout(); cancelTimeout();
Component parentComponent = SwingUtilities.getRoot(data.component); Component parentComponent = SwingUtilities.getRoot(data.component);

View file

@ -611,6 +611,10 @@ public final class ManaSymbols {
while (tok.hasMoreTokens()) { while (tok.hasMoreTokens()) {
String symbol = tok.nextToken(); String symbol = tok.nextToken();
Image image = sizedSymbols.get(symbol); Image image = sizedSymbols.get(symbol);
if (image == null && symbol != null) {
String symbol2 = "" + symbol.charAt(1) + symbol.charAt(0);
image = sizedSymbols.get(symbol2);
}
if (image == null) { if (image == null) {
// TEXT draw // TEXT draw

View file

@ -34,6 +34,7 @@ import mage.util.SubTypeList;
import mage.view.CardView; import mage.view.CardView;
import mage.view.PermanentView; import mage.view.PermanentView;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import static org.mage.card.arcane.ManaSymbols.getSizedManaSymbol;
/* /*
@ -119,6 +120,7 @@ public class ModernCardRenderer extends CardRenderer {
public static final BufferedImage BG_IMG_LAND = loadBackgroundImage("land"); public static final BufferedImage BG_IMG_LAND = loadBackgroundImage("land");
public static final BufferedImage BG_IMG_VEHICLE = loadBackgroundImage("vehicle"); public static final BufferedImage BG_IMG_VEHICLE = loadBackgroundImage("vehicle");
public static final BufferedImage BG_IMG_COLORLESS = loadBackgroundImage("colorless"); public static final BufferedImage BG_IMG_COLORLESS = loadBackgroundImage("colorless");
public static final BufferedImage BG_IMG_EXPEDITION = loadBackgroundImage("expedition");
public static final BufferedImage FRAME_INVENTION = loadFramePart("invention_frame"); public static final BufferedImage FRAME_INVENTION = loadFramePart("invention_frame");
@ -301,7 +303,11 @@ public class ModernCardRenderer extends CardRenderer {
// Just draw a brown rectangle // Just draw a brown rectangle
drawCardBack(g); drawCardBack(g);
} else { } else {
BufferedImage bg = getBackgroundImage(cardView.getColor(), cardView.getCardTypes(), cardView.getSubTypes()); boolean isExped = false;
if (cardView.getExpansionSetCode().equals("EXP")) {
isExped = true;
}
BufferedImage bg = getBackgroundImage(cardView.getColor(), cardView.getCardTypes(), cardView.getSubTypes(), isExped);
if (bg == null) { if (bg == null) {
return; return;
} }
@ -545,24 +551,13 @@ public class ModernCardRenderer extends CardRenderer {
if (!isZendikarFullArtLand()) { if (!isZendikarFullArtLand()) {
drawRulesText(g, textboxKeywords, textboxRules, drawRulesText(g, textboxKeywords, textboxRules,
totalContentInset + 2, typeLineY + boxHeight + 2, totalContentInset + 2, typeLineY + boxHeight + 2,
contentWidth - 4, cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3); contentWidth - 4, cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3, false);
} else { } else {
int x = totalContentInset; int x = totalContentInset;
int y = typeLineY + boxHeight + (cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3) / 2 - contentInset; int y = typeLineY + boxHeight + (cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3) / 2 - contentInset;
int w = contentWidth; int w = contentWidth;
int h = boxHeight - 4; int h = boxHeight - 4;
CardRendererUtils.drawZendikarLandBox(g,
x, y, w, h,
contentInset,
borderPaint, boxColor);
drawTypeLine(g, getCardSuperTypeLine(),
totalContentInset + contentInset, typeLineY + boxHeight + (cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3) / 2 - contentInset,
contentWidth / 2 - boxHeight, boxHeight - 4, false);
drawTypeLine(g, getCardSubTypeLine(),
totalContentInset + 4 * contentWidth / 7 + boxHeight, typeLineY + boxHeight + (cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3) / 2 - contentInset,
3 * contentWidth / 7 - boxHeight - contentInset, boxHeight - 4, true);
if (cardView.getFrameStyle() == FrameStyle.ZEN_FULL_ART_BASIC) { if (cardView.getFrameStyle() == FrameStyle.ZEN_FULL_ART_BASIC) {
// Draw curved lines (old Zendikar land style) - bigger (around 6%) inset on curve on bottom than inset (around 4.5%) on top... // Draw curved lines (old Zendikar land style) - bigger (around 6%) inset on curve on bottom than inset (around 4.5%) on top...
int x2 = x + contentWidth; int x2 = x + contentWidth;
@ -584,9 +579,49 @@ public class ModernCardRenderer extends CardRenderer {
boxColor, borderPaint); boxColor, borderPaint);
} }
// If an expedition, needs the rules box to be visible.
if (cardView.getExpansionSetCode().equals("EXP")) {
// Draw a small separator between the type line and box, and shadow
// at the left of the texbox, and above the name line
g.setPaint(textboxPaint);
float alpha = 0.55f;
AlphaComposite comp = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha);
Composite origc = g.getComposite();
g.setComposite(comp);
g.setBackground(new Color(155, 0, 0, 150));
g.fillRect(
totalContentInset + 1, typeLineY - boxHeight,
contentWidth - 2, cardHeight - borderWidth * 3 - typeLineY - 1);
g.setComposite(origc);
g.fillRect(
totalContentInset - 1, totalContentInset - 1,
contentWidth + 1, 1);
g.fillRect(
totalContentInset + 1, typeLineY - boxHeight,
contentWidth - 2, 1);
drawRulesText(g, textboxKeywords, textboxRules,
totalContentInset + 2, typeLineY - boxHeight,
contentWidth - 4, cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3, true);
}
CardRendererUtils.drawZendikarLandBox(g,
x, y, w, h,
contentInset,
borderPaint, boxColor);
drawTypeLine(g, getCardSuperTypeLine(),
totalContentInset + contentInset, typeLineY + boxHeight + (cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3) / 2 - contentInset,
contentWidth / 2 - boxHeight, boxHeight - 4, false);
drawTypeLine(g, getCardSubTypeLine(),
totalContentInset + 4 * contentWidth / 7 + boxHeight, typeLineY + boxHeight + (cardHeight - typeLineY - boxHeight - 4 - borderWidth * 3) / 2 - contentInset,
3 * contentWidth / 7 - boxHeight - contentInset, boxHeight - 4, true);
drawRulesText(g, textboxKeywords, textboxRules, drawRulesText(g, textboxKeywords, textboxRules,
x, y, x, y,
w, h); w, h, false);
} }
// Draw the bottom right stuff // Draw the bottom right stuff
@ -962,7 +997,7 @@ public class ModernCardRenderer extends CardRenderer {
return layout; return layout;
} }
protected void drawRulesText(Graphics2D g, ArrayList<TextboxRule> keywords, ArrayList<TextboxRule> rules, int x, int y, int w, int h) { protected void drawRulesText(Graphics2D g, ArrayList<TextboxRule> keywords, ArrayList<TextboxRule> rules, int x, int y, int w, int h, boolean forceRules) {
// Gather all rules to render // Gather all rules to render
List<TextboxRule> allRules = new ArrayList<>(rules); List<TextboxRule> allRules = new ArrayList<>(rules);
@ -974,14 +1009,19 @@ public class ModernCardRenderer extends CardRenderer {
} }
// Basic mana draw mana symbol in textbox (for basic lands) // Basic mana draw mana symbol in textbox (for basic lands)
if (allRules.size() == 1 && (allRules.get(0) instanceof TextboxBasicManaRule) && cardView.isLand() || isZendikarFullArtLand()) { if (!forceRules && (allRules.size() == 1 && (allRules.get(0) instanceof TextboxBasicManaRule) && cardView.isLand() || isZendikarFullArtLand())) {
if (!isZendikarFullArtLand()) { if (!isZendikarFullArtLand()) {
drawBasicManaTextbox(g, x, y, w, h, ((TextboxBasicManaRule) allRules.get(0)).getBasicManaSymbol()); drawBasicManaTextbox(g, x, y, w, h, ((TextboxBasicManaRule) allRules.get(0)).getBasicManaSymbol());
return; return;
} else // Big circle in the middle for Zendikar lands } else // Big circle in the middle for Zendikar lands
{
if (allRules.size() == 1) { if (allRules.size() == 1) {
// Size of mana symbol = 9/4 * h, 3/4h above line // Size of mana symbol = 9/4 * h, 3/4h above line
if (allRules.get(0) instanceof TextboxBasicManaRule) {
drawBasicManaSymbol(g, x + w / 2 - 9 * h / 8 + 1, y - 3 * h / 4, 9 * h / 4, 9 * h / 4, ((TextboxBasicManaRule) allRules.get(0)).getBasicManaSymbol()); drawBasicManaSymbol(g, x + w / 2 - 9 * h / 8 + 1, y - 3 * h / 4, 9 * h / 4, 9 * h / 4, ((TextboxBasicManaRule) allRules.get(0)).getBasicManaSymbol());
} else {
drawBasicManaSymbol(g, x + w / 2 - h - h / 8, y - 3 * h / 4, 9 * h / 4, 9 * h / 4, cardView.getFrameColor().toString());
}
return; return;
} else { } else {
if (allRules.size() > 1) { if (allRules.size() > 1) {
@ -990,6 +1030,7 @@ public class ModernCardRenderer extends CardRenderer {
return; return;
} }
} }
}
// Go through possible font sizes in descending order to find the best fit // Go through possible font sizes in descending order to find the best fit
RuleLayout bestLayout = null; RuleLayout bestLayout = null;
@ -1043,8 +1084,16 @@ public class ModernCardRenderer extends CardRenderer {
private void drawBasicManaSymbol(Graphics2D g, int x, int y, int w, int h, String symbol) { private void drawBasicManaSymbol(Graphics2D g, int x, int y, int w, int h, String symbol) {
String symbs = symbol; String symbs = symbol;
if (getSizedManaSymbol(symbol) != null) {
ManaSymbols.draw(g, symbs, x, y, w, Color.black, 2); ManaSymbols.draw(g, symbs, x, y, w, Color.black, 2);
} }
if (symbol.length() == 2) {
String symbs2 = "" + symbol.charAt(1) + symbol.charAt(0);
if (getSizedManaSymbol(symbs2) != null) {
ManaSymbols.draw(g, symbs2, x, y, w, Color.black, 2);
}
}
}
// Get the first line of the textbox, the keyword string // Get the first line of the textbox, the keyword string
private static String getKeywordRulesString(ArrayList<TextboxRule> keywords) { private static String getKeywordRulesString(ArrayList<TextboxRule> keywords) {
@ -1275,10 +1324,13 @@ public class ModernCardRenderer extends CardRenderer {
// Determine which background image to use from a set of colors // Determine which background image to use from a set of colors
// and the current card. // and the current card.
protected static BufferedImage getBackgroundImage(ObjectColor colors, Collection<CardType> types, SubTypeList subTypes) { protected static BufferedImage getBackgroundImage(ObjectColor colors, Collection<CardType> types, SubTypeList subTypes, boolean isExped) {
if (subTypes.contains(SubType.VEHICLE)) { if (subTypes.contains(SubType.VEHICLE)) {
return BG_IMG_VEHICLE; return BG_IMG_VEHICLE;
} else if (types.contains(CardType.LAND)) { } else if (types.contains(CardType.LAND)) {
if (isExped) {
return BG_IMG_EXPEDITION;
}
return BG_IMG_LAND; return BG_IMG_LAND;
} else if (types.contains(CardType.ARTIFACT)) { } else if (types.contains(CardType.ARTIFACT)) {
return BG_IMG_ARTIFACT; return BG_IMG_ARTIFACT;

View file

@ -272,7 +272,7 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
// Draw the textbox rules // Draw the textbox rules
drawRulesText(g, half.keywords, half.rules, drawRulesText(g, half.keywords, half.rules,
2, typeLineY + boxHeight + 2 - 4, 2, typeLineY + boxHeight + 2 - 4,
half.cw - 4, half.ch - typeLineY - boxHeight); half.cw - 4, half.ch - typeLineY - boxHeight, false);
} }
private Graphics2D getUnmodifiedHalfContext(Graphics2D g) { private Graphics2D getUnmodifiedHalfContext(Graphics2D g) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

View file

@ -27,18 +27,14 @@
*/ */
package mage.view; package mage.view;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.Serializable; import java.io.Serializable;
import java.io.BufferedWriter;
import java.io.PrintWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import mage.MageObject; import mage.MageObject;
import mage.abilities.costs.Cost; import mage.abilities.costs.Cost;
import mage.cards.Card; import mage.cards.Card;
@ -60,8 +56,6 @@ import mage.game.stack.StackObject;
import mage.players.Player; import mage.players.Player;
import mage.watchers.common.CastSpellLastTurnWatcher; import mage.watchers.common.CastSpellLastTurnWatcher;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
/** /**
* *
@ -105,7 +99,12 @@ public class GameView implements Serializable {
} }
} }
for (StackObject stackObject : state.getStack()) { for (StackObject stackObject : state.getStack()) {
if (stackObject instanceof StackAbility) { if (stackObject instanceof Spell) {
// Spell
CardView spellView = new CardView((Spell) stackObject, game, stackObject.getControllerId().equals(createdForPlayerId));
spellView.paid = ((Spell) stackObject).getSpellAbility().getManaCostsToPay().isPaid();
stack.put(stackObject.getId(), spellView);
} else if (stackObject instanceof StackAbility) {
// Stack Ability // Stack Ability
MageObject object = game.getObject(stackObject.getSourceId()); MageObject object = game.getObject(stackObject.getSourceId());
Card card = game.getCard(stackObject.getSourceId()); Card card = game.getCard(stackObject.getSourceId());
@ -161,9 +160,7 @@ public class GameView implements Serializable {
LOGGER.debug("Stack Object for stack ability not found: " + stackObject.getStackAbility().getRule()); LOGGER.debug("Stack Object for stack ability not found: " + stackObject.getStackAbility().getRule());
} }
} else { } else {
// Spell LOGGER.fatal("Unknown type of StackObject: " + stackObject.getName() + ' ' + stackObject.toString() + ' ' + stackObject.getClass().toString());
stack.put(stackObject.getId(), new CardView((Spell) stackObject, game, stackObject.getControllerId().equals(createdForPlayerId)));
checkPaid(stackObject.getId(), (Spell) stackObject);
} }
//stackOrder.add(stackObject.getId()); //stackOrder.add(stackObject.getId());
} }
@ -223,21 +220,6 @@ public class GameView implements Serializable {
cardView.paid = true; cardView.paid = true;
} }
private void checkPaid(UUID uuid, Spell spell) {
for (Cost cost : spell.getSpellAbility().getManaCostsToPay()) {
if (!cost.isPaid()) {
return;
}
}
CardView cardView = stack.get(uuid);
cardView.paid = true;
}
private void setPaid(UUID uuid) {
CardView cardView = stack.get(uuid);
cardView.paid = true;
}
private void updateLatestCardView(Game game, Card card, UUID stackId) { private void updateLatestCardView(Game game, Card card, UUID stackId) {
if (!card.isTransformable()) { if (!card.isTransformable()) {
return; return;

View file

@ -617,7 +617,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
} // end of for (allActions) } // end of for (allActions)
if (depth == maxDepth) { if (depth == maxDepth) {
logger.info(new StringBuilder("Sim Prio [").append(depth).append("] -- End for Max Depth -- Nodes calculated: ").append(SimulationNode2.nodeCount)); logger.info("Sim Prio [" + depth + "] -- End for Max Depth -- Nodes calculated: " + SimulationNode2.nodeCount);
} }
if (bestNode != null) { if (bestNode != null) {
node.children.clear(); node.children.clear();

View file

@ -49,7 +49,6 @@ public class AcrobaticManeuver extends CardImpl {
// Exile target creature you control, then return that card to the battlefield under its owner's control. // Exile target creature you control, then return that card to the battlefield under its owner's control.
this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent());
Effect effect = new ExileTargetForSourceEffect(); Effect effect = new ExileTargetForSourceEffect();
effect.setApplyEffectsAfter();
this.getSpellAbility().addEffect(effect); this.getSpellAbility().addEffect(effect);
this.getSpellAbility().addEffect(new ReturnToBattlefieldUnderOwnerControlTargetEffect()); this.getSpellAbility().addEffect(new ReturnToBattlefieldUnderOwnerControlTargetEffect());

View file

@ -56,10 +56,8 @@ public class Ambuscade extends CardImpl {
public Ambuscade(UUID ownerId, CardSetInfo setInfo) { public Ambuscade(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{G}"); super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{G}");
// Target creature you control gets +1/+0 until end of turn. // Target creature you control gets +1/+0 until end of turn.
Effect effect = new BoostTargetEffect(1, 0, Duration.EndOfTurn); Effect effect = new BoostTargetEffect(1, 0, Duration.EndOfTurn);
effect.setApplyEffectsAfter(); // needed to count the boost for the second effect
this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent());
this.getSpellAbility().addEffect(effect); this.getSpellAbility().addEffect(effect);

View file

@ -49,10 +49,9 @@ public class BarrelDownSokenzan extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}"); super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}");
this.subtype.add(SubType.ARCANE); this.subtype.add(SubType.ARCANE);
// Sweep - Return any number of Mountains you control to their owner's hand. Barrel Down Sokenzan deals damage to target creature equal to twice the number of Mountains returned this way. // Sweep - Return any number of Mountains you control to their owner's hand. Barrel Down Sokenzan deals damage to target creature equal to twice the number of Mountains returned this way.
this.getSpellAbility().addEffect(new SweepEffect(SubType.MOUNTAIN)); this.getSpellAbility().addEffect(new SweepEffect(SubType.MOUNTAIN));
DynamicValue sweepValue = new MultipliedValue(new SweepNumber("Mountain", false), 2); DynamicValue sweepValue = new MultipliedValue(new SweepNumber("Mountain"), 2);
this.getSpellAbility().addEffect(new DamageTargetEffect(sweepValue)); this.getSpellAbility().addEffect(new DamageTargetEffect(sweepValue));
this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addTarget(new TargetCreaturePermanent());
} }

View file

@ -65,7 +65,6 @@ public class BragoKingEternal extends CardImpl {
// When Brago, King Eternal deals combat damage to a player, exile any number of target nonland permanents you control, then return those cards to the battlefield under their owner's control. // When Brago, King Eternal deals combat damage to a player, exile any number of target nonland permanents you control, then return those cards to the battlefield under their owner's control.
Effect effect = new ExileTargetEffect(this.getId(), this.getName(), Zone.BATTLEFIELD); Effect effect = new ExileTargetEffect(this.getId(), this.getName(), Zone.BATTLEFIELD);
effect.setText("exile any number of target nonland permanents you control"); effect.setText("exile any number of target nonland permanents you control");
effect.setApplyEffectsAfter();
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(effect, false); Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(effect, false);
FilterControlledPermanent filterControlledNonlandPermanent = new FilterControlledPermanent(); FilterControlledPermanent filterControlledNonlandPermanent = new FilterControlledPermanent();
filterControlledNonlandPermanent.add(Predicates.not(new CardTypePredicate(CardType.LAND))); filterControlledNonlandPermanent.add(Predicates.not(new CardTypePredicate(CardType.LAND)));

View file

@ -42,12 +42,11 @@ import mage.target.common.TargetCreaturePermanent;
*/ */
public class CauldronHaze extends CardImpl { public class CauldronHaze extends CardImpl {
private String rule = "Choose any number of target creatures. Each of those creatures gains persist until end of turn"; private final String rule = "Choose any number of target creatures. Each of those creatures gains persist until end of turn";
public CauldronHaze(UUID ownerId, CardSetInfo setInfo) { public CauldronHaze(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W/B}"); super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W/B}");
// Choose any number of target creatures. Each of those creatures gains persist until end of turn. // Choose any number of target creatures. Each of those creatures gains persist until end of turn.
this.getSpellAbility().addEffect(new GainAbilityTargetEffect(new PersistAbility(), Duration.EndOfTurn, rule)); this.getSpellAbility().addEffect(new GainAbilityTargetEffect(new PersistAbility(), Duration.EndOfTurn, rule));
this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, Integer.MAX_VALUE)); this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, Integer.MAX_VALUE));

View file

@ -48,11 +48,10 @@ public class ChargeAcrossTheAraba extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{W}"); super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{W}");
this.subtype.add(SubType.ARCANE); this.subtype.add(SubType.ARCANE);
// Sweep - Return any number of Plains you control to their owner's hand. Creatures you control get +1/+1 until end of turn for each Plains returned this way. // Sweep - Return any number of Plains you control to their owner's hand. Creatures you control get +1/+1 until end of turn for each Plains returned this way.
this.getSpellAbility().addEffect(new SweepEffect(SubType.PLAINS)); this.getSpellAbility().addEffect(new SweepEffect(SubType.PLAINS));
DynamicValue sweepValue = new SweepNumber("Plains", true); DynamicValue sweepValue = new SweepNumber("Plains");
this.getSpellAbility().addEffect(new BoostControlledEffect(sweepValue, sweepValue, Duration.EndOfTurn)); this.getSpellAbility().addEffect(new BoostControlledEffect(sweepValue, sweepValue, Duration.EndOfTurn, null, false, true));
} }

View file

@ -58,7 +58,6 @@ public class ClearShot extends CardImpl {
// Target creature you control gets +1/+1 until end of turn. // Target creature you control gets +1/+1 until end of turn.
Effect effect = new BoostTargetEffect(1, 1, Duration.EndOfTurn); Effect effect = new BoostTargetEffect(1, 1, Duration.EndOfTurn);
effect.setApplyEffectsAfter(); // needed to count the boost for the second effect
this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent());
this.getSpellAbility().addEffect(effect); this.getSpellAbility().addEffect(effect);

View file

@ -48,7 +48,6 @@ public class Cloudshift extends CardImpl {
// Exile target creature you control, then return that card to the battlefield under your control. // Exile target creature you control, then return that card to the battlefield under your control.
this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent());
Effect effect = new ExileTargetForSourceEffect(); Effect effect = new ExileTargetForSourceEffect();
effect.setApplyEffectsAfter();
this.getSpellAbility().addEffect(effect); this.getSpellAbility().addEffect(effect);
this.getSpellAbility().addEffect(new ReturnToBattlefieldUnderYourControlTargetEffect(true)); this.getSpellAbility().addEffect(new ReturnToBattlefieldUnderYourControlTargetEffect(true));
} }

View file

@ -27,6 +27,7 @@
*/ */
package mage.cards.c; package mage.cards.c;
import java.util.UUID;
import mage.MageObject; import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
@ -41,8 +42,6 @@ import mage.players.Player;
import mage.target.TargetCard; import mage.target.TargetCard;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import java.util.UUID;
/** /**
* *
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
@ -96,11 +95,7 @@ class CultivateEffect extends OneShotEffect {
TargetCardInLibrary target = new TargetCardInLibrary(0, 2, StaticFilters.FILTER_BASIC_LAND_CARD); TargetCardInLibrary target = new TargetCardInLibrary(0, 2, StaticFilters.FILTER_BASIC_LAND_CARD);
if (controller.searchLibrary(target, game)) { if (controller.searchLibrary(target, game)) {
if (!target.getTargets().isEmpty()) { if (!target.getTargets().isEmpty()) {
Cards revealed = new CardsImpl(); Cards revealed = new CardsImpl(target.getTargets());
for (UUID cardId : target.getTargets()) {
Card card = controller.getLibrary().getCard(cardId, game);
revealed.add(card);
}
controller.revealCards(sourceObject.getIdName(), revealed, game); controller.revealCards(sourceObject.getIdName(), revealed, game);
if (target.getTargets().size() == 2) { if (target.getTargets().size() == 2) {
TargetCard target2 = new TargetCard(Zone.LIBRARY, filter); TargetCard target2 = new TargetCard(Zone.LIBRARY, filter);
@ -120,13 +115,10 @@ class CultivateEffect extends OneShotEffect {
controller.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, false, null); controller.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, false, null);
} }
} }
}
} }
controller.shuffleLibrary(source, game); controller.shuffleLibrary(source, game);
return true; return true;
}
controller.shuffleLibrary(source, game);
return false;
} }

View file

@ -0,0 +1,113 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.c;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.SuperType;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.SupertypePredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.Target;
import mage.target.common.TargetCreaturePermanent;
import mage.util.functions.EmptyApplyToPermanent;
/**
*
* @author jeffwadsworth
*/
public class Cytoshape extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nonlegendary creature");
static {
filter.add(Predicates.not(new SupertypePredicate(SuperType.LEGENDARY)));
}
public Cytoshape(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}{U}");
// Choose a nonlegendary creature on the battlefield. Target creature becomes a copy of that creature until end of turn.
this.getSpellAbility().addEffect(new CytoshapeEffect());
Target target = new TargetCreaturePermanent(1, 1, filter, true);
target.setTargetTag(1);
this.getSpellAbility().addTarget(target);
FilterCreaturePermanent filter2 = new FilterCreaturePermanent("target creature that will become a copy of that chosen creature");
target = new TargetCreaturePermanent(filter2);
target.setTargetTag(2);
this.getSpellAbility().addTarget(target);
}
public Cytoshape(final Cytoshape card) {
super(card);
}
@Override
public Cytoshape copy() {
return new Cytoshape(this);
}
}
class CytoshapeEffect extends OneShotEffect {
public CytoshapeEffect() {
super(Outcome.Copy);
this.staticText = "Choose a nonlegendary creature on the battlefield. Target creature becomes a copy of that creature until end of turn.";
}
public CytoshapeEffect(final CytoshapeEffect effect) {
super(effect);
}
@Override
public CytoshapeEffect copy() {
return new CytoshapeEffect(this);
}
@Override
public boolean apply(Game game, Ability ability) {
Permanent copyFrom = game.getPermanent(getTargetPointer().getFirst(game, ability));
if (copyFrom != null) {
Permanent copyTo = game.getPermanentOrLKIBattlefield(ability.getTargets().get(1).getFirstTarget());
if (copyTo != null) {
game.copyPermanent(Duration.EndOfTurn, copyFrom, copyTo.getId(), ability, new EmptyApplyToPermanent());
}
}
return true;
}
}

View file

@ -78,7 +78,6 @@ public class DromokasCommand extends CardImpl {
Mode mode = new Mode(); Mode mode = new Mode();
Effect effect = new SacrificeEffect(filterEnchantment, 1, "target player"); Effect effect = new SacrificeEffect(filterEnchantment, 1, "target player");
effect.setText("Target player sacrifices an enchantment"); effect.setText("Target player sacrifices an enchantment");
effect.setApplyEffectsAfter(); // so P/T chnaging effects take place before the fighting effect is applied
mode.getEffects().add(effect); mode.getEffects().add(effect);
mode.getTargets().add(new TargetPlayer()); mode.getTargets().add(new TargetPlayer());
this.getSpellAbility().getModes().addMode(mode); this.getSpellAbility().getModes().addMode(mode);
@ -87,7 +86,6 @@ public class DromokasCommand extends CardImpl {
mode = new Mode(); mode = new Mode();
effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance()); effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance());
effect.setText("Put a +1/+1 counter on target creature"); effect.setText("Put a +1/+1 counter on target creature");
effect.setApplyEffectsAfter(); // so the counter is taken into account if the target is also used in mode 4
mode.getEffects().add(effect); mode.getEffects().add(effect);
mode.getTargets().add(new TargetCreaturePermanent(filterCreature)); mode.getTargets().add(new TargetCreaturePermanent(filterCreature));
this.getSpellAbility().getModes().addMode(mode); this.getSpellAbility().getModes().addMode(mode);

View file

@ -69,7 +69,6 @@ public class EldraziDisplacer extends CardImpl {
// {2}{C}: Exile another target creature, then return it to the battlefield tapped under its owner's control. // {2}{C}: Exile another target creature, then return it to the battlefield tapped under its owner's control.
Effect effect = new ExileTargetForSourceEffect(); Effect effect = new ExileTargetForSourceEffect();
effect.setText("Exile another target creature"); effect.setText("Exile another target creature");
effect.setApplyEffectsAfter(); // Needed to let temporary continuous effects end if a permanent is blinked
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{2}{C}")); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{2}{C}"));
effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(true); effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(true);
effect.setText(", then return it to the battlefield tapped under its owner's control"); effect.setText(", then return it to the battlefield tapped under its owner's control");

View file

@ -40,15 +40,14 @@ import mage.game.permanent.token.AngelToken;
/** /**
* *
* @author noxx * @author noxx
*
*/ */
public class EntreatTheAngels extends CardImpl { public class EntreatTheAngels extends CardImpl {
public EntreatTheAngels(UUID ownerId, CardSetInfo setInfo) { public EntreatTheAngels(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{X}{W}{W}{W}"); super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{X}{W}{W}{W}");
// Create X 4/4 white Angel creature tokens with flying.
// create X 4/4 white Angel creature tokens with flying.
this.getSpellAbility().addEffect(new CreateTokenEffect(new AngelToken(), new ManacostVariableValue())); this.getSpellAbility().addEffect(new CreateTokenEffect(new AngelToken(), new ManacostVariableValue()));
// Miracle {X}{W}{W} // Miracle {X}{W}{W}

View file

@ -47,6 +47,7 @@ import mage.target.common.TargetCreaturePermanent;
* @author fireshoes * @author fireshoes
*/ */
public class EpicConfrontation extends CardImpl { public class EpicConfrontation extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you don't control"); private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you don't control");
static { static {
@ -58,7 +59,6 @@ public class EpicConfrontation extends CardImpl {
// Target creature you control gets +1/+2 until end of turn. It fights target creature you don't control. // Target creature you control gets +1/+2 until end of turn. It fights target creature you don't control.
Effect effect = new BoostTargetEffect(1, 2, Duration.EndOfTurn); Effect effect = new BoostTargetEffect(1, 2, Duration.EndOfTurn);
effect.setApplyEffectsAfter();
this.getSpellAbility().addEffect(effect); this.getSpellAbility().addEffect(effect);
effect = new FightTargetsEffect(); effect = new FightTargetsEffect();
effect.setText("It fights target creature you don't control"); effect.setText("It fights target creature you don't control");

View file

@ -59,7 +59,6 @@ public class EssenceFlux extends CardImpl {
// Exile target creature you control, then return that card to the battlefield under its owner's control. If it's a Spirit, put a +1/+1 counter on it. // Exile target creature you control, then return that card to the battlefield under its owner's control. If it's a Spirit, put a +1/+1 counter on it.
this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent());
Effect effect = new ExileTargetForSourceEffect(); Effect effect = new ExileTargetForSourceEffect();
effect.setApplyEffectsAfter();
this.getSpellAbility().addEffect(effect); this.getSpellAbility().addEffect(effect);
this.getSpellAbility().addEffect(new EssenceFluxEffect()); this.getSpellAbility().addEffect(new EssenceFluxEffect());
} }
@ -102,8 +101,7 @@ class EssenceFluxEffect extends OneShotEffect {
for (UUID targetId : this.getTargetPointer().getTargets(game, source)) { for (UUID targetId : this.getTargetPointer().getTargets(game, source)) {
if (exileZone.contains(targetId)) { if (exileZone.contains(targetId)) {
cardsToBattlefield.add(targetId); cardsToBattlefield.add(targetId);
} } else {
else {
Card card = game.getCard(targetId); Card card = game.getCard(targetId);
if (card != null && card instanceof MeldCard) { if (card != null && card instanceof MeldCard) {
MeldCard meldCard = (MeldCard) card; MeldCard meldCard = (MeldCard) card;

View file

@ -64,7 +64,6 @@ public class FelidarGuardian extends CardImpl {
// When Felidar Guardian enters the battlefield, you may exile another target permanent you control, then return that card to the battlefield under its owner's control. // When Felidar Guardian enters the battlefield, you may exile another target permanent you control, then return that card to the battlefield under its owner's control.
Effect effect = new ExileTargetForSourceEffect(); Effect effect = new ExileTargetForSourceEffect();
effect.setApplyEffectsAfter();
Ability ability = new EntersBattlefieldTriggeredAbility(effect, true); Ability ability = new EntersBattlefieldTriggeredAbility(effect, true);
ability.addEffect(new ReturnToBattlefieldUnderOwnerControlTargetEffect()); ability.addEffect(new ReturnToBattlefieldUnderOwnerControlTargetEffect());
ability.addTarget(new TargetControlledPermanent(filter)); ability.addTarget(new TargetControlledPermanent(filter));

View file

@ -51,7 +51,7 @@ import mage.target.common.TargetCreaturePermanent;
/** /**
* *
* @author LoneFox * @author LoneFox
*
*/ */
public class GrabTheReins extends CardImpl { public class GrabTheReins extends CardImpl {
@ -64,7 +64,6 @@ public class GrabTheReins extends CardImpl {
// Until end of turn, you gain control of target creature and it gains haste; // Until end of turn, you gain control of target creature and it gains haste;
Effect effect = new GainControlTargetEffect(Duration.EndOfTurn); Effect effect = new GainControlTargetEffect(Duration.EndOfTurn);
effect.setText("Until end of turn, you gain control of target creature"); effect.setText("Until end of turn, you gain control of target creature");
effect.setApplyEffectsAfter();
this.getSpellAbility().addEffect(effect); this.getSpellAbility().addEffect(effect);
effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn); effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn);
effect.setText("and it gains haste"); effect.setText("and it gains haste");
@ -133,8 +132,7 @@ class GrabTheReinsEffect extends OneShotEffect {
player.damage(amount, source.getSourceId(), game, false, true); player.damage(amount, source.getSourceId(), game, false, true);
return true; return true;
} }
} } else {
else {
return true; return true;
} }
} }

View file

@ -53,6 +53,7 @@ public class HuntTheHunter extends CardImpl {
private static final FilterControlledCreaturePermanent filterControlledGreen = new FilterControlledCreaturePermanent("green creature you control"); private static final FilterControlledCreaturePermanent filterControlledGreen = new FilterControlledCreaturePermanent("green creature you control");
private static final FilterCreaturePermanent filterOpponentGreen = new FilterCreaturePermanent("green creature an opponent controls"); private static final FilterCreaturePermanent filterOpponentGreen = new FilterCreaturePermanent("green creature an opponent controls");
static { static {
filterControlledGreen.add(new ColorPredicate(ObjectColor.GREEN)); filterControlledGreen.add(new ColorPredicate(ObjectColor.GREEN));
filterOpponentGreen.add(new ControllerPredicate(TargetController.OPPONENT)); filterOpponentGreen.add(new ControllerPredicate(TargetController.OPPONENT));
@ -62,10 +63,8 @@ public class HuntTheHunter extends CardImpl {
public HuntTheHunter(UUID ownerId, CardSetInfo setInfo) { public HuntTheHunter(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{G}"); super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{G}");
// Target green creature you control gets +2/+2 until end of turn. It fights target green creature an opponent controls. // Target green creature you control gets +2/+2 until end of turn. It fights target green creature an opponent controls.
Effect effect = new BoostTargetEffect(2, 2, Duration.EndOfTurn); Effect effect = new BoostTargetEffect(2, 2, Duration.EndOfTurn);
effect.setApplyEffectsAfter();
this.getSpellAbility().addEffect(effect); this.getSpellAbility().addEffect(effect);
this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(1, 1, filterControlledGreen, false)); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(1, 1, filterControlledGreen, false));

View file

@ -49,6 +49,7 @@ import mage.target.common.TargetCreaturePermanent;
public class HuntTheWeak extends CardImpl { public class HuntTheWeak extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you don't control"); private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you don't control");
static { static {
filter.add(new ControllerPredicate(TargetController.NOT_YOU)); filter.add(new ControllerPredicate(TargetController.NOT_YOU));
} }
@ -56,10 +57,8 @@ public class HuntTheWeak extends CardImpl {
public HuntTheWeak(UUID ownerId, CardSetInfo setInfo) { public HuntTheWeak(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{G}"); super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{G}");
// Put a +1/+1 counter on target creature you control. Then that creature fights target creature you don't control. // Put a +1/+1 counter on target creature you control. Then that creature fights target creature you don't control.
Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance()); Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance());
effect.setApplyEffectsAfter();
this.getSpellAbility().addEffect(effect); this.getSpellAbility().addEffect(effect);
effect = new FightTargetsEffect(); effect = new FightTargetsEffect();
effect.setText("Then that creature fights target creature you don't control"); effect.setText("Then that creature fights target creature you don't control");

View file

@ -64,7 +64,6 @@ public class NissasJudgment extends CardImpl {
// Support 2. // Support 2.
Effect effect = new SupportEffect(this, 2, false); Effect effect = new SupportEffect(this, 2, false);
effect.setApplyEffectsAfter();
getSpellAbility().addEffect(effect); getSpellAbility().addEffect(effect);
// Choose up to one target creature an opponent controls. Each creature you control with a +1/+1 counter on it deals damage equal to its power to that creature. // Choose up to one target creature an opponent controls. Each creature you control with a +1/+1 counter on it deals damage equal to its power to that creature.

View file

@ -49,11 +49,10 @@ public class PlowThroughReito extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}");
this.subtype.add(SubType.ARCANE); this.subtype.add(SubType.ARCANE);
// Sweep - Return any number of Plains you control to their owner's hand. Target creature gets +1/+1 until end of turn for each Plains returned this way. // Sweep - Return any number of Plains you control to their owner's hand. Target creature gets +1/+1 until end of turn for each Plains returned this way.
this.getSpellAbility().addEffect(new SweepEffect(SubType.PLAINS)); this.getSpellAbility().addEffect(new SweepEffect(SubType.PLAINS));
DynamicValue sweepValue = new SweepNumber("Plains", true); DynamicValue sweepValue = new SweepNumber("Plains");
this.getSpellAbility().addEffect(new BoostTargetEffect(sweepValue, sweepValue, Duration.EndOfTurn)); this.getSpellAbility().addEffect(new BoostTargetEffect(sweepValue, sweepValue, Duration.EndOfTurn, true));
this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addTarget(new TargetCreaturePermanent());
} }

View file

@ -45,7 +45,6 @@ import mage.target.Target;
import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetControlledCreaturePermanent;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
/** /**
* *
* @author LevelX2 * @author LevelX2
@ -66,7 +65,6 @@ public class SavagePunch extends CardImpl {
new BoostTargetEffect(2, 2, Duration.EndOfTurn), new BoostTargetEffect(2, 2, Duration.EndOfTurn),
new LockedInCondition(FerociousCondition.instance), new LockedInCondition(FerociousCondition.instance),
"<i>Ferocious</i> &mdash; The creature you control gets +2/+2 until end of turn before it fights if you control a creature with power 4 or greater"); "<i>Ferocious</i> &mdash; The creature you control gets +2/+2 until end of turn before it fights if you control a creature with power 4 or greater");
effect.setApplyEffectsAfter();
this.getSpellAbility().addEffect(effect); this.getSpellAbility().addEffect(effect);
// Target creature you control fights target creature you don't control. // Target creature you control fights target creature you don't control.

View file

@ -75,7 +75,6 @@ public class SavageStomp extends CardImpl {
// Put a +1/+1 counter on target creature you control. Then that creature fights target creature you don't control. // Put a +1/+1 counter on target creature you control. Then that creature fights target creature you don't control.
Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance()); Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance());
effect.setApplyEffectsAfter();
this.getSpellAbility().addEffect(effect); this.getSpellAbility().addEffect(effect);
effect = new FightTargetsEffect(); effect = new FightTargetsEffect();
effect.setText("Then that creature fights target creature you don't control"); effect.setText("Then that creature fights target creature you don't control");

View file

@ -48,10 +48,9 @@ public class SinkIntoTakenuma extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}"); super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}");
this.subtype.add(SubType.ARCANE); this.subtype.add(SubType.ARCANE);
// Sweep - Return any number of Swamps you control to their owner's hand. Target player discards a card for each Swamp returned this way. // Sweep - Return any number of Swamps you control to their owner's hand. Target player discards a card for each Swamp returned this way.
this.getSpellAbility().addEffect(new SweepEffect(SubType.SWAMP)); this.getSpellAbility().addEffect(new SweepEffect(SubType.SWAMP));
DynamicValue sweepValue = new SweepNumber("Swamp", false); DynamicValue sweepValue = new SweepNumber("Swamp");
this.getSpellAbility().addEffect(new DiscardTargetEffect(sweepValue)); this.getSpellAbility().addEffect(new DiscardTargetEffect(sweepValue));
this.getSpellAbility().addTarget(new TargetPlayer()); this.getSpellAbility().addTarget(new TargetPlayer());
} }

View file

@ -36,7 +36,6 @@ import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.common.ChooseOpponentEffect; import mage.abilities.effects.common.ChooseOpponentEffect;
import mage.constants.SubType;
import mage.abilities.keyword.TrampleAbility; import mage.abilities.keyword.TrampleAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
@ -45,6 +44,7 @@ import mage.constants.Duration;
import mage.constants.Layer; import mage.constants.Layer;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubLayer; import mage.constants.SubLayer;
import mage.constants.SubType;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.common.FilterLandPermanent; import mage.filter.common.FilterLandPermanent;
import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.filter.predicate.permanent.ControllerIdPredicate;
@ -107,7 +107,7 @@ class SkyshroudWarBeastEffect extends ContinuousEffectImpl {
MageObject target = game.getObject(source.getSourceId()); MageObject target = game.getObject(source.getSourceId());
if (target != null) { if (target != null) {
UUID playerId = (UUID) game.getState().getValue(source.getSourceId().toString() + ChooseOpponentEffect.VALUE_KEY); UUID playerId = (UUID) game.getState().getValue(source.getSourceId().toString() + ChooseOpponentEffect.VALUE_KEY);
FilterLandPermanent filter = new FilterLandPermanent(); FilterLandPermanent filter = FilterLandPermanent.nonbasicLand();
filter.add(new ControllerIdPredicate(playerId)); filter.add(new ControllerIdPredicate(playerId));
int number = new PermanentsOnBattlefieldCount(filter).calculate(game, source, this); int number = new PermanentsOnBattlefieldCount(filter).calculate(game, source, this);
target.getPower().setValue(number); target.getPower().setValue(number);

View file

@ -27,6 +27,7 @@
*/ */
package mage.cards.s; package mage.cards.s;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
@ -37,8 +38,6 @@ import mage.constants.*;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import java.util.UUID;
/** /**
* *
* @author LevelX2 * @author LevelX2
@ -50,7 +49,6 @@ public class StartYourEngines extends CardImpl {
// Vehicles you control becomes artifact creatures until end of turn. // Vehicles you control becomes artifact creatures until end of turn.
Effect effect = new StartYourEnginesEffect(); Effect effect = new StartYourEnginesEffect();
effect.setApplyEffectsAfter(); // needed to recognize vehicle as creatures by the next effect
this.getSpellAbility().addEffect(effect); this.getSpellAbility().addEffect(effect);
// Creatures you control get +2/+0 until end of turn. // Creatures you control get +2/+0 until end of turn.

View file

@ -49,6 +49,7 @@ import mage.target.common.TargetCreaturePermanent;
public class SwiftKick extends CardImpl { public class SwiftKick extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you don't control"); private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you don't control");
static { static {
filter.add(new ControllerPredicate(TargetController.NOT_YOU)); filter.add(new ControllerPredicate(TargetController.NOT_YOU));
} }
@ -56,10 +57,8 @@ public class SwiftKick extends CardImpl {
public SwiftKick(UUID ownerId, CardSetInfo setInfo) { public SwiftKick(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{R}"); super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{R}");
// Target creature you control gets +1/+0 until end of turn. It fights target creature you don't control. // Target creature you control gets +1/+0 until end of turn. It fights target creature you don't control.
Effect effect = new BoostTargetEffect(1, 0, Duration.EndOfTurn); Effect effect = new BoostTargetEffect(1, 0, Duration.EndOfTurn);
effect.setApplyEffectsAfter();
this.getSpellAbility().addEffect(effect); this.getSpellAbility().addEffect(effect);
this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent());

View file

@ -132,7 +132,7 @@ class SylvanLibraryEffect extends OneShotEffect {
} }
} }
} }
controller.putCardsOnTopOfLibrary(cardsPutBack, game, source, applyEffectsAfter); controller.putCardsOnTopOfLibrary(cardsPutBack, game, source, false);
} }
} }
return true; return true;

View file

@ -66,11 +66,9 @@ public class TemurCharm extends CardImpl {
public TemurCharm(UUID ownerId, CardSetInfo setInfo) { public TemurCharm(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{G}{U}{R}"); super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{G}{U}{R}");
// Choose one - // Choose one -
// <strong><EFBFBD></strong> Target creature you control gets +1/+1 until end of turn. That creature fights target creature you don't control. // <strong><EFBFBD></strong> Target creature you control gets +1/+1 until end of turn. That creature fights target creature you don't control.
Effect effect = new BoostTargetEffect(1, 1, Duration.EndOfTurn); Effect effect = new BoostTargetEffect(1, 1, Duration.EndOfTurn);
effect.setApplyEffectsAfter();
this.getSpellAbility().addEffect(effect); this.getSpellAbility().addEffect(effect);
effect = new FightTargetsEffect(); effect = new FightTargetsEffect();
effect.setText("That creature fights target creature you don't control"); effect.setText("That creature fights target creature you don't control");

View file

@ -58,7 +58,6 @@ public class WildInstincts extends CardImpl {
// Target creature you control gets +2/+2 until end of turn. It fights target creature an opponent controls. // Target creature you control gets +2/+2 until end of turn. It fights target creature an opponent controls.
Effect effect = new BoostTargetEffect(2, 2, Duration.EndOfTurn); Effect effect = new BoostTargetEffect(2, 2, Duration.EndOfTurn);
effect.setApplyEffectsAfter();
getSpellAbility().addEffect(effect); getSpellAbility().addEffect(effect);
getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); getSpellAbility().addTarget(new TargetControlledCreaturePermanent());
effect = new FightTargetsEffect(); effect = new FightTargetsEffect();

View file

@ -42,8 +42,8 @@ import mage.cards.Cards;
import mage.cards.CardsImpl; import mage.cards.CardsImpl;
import mage.cards.MeldCard; import mage.cards.MeldCard;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.permanent.AnotherPredicate; import mage.filter.predicate.permanent.AnotherPredicate;
@ -76,7 +76,6 @@ public class WispweaverAngel extends CardImpl {
// When Wispweaver Angel enters the battlefield, you may exile another target creature you control, then return that card to the battlefield under its owner's control. // When Wispweaver Angel enters the battlefield, you may exile another target creature you control, then return that card to the battlefield under its owner's control.
Effect effect = new ExileTargetForSourceEffect(); Effect effect = new ExileTargetForSourceEffect();
effect.setApplyEffectsAfter();
Ability ability = new EntersBattlefieldTriggeredAbility(effect, true); Ability ability = new EntersBattlefieldTriggeredAbility(effect, true);
ability.addTarget(new TargetControlledCreaturePermanent(1, 1, filter, false)); ability.addTarget(new TargetControlledCreaturePermanent(1, 1, filter, false));
ability.addEffect(new WispweaverAngelEffect()); ability.addEffect(new WispweaverAngelEffect());

View file

@ -85,6 +85,7 @@ public class Dissension extends ExpansionSet {
cards.add(new SetCardInfo("Crypt Champion", 40, Rarity.UNCOMMON, mage.cards.c.CryptChampion.class)); cards.add(new SetCardInfo("Crypt Champion", 40, Rarity.UNCOMMON, mage.cards.c.CryptChampion.class));
cards.add(new SetCardInfo("Cytoplast Manipulator", 23, Rarity.RARE, mage.cards.c.CytoplastManipulator.class)); cards.add(new SetCardInfo("Cytoplast Manipulator", 23, Rarity.RARE, mage.cards.c.CytoplastManipulator.class));
cards.add(new SetCardInfo("Cytoplast Root-Kin", 81, Rarity.RARE, mage.cards.c.CytoplastRootKin.class)); cards.add(new SetCardInfo("Cytoplast Root-Kin", 81, Rarity.RARE, mage.cards.c.CytoplastRootKin.class));
cards.add(new SetCardInfo("Cytoshape", 108, Rarity.RARE, mage.cards.c.Cytoshape.class));
cards.add(new SetCardInfo("Cytospawn Shambler", 82, Rarity.COMMON, mage.cards.c.CytospawnShambler.class)); cards.add(new SetCardInfo("Cytospawn Shambler", 82, Rarity.COMMON, mage.cards.c.CytospawnShambler.class));
cards.add(new SetCardInfo("Delirium Skeins", 41, Rarity.COMMON, mage.cards.d.DeliriumSkeins.class)); cards.add(new SetCardInfo("Delirium Skeins", 41, Rarity.COMMON, mage.cards.d.DeliriumSkeins.class));
cards.add(new SetCardInfo("Demonfire", 60, Rarity.RARE, mage.cards.d.Demonfire.class)); cards.add(new SetCardInfo("Demonfire", 60, Rarity.RARE, mage.cards.d.Demonfire.class));

View file

@ -47,50 +47,50 @@ public class ZendikarExpeditions extends ExpansionSet {
super("Zendikar Expeditions", "EXP", ExpansionSet.buildDate(2015, 10, 2), SetType.PROMOTIONAL); super("Zendikar Expeditions", "EXP", ExpansionSet.buildDate(2015, 10, 2), SetType.PROMOTIONAL);
this.hasBoosters = false; this.hasBoosters = false;
this.hasBasicLands = false; this.hasBasicLands = false;
cards.add(new SetCardInfo("Ancient Tomb", 36, Rarity.MYTHIC, mage.cards.a.AncientTomb.class)); cards.add(new SetCardInfo("Ancient Tomb", 36, Rarity.MYTHIC, mage.cards.a.AncientTomb.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Arid Mesa", 24, Rarity.MYTHIC, mage.cards.a.AridMesa.class)); cards.add(new SetCardInfo("Arid Mesa", 24, Rarity.MYTHIC, mage.cards.a.AridMesa.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Blood Crypt", 8, Rarity.MYTHIC, mage.cards.b.BloodCrypt.class)); cards.add(new SetCardInfo("Blood Crypt", 8, Rarity.MYTHIC, mage.cards.b.BloodCrypt.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Bloodstained Mire", 18, Rarity.MYTHIC, mage.cards.b.BloodstainedMire.class)); cards.add(new SetCardInfo("Bloodstained Mire", 18, Rarity.MYTHIC, mage.cards.b.BloodstainedMire.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Breeding Pool", 15, Rarity.MYTHIC, mage.cards.b.BreedingPool.class)); cards.add(new SetCardInfo("Breeding Pool", 15, Rarity.MYTHIC, mage.cards.b.BreedingPool.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Canopy Vista", 5, Rarity.MYTHIC, mage.cards.c.CanopyVista.class)); cards.add(new SetCardInfo("Canopy Vista", 5, Rarity.MYTHIC, mage.cards.c.CanopyVista.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Cascade Bluffs", 32, Rarity.MYTHIC, mage.cards.c.CascadeBluffs.class)); cards.add(new SetCardInfo("Cascade Bluffs", 32, Rarity.MYTHIC, mage.cards.c.CascadeBluffs.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Cinder Glade", 4, Rarity.MYTHIC, mage.cards.c.CinderGlade.class)); cards.add(new SetCardInfo("Cinder Glade", 4, Rarity.MYTHIC, mage.cards.c.CinderGlade.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Dust Bowl", 37, Rarity.MYTHIC, mage.cards.d.DustBowl.class)); cards.add(new SetCardInfo("Dust Bowl", 37, Rarity.MYTHIC, mage.cards.d.DustBowl.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Eye of Ugin", 38, Rarity.MYTHIC, mage.cards.e.EyeOfUgin.class)); cards.add(new SetCardInfo("Eye of Ugin", 38, Rarity.MYTHIC, mage.cards.e.EyeOfUgin.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Fetid Heath", 31, Rarity.MYTHIC, mage.cards.f.FetidHeath.class)); cards.add(new SetCardInfo("Fetid Heath", 31, Rarity.MYTHIC, mage.cards.f.FetidHeath.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Fire-Lit Thicket", 29, Rarity.MYTHIC, mage.cards.f.FireLitThicket.class)); cards.add(new SetCardInfo("Fire-Lit Thicket", 29, Rarity.MYTHIC, mage.cards.f.FireLitThicket.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Flooded Grove", 35, Rarity.MYTHIC, mage.cards.f.FloodedGrove.class)); cards.add(new SetCardInfo("Flooded Grove", 35, Rarity.MYTHIC, mage.cards.f.FloodedGrove.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Flooded Strand", 16, Rarity.MYTHIC, mage.cards.f.FloodedStrand.class)); cards.add(new SetCardInfo("Flooded Strand", 16, Rarity.MYTHIC, mage.cards.f.FloodedStrand.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Forbidden Orchard", 39, Rarity.MYTHIC, mage.cards.f.ForbiddenOrchard.class)); cards.add(new SetCardInfo("Forbidden Orchard", 39, Rarity.MYTHIC, mage.cards.f.ForbiddenOrchard.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Godless Shrine", 11, Rarity.MYTHIC, mage.cards.g.GodlessShrine.class)); cards.add(new SetCardInfo("Godless Shrine", 11, Rarity.MYTHIC, mage.cards.g.GodlessShrine.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Graven Cairns", 28, Rarity.MYTHIC, mage.cards.g.GravenCairns.class)); cards.add(new SetCardInfo("Graven Cairns", 28, Rarity.MYTHIC, mage.cards.g.GravenCairns.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Hallowed Fountain", 6, Rarity.MYTHIC, mage.cards.h.HallowedFountain.class)); cards.add(new SetCardInfo("Hallowed Fountain", 6, Rarity.MYTHIC, mage.cards.h.HallowedFountain.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Horizon Canopy", 40, Rarity.MYTHIC, mage.cards.h.HorizonCanopy.class)); cards.add(new SetCardInfo("Horizon Canopy", 40, Rarity.MYTHIC, mage.cards.h.HorizonCanopy.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Kor Haven", 41, Rarity.MYTHIC, mage.cards.k.KorHaven.class)); cards.add(new SetCardInfo("Kor Haven", 41, Rarity.MYTHIC, mage.cards.k.KorHaven.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Mana Confluence", 42, Rarity.MYTHIC, mage.cards.m.ManaConfluence.class)); cards.add(new SetCardInfo("Mana Confluence", 42, Rarity.MYTHIC, mage.cards.m.ManaConfluence.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Marsh Flats", 21, Rarity.MYTHIC, mage.cards.m.MarshFlats.class)); cards.add(new SetCardInfo("Marsh Flats", 21, Rarity.MYTHIC, mage.cards.m.MarshFlats.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Misty Rainforest", 25, Rarity.MYTHIC, mage.cards.m.MistyRainforest.class)); cards.add(new SetCardInfo("Misty Rainforest", 25, Rarity.MYTHIC, mage.cards.m.MistyRainforest.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Mystic Gate", 26, Rarity.MYTHIC, mage.cards.m.MysticGate.class)); cards.add(new SetCardInfo("Mystic Gate", 26, Rarity.MYTHIC, mage.cards.m.MysticGate.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Overgrown Tomb", 13, Rarity.MYTHIC, mage.cards.o.OvergrownTomb.class)); cards.add(new SetCardInfo("Overgrown Tomb", 13, Rarity.MYTHIC, mage.cards.o.OvergrownTomb.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Polluted Delta", 17, Rarity.MYTHIC, mage.cards.p.PollutedDelta.class)); cards.add(new SetCardInfo("Polluted Delta", 17, Rarity.MYTHIC, mage.cards.p.PollutedDelta.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Prairie Stream", 1, Rarity.MYTHIC, mage.cards.p.PrairieStream.class)); cards.add(new SetCardInfo("Prairie Stream", 1, Rarity.MYTHIC, mage.cards.p.PrairieStream.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Rugged Prairie", 34, Rarity.MYTHIC, mage.cards.r.RuggedPrairie.class)); cards.add(new SetCardInfo("Rugged Prairie", 34, Rarity.MYTHIC, mage.cards.r.RuggedPrairie.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Sacred Foundry", 14, Rarity.MYTHIC, mage.cards.s.SacredFoundry.class)); cards.add(new SetCardInfo("Sacred Foundry", 14, Rarity.MYTHIC, mage.cards.s.SacredFoundry.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Scalding Tarn", 22, Rarity.MYTHIC, mage.cards.s.ScaldingTarn.class)); cards.add(new SetCardInfo("Scalding Tarn", 22, Rarity.MYTHIC, mage.cards.s.ScaldingTarn.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Smoldering Marsh", 3, Rarity.MYTHIC, mage.cards.s.SmolderingMarsh.class)); cards.add(new SetCardInfo("Smoldering Marsh", 3, Rarity.MYTHIC, mage.cards.s.SmolderingMarsh.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Steam Vents", 12, Rarity.MYTHIC, mage.cards.s.SteamVents.class)); cards.add(new SetCardInfo("Steam Vents", 12, Rarity.MYTHIC, mage.cards.s.SteamVents.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Stomping Ground", 9, Rarity.MYTHIC, mage.cards.s.StompingGround.class)); cards.add(new SetCardInfo("Stomping Ground", 9, Rarity.MYTHIC, mage.cards.s.StompingGround.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Strip Mine", 43, Rarity.MYTHIC, mage.cards.s.StripMine.class)); cards.add(new SetCardInfo("Strip Mine", 43, Rarity.MYTHIC, mage.cards.s.StripMine.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Sunken Hollow", 2, Rarity.MYTHIC, mage.cards.s.SunkenHollow.class)); cards.add(new SetCardInfo("Sunken Hollow", 2, Rarity.MYTHIC, mage.cards.s.SunkenHollow.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Sunken Ruins", 27, Rarity.MYTHIC, mage.cards.s.SunkenRuins.class)); cards.add(new SetCardInfo("Sunken Ruins", 27, Rarity.MYTHIC, mage.cards.s.SunkenRuins.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Tectonic Edge", 44, Rarity.MYTHIC, mage.cards.t.TectonicEdge.class)); cards.add(new SetCardInfo("Tectonic Edge", 44, Rarity.MYTHIC, mage.cards.t.TectonicEdge.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Temple Garden", 10, Rarity.MYTHIC, mage.cards.t.TempleGarden.class)); cards.add(new SetCardInfo("Temple Garden", 10, Rarity.MYTHIC, mage.cards.t.TempleGarden.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Twilight Mire", 33, Rarity.MYTHIC, mage.cards.t.TwilightMire.class)); cards.add(new SetCardInfo("Twilight Mire", 33, Rarity.MYTHIC, mage.cards.t.TwilightMire.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Verdant Catacombs", 23, Rarity.MYTHIC, mage.cards.v.VerdantCatacombs.class)); cards.add(new SetCardInfo("Verdant Catacombs", 23, Rarity.MYTHIC, mage.cards.v.VerdantCatacombs.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Wasteland", 45, Rarity.MYTHIC, mage.cards.w.Wasteland.class)); cards.add(new SetCardInfo("Wasteland", 45, Rarity.MYTHIC, mage.cards.w.Wasteland.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Watery Grave", 7, Rarity.MYTHIC, mage.cards.w.WateryGrave.class)); cards.add(new SetCardInfo("Watery Grave", 7, Rarity.MYTHIC, mage.cards.w.WateryGrave.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Windswept Heath", 20, Rarity.MYTHIC, mage.cards.w.WindsweptHeath.class)); cards.add(new SetCardInfo("Windswept Heath", 20, Rarity.MYTHIC, mage.cards.w.WindsweptHeath.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Wooded Bastion", 30, Rarity.MYTHIC, mage.cards.w.WoodedBastion.class)); cards.add(new SetCardInfo("Wooded Bastion", 30, Rarity.MYTHIC, mage.cards.w.WoodedBastion.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Wooded Foothills", 19, Rarity.MYTHIC, mage.cards.w.WoodedFoothills.class)); cards.add(new SetCardInfo("Wooded Foothills", 19, Rarity.MYTHIC, mage.cards.w.WoodedFoothills.class, FULL_ART_BFZ_VARIOUS));
} }
} }

View file

@ -31,5 +31,52 @@ public class AnnihilatorTest extends CardTestPlayerBase {
assertPermanentCount(playerA, 1); assertPermanentCount(playerA, 1);
} }
/**
* I was attacked with an It that Betrays while i had an Academy Rector and
* with the annihilator trigger on the stack i cast Cauldron Haze targeting
* academy rector then sacrificed her to the annihilator trigger and chose
* not to exile her. My persist resolved before the second ability of it
* that betrays because i was not the active player, the game log shows:
*
* 9:18 AM: Ability triggers: Academy Rector [e15] - Persist (When this
* creature dies, if it had no -1/-1 counters on it, return it to the
* battlefield under its owner's control with a -1/-1 counter on it.)
*
* 9:19 AM: EllNubNub puts Academy Rector [e15] from graveyard onto the
* Battlefield
*
* 9:20 AM: hellmo puts Academy Rector [e15] from battlefield onto the
* Battlefield
*
* The It that Betrays trigger should have fissled, instead it stole her
* from my battlefield and removed the persist counter.
*/
@Test
public void testCardItThatBetrays() {
addCard(Zone.BATTLEFIELD, playerA, "Plains", 2);
// Choose any number of target creatures. Each of those creatures gains persist until end of turn.
// Persist (When this creature dies, if it had no -1/-1 counters on it, return it to the battlefield under its owner's control with a -1/-1 counter on it.)
addCard(Zone.HAND, playerA, "Cauldron Haze", 1); // Instant {1}{W/B}
// When Academy Rector dies, you may exile it. If you do, search your library for an enchantment card, put that card onto the battlefield, then shuffle your library.
addCard(Zone.BATTLEFIELD, playerA, "Academy Rector", 1);
// Annihilator 2 (Whenever this creature attacks, defending player sacrifices two permanents.)
// Whenever an opponent sacrifices a nontoken permanent, put that card onto the battlefield under your control.
addCard(Zone.BATTLEFIELD, playerB, "It That Betrays");
attack(2, playerB, "It That Betrays");
setChoice(playerA, "Academy Rector"); // Annihilator
setChoice(playerA, "Plains"); // Annihilator
castSpell(2, PhaseStep.DECLARE_ATTACKERS, playerA, "Cauldron Haze", "Academy Rector", "Annihilator");
setChoice(playerA, "No"); // Academy Rector No Exile
setStopAt(2, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertGraveyardCount(playerA, "Cauldron Haze", 1);
assertPermanentCount(playerB, "Academy Rector", 0);
assertPowerToughness(playerA, "Academy Rector", 0, 1);
}
} }

View file

@ -853,4 +853,45 @@ public class MorphTest extends CardTestPlayerBase {
assertTappedCount("Island", true, 3); assertTappedCount("Island", true, 3);
} }
/**
* If you have Endless Whispers in play and a morph creature dies, it should
* be returned to play face up at end of turn under the control of an
* opponent.
*/
@Test
public void testMorphEndlessWhispers() {
/*
Quicksilver Dragon {4}{U}{U}
Creature - Dragon
5/5
Flying
{U}: If target spell has only one target and that target is Quicksilver Dragon, change that spell's target to another creature.
Morph {4}{U}
*/
addCard(Zone.HAND, playerA, "Quicksilver Dragon");
addCard(Zone.BATTLEFIELD, playerA, "Island", 3);
// Each creature has "When this creature dies, choose target opponent. That player puts this card from its owner's graveyard
// onto the battlefield under his or her control at the beginning of the next end step."
addCard(Zone.BATTLEFIELD, playerA, "Endless Whispers", 1);
addCard(Zone.HAND, playerB, "Lightning Bolt");
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Quicksilver Dragon");
setChoice(playerA, "Yes"); // cast it face down as 2/2 creature
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", "");
setStopAt(2, PhaseStep.UPKEEP);
execute();
assertGraveyardCount(playerB, "Lightning Bolt", 1);
assertGraveyardCount(playerA, "Quicksilver Dragon", 0);
assertPermanentCount(playerA, "Quicksilver Dragon", 0);
assertPermanentCount(playerB, "Quicksilver Dragon", 1);
}
} }

View file

@ -0,0 +1,25 @@
package org.mage.test.cards.triggers;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
public class ShapeStealerTest extends CardTestPlayerBase {
private String shapeStealer = "Shape Stealer";
private String myojinOfCleansingFire = "Myojin of Cleansing Fire";
@Test
public void testShapeStealerSingleBlocker() {
addCard(Zone.BATTLEFIELD, playerA, shapeStealer);
addCard(Zone.BATTLEFIELD, playerB, myojinOfCleansingFire);
attack(1, playerA, shapeStealer);
block(1, playerB, myojinOfCleansingFire, shapeStealer);
setStopAt(1, PhaseStep.END_COMBAT);
execute();
assertDamageReceived(playerA, shapeStealer, 4);
assertPowerToughness(playerA, shapeStealer, 4, 6);
assertDamageReceived(playerB, myojinOfCleansingFire, 4);
}
}

View file

@ -220,12 +220,10 @@ public abstract class AbilityImpl implements Ability {
* too late Example: * too late Example:
* {@link org.mage.test.cards.replacement.DryadMilitantTest#testDiesByDestroy testDiesByDestroy} * {@link org.mage.test.cards.replacement.DryadMilitantTest#testDiesByDestroy testDiesByDestroy}
*/ */
if (effect.applyEffectsAfter()) {
game.applyEffects(); game.applyEffects();
game.getState().getTriggers().checkStateTriggers(game); game.getState().getTriggers().checkStateTriggers(game);
} }
} }
}
return result; return result;
} }

View file

@ -28,6 +28,8 @@
*/ */
package mage.abilities; package mage.abilities;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import mage.MageObject; import mage.MageObject;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
@ -36,9 +38,6 @@ import mage.game.events.NumberOfTriggersEvent;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.game.stack.Spell; import mage.game.stack.Spell;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/** /**
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
* <p> * <p>
@ -98,7 +97,10 @@ public class TriggeredAbilities extends ConcurrentHashMap<String, TriggeredAbili
// need to check if object was face down for dies and destroy events because the ability triggers in the new zone, zone counter -1 is used // need to check if object was face down for dies and destroy events because the ability triggers in the new zone, zone counter -1 is used
Permanent permanent = (Permanent) game.getLastKnownInformation(ability.getSourceId(), Zone.BATTLEFIELD, ability.getSourceObjectZoneChangeCounter() - 1); Permanent permanent = (Permanent) game.getLastKnownInformation(ability.getSourceId(), Zone.BATTLEFIELD, ability.getSourceObjectZoneChangeCounter() - 1);
if (permanent != null) { if (permanent != null) {
if (!ability.getWorksFaceDown() && permanent.isFaceDown(game)) { if (permanent.isFaceDown(game)
&& !isGainedAbility(ability, permanent) // the face down creature got the ability from an effect => so it should work
&& !ability.getWorksFaceDown()) { // the ability is declared to work also face down
// Not all triggered abilities of face down creatures work if they are faced down
return; return;
} }
controllerSet = true; controllerSet = true;
@ -161,7 +163,6 @@ public class TriggeredAbilities extends ConcurrentHashMap<String, TriggeredAbili
return key; return key;
} }
public void removeAbilitiesOfSource(UUID sourceId) { public void removeAbilitiesOfSource(UUID sourceId) {
keySet().removeIf(key -> key.endsWith(sourceId.toString())); keySet().removeIf(key -> key.endsWith(sourceId.toString()));
} }
@ -171,6 +172,10 @@ public class TriggeredAbilities extends ConcurrentHashMap<String, TriggeredAbili
sources.clear(); sources.clear();
} }
public boolean isGainedAbility(TriggeredAbility abilityToCheck, MageObject attachedTo) {
return sources.containsKey(getKey(abilityToCheck, attachedTo));
}
public void removeAbilitiesOfNonExistingSources(Game game) { public void removeAbilitiesOfNonExistingSources(Game game) {
// e.g. Token that had triggered abilities // e.g. Token that had triggered abilities

View file

@ -56,9 +56,7 @@ public class OpponentSacrificesNonTokenPermanentTriggeredAbility extends Trigger
if (game.getPlayer(getControllerId()).hasOpponent(event.getPlayerId(), game)) { if (game.getPlayer(getControllerId()).hasOpponent(event.getPlayerId(), game)) {
Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD);
if (permanent != null && !(permanent instanceof PermanentToken)) { if (permanent != null && !(permanent instanceof PermanentToken)) {
for (Effect effect : getEffects()) { getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game.getState().getZoneChangeCounter(event.getTargetId())));
effect.setTargetPointer(new FixedTarget(event.getTargetId()));
}
return true; return true;
} }
} }

View file

@ -30,7 +30,6 @@ package mage.abilities.dynamicvalue.common;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
import mage.cards.Card;
import mage.game.Game; import mage.game.Game;
/** /**
@ -39,37 +38,21 @@ import mage.game.Game;
*/ */
public class SweepNumber implements DynamicValue { public class SweepNumber implements DynamicValue {
private int zoneChangeCounter = 0;
private final String sweepSubtype; private final String sweepSubtype;
private final boolean previousZone;
public SweepNumber(String sweepSubtype, boolean previousZone) { public SweepNumber(String sweepSubtype) {
this.sweepSubtype = sweepSubtype; this.sweepSubtype = sweepSubtype;
this.previousZone = previousZone;
} }
@Override @Override
public int calculate(Game game, Ability source, Effect effect) { public int calculate(Game game, Ability source, Effect effect) {
if (zoneChangeCounter == 0) { Integer sweepNumber = (Integer) game.getState().getValue("sweep" + source.getSourceId() + game.getState().getZoneChangeCounter(source.getSourceId()));
Card card = game.getCard(source.getSourceId()); return sweepNumber != null ? sweepNumber : 0;
if (card != null) {
zoneChangeCounter = card.getZoneChangeCounter(game);
if (previousZone) {
zoneChangeCounter--;
}
}
}
int number = 0;
Integer sweepNumber = (Integer) game.getState().getValue(new StringBuilder("sweep").append(source.getSourceId()).append(zoneChangeCounter).toString());
if (sweepNumber != null) {
number = sweepNumber;
}
return number;
} }
@Override @Override
public SweepNumber copy() { public SweepNumber copy() {
return new SweepNumber(sweepSubtype, previousZone); return new SweepNumber(sweepSubtype);
} }
@Override @Override
@ -79,6 +62,6 @@ public class SweepNumber implements DynamicValue {
@Override @Override
public String getMessage() { public String getMessage() {
return new StringBuilder("the number of ").append(sweepSubtype).append(sweepSubtype.endsWith("s") ? "":"s").append(" returned this way").toString(); return "the number of " + sweepSubtype + (sweepSubtype.endsWith("s") ? "" : "s") + " returned this way";
} }
} }

View file

@ -88,10 +88,6 @@ public interface Effect extends Serializable {
Object getValue(String key); Object getValue(String key);
void setApplyEffectsAfter();
boolean applyEffectsAfter();
Effect copy(); Effect copy();
} }

View file

@ -138,18 +138,4 @@ public abstract class EffectImpl implements Effect {
} }
return values.get(key); return values.get(key);
} }
/**
* If set, the game.applyEffects() method will be called to apply the
* effects before the next effect (of the same ability) will resolve.
*/
@Override
public void setApplyEffectsAfter() {
applyEffectsAfter = true;
}
@Override
public boolean applyEffectsAfter() {
return applyEffectsAfter;
}
} }

View file

@ -37,6 +37,7 @@ import mage.constants.Duration;
import mage.constants.Layer; import mage.constants.Layer;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubLayer; import mage.constants.SubLayer;
import mage.filter.StaticFilters;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
@ -54,15 +55,15 @@ public class BoostControlledEffect extends ContinuousEffectImpl {
protected boolean lockedIn = false; protected boolean lockedIn = false;
public BoostControlledEffect(int power, int toughness, Duration duration) { public BoostControlledEffect(int power, int toughness, Duration duration) {
this(power, toughness, duration, new FilterCreaturePermanent("creatures"), false); this(power, toughness, duration, StaticFilters.FILTER_PERMANENT_CREATURES, false);
} }
public BoostControlledEffect(DynamicValue power, DynamicValue toughness, Duration duration) { public BoostControlledEffect(DynamicValue power, DynamicValue toughness, Duration duration) {
this(power, toughness, duration, new FilterCreaturePermanent("creatures"), false); this(power, toughness, duration, StaticFilters.FILTER_PERMANENT_CREATURES, false);
} }
public BoostControlledEffect(int power, int toughness, Duration duration, boolean excludeSource) { public BoostControlledEffect(int power, int toughness, Duration duration, boolean excludeSource) {
this(power, toughness, duration, new FilterCreaturePermanent("creatures"), excludeSource); this(power, toughness, duration, StaticFilters.FILTER_PERMANENT_CREATURES, excludeSource);
} }
public BoostControlledEffect(int power, int toughness, Duration duration, FilterCreaturePermanent filter) { public BoostControlledEffect(int power, int toughness, Duration duration, FilterCreaturePermanent filter) {
@ -91,7 +92,7 @@ public class BoostControlledEffect extends ContinuousEffectImpl {
super(duration, Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, Outcome.BoostCreature); super(duration, Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, Outcome.BoostCreature);
this.power = power; this.power = power;
this.toughness = toughness; this.toughness = toughness;
this.filter = filter; this.filter = (filter == null ? StaticFilters.FILTER_PERMANENT_CREATURES : filter);
this.excludeSource = excludeSource; this.excludeSource = excludeSource;
this.lockedIn = lockedIn; this.lockedIn = lockedIn;
setText(); setText();

View file

@ -70,7 +70,7 @@ public class SweepEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
if (controller != null) { if (controller != null) {
FilterPermanent filter = new FilterControlledLandPermanent(new StringBuilder("any number of ").append(sweepSubtype).append("s you control").toString()); FilterPermanent filter = new FilterControlledLandPermanent("any number of " + sweepSubtype + "s you control");
filter.add(new SubtypePredicate(sweepSubtype)); filter.add(new SubtypePredicate(sweepSubtype));
Target target = new TargetPermanent(0, Integer.MAX_VALUE, filter, true); Target target = new TargetPermanent(0, Integer.MAX_VALUE, filter, true);
if (controller.chooseTarget(outcome, target, source, game)) { if (controller.chooseTarget(outcome, target, source, game)) {

View file

@ -126,8 +126,8 @@ public class FlashbackAbility extends SpellAbility {
spellAbilityCopy.setId(this.getId()); spellAbilityCopy.setId(this.getId());
spellAbilityCopy.getManaCosts().clear(); spellAbilityCopy.getManaCosts().clear();
spellAbilityCopy.getManaCostsToPay().clear(); spellAbilityCopy.getManaCostsToPay().clear();
spellAbilityCopy.getCosts().addAll(this.getCosts()); spellAbilityCopy.getCosts().addAll(this.getCosts().copy());
spellAbilityCopy.addCost(this.getManaCosts()); spellAbilityCopy.addCost(this.getManaCosts().copy());
spellAbilityCopy.setSpellAbilityCastMode(this.getSpellAbilityCastMode()); spellAbilityCopy.setSpellAbilityCastMode(this.getSpellAbilityCastMode());
spellAbilityToResolve = spellAbilityCopy; spellAbilityToResolve = spellAbilityCopy;
ContinuousEffect effect = new FlashbackReplacementEffect(); ContinuousEffect effect = new FlashbackReplacementEffect();

View file

@ -25,7 +25,6 @@
* authors and should not be interpreted as representing official policies, either expressed * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package mage.abilities.keyword; package mage.abilities.keyword;
import mage.abilities.TriggeredAbilityImpl; import mage.abilities.TriggeredAbilityImpl;
@ -41,7 +40,6 @@ import mage.game.events.GameEvent.EventType;
* *
* @author LevelX2 * @author LevelX2
*/ */
public class InspiredAbility extends TriggeredAbilityImpl { public class InspiredAbility extends TriggeredAbilityImpl {
public InspiredAbility(Effect effect) { public InspiredAbility(Effect effect) {
@ -73,6 +71,6 @@ public class InspiredAbility extends TriggeredAbilityImpl {
@Override @Override
public String getRule() { public String getRule() {
return new StringBuilder("<i>Inspired</i> - Whenever {this} becomes untapped, ").append(super.getRule()).toString(); return "<i>Inspired</i> - Whenever {this} becomes untapped, " + super.getRule();
} }
} }

View file

@ -25,10 +25,10 @@
* authors and should not be interpreted as representing official policies, either expressed * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package mage.abilities.keyword; package mage.abilities.keyword;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.abilities.TriggeredAbilityImpl; import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCost;
import mage.abilities.costs.mana.ManaCosts; import mage.abilities.costs.mana.ManaCosts;
@ -45,53 +45,59 @@ import mage.watchers.common.MiracleWatcher;
/** /**
* 702.92. Miracle * 702.92. Miracle
* *
* 702.92a Miracle is a static ability linked to a triggered ability (see rule 603.10). * 702.92a Miracle is a static ability linked to a triggered ability (see rule
* "Miracle [cost]" means "You may reveal this card from your hand as you draw it if * 603.10). "Miracle [cost]" means "You may reveal this card from your hand as
* it's the first card you've drawn this turn. When you reveal this card this way, * you draw it if it's the first card you've drawn this turn. When you reveal
* you may cast it by paying [cost] rather than its mana cost." * this card this way, you may cast it by paying [cost] rather than its mana
* cost."
* *
* 702.92b If a player chooses to reveal a card using its miracle ability, he or she * 702.92b If a player chooses to reveal a card using its miracle ability, he or
* plays with that card revealed until that card leaves his or her hand, that ability * she plays with that card revealed until that card leaves his or her hand,
* resolves, or that ability otherwise leaves the stack. * that ability resolves, or that ability otherwise leaves the stack.
* *
* You can cast a card for its miracle cost only as the miracle triggered ability resolves. * You can cast a card for its miracle cost only as the miracle triggered
* If you don't want to cast it at that time (or you can't cast it, perhaps because * ability resolves. If you don't want to cast it at that time (or you can't
* there are no legal targets available), you won't be able to cast it later for the miracle cost. * cast it, perhaps because there are no legal targets available), you won't be
* able to cast it later for the miracle cost.
* *
* RULINGS: * RULINGS: You still draw the card, whether you use the miracle ability or not.
* You still draw the card, whether you use the miracle ability or not. Any ability that * Any ability that triggers whenever you draw a card, for example, will
* triggers whenever you draw a card, for example, will trigger. If you don't cast the card * trigger. If you don't cast the card using its miracle ability, it will remain
* using its miracle ability, it will remain in your hand. * in your hand.
* *
* You can reveal and cast a card with miracle on any turn, not just your own, if it's the * You can reveal and cast a card with miracle on any turn, not just your own,
* first card you've drawn that turn. * if it's the first card you've drawn that turn.
* *
* You don't have to reveal a drawn card with miracle if you don't wish to cast it at that time. * You don't have to reveal a drawn card with miracle if you don't wish to cast
* it at that time.
* *
* You can cast a card for its miracle cost only as the miracle triggered ability resolves. * You can cast a card for its miracle cost only as the miracle triggered
* If you don't want to cast it at that time (or you can't cast it, perhaps because there are * ability resolves. If you don't want to cast it at that time (or you can't
* no legal targets available), you won't be able to cast it later for the miracle cost. * cast it, perhaps because there are no legal targets available), you won't be
* able to cast it later for the miracle cost.
* *
* You cast the card with miracle during the resolution of the triggered ability. Ignore any timing * You cast the card with miracle during the resolution of the triggered
* restrictions based on the card's type. * ability. Ignore any timing restrictions based on the card's type.
* *
* It's important to reveal a card with miracle before it is mixed with the other cards in your hand. * It's important to reveal a card with miracle before it is mixed with the
* other cards in your hand.
* *
* Multiple card draws are always treated as a sequence of individual card draws. For example, if * Multiple card draws are always treated as a sequence of individual card
* you haven't drawn any cards yet during a turn and cast a spell that instructs you to draw three * draws. For example, if you haven't drawn any cards yet during a turn and cast
* cards, you'll draw them one at a time. Only the first card drawn this way may be revealed and cast * a spell that instructs you to draw three cards, you'll draw them one at a
* using its miracle ability. * time. Only the first card drawn this way may be revealed and cast using its
* miracle ability.
* *
* If the card with miracle leaves your hand before the triggered ability resolves, you won't be able * If the card with miracle leaves your hand before the triggered ability
* to cast it using its miracle ability. * resolves, you won't be able to cast it using its miracle ability.
* *
* You draw your opening hand before any turn begins. Cards you draw for your opening hand * You draw your opening hand before any turn begins. Cards you draw for your
* can't be cast using miracle. * opening hand can't be cast using miracle.
* *
* @author noxx, LevelX2 * @author noxx, LevelX2
*/ */
public class MiracleAbility extends TriggeredAbilityImpl { public class MiracleAbility extends TriggeredAbilityImpl {
private static final String staticRule = " <i>(You may cast this card for its miracle cost when you draw it if it's the first card you drew this turn.)</i>"; private static final String staticRule = " <i>(You may cast this card for its miracle cost when you draw it if it's the first card you drew this turn.)</i>";
private String ruleText; private String ruleText;
@ -161,17 +167,12 @@ class MiracleEffect extends OneShotEffect {
// use target pointer here, so it's the same card that triggered the event (not gone back to library e.g.) // use target pointer here, so it's the same card that triggered the event (not gone back to library e.g.)
Card card = game.getCard(getTargetPointer().getFirst(game, source)); Card card = game.getCard(getTargetPointer().getFirst(game, source));
if (controller != null && card != null) { if (controller != null && card != null) {
ManaCosts<ManaCost> costRef = card.getSpellAbility().getManaCostsToPay(); SpellAbility abilityToCast = card.getSpellAbility().copy();
ManaCosts<ManaCost> costRef = abilityToCast.getManaCostsToPay();
// replace with the new cost // replace with the new cost
costRef.clear(); costRef.clear();
costRef.add(miracleCosts); costRef.add(miracleCosts);
controller.cast(card.getSpellAbility(), game, false); controller.cast(abilityToCast, game, false);
// Reset the casting costs (in case the player cancels cast and plays the card later)
costRef.clear();
for (ManaCost manaCost : card.getSpellAbility().getManaCosts()) {
costRef.add(manaCost);
}
return true; return true;
} }
return false; return false;

View file

@ -210,11 +210,15 @@ public final class StaticFilters {
static { static {
FILTER_LAND.setLockedFilter(true); FILTER_LAND.setLockedFilter(true);
} }
public static final FilterLandPermanent FILTER_LANDS = new FilterLandPermanent("lands"); public static final FilterLandPermanent FILTER_LANDS = new FilterLandPermanent("lands");
static { static {
FILTER_LANDS.setLockedFilter(true); FILTER_LANDS.setLockedFilter(true);
} }
public static final FilterLandPermanent FILTER_LANDS_NONBASIC = FilterLandPermanent.nonbasicLands();
public static final FilterBasicLandCard FILTER_BASIC_LAND_CARD = new FilterBasicLandCard(); public static final FilterBasicLandCard FILTER_BASIC_LAND_CARD = new FilterBasicLandCard();
static { static {