Merge origin/master

This commit is contained in:
emerald000 2014-07-14 01:01:39 -04:00
commit 7ca60078a0
36 changed files with 740 additions and 489 deletions

View file

@ -34,50 +34,12 @@
package mage.client.cards;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import javax.swing.JScrollPane;
import javax.swing.Popup;
import javax.swing.PopupFactory;
import javax.swing.text.BadLocationException;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import javax.swing.text.StyledDocument;
import mage.cards.CardDimensions;
import mage.cards.MagePermanent;
import mage.cards.Sets;
import mage.cards.TextPopup;
import mage.cards.action.ActionCallback;
import mage.client.MageFrame;
import static mage.client.constants.Constants.CONTENT_MAX_XOFFSET;
import static mage.client.constants.Constants.FRAME_MAX_HEIGHT;
import static mage.client.constants.Constants.FRAME_MAX_WIDTH;
import static mage.client.constants.Constants.NAME_FONT_MAX_SIZE;
import static mage.client.constants.Constants.NAME_MAX_YOFFSET;
import static mage.client.constants.Constants.POWBOX_TEXT_MAX_LEFT;
import static mage.client.constants.Constants.POWBOX_TEXT_MAX_TOP;
import static mage.client.constants.Constants.SYMBOL_MAX_XOFFSET;
import static mage.client.constants.Constants.SYMBOL_MAX_YOFFSET;
import static mage.client.constants.Constants.TYPE_MAX_YOFFSET;
import mage.client.game.PlayAreaPanel;
import mage.client.util.Config;
import mage.client.util.DefaultActionCallback;
@ -86,11 +48,18 @@ import mage.client.util.gui.ArrowBuilder;
import mage.constants.CardType;
import mage.constants.EnlargeMode;
import mage.remote.Session;
import mage.view.AbilityView;
import mage.view.CardView;
import mage.view.CounterView;
import mage.view.PermanentView;
import mage.view.StackAbilityView;
import mage.view.*;
import javax.swing.*;
import javax.swing.text.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import static mage.client.constants.Constants.*;
/**
*
@ -557,4 +526,8 @@ public class Card extends MagePermanent implements MouseMotionListener, MouseLis
@Override
public void setSelected(boolean selected) {
}
@Override
public void setCardAreaRef(JPanel cardArea) {
}
}

View file

@ -39,14 +39,14 @@ import mage.client.plugins.impl.Plugins;
import mage.client.util.CardsViewUtil;
import mage.client.util.Config;
import mage.view.*;
import org.apache.log4j.Logger;
import org.mage.card.arcane.CardPanel;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.util.*;
import java.util.Map.Entry;
import mage.cards.action.ActionCallback;
import mage.client.plugins.adapters.MageActionCallback;
import org.apache.log4j.Logger;
/**
*
@ -61,6 +61,8 @@ public class Cards extends javax.swing.JPanel {
private static final int GAP_X = 5;
private String zone;
private static final Border emptyBorder = new EmptyBorder(0,0,0,0);
/**
* Defines whether component should be visible whenever there is no objects within.
* True by default.
@ -82,18 +84,15 @@ public class Cards extends javax.swing.JPanel {
if (!skipAddingScrollPane) {
jScrollPane1.setOpaque(false);
jScrollPane1.getViewport().setOpaque(false);
jScrollPane1.setBorder(emptyBorder);
}
if (Plugins.getInstance().isCardPluginLoaded()) {
cardArea.setLayout(null);
}
cardArea.setBorder(emptyBorder);
}
public void cleanUp() {
// ActionCallback actionCallback = Plugins.getInstance().getActionCallback();
// if (actionCallback instanceof MageActionCallback) {
// ((MageActionCallback) actionCallback).setCardPreviewComponent(null);
// }
}
public void cleanUp() {}
/**
* Sets components background color
@ -182,12 +181,13 @@ public class Cards extends javax.swing.JPanel {
}
if (changed) {
layoutCards(getCardDimension(), cards, order);
layoutCards();
}
if (!isVisibleIfEmpty) {
cardArea.setVisible(cards.size() > 0);
}
sizeCards(getCardDimension());
this.revalidate();
this.repaint();
@ -196,13 +196,13 @@ public class Cards extends javax.swing.JPanel {
}
public void sizeCards(Dimension cardDimension) {
cardArea.setPreferredSize(new Dimension((int)(cards.size() * (cardDimension.getWidth() + GAP_X)) + 5, (int)(cardDimension.getHeight()) + 20));
cardArea.setPreferredSize(new Dimension((int)((cards.size()) * (cardDimension.getWidth() + GAP_X)) + 20, (int)(cardDimension.getHeight()) + 20));
cardArea.revalidate();
cardArea.repaint();
}
private Dimension getCardDimension() {
if (cardDimension == null) {
if (cardDimension == null) {
cardDimension = new Dimension(Config.dimensions.frameWidth, Config.dimensions.frameHeight);
}
return cardDimension;
@ -215,6 +215,19 @@ public class Cards extends javax.swing.JPanel {
}
cards.put(card.getId(), cardImg);
cardArea.add(cardImg);
definePosition(cardImg);
cardImg.setCardAreaRef(cardArea);
}
private void definePosition(MageCard card) {
int dx = 0;
for (Component comp: cardArea.getComponents()) {
if (!comp.equals(card)) {
dx = Math.max(dx, (int)comp.getLocation().getX());
}
}
dx += ((CardPanel)card).getCardWidth() + GAP_X;
card.setLocation(dx, (int)card.getLocation().getY());
}
private void removeCard(UUID cardId) {
@ -232,35 +245,7 @@ public class Cards extends javax.swing.JPanel {
}
private int countCards() {
int count = 0;
for (Component comp: cardArea.getComponents()) {
count++;
}
return count;
}
private void layoutCards(Dimension dimension, Map<UUID, MageCard> cards, java.util.List<UUID> order) {
if (Plugins.getInstance().isCardPluginLoaded()) {
int dx = GAP_X;
if (order != null) {
for (UUID cardId : order) {
MageCard card = cards.get(cardId);
if (card != null) {
card.setLocation(dx, 0);
card.setCardBounds(dx, 0, dimension.width, dimension.height);
dx += dimension.width + GAP_X;
} else {
System.err.println("[ERROR] Cards.java: couldn't find a card from ordered list!");
}
}
} else {
for (MageCard card: cards.values()) {
card.setLocation(dx, 0);
card.setCardBounds(dx, 0, dimension.width, dimension.height);
dx += dimension.width + GAP_X;
}
}
}
return cardArea.getComponentCount();
}
/** This method is called from within the constructor to
@ -311,7 +296,29 @@ public class Cards extends javax.swing.JPanel {
public void setCardDimension(Dimension dimension) {
this.cardDimension = dimension;
layoutCards(cardDimension, cards, null);
layoutCards();
}
private void layoutCards() {
java.util.List<CardPanel> cards = new ArrayList();
for (Component component : cardArea.getComponents()) {
if (component instanceof CardPanel) {
cards.add((CardPanel)component);
}
}
Collections.sort(cards, new Comparator<CardPanel>() {
@Override
public int compare(CardPanel cp1, CardPanel cp2) {
return Integer.valueOf(cp1.getLocation().x).compareTo(cp2.getLocation().x);
}
});
int dx = 0;
for (Component component : cards) {
component.setLocation(dx, component.getLocation().y);
dx += ((CardPanel) component).getCardWidth() + GAP_X;
}
}
public void setZone(String zone) {

View file

@ -27,47 +27,6 @@
*/
package mage.client.game;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import javax.swing.AbstractAction;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLayeredPane;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingWorker;
import javax.swing.border.LineBorder;
import javax.swing.plaf.basic.BasicSplitPaneDivider;
import javax.swing.plaf.basic.BasicSplitPaneUI;
import mage.cards.Card;
import mage.cards.action.ActionCallback;
import mage.client.MageFrame;
@ -78,12 +37,7 @@ import mage.client.components.HoverButton;
import mage.client.components.MageComponents;
import mage.client.components.ext.dlg.DialogManager;
import mage.client.components.layout.RelativeLayout;
import mage.client.dialog.ExileZoneDialog;
import mage.client.dialog.PickChoiceDialog;
import mage.client.dialog.PickNumberDialog;
import mage.client.dialog.PickPileDialog;
import mage.client.dialog.PreferencesDialog;
import mage.client.dialog.ShowCardsDialog;
import mage.client.dialog.*;
import mage.client.game.FeedbackPanel.FeedbackMode;
import mage.client.plugins.adapters.MageActionCallback;
import mage.client.plugins.impl.Plugins;
@ -94,29 +48,23 @@ import mage.client.util.PhaseManager;
import mage.client.util.gui.ArrowBuilder;
import mage.constants.EnlargeMode;
import mage.constants.PhaseStep;
import static mage.constants.PhaseStep.BEGIN_COMBAT;
import static mage.constants.PhaseStep.COMBAT_DAMAGE;
import static mage.constants.PhaseStep.DECLARE_ATTACKERS;
import static mage.constants.PhaseStep.DECLARE_BLOCKERS;
import static mage.constants.PhaseStep.DRAW;
import static mage.constants.PhaseStep.END_COMBAT;
import static mage.constants.PhaseStep.END_TURN;
import static mage.constants.PhaseStep.FIRST_COMBAT_DAMAGE;
import static mage.constants.PhaseStep.UNTAP;
import static mage.constants.PhaseStep.UPKEEP;
import mage.remote.Session;
import mage.view.AbilityPickerView;
import mage.view.CardsView;
import mage.view.ExileView;
import mage.view.GameView;
import mage.view.LookedAtView;
import mage.view.MatchView;
import mage.view.PlayerView;
import mage.view.RevealedView;
import mage.view.SimpleCardsView;
import mage.view.*;
import org.apache.log4j.Logger;
import org.mage.plugins.card.utils.impl.ImageManagerImpl;
import javax.swing.*;
import javax.swing.GroupLayout.Alignment;
import javax.swing.border.LineBorder;
import javax.swing.plaf.basic.BasicSplitPaneDivider;
import javax.swing.plaf.basic.BasicSplitPaneUI;
import java.awt.*;
import java.awt.event.*;
import java.io.Serializable;
import java.util.*;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
/**
*
* @author BetaSteward_at_googlemail.com, nantuko8
@ -503,6 +451,15 @@ public final class GamePanel extends javax.swing.JPanel {
handCards.clear();
handCards.put(YOUR_HAND, CardsViewUtil.convertSimple(game.getHand(), loadedCards));
// Mark playable
if (game.getCanPlayInHand() != null) {
for (CardView card : handCards.get(YOUR_HAND).values()) {
if (game.getCanPlayInHand().contains(card.getId())) {
card.setPlayable(true);
}
}
}
// Get opponents hand cards if available
if (game.getOpponentHands() != null) {
for (Map.Entry<String, SimpleCardsView> hand: game.getOpponentHands().entrySet()) {

View file

@ -5,13 +5,13 @@ import mage.client.cards.BigCard;
import mage.client.dialog.PreferencesDialog;
import mage.client.util.Config;
import mage.constants.Zone;
import mage.view.CardsView;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.util.UUID;
import mage.view.CardsView;
public class HandPanel extends JPanel {
@ -31,12 +31,13 @@ public class HandPanel extends JPanel {
public void initComponents() {
hand = new mage.client.cards.Cards(true);
hand.setCardDimension(getHandCardDimension());
jPanel = new JPanel();
jScrollPane1 = new JScrollPane(jPanel);
jScrollPane1.getViewport().setBackground(new Color(0,0,0,0));
jPanel.setLayout(new GridBagLayout()); // centers hand
jPanel.setBackground(new Color(0,0,0,0));
jPanel.setBackground(new Color(0, 0, 0, 0));
jPanel.add(hand);
setOpaque(false);
@ -47,12 +48,13 @@ public class HandPanel extends JPanel {
jScrollPane1.setBorder(emptyBorder);
jScrollPane1.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
jScrollPane1.getHorizontalScrollBar().setUnitIncrement(8);
jScrollPane1.setViewportBorder(emptyBorder);
setLayout(new BorderLayout());
add(jScrollPane1, BorderLayout.CENTER);
hand.setHScrollSpeed(8);
hand.setBackgroundColor(new Color(0, 0, 0, 100));
hand.setBackgroundColor(new Color(0, 0, 0, 0));
hand.setVisibleIfEmpty(false);
hand.setBorder(emptyBorder);
hand.setZone(Zone.HAND.toString());
@ -87,7 +89,7 @@ public class HandPanel extends JPanel {
private JPanel jPanel;
private JScrollPane jScrollPane1;
private Border emptyBorder = new EmptyBorder(0,0,0,0);
private static final Border emptyBorder = new EmptyBorder(0,0,0,0);
private mage.client.cards.Cards hand;
}

View file

@ -1,19 +1,17 @@
package mage.client.plugins.adapters;
import mage.cards.MageCard;
import mage.cards.MagePermanent;
import mage.cards.action.ActionCallback;
import mage.cards.action.TransferData;
import mage.client.MageFrame;
import mage.client.cards.BigCard;
import mage.client.components.MageComponents;
import mage.client.dialog.PreferencesDialog;
import mage.client.game.PlayAreaPanel;
import mage.client.game.PlayerPanelExt;
import mage.client.plugins.impl.Plugins;
import mage.client.util.DefaultActionCallback;
import mage.client.util.ImageHelper;
import mage.client.util.gui.ArrowBuilder;
import mage.client.util.gui.ArrowUtil;
import mage.client.util.gui.GuiDisplayUtil;
import mage.components.CardInfoPane;
import mage.constants.EnlargeMode;
@ -21,10 +19,9 @@ import mage.remote.Session;
import mage.utils.ThreadUtils;
import mage.view.CardView;
import mage.view.PermanentView;
import mage.view.PlayerView;
import mage.view.SimpleCardsView;
import org.apache.log4j.Logger;
import org.jdesktop.swingx.JXPanel;
import org.mage.card.arcane.CardPanel;
import org.mage.plugins.card.images.ImageCache;
import javax.swing.*;
@ -32,8 +29,8 @@ import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.image.BufferedImage;
import java.util.*;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
@ -43,11 +40,15 @@ import java.util.concurrent.TimeUnit;
* Class that handles the callbacks from the card panels to mage to display big card
* images from the cards the mouse hovers on. Also handles tooltip text window.
*
* @author Nantuko
* @author Nantuko, noxx
*/
public class MageActionCallback implements ActionCallback {
private static final Logger logger = Logger.getLogger(ActionCallback.class);
public static final int GAP_X = 5;
public static final double COMPARE_GAP_X = 30;
public static final int GO_DOWN_ON_DRAG_Y_OFFSET = 0;
public static final int MIN_X_OFFSET_REQUIRED = 25;
private Popup popup;
private JPopupMenu jPopupMenu;
@ -69,6 +70,12 @@ public class MageActionCallback implements ActionCallback {
private static final ScheduledExecutorService timeoutExecutor = Executors.newScheduledThreadPool(1);
private ScheduledFuture<?> hideTimeout;
private CardView currentCard;
private boolean isDragging;
private Point initialCardPos;
private Point initialMousePos;
private Set<CardPanel> cardPanels = new HashSet<CardPanel>();
public MageActionCallback() {
enlargeMode = EnlargeMode.NORMAL;
}
@ -90,21 +97,6 @@ public class MageActionCallback implements ActionCallback {
public void mouseClicked(MouseEvent e, TransferData data) {
}
@Override
public void mousePressed(MouseEvent e, TransferData data) {
data.component.requestFocusInWindow();
// Closes popup & enlarged view if a card/Permanent is selected
hidePopup();
}
@Override
public void mouseReleased(MouseEvent e, TransferData data) {
data.component.requestFocusInWindow();
defaultCallback.mouseClicked(e, data.gameId, session, data.card);
// Closes popup & enlarged view if a card/Permanent is selected
hidePopup();
}
@Override
public void mouseEntered(MouseEvent e, final TransferData data) {
hidePopup();
@ -116,109 +108,18 @@ public class MageActionCallback implements ActionCallback {
Component parentComponent = SwingUtilities.getRoot(data.component);
Point parentPoint = parentComponent.getLocationOnScreen();
drawArrowsForTargets(data, parentPoint);
drawArrowsForSource(data, parentPoint);
drawArrowsForPairedCards(data, parentPoint);
drawArrowsForEnchantPlayers(data, parentPoint);
if (data.locationOnScreen == null) {
data.locationOnScreen = data.component.getLocationOnScreen();
}
ArrowUtil.drawArrowsForTargets(data, parentPoint);
ArrowUtil.drawArrowsForSource(data, parentPoint);
ArrowUtil.drawArrowsForPairedCards(data, parentPoint);
ArrowUtil.drawArrowsForEnchantPlayers(data, parentPoint);
showPopup(data, parentComponent, parentPoint);
}
private void drawArrowsForPairedCards(TransferData data, Point parentPoint) {
if (data.card.getPairedCard() != null) {
Point me = new Point(data.locationOnScreen);
me.translate(-parentPoint.x, -parentPoint.y);
UUID uuid = data.card.getPairedCard();
for (PlayAreaPanel pa : MageFrame.getGame(data.gameId).getPlayers().values()) {
MagePermanent permanent = pa.getBattlefieldPanel().getPermanents().get(uuid);
if (permanent != null) {
Point target = permanent.getLocationOnScreen();
target.translate(-parentPoint.x, -parentPoint.y);
ArrowBuilder.getBuilder().addArrow(data.gameId, (int) me.getX() + 35, (int) me.getY(), (int) target.getX() + 40, (int) target.getY() + 10, Color.green, ArrowBuilder.Type.PAIRED);
}
}
}
}
private void drawArrowsForEnchantPlayers(TransferData data, Point parentPoint) {
if (data.gameId != null && MageFrame.getGame(data.gameId) != null) {
for (PlayAreaPanel pa : MageFrame.getGame(data.gameId).getPlayers().values()) {
PlayerPanelExt playAreaPanel = pa.getPlayerPanel();
if (playAreaPanel != null && playAreaPanel.getPlayer() != null && playAreaPanel.getPlayer().hasAttachments()) {
Point me = new Point(data.locationOnScreen);
me.translate(-parentPoint.x, -parentPoint.y);
for (UUID attachmentId : playAreaPanel.getPlayer().getAttachments()) {
if (attachmentId.equals(data.card.getId())) {
Point player = pa.getLocationOnScreen();
player.translate(-parentPoint.x, -parentPoint.y);
ArrowBuilder.getBuilder().addArrow(data.gameId,(int) me.getX() + 35, (int) me.getY(), (int) player.getX() + 40, (int) player.getY() - 40, Color.magenta, ArrowBuilder.Type.ENCHANT_PLAYERS);
}
}
}
}
}
}
private void drawArrowsForSource(TransferData data, Point parentPoint) {
if (data.card.isAbility()) {
Point me = new Point(data.locationOnScreen);
me.translate(-parentPoint.x, -parentPoint.y);
UUID uuid = data.card.getParentId();
for (PlayAreaPanel pa : MageFrame.getGame(data.gameId).getPlayers().values()) {
MagePermanent permanent = pa.getBattlefieldPanel().getPermanents().get(uuid);
if (permanent != null) {
Point source = permanent.getLocationOnScreen();
source.translate(-parentPoint.x, -parentPoint.y);
ArrowBuilder.getBuilder().addArrow(data.gameId, (int) source.getX() + 40, (int) source.getY() + 10, (int) me.getX() + 35, (int) me.getY() + 20, Color.blue, ArrowBuilder.Type.SOURCE);
}
}
}
}
private void drawArrowsForTargets(TransferData data, Point parentPoint) {
List<UUID> targets = data.card.getTargets();
if (targets == null) {
return;
}
Point me = new Point(data.locationOnScreen);
me.translate(-parentPoint.x, -parentPoint.y);
for (UUID uuid : targets) {
PlayAreaPanel p = MageFrame.getGame(data.gameId).getPlayers().get(uuid);
if (p != null) {
Point target = p.getLocationOnScreen();
target.translate(-parentPoint.x, -parentPoint.y);
ArrowBuilder.getBuilder().addArrow(data.gameId, (int) me.getX() + 35, (int) me.getY(), (int) target.getX() + 40, (int) target.getY() - 40, Color.red, ArrowBuilder.Type.TARGET);
continue;
}
for (PlayAreaPanel panel : MageFrame.getGame(data.gameId).getPlayers().values()) {
MagePermanent permanent = panel.getBattlefieldPanel().getPermanents().get(uuid);
if (permanent != null) {
Point target = permanent.getLocationOnScreen();
target.translate(-parentPoint.x, -parentPoint.y);
ArrowBuilder.getBuilder().addArrow(data.gameId, (int) me.getX() + 35, (int) me.getY(), (int) target.getX() + 40, (int) target.getY() + 10, Color.red, ArrowBuilder.Type.TARGET);
continue;
}
PlayerView view = panel.getPlayerPanel().getPlayer();
if (view != null) {
SimpleCardsView graveyard = view.getGraveyard();
if (graveyard.containsKey(uuid)) {
p = MageFrame.getGame(data.gameId).getPlayers().get(view.getPlayerId());
if (p != null) {
Point target = p.getLocationOnScreen();
target.translate(-parentPoint.x, -parentPoint.y);
int yOffset = p.isSmallMode() ? (PlayAreaPanel.PANEL_HEIGHT - PlayAreaPanel.PANEL_HEIGHT_SMALL) : 0;
ArrowBuilder.getBuilder().addArrow(data.gameId, (int) me.getX() + 35, (int) me.getY(), (int) target.getX() + 15, (int) target.getY() + 145 - yOffset, Color.red, ArrowBuilder.Type.TARGET);
}
}
}
}
}
}
private void showPopup(final TransferData data, final Component parentComponent, final Point parentPoint) {
if (data.component != null) {
String showTooltips = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_SHOW_TOOLTIPS_ANY_ZONE, "true");
@ -229,6 +130,12 @@ public class MageActionCallback implements ActionCallback {
if (cardInfoPane == null) {
PopupFactory factory = PopupFactory.getSharedInstance();
if (data.locationOnScreen == null) {
if (data.component == null) {
return;
}
data.locationOnScreen = data.component.getLocationOnScreen();
}
popup = factory.getPopup(data.component, data.popupText, (int) data.locationOnScreen.getX() + data.popupOffsetX, (int) data.locationOnScreen.getY() + data.popupOffsetY + 40);
popup.show();
// hack to get popup to resize to fit text
@ -256,6 +163,10 @@ public class MageActionCallback implements ActionCallback {
((CardInfoPane) popup2).setCard(data.card, popupContainer);
if (data.locationOnScreen == null) {
data.locationOnScreen = data.component.getLocationOnScreen();
}
Point location = new Point((int) data.locationOnScreen.getX() + data.popupOffsetX - 40, (int) data.locationOnScreen.getY() + data.popupOffsetY - 40);
location = GuiDisplayUtil.keepComponentInsideParent(location, parentPoint, popup2, parentComponent);
location.translate(-parentPoint.x, -parentPoint.y);
@ -265,15 +176,15 @@ public class MageActionCallback implements ActionCallback {
final Component c = MageFrame.getUI().getComponent(MageComponents.DESKTOP_PANE);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
if (!popupTextWindowOpen || !enlargedWindowState.equals(EnlargedWindowState.CLOSED)) {
return;
}
popupContainer.setVisible(true);
c.repaint();
}
}
@Override
public void run() {
if (!popupTextWindowOpen || !enlargedWindowState.equals(EnlargedWindowState.CLOSED)) {
return;
}
popupContainer.setVisible(true);
c.repaint();
}
}
);
} catch (InterruptedException e) {
@ -283,8 +194,127 @@ public class MageActionCallback implements ActionCallback {
});
}
@Override
public void mousePressed(MouseEvent e, TransferData data) {
data.component.requestFocusInWindow();
currentCard = data.card;
isDragging = false;
cardPanels.clear();
Point mouse = new Point(e.getX(), e.getY());
SwingUtilities.convertPointToScreen(mouse, data.component);
initialMousePos = new Point((int)mouse.getX(), (int)mouse.getY());
initialCardPos = data.component.getLocation();
// Closes popup & enlarged view if a card/Permanent is selected
hidePopup();
}
@Override
public void mouseReleased(MouseEvent e, TransferData transferData) {
int maxXOffset = 0;
if (isDragging) {
CardPanel card = ((CardPanel)transferData.component);
Point mouse = new Point(e.getX(), e.getY());
SwingUtilities.convertPointToScreen(mouse, transferData.component);
int xOffset = card.getXOffset(card.getCardWidth());
maxXOffset = Math.abs((int) (mouse.getX() - initialMousePos.x) - xOffset);
}
if (maxXOffset > MIN_X_OFFSET_REQUIRED) { // we need this for protection from small card movements
CardPanel card = ((CardPanel)transferData.component);
for (Component component : card.getCardArea().getComponents()) {
if (component instanceof CardPanel) {
if (cardPanels.contains(component)) {
component.setLocation(component.getLocation().x, component.getLocation().y - GO_DOWN_ON_DRAG_Y_OFFSET);
}
}
}
sort(card, card.getCardArea(), true);
cardPanels.clear();
} else {
transferData.component.requestFocusInWindow();
defaultCallback.mouseClicked(e, transferData.gameId, session, transferData.card);
// Closes popup & enlarged view if a card/Permanent is selected
hidePopup();
}
}
@Override
public void mouseMoved(MouseEvent e, TransferData transferData) {
handlePopup(transferData);
}
@Override
public void mouseDragged(MouseEvent e, TransferData transferData) {
CardPanel card = ((CardPanel)transferData.component);
if (card.getZone() == null || !card.getZone().equalsIgnoreCase("hand")) {
// drag'n'drop is allowed for HAND zone only
return;
}
currentCard = null;
isDragging = true;
Point p = card.getCardLocation();
Point mouse = new Point(e.getX(), e.getY());
SwingUtilities.convertPointToScreen(mouse, transferData.component);
int xOffset = card.getXOffset(card.getCardWidth());
int newX = Math.max(initialCardPos.x + (int)(mouse.getX() - initialMousePos.x) - xOffset, 0);
card.setCardBounds(
newX,
p.y,
card.getCardWidth(),
card.getCardHeight());
card.getCardArea().setComponentZOrder(card, 0);
sort(card, card.getCardArea(), false);
}
private void sort(CardPanel card, JPanel container, boolean sortSource) {
java.util.List<CardPanel> cards = new ArrayList<CardPanel>();
for (Component component : container.getComponents()) {
if (component instanceof CardPanel) {
if (!component.equals(card)) {
if (!cardPanels.contains(component)) {
component.setLocation(component.getLocation().x, component.getLocation().y + GO_DOWN_ON_DRAG_Y_OFFSET);
}
cardPanels.add((CardPanel)component);
}
cards.add((CardPanel)component);
}
}
sortLayout(cards, card, sortSource);
}
private void sortLayout(List<CardPanel> cards, CardPanel source, boolean includeSource) {
source.getLocation().x -= COMPARE_GAP_X; // this creates nice effect
Collections.sort(cards, new Comparator<CardPanel>() {
@Override
public int compare(CardPanel cp1, CardPanel cp2) {
return Integer.valueOf(cp1.getLocation().x).compareTo(cp2.getLocation().x);
}
});
int dx = 0;
boolean createdGapForSource = false;
for (Component component : cards) {
if (!includeSource) {
if (!component.equals(source)) {
component.setLocation(dx, component.getLocation().y);
dx += ((CardPanel) component).getCardWidth() + GAP_X;
// once dx is bigger than source's x position
// we need to create a gap for the source card
// but only once
if (!createdGapForSource && (dx + COMPARE_GAP_X) > source.getLocation().x) {
createdGapForSource = true;
dx += ((CardPanel) component).getCardWidth() + GAP_X;
}
}
} else {
component.setLocation(dx, component.getLocation().y);
dx += ((CardPanel) component).getCardWidth() + GAP_X;
}
}
}
private void handlePopup(TransferData transferData) {
if (!Plugins.getInstance().isCardPluginLoaded()) {
return;
}
@ -469,6 +499,7 @@ public class MageActionCallback implements ActionCallback {
final Component popupContainer = MageFrame.getUI().getComponent(mageComponentCardPreviewContainer);
Component cardPreviewPane = MageFrame.getUI().getComponent(mageComponentCardPreviewPane);
if (cardPreviewPane != null) {
transferData.locationOnScreen = transferData.component.getLocationOnScreen();
Point location = new Point((int) transferData.locationOnScreen.getX() + transferData.popupOffsetX - 40, (int) transferData.locationOnScreen.getY() + transferData.popupOffsetY - 40);
location = GuiDisplayUtil.keepComponentInsideParent(location, parentPoint, cardPreviewPane, parentComponent);
location.translate(-parentPoint.x, -parentPoint.y);

View file

@ -180,4 +180,5 @@ public class ArrowBuilder {
arrowPanels.get(gameId).setVisible(true);
}
}
}

View file

@ -0,0 +1,116 @@
package mage.client.util.gui;
import mage.cards.MagePermanent;
import mage.cards.action.TransferData;
import mage.client.MageFrame;
import mage.client.game.PlayAreaPanel;
import mage.client.game.PlayerPanelExt;
import mage.view.PlayerView;
import mage.view.SimpleCardsView;
import java.awt.*;
import java.util.*;
/**
* @author noxx
*/
public class ArrowUtil {
private ArrowUtil() {}
public static void drawArrowsForPairedCards(TransferData data, Point parentPoint) {
if (data.card.getPairedCard() != null) {
Point me = new Point(data.locationOnScreen);
me.translate(-parentPoint.x, -parentPoint.y);
UUID uuid = data.card.getPairedCard();
for (PlayAreaPanel pa : MageFrame.getGame(data.gameId).getPlayers().values()) {
MagePermanent permanent = pa.getBattlefieldPanel().getPermanents().get(uuid);
if (permanent != null) {
Point target = permanent.getLocationOnScreen();
target.translate(-parentPoint.x, -parentPoint.y);
ArrowBuilder.getBuilder().addArrow(data.gameId, (int) me.getX() + 35, (int) me.getY(), (int) target.getX() + 40, (int) target.getY() + 10, Color.green, ArrowBuilder.Type.PAIRED);
}
}
}
}
public static void drawArrowsForEnchantPlayers(TransferData data, Point parentPoint) {
if (data.gameId != null && MageFrame.getGame(data.gameId) != null) {
for (PlayAreaPanel pa : MageFrame.getGame(data.gameId).getPlayers().values()) {
PlayerPanelExt playAreaPanel = pa.getPlayerPanel();
if (playAreaPanel != null && playAreaPanel.getPlayer() != null && playAreaPanel.getPlayer().hasAttachments()) {
Point me = new Point(data.locationOnScreen);
me.translate(-parentPoint.x, -parentPoint.y);
for (UUID attachmentId : playAreaPanel.getPlayer().getAttachments()) {
if (attachmentId.equals(data.card.getId())) {
Point player = pa.getLocationOnScreen();
player.translate(-parentPoint.x, -parentPoint.y);
ArrowBuilder.getBuilder().addArrow(data.gameId,(int) me.getX() + 35, (int) me.getY(), (int) player.getX() + 40, (int) player.getY() - 40, Color.magenta, ArrowBuilder.Type.ENCHANT_PLAYERS);
}
}
}
}
}
}
public static void drawArrowsForSource(TransferData data, Point parentPoint) {
if (data.card.isAbility()) {
Point me = new Point(data.locationOnScreen);
me.translate(-parentPoint.x, -parentPoint.y);
UUID uuid = data.card.getParentId();
for (PlayAreaPanel pa : MageFrame.getGame(data.gameId).getPlayers().values()) {
MagePermanent permanent = pa.getBattlefieldPanel().getPermanents().get(uuid);
if (permanent != null) {
Point source = permanent.getLocationOnScreen();
source.translate(-parentPoint.x, -parentPoint.y);
ArrowBuilder.getBuilder().addArrow(data.gameId, (int) source.getX() + 40, (int) source.getY() + 10, (int) me.getX() + 35, (int) me.getY() + 20, Color.blue, ArrowBuilder.Type.SOURCE);
}
}
}
}
public static void drawArrowsForTargets(TransferData data, Point parentPoint) {
java.util.List<UUID> targets = data.card.getTargets();
if (targets == null) {
return;
}
Point me = new Point(data.locationOnScreen);
me.translate(-parentPoint.x, -parentPoint.y);
for (UUID uuid : targets) {
PlayAreaPanel p = MageFrame.getGame(data.gameId).getPlayers().get(uuid);
if (p != null) {
Point target = p.getLocationOnScreen();
target.translate(-parentPoint.x, -parentPoint.y);
ArrowBuilder.getBuilder().addArrow(data.gameId, (int) me.getX() + 35, (int) me.getY(), (int) target.getX() + 40, (int) target.getY() - 40, Color.red, ArrowBuilder.Type.TARGET);
continue;
}
for (PlayAreaPanel panel : MageFrame.getGame(data.gameId).getPlayers().values()) {
MagePermanent permanent = panel.getBattlefieldPanel().getPermanents().get(uuid);
if (permanent != null) {
Point target = permanent.getLocationOnScreen();
target.translate(-parentPoint.x, -parentPoint.y);
ArrowBuilder.getBuilder().addArrow(data.gameId, (int) me.getX() + 35, (int) me.getY(), (int) target.getX() + 40, (int) target.getY() + 10, Color.red, ArrowBuilder.Type.TARGET);
continue;
}
PlayerView view = panel.getPlayerPanel().getPlayer();
if (view != null) {
SimpleCardsView graveyard = view.getGraveyard();
if (graveyard.containsKey(uuid)) {
p = MageFrame.getGame(data.gameId).getPlayers().get(view.getPlayerId());
if (p != null) {
Point target = p.getLocationOnScreen();
target.translate(-parentPoint.x, -parentPoint.y);
int yOffset = p.isSmallMode() ? (PlayAreaPanel.PANEL_HEIGHT - PlayAreaPanel.PANEL_HEIGHT_SMALL) : 0;
ArrowBuilder.getBuilder().addArrow(data.gameId, (int) me.getX() + 35, (int) me.getY(), (int) target.getX() + 15, (int) target.getY() + 145 - yOffset, Color.red, ArrowBuilder.Type.TARGET);
}
}
}
}
}
}
}

View file

@ -20,19 +20,31 @@ import java.util.UUID;
*/
public class OldCardLayoutStrategy implements CardLayoutStrategy {
/**
* This offset is used once to shift all attachments
*/
private static final int ATTACHMENTS_DX_OFFSET = 8;
/**
* This offset is used for each attachment
*/
private static final int ATTACHMENT_DX_OFFSET = 0;
private static final int ATTACHMENT_DY_OFFSET = 10;
@Override
public void doLayout(JLayeredPane jLayeredPane, int width) {
Map<UUID, MagePermanent> permanents = ((BattlefieldPanel)jLayeredPane).getPermanents();
JLayeredPane jPanel = ((BattlefieldPanel)jLayeredPane).getMainPanel();
Map<UUID, MagePermanent> permanents = ((BattlefieldPanel) jLayeredPane).getPermanents();
JLayeredPane jPanel = ((BattlefieldPanel) jLayeredPane).getMainPanel();
int height = Plugins.getInstance().sortPermanents(((BattlefieldPanel)jLayeredPane).getUiComponentsList(), permanents.values());
int height = Plugins.getInstance().sortPermanents(((BattlefieldPanel) jLayeredPane).getUiComponentsList(), permanents.values());
jPanel.setPreferredSize(new Dimension(width - 30, height));
for (PermanentView permanent: ((BattlefieldPanel)jLayeredPane).getBattlefield().values()) {
for (PermanentView permanent : ((BattlefieldPanel) jLayeredPane).getBattlefield().values()) {
if (permanent.getAttachments() != null) {
groupAttachments(jLayeredPane, jPanel, permanents, permanent);
}
}
}
private void groupAttachments(JLayeredPane jLayeredPane, JLayeredPane jPanel, Map<UUID, MagePermanent> permanents, PermanentView permanent) {
@ -60,7 +72,11 @@ public class OldCardLayoutStrategy implements CardLayoutStrategy {
if (link != null) {
link.setBounds(r);
perm.getLinks().add(link);
r.translate(8, 10);
if (index == 1) {
r.translate(ATTACHMENTS_DX_OFFSET, ATTACHMENT_DY_OFFSET); // do it once
} else {
r.translate(ATTACHMENT_DX_OFFSET, ATTACHMENT_DY_OFFSET);
}
perm.setBounds(r);
jLayeredPane.moveToFront(link);
jLayeredPane.moveToFront(perm);

View file

@ -80,6 +80,7 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti
public int cardXOffset, cardYOffset, cardWidth, cardHeight;
private boolean isSelected;
private boolean isPlayable;
private boolean showCastingCost;
private boolean hasImage = false;
private float alpha = 1.0f;
@ -106,6 +107,8 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti
private boolean displayTitleAnyway;
private JPanel cardArea;
public CardPanel(CardView newGameCard, UUID gameId, final boolean loadImage, ActionCallback callback, final boolean foil, Dimension dimension) {
this.gameCard = newGameCard;
this.callback = callback;
@ -152,7 +155,7 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti
}
if (this.gameCard.isToken()) {
// token icon
// token icon
iconPanel = new JPanel();
iconPanel.setLayout(null);
iconPanel.setOpaque(false);
@ -354,6 +357,11 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti
repaint();
}
@Override
public void setCardAreaRef(JPanel cardArea) {
this.cardArea = cardArea;
}
public boolean getSelected() {
return this.isSelected;
}
@ -413,6 +421,11 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti
g2d.fillRoundRect(cardXOffset + 1, cardYOffset + 1, cardWidth - 2, cardHeight - 2, cornerSize, cornerSize);
}
if (isPlayable) {
g2d.setColor(new Color(250, 250, 0, 200));
g2d.fillRoundRect(cardXOffset + 1, cardYOffset + 1, cardWidth - 2, cardHeight - 2, cornerSize, cornerSize);
}
//TODO:uncomment
/*
if (gameCard.isAttacking()) {
@ -516,22 +529,37 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti
}
@Override
public final void setCardBounds(int x, int y, int width, int height) {
cardWidth = width;
cardHeight = height;
int rotCenterX = Math.round(width / 2f);
int rotCenterY = height - rotCenterX;
int rotCenterToTopCorner = Math.round(width * CardPanel.ROT_CENTER_TO_TOP_CORNER);
int rotCenterToBottomCorner = Math.round(width * CardPanel.ROT_CENTER_TO_BOTTOM_CORNER);
int xOffset = rotCenterX - rotCenterToBottomCorner;
int yOffset = rotCenterY - rotCenterToTopCorner;
public final void setCardBounds(int x, int y, int cardWidth, int cardHeight) {
this.cardWidth = cardWidth;
this.cardHeight = cardHeight;
int rotCenterX = Math.round(cardWidth / 2f);
int rotCenterY = cardHeight - rotCenterX;
int rotCenterToTopCorner = Math.round(cardWidth * CardPanel.ROT_CENTER_TO_TOP_CORNER);
int rotCenterToBottomCorner = Math.round(cardWidth * CardPanel.ROT_CENTER_TO_BOTTOM_CORNER);
int xOffset = getXOffset(cardWidth);
int yOffset = getYOffset(cardWidth, cardHeight);
cardXOffset = -xOffset;
cardYOffset = -yOffset;
width = -xOffset + rotCenterX + rotCenterToTopCorner;
height = -yOffset + rotCenterY + rotCenterToBottomCorner;
int width = -xOffset + rotCenterX + rotCenterToTopCorner;
int height = -yOffset + rotCenterY + rotCenterToBottomCorner;
setBounds(x + xOffset, y + yOffset, width, height);
}
public int getXOffset(int cardWidth) {
int rotCenterX = Math.round(cardWidth / 2f);
int rotCenterToBottomCorner = Math.round(cardWidth * CardPanel.ROT_CENTER_TO_BOTTOM_CORNER);
int xOffset = rotCenterX - rotCenterToBottomCorner;
return xOffset;
}
public int getYOffset(int cardWidth, int cardHeight) {
int rotCenterX = Math.round(cardWidth / 2f);
int rotCenterY = cardHeight - rotCenterX;
int rotCenterToTopCorner = Math.round(cardWidth * CardPanel.ROT_CENTER_TO_TOP_CORNER);
int yOffset = rotCenterY - rotCenterToTopCorner;
return yOffset;
}
public int getCardX() {
return getX() + cardXOffset;
}
@ -686,6 +714,8 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti
}
setText(card);
this.isPlayable = card.isPlayable();
boolean updateImage = !gameCard.getName().equals(card.getName()) || gameCard.isFaceDown() != card.isFaceDown(); // update after e.g. turning a night/day card
this.gameCard = card;
@ -777,6 +807,8 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti
@Override
public void mouseDragged(MouseEvent e) {
data.component = this;
callback.mouseDragged(e, data);
}
@Override
@ -832,13 +864,9 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti
data.card = this.gameCard;
data.popupText = popupText;
data.gameId = this.gameId;
data.locationOnScreen = data.component.getLocationOnScreen(); // we need this for popup
data.popupOffsetX = isTapped() ? cardHeight + cardXOffset + POPUP_X_GAP : cardWidth + cardXOffset + POPUP_X_GAP;
data.popupOffsetY = 40;
if (this.isShowing()) {
data.locationOnScreen = this.getLocationOnScreen();
} else {
}
return data;
}
@ -965,4 +993,7 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti
callback.mouseWheelMoved(e, data);
}
public JPanel getCardArea() {
return cardArea;
}
}

View file

@ -47,6 +47,8 @@ public class CardPluginImpl implements CardPlugin {
private static final Logger log = Logger.getLogger(CardPluginImpl.class);
private static final int ATTACHMENT_DY_OFFSET = 10;
private static final int GUTTER_Y = 15;
private static final int GUTTER_X = 5;
static final float EXTRA_CARD_SPACING_X = 0.04f;
@ -149,12 +151,18 @@ public class CardPluginImpl implements CardPlugin {
}
Stack stack = new Stack();
if (permanent.getOriginalPermanent().getAttachments() != null) {
stack.setMaxAttachedCount(permanent.getOriginalPermanent().getAttachments().size());
}
stack.add(permanent);
allLands.add(insertIndex == -1 ? allLands.size() : insertIndex, stack);
}
Row allCreatures = new Row(permanents, RowType.creature);
Row allOthers = new Row(permanents, RowType.other);
Row allAttached = new Row(permanents, RowType.attached);
boolean othersOnTheRight = true;
if (options != null && options.containsKey("nonLandPermanentsInOnePile")) {
@ -266,6 +274,14 @@ public class CardPluginImpl implements CardPlugin {
y = rowBottom;
}
// we need this only for defining card size
// attached permanents will be handled separately
for (Stack stack : allAttached) {
for (MagePermanent panel : stack) {
panel.setCardBounds(0, 0, cardWidth, cardHeight);
}
}
return y;
}
@ -338,7 +354,7 @@ public class CardPluginImpl implements CardPlugin {
}
private static enum RowType {
land, creature, other;
land, creature, other, attached;
public boolean isType(MagePermanent card) {
switch (this) {
@ -348,6 +364,8 @@ public class CardPluginImpl implements CardPlugin {
return CardUtil.isCreature(card);
case other:
return !CardUtil.isLand(card) && !CardUtil.isCreature(card);
case attached:
return card.getOriginalPermanent().isAttachedTo();
default:
throw new RuntimeException("Unhandled type: " + this);
}
@ -371,8 +389,15 @@ public class CardPluginImpl implements CardPlugin {
if (!type.isType(panel)) {
continue;
}
// all attached permanents are grouped separately later
if (!type.equals(RowType.attached) && RowType.attached.isType(panel)) {
continue;
}
Stack stack = new Stack();
stack.add(panel);
if (panel.getOriginalPermanent().getAttachments() != null) {
stack.setMaxAttachedCount(panel.getOriginalPermanent().getAttachments().size());
}
add(stack);
}
}
@ -410,6 +435,11 @@ public class CardPluginImpl implements CardPlugin {
private class Stack extends ArrayList<MagePermanent> {
private static final long serialVersionUID = 1L;
/**
* Max attached object count attached to single permanent in the stack.
*/
private int maxAttachedCount = 0;
public Stack() {
super(8);
}
@ -419,7 +449,15 @@ public class CardPluginImpl implements CardPlugin {
}
private int getHeight() {
return cardHeight + (size() - 1) * stackSpacingY + cardSpacingY;
return cardHeight + (size() - 1) * stackSpacingY + cardSpacingY + ATTACHMENT_DY_OFFSET*maxAttachedCount;
}
public int getMaxAttachedCount() {
return maxAttachedCount;
}
public void setMaxAttachedCount(int maxAttachedCount) {
this.maxAttachedCount = maxAttachedCount;
}
}

View file

@ -1,11 +1,12 @@
package mage.cards;
import java.awt.Image;
import java.util.UUID;
import javax.swing.JPanel;
import mage.cards.action.ActionCallback;
import mage.view.CardView;
import javax.swing.*;
import java.awt.*;
import java.util.UUID;
public abstract class MageCard extends JPanel {
private static final long serialVersionUID = 6089945326434301879L;
@ -27,4 +28,5 @@ public abstract class MageCard extends JPanel {
public abstract boolean isTransformed();
public abstract void showCardTitle();
public abstract void setSelected(boolean selected);
public abstract void setCardAreaRef(JPanel cardArea);
}

View file

@ -8,6 +8,7 @@ public interface ActionCallback {
void mousePressed(MouseEvent e, TransferData data);
void mouseReleased(MouseEvent e, TransferData data);
void mouseMoved(MouseEvent e, TransferData data);
void mouseDragged(MouseEvent e, TransferData data);
void mouseEntered(MouseEvent e, TransferData data);
void mouseExited(MouseEvent e, TransferData data);
void mouseWheelMoved(MouseWheelEvent e, TransferData data);

View file

@ -17,6 +17,11 @@ public class EmptyCallback implements ActionCallback {
public void mouseMoved(MouseEvent e, TransferData data) {
}
@Override
public void mouseDragged(MouseEvent e, TransferData data) {
}
@Override
public void mouseEntered(MouseEvent e, TransferData data) {
}

View file

@ -28,17 +28,11 @@
package mage.view;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.MageObject;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.Modes;
import mage.abilities.SpellAbility;
import mage.abilities.common.TurnFaceUpAbility;
import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.keyword.MorphAbility;
import mage.cards.Card;
import mage.cards.SplitCard;
import mage.constants.CardType;
@ -49,7 +43,6 @@ import mage.counters.Counter;
import mage.counters.CounterType;
import mage.game.command.Emblem;
import mage.game.permanent.Permanent;
import mage.game.permanent.PermanentCard;
import mage.game.permanent.PermanentToken;
import mage.game.permanent.token.Token;
import mage.game.stack.Spell;
@ -57,6 +50,10 @@ import mage.game.stack.StackAbility;
import mage.target.Target;
import mage.target.Targets;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
* @author BetaSteward_at_googlemail.com
*/
@ -114,6 +111,8 @@ public class CardView extends SimpleCardView {
protected boolean rotate;
protected boolean hideInfo; // controlls if the tooltip window is shown (eg. controlled face down morph card)
protected boolean isPlayable;
public CardView(Card card) {
this(card, null, false);
}
@ -673,5 +672,12 @@ public class CardView extends SimpleCardView {
public boolean hideInfo() {
return hideInfo;
}
public boolean isPlayable() {
return isPlayable;
}
public void setPlayable(boolean isPlayable) {
this.isPlayable = isPlayable;
}
}

View file

@ -28,11 +28,6 @@
package mage.view;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.costs.Cost;
import mage.cards.Card;
@ -51,6 +46,9 @@ import mage.game.stack.StackAbility;
import mage.game.stack.StackObject;
import mage.players.Player;
import java.io.Serializable;
import java.util.*;
/**
*
@ -62,6 +60,7 @@ public class GameView implements Serializable {
private final int priorityTime;
private final List<PlayerView> players = new ArrayList<>();
private SimpleCardsView hand;
private Set<UUID> canPlayInHand;
private Map<String, SimpleCardsView> opponentHands;
private final CardsView stack = new CardsView();
private final List<ExileView> exiles = new ArrayList<>();
@ -280,4 +279,11 @@ public class GameView implements Serializable {
return isPlayer;
}
public Set<UUID> getCanPlayInHand() {
return canPlayInHand;
}
public void setCanPlayInHand(Set<UUID> canPlayInHand) {
this.canPlayInHand = canPlayInHand;
}
}

View file

@ -28,9 +28,6 @@
package mage.view;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.TurnFaceUpAbility;
import mage.abilities.common.TurnedFaceUpTriggeredAbility;
@ -38,10 +35,13 @@ import mage.cards.Card;
import mage.constants.Rarity;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.permanent.PermanentCard;
import mage.game.permanent.PermanentToken;
import mage.players.Player;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
*
* @author BetaSteward_at_googlemail.com
@ -59,6 +59,7 @@ public class PermanentView extends CardView {
private final boolean copy;
private final String nameOwner; // only filled if != controller
private final boolean controlled;
private UUID attachedTo;
public PermanentView(Permanent permanent, Card card, UUID createdForPlayerId, Game game) {
super(permanent, null, permanent.getControllerId().equals(createdForPlayerId));
@ -73,6 +74,7 @@ public class PermanentView extends CardView {
attachments = new ArrayList<>();
attachments.addAll(permanent.getAttachments());
}
this.attachedTo = permanent.getAttachedTo();
if (isToken()) {
original = new CardView(((PermanentToken)permanent).getToken());
original.expansionSetCode = permanent.getExpansionSetCode();
@ -179,5 +181,12 @@ public class PermanentView extends CardView {
public boolean isControlled() {
return controlled;
}
public UUID getAttachedTo() {
return attachedTo;
}
public boolean isAttachedTo() {
return attachedTo != null;
}
}

View file

@ -28,17 +28,6 @@
package mage.server.game;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import mage.cards.Cards;
import mage.constants.ManaType;
import mage.game.Game;
@ -50,14 +39,16 @@ import mage.server.User;
import mage.server.UserManager;
import mage.server.util.ConfigSettings;
import mage.server.util.ThreadExecutor;
import mage.view.AbilityPickerView;
import mage.view.CardsView;
import mage.view.GameClientMessage;
import mage.view.GameView;
import mage.view.LookedAtView;
import mage.view.SimpleCardsView;
import mage.view.*;
import org.apache.log4j.Logger;
import java.io.Serializable;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/**
*
* @author BetaSteward_at_googlemail.com
@ -245,15 +236,9 @@ public class GameSession extends GameWatcher {
player.setUserData(this.userData);
GameView gameView = new GameView(game.getState(), game, playerId);
gameView.setHand(new SimpleCardsView(player.getHand().getCards(game)));
gameView.setCanPlayInHand(player.getPlayableInHand(game));
if (player.getPlayersUnderYourControl().size() > 0) {
Map<String, SimpleCardsView> handCards = new HashMap<>();
for (UUID controlledPlayerId : player.getPlayersUnderYourControl()) {
Player opponent = game.getPlayer(controlledPlayerId);
handCards.put(opponent.getName(), new SimpleCardsView(opponent.getHand().getCards(game)));
}
gameView.setOpponentHands(handCards);
}
processControlledPlayers(player, gameView);
//TODO: should player who controls another player's turn be able to look at all these cards?
@ -267,6 +252,17 @@ public class GameSession extends GameWatcher {
return gameView;
}
private void processControlledPlayers(Player player, GameView gameView) {
if (player.getPlayersUnderYourControl().size() > 0) {
Map<String, SimpleCardsView> handCards = new HashMap<>();
for (UUID controlledPlayerId : player.getPlayersUnderYourControl()) {
Player opponent = game.getPlayer(controlledPlayerId);
handCards.put(opponent.getName(), new SimpleCardsView(opponent.getHand().getCards(game)));
}
gameView.setOpponentHands(handCards);
}
}
public void removeGame() {
User user = UserManager.getInstance().getUser(userId);
if (user != null) {

View file

@ -87,7 +87,7 @@ public class AthreosGodOfPassage extends CardImpl {
effect.setText("As long as your devotion to white and black is less than seven, Athreos isn't a creature");
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect));
// Whenever another creature you own dies, return it to your hand unless target opponent pays 3 life.
Ability ability = new AthreosDiesCreatureTriggeredAbility(new AthreosGodOfPassageReturnEffect(), false, filter, true);
Ability ability = new AthreosDiesCreatureTriggeredAbility(new AthreosGodOfPassageReturnEffect(), false, filter);
ability.addTarget(new TargetOpponent());
this.addAbility(ability);
@ -152,12 +152,10 @@ class AthreosGodOfPassageReturnEffect extends OneShotEffect {
class AthreosDiesCreatureTriggeredAbility extends TriggeredAbilityImpl {
protected FilterCreaturePermanent filter;
private boolean setTargetPointer;
public AthreosDiesCreatureTriggeredAbility(Effect effect, boolean optional, FilterCreaturePermanent filter, boolean setTargetPointer) {
public AthreosDiesCreatureTriggeredAbility(Effect effect, boolean optional, FilterCreaturePermanent filter) {
super(Zone.BATTLEFIELD, effect, optional);
this.filter = filter;
this.setTargetPointer = setTargetPointer;
}
public AthreosDiesCreatureTriggeredAbility(AthreosDiesCreatureTriggeredAbility ability) {
@ -177,10 +175,8 @@ class AthreosDiesCreatureTriggeredAbility extends TriggeredAbilityImpl {
if (zEvent.getFromZone().equals(Zone.BATTLEFIELD) && zEvent.getToZone().equals(Zone.GRAVEYARD)) {
Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD);
if (permanent != null && filter.match(permanent, sourceId, controllerId, game)) {
if (setTargetPointer) {
for (Effect effect : this.getEffects()) {
effect.setValue("creatureId", event.getTargetId());
}
for (Effect effect : this.getEffects()) {
effect.setValue("creatureId", event.getTargetId());
}
return true;
}

View file

@ -68,18 +68,19 @@ public class AvariceAmulet extends CardImpl {
// Equipped creature gets +2/+0
Effect effect = new BoostEquippedEffect(2, 0);
effect.setText("Equipped creature gets +2/+0");
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect));
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect);
// and has vigilance
effect = new GainAbilityAttachedEffect(VigilanceAbility.getInstance(), AttachmentType.EQUIPMENT);
effect.setText("and has vigilance");
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect));
ability.addEffect(effect);
//and "At the beginning of your upkeep, draw a card."
effect = new GainAbilityAttachedEffect(new BeginningOfUpkeepTriggeredAbility(new DrawCardSourceControllerEffect(1), TargetController.YOU, false), AttachmentType.EQUIPMENT);
effect.setText("and \"At the beginning of your upkeep, draw a card.\"");
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect));
ability.addEffect(effect);
this.addAbility(ability);
// When equipped creature dies, target opponent gains control of Avarice Amulet.
Ability ability = new DiesAttachedTriggeredAbility(new AvariceAmuletChangeControlEffect(), "equipped creature", false);
ability = new DiesAttachedTriggeredAbility(new AvariceAmuletChangeControlEffect(), "equipped creature", false);
ability.addTarget(new TargetOpponent());
this.addAbility(ability);

View file

@ -29,9 +29,11 @@ package mage.sets.magic2015;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.combat.CantBeBlockedByOneAllEffect;
import mage.abilities.effects.common.combat.CantBeBlockedByOneEffect;
import mage.abilities.effects.common.continious.GainAbilityAllEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Duration;
@ -65,7 +67,8 @@ public class BelligerentSliver extends CardImpl {
this.toughness = new MageInt(2);
// Sliver creatures you control have "This creature can't be blocked except by two or more creatures."
Effect effect = new CantBeBlockedByOneAllEffect(2, filter, Duration.WhileOnBattlefield);
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new CantBeBlockedByOneEffect(2, Duration.WhileOnBattlefield));
Effect effect = new GainAbilityAllEffect(ability, Duration.WhileOnBattlefield, filter);
effect.setText("Sliver creatures you control have \"This creature can't be blocked except by two or more creatures.\"");
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect));
}

View file

@ -32,6 +32,7 @@ import mage.MageInt;
import mage.abilities.common.AuraAttachedTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.continious.BoostSourceEffect;
import mage.abilities.keyword.FlyingAbility;
@ -60,7 +61,9 @@ public class BroodKeeper extends CardImpl {
// Whenever an Aura becomes attached to Brood Keeper, put a 2/2 red Dragon creature token with flying onto the battlefield.
// It has "{R}: This creature gets +1/+0 until end of turn."
this.addAbility(new AuraAttachedTriggeredAbility(new CreateTokenEffect(new BroodKeeperDragonToken()), false));
Effect effect = new CreateTokenEffect(new BroodKeeperDragonToken());
effect.setText("put a 2/2 red Dragon creature token with flying onto the battlefield. It has \"{R}: This creature gets +1/+0 until end of turn.\"");
this.addAbility(new AuraAttachedTriggeredAbility(effect, false));
}
public BroodKeeper(final BroodKeeper card) {

View file

@ -96,6 +96,12 @@ public class SiegeDragon extends CardImpl {
class SiegeDragonAttacksTriggeredAbility extends TriggeredAbilityImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("wall");
static {
filter.add(new SubtypePredicate("Wall"));
}
public SiegeDragonAttacksTriggeredAbility() {
super(Zone.BATTLEFIELD, new SiegeDragonDamageEffect());
}
@ -111,14 +117,13 @@ class SiegeDragonAttacksTriggeredAbility extends TriggeredAbilityImpl {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.ATTACKER_DECLARED && event.getSourceId().equals(this.getSourceId())) {
FilterCreaturePermanent filter = new FilterCreaturePermanent();
filter.add(new ControllerIdPredicate(event.getTargetId()));
filter.add(new SubtypePredicate("Wall"));
List<Permanent> permanents = game.getBattlefield().getActivePermanents(filter, this.getControllerId(), this.getSourceId(), game);
return permanents.isEmpty();
}
return false;
return GameEvent.EventType.ATTACKER_DECLARED.equals(event.getType()) && event.getSourceId().equals(this.getSourceId());
}
@Override
public boolean checkInterveningIfClause(Game game) {
UUID defendingPlayerId = game.getCombat().getDefendingPlayerId(getSourceId(), game);
return defendingPlayerId != null && game.getBattlefield().countAll(filter, defendingPlayerId, game) < 1;
}
@Override
@ -144,10 +149,10 @@ class SiegeDragonDamageEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
UUID defenderId = game.getCombat().getDefenderId(source.getSourceId());
if (defenderId != null) {
UUID defendingPlayerId = game.getCombat().getDefendingPlayerId(source.getSourceId(), game);
if (defendingPlayerId != null) {
FilterCreaturePermanent filter = new FilterCreaturePermanent();
filter.add(new ControllerIdPredicate(defenderId));
filter.add(new ControllerIdPredicate(defendingPlayerId));
filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class)));
List<Permanent> permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game);
for (Permanent permanent : permanents) {

View file

@ -106,7 +106,7 @@ class TangleWireEffect extends OneShotEffect {
int counterCount = permanent.getCounters().getCount(CounterType.FADE);
int amount = Math.min(counterCount, targetCount);
Target target = new TargetControlledPermanent(amount, amount, filter, false);
Target target = new TargetControlledPermanent(amount, amount, filter, true);
target.setNotTarget(true);
if (amount > 0 && player.chooseTarget(Outcome.Tap, target, source, game)) {

View file

@ -62,9 +62,9 @@ public class CephalidColiseum extends CardImpl {
// Threshold - {U}, {tap}, Sacrifice Cephalid Coliseum: Target player draws three cards, then discards three cards. Activate this ability only if seven or more cards are in your graveyard.
Ability thresholdAbility = new ConditionalGainActivatedAbility(Zone.BATTLEFIELD,
new DrawCardTargetEffect(3),
new ManaCostsImpl("{G}"),
new ManaCostsImpl("{U}"),
new CardsInControllerGraveCondition(7),
"<i>Threshold</i> - {G}, {T}, Sacrifice {this}: Target player draws three cards, then discards three cards. Activate this ability only if seven or more cards are in your graveyard.");
"<i>Threshold</i> - {U}, {T}, Sacrifice {this}: Target player draws three cards, then discards three cards. Activate this ability only if seven or more cards are in your graveyard.");
thresholdAbility.addEffect(new DiscardTargetEffect(3));
thresholdAbility.addCost(new TapSourceCost());
thresholdAbility.addCost(new SacrificeSourceCost());

View file

@ -28,6 +28,7 @@
package mage.sets.onslaught;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.CycleAllTriggeredAbility;
import mage.abilities.common.delayed.AtEndOfTurnDelayedTriggeredAbility;
@ -86,12 +87,14 @@ class AstralSlideEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
MageObject sourceObject = game.getObject(source.getSourceId());
if (controller != null && sourceObject != null) {
Permanent permanent = game.getPermanent(source.getFirstTarget());
if (permanent != null) {
if (controller.moveCardToExileWithInfo(permanent, null, "", source.getSourceId(), game, Zone.BATTLEFIELD)) {
UUID exileId = UUID.randomUUID();
if (controller.moveCardToExileWithInfo(permanent, exileId, sourceObject.getLogName(), source.getSourceId(), game, Zone.BATTLEFIELD)) {
//create delayed triggered ability
AtEndOfTurnDelayedTriggeredAbility delayedAbility = new AtEndOfTurnDelayedTriggeredAbility(new ReturnFromExileEffect(source.getSourceId(), Zone.BATTLEFIELD, false));
AtEndOfTurnDelayedTriggeredAbility delayedAbility = new AtEndOfTurnDelayedTriggeredAbility(new ReturnFromExileEffect(exileId, Zone.BATTLEFIELD, false));
delayedAbility.setSourceId(source.getSourceId());
delayedAbility.setControllerId(source.getControllerId());
game.addDelayedTriggeredAbility(delayedAbility);

View file

@ -89,31 +89,34 @@ class ChainOfVaporEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
Permanent permanent = game.getPermanent(source.getFirstTarget());
if (permanent != null) {
if(!permanent.moveToZone(Zone.HAND, source.getId(), game, false)){
if (!controller.moveCardToHandWithInfo(permanent, source.getSourceId(), game, Zone.BATTLEFIELD)){
return false;
}
}
Player player = game.getPlayer(permanent.getControllerId());
if(player.chooseUse(Outcome.ReturnToHand, "Sacrifice a land to copy this spell?", game)){
if (player.chooseUse(Outcome.ReturnToHand, "Sacrifice a land to copy this spell?", game)){
TargetControlledPermanent target = new TargetControlledPermanent(new FilterControlledLandPermanent());
if(player.chooseTarget(Outcome.Sacrifice, target, source, game)){
if (player.chooseTarget(Outcome.Sacrifice, target, source, game)){
Permanent land = game.getPermanent(target.getFirstTarget());
if(land != null){
if(land.sacrifice(source.getId(), game)){
Spell spell = game.getStack().getSpell(source.getId());
Spell spell = game.getStack().getSpell(source.getSourceId());
if (spell != null) {
Spell copy = spell.copySpell();
copy.setControllerId(player.getId());
copy.setCopiedSpell(true);
game.getStack().push(copy);
copy.chooseNewTargets(game, source.getControllerId());
copy.chooseNewTargets(game, player.getId());
String activateMessage = copy.getActivatedMessage(game);
if (activateMessage.startsWith(" casts ")) {
activateMessage = activateMessage.substring(6);
}
game.informPlayers(player.getName() + " copies " + activateMessage);;
game.informPlayers(player.getName() + " copies " + activateMessage);
return true;
}
return false;

View file

@ -34,9 +34,13 @@ import mage.constants.Rarity;
import mage.MageInt;
import mage.Mana;
import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.costs.common.SacrificeTargetCost;
import mage.abilities.mana.SimpleManaAbility;
import mage.cards.CardImpl;
import mage.constants.Zone;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.mageobject.SubtypePredicate;
import mage.target.common.TargetControlledCreaturePermanent;
/**
*
@ -44,6 +48,12 @@ import mage.constants.Zone;
*/
public class SkirkProspector extends CardImpl {
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("a Goblin");
static {
filter.add(new SubtypePredicate(("Goblin")));
}
public SkirkProspector(UUID ownerId) {
super(ownerId, 230, "Skirk Prospector", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{R}");
this.expansionSetCode = "ONS";
@ -54,7 +64,7 @@ public class SkirkProspector extends CardImpl {
this.toughness = new MageInt(1);
// Sacrifice a Goblin: Add {R} to your mana pool.
this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, Mana.RedMana, new SacrificeSourceCost()));
this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, Mana.RedMana, new SacrificeTargetCost(new TargetControlledCreaturePermanent(1,1,filter,true))));
}
public SkirkProspector(final SkirkProspector card) {

View file

@ -0,0 +1,70 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.sets.planeshift;
import java.util.UUID;
import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.filter.FilterCard;
import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.target.common.TargetCardInLibrary;
/**
*
* @author LevelX2
*/
public class EladamrisCall extends CardImpl {
private static final FilterCard filter = new FilterCard("creature card");
static {
filter.add(new CardTypePredicate(CardType.CREATURE));
}
public EladamrisCall(UUID ownerId) {
super(ownerId, 106, "Eladamri's Call", Rarity.RARE, new CardType[]{CardType.INSTANT}, "{G}{W}");
this.expansionSetCode = "PLS";
this.color.setGreen(true);
this.color.setWhite(true);
// Search your library for a creature card, reveal that card, and put it into your hand. Then shuffle your library.
this.getSpellAbility().addEffect(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true, true));
}
public EladamrisCall(final EladamrisCall card) {
super(card);
}
@Override
public EladamrisCall copy() {
return new EladamrisCall(this);
}
}

View file

@ -36,7 +36,7 @@ import mage.constants.Duration;
import mage.constants.Rarity;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterLandPermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.SupertypePredicate;
@ -46,7 +46,7 @@ import mage.filter.predicate.mageobject.SupertypePredicate;
*/
public class BackToBasics extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent("Nonbasic lands");
private static final FilterLandPermanent filter = new FilterLandPermanent("Nonbasic lands");
static {
filter.add(Predicates.not(new SupertypePredicate("Basic")));

View file

@ -63,7 +63,7 @@ public class DeftbladeElite extends CardImpl {
// {1}{W}: Prevent all combat damage that would be dealt to and dealt by Deftblade Elite this turn.
Effect effect = new PreventCombatDamageToSourceEffect(Duration.EndOfTurn);
effect.setText("Prevent all combat damage that would be dealt to");
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{3}{W}"));
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{1}{W}"));
effect = new PreventCombatDamageBySourceEffect(Duration.EndOfTurn);
effect.setText("and dealt by {this} this turn");
ability.addEffect(effect);

View file

@ -18,6 +18,7 @@ import mage.players.Player;
import mage.target.common.TargetCardInLibrary;
import java.util.UUID;
import mage.constants.TimingRule;
/**
* @author Loki
@ -25,6 +26,7 @@ import java.util.UUID;
public class TransmuteAbility extends SimpleActivatedAbility {
public TransmuteAbility(String manaCost) {
super(Zone.HAND, new TransmuteEffect(), new ManaCostsImpl(manaCost));
this.setTiming(TimingRule.SORCERY);
this.addCost(new DiscardSourceCost());
}

View file

@ -28,23 +28,6 @@
package mage.game;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;
import java.util.Stack;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.ActivatedAbility;
@ -69,13 +52,7 @@ import mage.cards.CardsImpl;
import mage.cards.SplitCard;
import mage.cards.decks.Deck;
import mage.choices.Choice;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.MultiplayerAttackOption;
import mage.constants.Outcome;
import mage.constants.PhaseStep;
import mage.constants.RangeOfInfluence;
import mage.constants.Zone;
import mage.constants.*;
import mage.counters.CounterType;
import mage.filter.Filter;
import mage.filter.FilterPermanent;
@ -90,14 +67,8 @@ import mage.game.combat.Combat;
import mage.game.command.CommandObject;
import mage.game.command.Commander;
import mage.game.command.Emblem;
import mage.game.events.DamageEvent;
import mage.game.events.GameEvent;
import mage.game.events.Listener;
import mage.game.events.PlayerQueryEvent;
import mage.game.events.PlayerQueryEventSource;
import mage.game.events.TableEvent;
import mage.game.events.*;
import mage.game.events.TableEvent.EventType;
import mage.game.events.TableEventSource;
import mage.game.permanent.Battlefield;
import mage.game.permanent.Permanent;
import mage.game.permanent.PermanentCard;
@ -115,14 +86,14 @@ import mage.target.Target;
import mage.target.TargetPermanent;
import mage.target.TargetPlayer;
import mage.util.functions.ApplyToPermanent;
import mage.watchers.common.CastSpellLastTurnWatcher;
import mage.watchers.common.MiracleWatcher;
import mage.watchers.common.MorbidWatcher;
import mage.watchers.common.PlayerDamagedBySourceWatcher;
import mage.watchers.common.PlayerLostLifeWatcher;
import mage.watchers.common.SoulbondWatcher;
import mage.watchers.common.*;
import org.apache.log4j.Logger;
import java.io.IOException;
import java.io.Serializable;
import java.util.*;
import java.util.Map.Entry;
public abstract class GameImpl implements Game, Serializable {
private static final transient Logger logger = Logger.getLogger(GameImpl.class);
@ -1859,7 +1830,7 @@ public abstract class GameImpl implements Game, Serializable {
@Override
public boolean canPlaySorcery(UUID playerId) {
return getActivePlayerId().equals(playerId) && getStack().isEmpty() && isMainPhase();
return isMainPhase() && getActivePlayerId().equals(playerId) && getStack().isEmpty();
}
/**

View file

@ -28,21 +28,9 @@
package mage.players;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import mage.MageItem;
import mage.MageObject;
import mage.abilities.Abilities;
import mage.abilities.Ability;
import mage.abilities.ActivatedAbility;
import mage.abilities.Mode;
import mage.abilities.Modes;
import mage.abilities.SpellAbility;
import mage.abilities.TriggeredAbility;
import mage.abilities.*;
import mage.abilities.costs.AlternativeSourceCosts;
import mage.abilities.costs.VariableCost;
import mage.abilities.costs.mana.ManaCost;
@ -69,6 +57,9 @@ import mage.target.TargetCard;
import mage.target.common.TargetCardInLibrary;
import mage.util.Copyable;
import java.io.Serializable;
import java.util.*;
/**
*
* @author BetaSteward_at_googlemail.com
@ -340,6 +331,8 @@ public interface Player extends MageItem, Copyable<Player> {
List<Ability> getPlayable(Game game, boolean hidden);
List<Ability> getPlayableOptions(Ability ability, Game game);
Set<UUID> getPlayableInHand(Game game);
void addCounters(Counter counter, Game game);
List<UUID> getAttachments();
boolean addAttachment(UUID permanentId, Game game);

View file

@ -28,31 +28,9 @@
package mage.players;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
import mage.MageObject;
import mage.Mana;
import mage.abilities.Abilities;
import mage.abilities.AbilitiesImpl;
import mage.abilities.Ability;
import mage.abilities.ActivatedAbility;
import mage.abilities.DelayedTriggeredAbility;
import mage.abilities.Mode;
import mage.abilities.PlayLandAbility;
import mage.abilities.SpecialAction;
import mage.abilities.SpellAbility;
import mage.abilities.TriggeredAbility;
import mage.abilities.*;
import mage.abilities.common.PassAbility;
import mage.abilities.common.delayed.AtTheEndOfTurnStepPostDelayedTriggeredAbility;
import mage.abilities.costs.AdjustingSourceCosts;
@ -62,12 +40,7 @@ import mage.abilities.costs.AlternativeSourceCosts;
import mage.abilities.effects.RestrictionEffect;
import mage.abilities.effects.RestrictionUntapNotMoreThanEffect;
import mage.abilities.effects.common.LoseControlOnOtherPlayersControllerEffect;
import mage.abilities.keyword.FlashbackAbility;
import mage.abilities.keyword.HexproofAbility;
import mage.abilities.keyword.InfectAbility;
import mage.abilities.keyword.LifelinkAbility;
import mage.abilities.keyword.ProtectionAbility;
import mage.abilities.keyword.ShroudAbility;
import mage.abilities.keyword.*;
import mage.abilities.mana.ManaAbility;
import mage.abilities.mana.ManaOptions;
import mage.actions.MageDrawAction;
@ -76,14 +49,7 @@ import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.cards.SplitCard;
import mage.cards.decks.Deck;
import mage.constants.AsThoughEffectType;
import mage.constants.CardType;
import mage.constants.ManaType;
import mage.constants.Outcome;
import mage.constants.RangeOfInfluence;
import mage.constants.SpellAbilityType;
import mage.constants.TimingRule;
import mage.constants.Zone;
import mage.constants.*;
import mage.counters.Counter;
import mage.counters.CounterType;
import mage.counters.Counters;
@ -116,6 +82,10 @@ import mage.target.common.TargetDiscard;
import mage.watchers.common.BloodthirstWatcher;
import org.apache.log4j.Logger;
import java.io.Serializable;
import java.util.*;
import java.util.Map.Entry;
public abstract class PlayerImpl implements Player, Serializable {
private static final transient Logger log = Logger.getLogger(PlayerImpl.class);
@ -1544,7 +1514,7 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override
public void idleTimeout(Game game) {
game.informPlayers(new StringBuilder(getName()).append(" has run out of time. Loosing the Match.").toString());
game.informPlayers(new StringBuilder(getName()).append(" was idle for too long. Loosing the Match.").toString());
quit = true;
idleTimeout = true;
this.concede(game);
@ -1973,6 +1943,25 @@ public abstract class PlayerImpl implements Player, Serializable {
return playable;
}
@Override
public Set<UUID> getPlayableInHand(Game game) {
Set<UUID> playable = new HashSet<>();
ManaOptions available = getManaAvailable(game);
available.addMana(manaPool.getMana());
for (Card card: hand.getCards(game)) {
for (ActivatedAbility ability: card.getAbilities().getPlayableAbilities(Zone.HAND)) {
if (canPlay(ability, available, game)) {
playable.add(card.getId());
break;
}
}
}
return playable;
}
/**
* Only used for AIs
*

View file

@ -327,7 +327,7 @@ public abstract class TargetImpl implements Target {
@Override
public boolean isLegal(Ability source, Game game) {
//20101001 - 608.2b
Set <UUID> illegalTargets = new HashSet<UUID>();
Set <UUID> illegalTargets = new HashSet<>();
int replacedTargets = 0;
for (UUID targetId: targets.keySet()) {
Card card = game.getCard(targetId);

View file

@ -53,7 +53,12 @@ public class TargetCreatureOrPlayerAmount extends TargetAmount {
protected FilterCreatureOrPlayer filter;
public TargetCreatureOrPlayerAmount(int amount) {
// 107.1c If a rule or ability instructs a player to choose any number, that player may choose
// any positive number or zero, unless something (such as damage or counters) is being divided
// or distributed among any number of players and/or objects. In that case, a nonzero number
// of players and/or objects must be chosen if possible.
this(new StaticValue(amount));
this.minNumberOfTargets = 1;
}
public TargetCreatureOrPlayerAmount(DynamicValue amount) {