mirror of
https://github.com/correl/mage.git
synced 2024-11-15 03:00:16 +00:00
...
This commit is contained in:
parent
df642c2bd5
commit
3fa0e8b8f4
544 changed files with 13327 additions and 3074 deletions
|
@ -1,7 +1,10 @@
|
|||
server-name=localhost
|
||||
port=17171
|
||||
remote-server=mage-server
|
||||
cards-resource-path=resources/images/cards/
|
||||
symbols-resource-path=resources/images/symbols/
|
||||
resource-path=resources/images/
|
||||
cards-resource-path=C:\\Program Files (x86)\\Wizards of the Coast\\Magic Online III\\Graphics\\Cards\\
|
||||
symbols-resource-path=C:\\Program Files (x86)\\Wizards of the Coast\\Magic Online III\\Graphics\\Chat\\chat_graphic_typingicon_
|
||||
resource-path=C:\\Program Files (x86)\\Wizards of the Coast\\Magic Online III\\Graphics\\Cards\\Pics\\
|
||||
#cards-resource-path=resources/images/cards/
|
||||
#symbols-resource-path=resources/images/symbols/
|
||||
#resource-path=resources/images/
|
||||
card-scaling-factor=0.4
|
|
@ -20,6 +20,7 @@ debug.test.classpath=\
|
|||
dist.dir=dist
|
||||
dist.jar=${dist.dir}/Mage.Client.jar
|
||||
dist.javadoc.dir=${dist.dir}/javadoc
|
||||
endorsed.classpath=
|
||||
excludes=
|
||||
includes=**
|
||||
jar.compress=false
|
||||
|
@ -52,7 +53,7 @@ jaxbwiz.endorsed.dirs="${netbeans.home}/../ide12/modules/ext/jaxb/api"
|
|||
main.class=mage.client.MageFrame
|
||||
manifest.file=manifest.mf
|
||||
meta.inf.dir=${src.dir}/META-INF
|
||||
platform.active=default_platform
|
||||
platform.active=JDK_1.6_21
|
||||
project.license=bsd
|
||||
project.Mage=../Mage
|
||||
project.Mage_Common=../Mage.Common
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
<configuration>
|
||||
<data xmlns="http://www.netbeans.org/ns/j2se-project/3">
|
||||
<name>Mage.Client</name>
|
||||
<explicit-platform explicit-source-supported="true"/>
|
||||
<source-roots>
|
||||
<root id="src.dir"/>
|
||||
</source-roots>
|
||||
|
|
BIN
Mage.Client/release/sample-decks/SanJuanSwartz.dck
Normal file
BIN
Mage.Client/release/sample-decks/SanJuanSwartz.dck
Normal file
Binary file not shown.
|
@ -45,7 +45,9 @@ import javax.swing.JLayeredPane;
|
|||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import mage.client.dialog.AboutDialog;
|
||||
import mage.client.dialog.CombatDialog;
|
||||
import mage.client.dialog.ConnectDialog;
|
||||
import mage.client.dialog.PickNumberDialog;
|
||||
import mage.client.remote.Session;
|
||||
import mage.client.util.EDTExceptionHandler;
|
||||
import mage.util.Logging;
|
||||
|
@ -60,6 +62,8 @@ public class MageFrame extends javax.swing.JFrame {
|
|||
|
||||
private static Session session;
|
||||
private ConnectDialog connectDialog;
|
||||
private static CombatDialog combat;
|
||||
private static PickNumberDialog pickNumber;
|
||||
|
||||
/**
|
||||
* @return the session
|
||||
|
@ -96,8 +100,12 @@ public class MageFrame extends javax.swing.JFrame {
|
|||
|
||||
session = new Session(this);
|
||||
connectDialog = new ConnectDialog(session);
|
||||
combat = new CombatDialog();
|
||||
pickNumber = new PickNumberDialog();
|
||||
desktopPane.add(connectDialog, JLayeredPane.POPUP_LAYER);
|
||||
// connectDialog.setLocation(50, 50);
|
||||
desktopPane.add(combat, JLayeredPane.POPUP_LAYER);
|
||||
combat.hideDialog();
|
||||
desktopPane.add(pickNumber, JLayeredPane.POPUP_LAYER);
|
||||
disableButtons();
|
||||
}
|
||||
|
||||
|
@ -311,6 +319,14 @@ public class MageFrame extends javax.swing.JFrame {
|
|||
this.deckEditorPane.setVisible(false);
|
||||
}
|
||||
|
||||
public static CombatDialog getCombatDialog() {
|
||||
return combat;
|
||||
}
|
||||
|
||||
public static PickNumberDialog getPickNumberDialog() {
|
||||
return pickNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
|
|
|
@ -63,6 +63,7 @@ import javax.swing.text.StyledDocument;
|
|||
import mage.Constants.CardType;
|
||||
import mage.client.MageFrame;
|
||||
import mage.client.remote.Session;
|
||||
import mage.client.util.Config;
|
||||
|
||||
import mage.client.util.ImageHelper;
|
||||
import mage.view.CardView;
|
||||
|
@ -79,10 +80,11 @@ public class Card extends javax.swing.JPanel implements MouseMotionListener, Mou
|
|||
protected Point p;
|
||||
protected CardDimensions dimension;
|
||||
|
||||
protected UUID gameId;
|
||||
protected BigCard bigCard;
|
||||
protected final UUID gameId;
|
||||
protected final BigCard bigCard;
|
||||
protected CardView card;
|
||||
protected Popup popup;
|
||||
protected boolean popupShowing;
|
||||
|
||||
protected TextPopup popupText = new TextPopup();
|
||||
protected BufferedImage background;
|
||||
|
@ -97,7 +99,7 @@ public class Card extends javax.swing.JPanel implements MouseMotionListener, Mou
|
|||
this.gameId = gameId;
|
||||
this.card = card;
|
||||
this.bigCard = bigCard;
|
||||
small = new BufferedImage(dimension.frameWidth, dimension.frameHeight, BufferedImage.TYPE_INT_RGB);
|
||||
small = new BufferedImage(Config.dimensions.frameWidth, Config.dimensions.frameHeight, BufferedImage.TYPE_INT_RGB);
|
||||
background = ImageHelper.getBackground(card);
|
||||
|
||||
StyledDocument doc = text.getStyledDocument();
|
||||
|
@ -136,7 +138,7 @@ public class Card extends javax.swing.JPanel implements MouseMotionListener, Mou
|
|||
|
||||
gSmall.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
gSmall.setColor(Color.BLACK);
|
||||
gSmall.drawImage(ImageHelper.ScaleImage(image, dimension.frameWidth, dimension.frameHeight), 0, 0, this);
|
||||
gSmall.drawImage(ImageHelper.ScaleImage(image, Config.dimensions.frameWidth, Config.dimensions.frameHeight), 0, 0, this);
|
||||
|
||||
gImage.setFont(new Font("Arial", Font.PLAIN, NAME_FONT_MAX_SIZE));
|
||||
gImage.drawString(card.getName(), CONTENT_MAX_XOFFSET, NAME_MAX_YOFFSET);
|
||||
|
@ -152,17 +154,17 @@ public class Card extends javax.swing.JPanel implements MouseMotionListener, Mou
|
|||
|
||||
gImage.dispose();
|
||||
|
||||
gSmall.setFont(new Font("Arial", Font.PLAIN, dimension.nameFontSize));
|
||||
gSmall.drawString(card.getName(), dimension.contentXOffset, dimension.nameYOffset);
|
||||
gSmall.setFont(new Font("Arial", Font.PLAIN, Config.dimensions.nameFontSize));
|
||||
gSmall.drawString(card.getName(), Config.dimensions.contentXOffset, Config.dimensions.nameYOffset);
|
||||
if (card.getCardTypes().contains(CardType.CREATURE)) {
|
||||
gSmall.drawString(card.getPower() + "/" + card.getToughness(), dimension.powBoxTextLeft, dimension.powBoxTextTop);
|
||||
gSmall.drawString(card.getPower() + "/" + card.getToughness(), Config.dimensions.powBoxTextLeft, Config.dimensions.powBoxTextTop);
|
||||
}
|
||||
else if (card.getCardTypes().contains(CardType.PLANESWALKER)) {
|
||||
gSmall.drawString(card.getLoyalty(), dimension.powBoxTextLeft, dimension.powBoxTextTop);
|
||||
gSmall.drawString(card.getLoyalty(), Config.dimensions.powBoxTextLeft, Config.dimensions.powBoxTextTop);
|
||||
}
|
||||
|
||||
if (card.getCardTypes().size() > 0)
|
||||
gSmall.drawString(cardType, dimension.contentXOffset, dimension.typeYOffset);
|
||||
gSmall.drawString(cardType, Config.dimensions.contentXOffset, Config.dimensions.typeYOffset);
|
||||
drawText();
|
||||
|
||||
gSmall.dispose();
|
||||
|
@ -187,6 +189,7 @@ public class Card extends javax.swing.JPanel implements MouseMotionListener, Mou
|
|||
for (String rule: getRules()) {
|
||||
sb.append("\n").append(rule);
|
||||
}
|
||||
sb.append("\n").append(card.getId());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
@ -272,7 +275,7 @@ public class Card extends javax.swing.JPanel implements MouseMotionListener, Mou
|
|||
} else {
|
||||
g2.setColor(Color.BLACK);
|
||||
}
|
||||
g2.drawRect(0, 0, dimension.frameWidth - 1, dimension.frameHeight - 1);
|
||||
g2.drawRect(0, 0, Config.dimensions.frameWidth - 1, Config.dimensions.frameHeight - 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -301,21 +304,27 @@ public class Card extends javax.swing.JPanel implements MouseMotionListener, Mou
|
|||
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent arg0) {
|
||||
if (!popupShowing) {
|
||||
if (popup != null)
|
||||
popup.hide();
|
||||
PopupFactory factory = PopupFactory.getSharedInstance();
|
||||
popup = factory.getPopup(this, popupText, (int) this.getLocationOnScreen().getX() + dimension.frameWidth, (int) this.getLocationOnScreen().getY() + 40);
|
||||
popup = factory.getPopup(this, popupText, (int) this.getLocationOnScreen().getX() + Config.dimensions.frameWidth, (int) this.getLocationOnScreen().getY() + 40);
|
||||
popup.show();
|
||||
//hack to get popup to resize to fit text
|
||||
popup.hide();
|
||||
popup = factory.getPopup(this, popupText, (int) this.getLocationOnScreen().getX() + dimension.frameWidth, (int) this.getLocationOnScreen().getY() + 40);
|
||||
popup = factory.getPopup(this, popupText, (int) this.getLocationOnScreen().getX() + Config.dimensions.frameWidth, (int) this.getLocationOnScreen().getY() + 40);
|
||||
popup.show();
|
||||
popupShowing = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(MouseEvent arg0) {
|
||||
if (popup != null)
|
||||
if(getMousePosition(true) != null) return;
|
||||
if (popup != null) {
|
||||
popup.hide();
|
||||
popupShowing = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -36,19 +36,19 @@ import static mage.client.util.Constants.*;
|
|||
*/
|
||||
public class CardDimensions {
|
||||
|
||||
public static int frameHeight;
|
||||
public static int frameWidth;
|
||||
public static int symbolHeight;
|
||||
public static int symbolWidth;
|
||||
public static int contentXOffset;
|
||||
public static int nameYOffset;
|
||||
public static int typeYOffset;
|
||||
public static int textYOffset;
|
||||
public static int textWidth;
|
||||
public static int textHeight;
|
||||
public static int powBoxTextTop;
|
||||
public static int powBoxTextLeft;
|
||||
public static int nameFontSize;
|
||||
public int frameHeight;
|
||||
public int frameWidth;
|
||||
public int symbolHeight;
|
||||
public int symbolWidth;
|
||||
public int contentXOffset;
|
||||
public int nameYOffset;
|
||||
public int typeYOffset;
|
||||
public int textYOffset;
|
||||
public int textWidth;
|
||||
public int textHeight;
|
||||
public int powBoxTextTop;
|
||||
public int powBoxTextLeft;
|
||||
public int nameFontSize;
|
||||
|
||||
public CardDimensions(double scaleFactor) {
|
||||
frameHeight = (int)(FRAME_MAX_HEIGHT * scaleFactor);
|
||||
|
|
|
@ -16,12 +16,12 @@
|
|||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<EmptySpace min="0" pref="400" max="32767" attributes="0"/>
|
||||
<EmptySpace min="0" pref="294" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<EmptySpace min="0" pref="300" max="32767" attributes="0"/>
|
||||
<EmptySpace min="0" pref="197" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
|
|
|
@ -37,12 +37,17 @@ package mage.client.cards;
|
|||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.ComponentListener;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.UUID;
|
||||
import mage.client.util.Config;
|
||||
import mage.client.util.Event;
|
||||
|
@ -54,45 +59,52 @@ import mage.view.CardsView;
|
|||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class CardGrid extends javax.swing.JLayeredPane implements MouseListener, ComponentListener {
|
||||
public class CardGrid extends javax.swing.JLayeredPane implements MouseListener {
|
||||
|
||||
protected CardEventSource cardEventSource = new CardEventSource();
|
||||
protected BigCard bigCard;
|
||||
protected UUID gameId;
|
||||
protected List<Card> cards = new ArrayList<Card>();
|
||||
private Map<UUID, Card> cards = new HashMap<UUID, Card>();
|
||||
|
||||
public CardGrid() {
|
||||
initComponents();
|
||||
addComponentListener(this);
|
||||
setPreferredSize(new Dimension(Config.dimensions.frameWidth, Config.dimensions.frameHeight));
|
||||
}
|
||||
|
||||
public void loadCards(CardsView showCards, BigCard bigCard, UUID gameId) {
|
||||
this.bigCard = bigCard;
|
||||
this.gameId = gameId;
|
||||
cards.clear();
|
||||
for (CardView card: showCards) {
|
||||
for (CardView card: showCards.values()) {
|
||||
if (!cards.containsKey(card.getId())) {
|
||||
Card cardImg = new Card(card, bigCard, Config.dimensions, gameId);
|
||||
cardImg.update(card);
|
||||
cardImg.addMouseListener(this);
|
||||
cards.add(cardImg);
|
||||
add(cardImg);
|
||||
cardImg.update(card);
|
||||
cards.put(card.getId(), cardImg);
|
||||
}
|
||||
}
|
||||
for (Iterator<Entry<UUID, Card>> i = cards.entrySet().iterator(); i.hasNext();) {
|
||||
Entry<UUID, Card> entry = i.next();
|
||||
if (!showCards.containsKey(entry.getKey())) {
|
||||
removeCard(entry.getKey());
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
drawCards();
|
||||
this.setVisible(true);
|
||||
}
|
||||
|
||||
public void drawCards() {
|
||||
removeAll();
|
||||
int maxWidth = this.getParent().getWidth();
|
||||
int numColumns = maxWidth / Config.dimensions.frameWidth;
|
||||
int curColumn = 0;
|
||||
int curRow = 0;
|
||||
if (cards.size() > 0) {
|
||||
Rectangle rectangle = new Rectangle(Config.dimensions.frameWidth, Config.dimensions.frameHeight);
|
||||
for (Card cardImg: cards) {
|
||||
List<Card> sortedCards = new ArrayList<Card>(cards.values());
|
||||
Collections.sort(sortedCards, new CardComparator());
|
||||
for (Card cardImg: sortedCards) {
|
||||
rectangle.setLocation(curColumn * Config.dimensions.frameWidth, curRow * 20);
|
||||
cardImg.setBounds(rectangle);
|
||||
add(cardImg);
|
||||
moveToFront(cardImg);
|
||||
curColumn++;
|
||||
if (curColumn == numColumns) {
|
||||
|
@ -104,6 +116,17 @@ public class CardGrid extends javax.swing.JLayeredPane implements MouseListener,
|
|||
resizeArea();
|
||||
}
|
||||
|
||||
private void removeCard(UUID cardId) {
|
||||
for (Component comp: getComponents()) {
|
||||
if (comp instanceof Card) {
|
||||
if (((Card)comp).getCardId().equals(cardId)) {
|
||||
remove(comp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void addCardEventListener(Listener<Event> listener) {
|
||||
cardEventSource.addListener(listener);
|
||||
}
|
||||
|
@ -125,11 +148,11 @@ public class CardGrid extends javax.swing.JLayeredPane implements MouseListener,
|
|||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGap(0, 400, Short.MAX_VALUE)
|
||||
.addGap(0, 294, Short.MAX_VALUE)
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGap(0, 300, Short.MAX_VALUE)
|
||||
.addGap(0, 197, Short.MAX_VALUE)
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
|
@ -157,26 +180,6 @@ public class CardGrid extends javax.swing.JLayeredPane implements MouseListener,
|
|||
@Override
|
||||
public void mouseExited(MouseEvent e) {}
|
||||
|
||||
@Override
|
||||
public void componentResized(ComponentEvent e) {
|
||||
resizeArea();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentMoved(ComponentEvent e) {
|
||||
resizeArea();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentShown(ComponentEvent e) {
|
||||
resizeArea();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentHidden(ComponentEvent e) {
|
||||
resizeArea();
|
||||
}
|
||||
|
||||
private void resizeArea() {
|
||||
Dimension area = new Dimension(0, 0);
|
||||
Dimension size = getPreferredSize();
|
||||
|
@ -198,3 +201,12 @@ public class CardGrid extends javax.swing.JLayeredPane implements MouseListener,
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
class CardComparator implements Comparator<Card> {
|
||||
|
||||
@Override
|
||||
public int compare(Card o1, Card o2) {
|
||||
return o1.card.getName().compareTo(o2.card.getName());
|
||||
}
|
||||
|
||||
}
|
|
@ -34,12 +34,16 @@
|
|||
|
||||
package mage.client.cards;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.UUID;
|
||||
import mage.client.util.Config;
|
||||
import mage.view.CardView;
|
||||
import mage.view.CardsView;
|
||||
import static mage.client.util.Constants.*;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -47,26 +51,52 @@ import static mage.client.util.Constants.*;
|
|||
*/
|
||||
public class Cards extends javax.swing.JPanel {
|
||||
|
||||
private Map<UUID, Card> cards = new HashMap<UUID, Card>();
|
||||
|
||||
/** Creates new form Cards */
|
||||
public Cards() {
|
||||
initComponents();
|
||||
cardArea.setPreferredSize(new Dimension(Config.dimensions.frameWidth, Config.dimensions.frameHeight));
|
||||
}
|
||||
|
||||
public void loadCards(CardsView cards, BigCard bigCard, UUID gameId) {
|
||||
cardArea.removeAll();
|
||||
for (CardView card: cards) {
|
||||
public boolean loadCards(CardsView cardsView, BigCard bigCard, UUID gameId) {
|
||||
boolean changed = false;
|
||||
for (CardView card: cardsView.values()) {
|
||||
if (!cards.containsKey(card.getId())) {
|
||||
Card cardImg = new Card(card, bigCard, Config.dimensions, gameId);
|
||||
cards.put(card.getId(), cardImg);
|
||||
cardArea.add(cardImg);
|
||||
cardImg.update(card);
|
||||
changed = true;
|
||||
}
|
||||
cards.get(card.getId()).update(card);
|
||||
}
|
||||
for (Iterator<Entry<UUID, Card>> i = cards.entrySet().iterator(); i.hasNext();) {
|
||||
Entry<UUID, Card> entry = i.next();
|
||||
if (!cardsView.containsKey(entry.getKey())) {
|
||||
removeCard(entry.getKey());
|
||||
i.remove();
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
cardArea.setPreferredSize(new Dimension(cards.size() * Config.dimensions.frameWidth, Config.dimensions.frameHeight));
|
||||
cardArea.revalidate();
|
||||
cardArea.repaint();
|
||||
this.revalidate();
|
||||
this.repaint();
|
||||
return changed;
|
||||
}
|
||||
|
||||
private void removeCard(UUID cardId) {
|
||||
for (Component comp: cardArea.getComponents()) {
|
||||
if (comp instanceof Card) {
|
||||
if (((Card)comp).getCardId().equals(cardId)) {
|
||||
cardArea.remove(comp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** This method is called from within the constructor to
|
||||
* initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
<LineBorder/>
|
||||
</Border>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||
<Connection code="new Dimension(Config.dimensions.frameWidth, Config.dimensions.frameHeight)" type="code"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
|
||||
|
|
|
@ -44,7 +44,6 @@ import mage.client.util.Event;
|
|||
import mage.client.util.Listener;
|
||||
import mage.view.CardView;
|
||||
import mage.view.CardsView;
|
||||
import static mage.client.util.Constants.*;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -57,7 +56,6 @@ public class CardsList extends javax.swing.JPanel implements MouseListener {
|
|||
/** Creates new form Cards */
|
||||
public CardsList() {
|
||||
initComponents();
|
||||
cardArea.setPreferredSize(new Dimension(Config.dimensions.frameWidth, Config.dimensions.frameHeight));
|
||||
}
|
||||
|
||||
public void loadCards(CardsView showCards, BigCard bigCard, UUID gameId) {
|
||||
|
@ -65,7 +63,7 @@ public class CardsList extends javax.swing.JPanel implements MouseListener {
|
|||
if (showCards != null && showCards.size() > 0) {
|
||||
Rectangle rectangle = new Rectangle(Config.dimensions.frameWidth, Config.dimensions.frameHeight);
|
||||
int count = 0;
|
||||
for (CardView card: showCards) {
|
||||
for (CardView card: showCards.values()) {
|
||||
Card cardImg = new Card(card, bigCard, Config.dimensions, gameId);
|
||||
cardImg.setBounds(rectangle);
|
||||
cardArea.add(cardImg);
|
||||
|
@ -110,6 +108,7 @@ public class CardsList extends javax.swing.JPanel implements MouseListener {
|
|||
cardArea = new javax.swing.JLayeredPane();
|
||||
|
||||
setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
|
||||
setPreferredSize(new Dimension(Config.dimensions.frameWidth, Config.dimensions.frameHeight));
|
||||
setLayout(new java.awt.BorderLayout());
|
||||
|
||||
jScrollPane1.setViewportView(cardArea);
|
||||
|
@ -131,15 +130,19 @@ public class CardsList extends javax.swing.JPanel implements MouseListener {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(MouseEvent e) {
|
||||
}
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import javax.swing.PopupFactory;
|
||||
import mage.client.util.Config;
|
||||
import mage.client.util.ImageHelper;
|
||||
import mage.view.CounterView;
|
||||
import mage.view.PermanentView;
|
||||
|
@ -69,7 +70,7 @@ public class Permanent extends Card {
|
|||
super(permanent, bigCard, dimensions, gameId);
|
||||
this.setSize(this.getPreferredSize());
|
||||
this.permanent = permanent;
|
||||
tappedImage = new BufferedImage(dimension.frameHeight, dimension.frameWidth, BufferedImage.TYPE_INT_RGB);
|
||||
tappedImage = new BufferedImage(Config.dimensions.frameHeight, Config.dimensions.frameWidth, BufferedImage.TYPE_INT_RGB);
|
||||
}
|
||||
|
||||
public UUID getPermanentId() {
|
||||
|
@ -153,10 +154,10 @@ public class Permanent extends Card {
|
|||
g2.setColor(Color.BLACK);
|
||||
}
|
||||
if (permanent.isTapped()) {
|
||||
g2.drawRect(0, 0, dimension.frameHeight - 1, dimension.frameWidth - 1);
|
||||
g2.drawRect(0, 0, Config.dimensions.frameHeight - 1, Config.dimensions.frameWidth - 1);
|
||||
}
|
||||
else {
|
||||
g2.drawRect(0, 0, dimension.frameWidth - 1, dimension.frameHeight - 1);
|
||||
g2.drawRect(0, 0, Config.dimensions.frameWidth - 1, Config.dimensions.frameHeight - 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -185,10 +186,10 @@ public class Permanent extends Card {
|
|||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
if (permanent != null && permanent.isTapped()) {
|
||||
return new Dimension(dimension.frameHeight, dimension.frameWidth);
|
||||
return new Dimension(Config.dimensions.frameHeight, Config.dimensions.frameWidth);
|
||||
}
|
||||
else {
|
||||
return new Dimension(dimension.frameWidth, dimension.frameHeight);
|
||||
return new Dimension(Config.dimensions.frameWidth, Config.dimensions.frameHeight);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -203,10 +204,11 @@ public class Permanent extends Card {
|
|||
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent arg0) {
|
||||
if (!popupShowing) {
|
||||
if (popup != null)
|
||||
popup.hide();
|
||||
PopupFactory factory = PopupFactory.getSharedInstance();
|
||||
int x = (int) this.getLocationOnScreen().getX() + (permanent.isTapped()?dimension.frameHeight:dimension.frameWidth);
|
||||
int x = (int) this.getLocationOnScreen().getX() + (permanent.isTapped()?Config.dimensions.frameHeight:Config.dimensions.frameWidth);
|
||||
int y = (int) this.getLocationOnScreen().getY() + 40;
|
||||
popup = factory.getPopup(this, popupText, x, y);
|
||||
popup.show();
|
||||
|
@ -214,6 +216,8 @@ public class Permanent extends Card {
|
|||
popup.hide();
|
||||
popup = factory.getPopup(this, popupText, x, y);
|
||||
popup.show();
|
||||
popupShowing = true;
|
||||
}
|
||||
}
|
||||
|
||||
/** This method is called from within the constructor to
|
||||
|
|
|
@ -34,12 +34,14 @@
|
|||
|
||||
package mage.client.chat;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Logger;
|
||||
import mage.client.MageFrame;
|
||||
import mage.client.remote.Session;
|
||||
import mage.util.Logging;
|
||||
import mage.view.ChatMessage.MessageColor;
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
|
@ -69,7 +71,24 @@ public class ChatPanel extends javax.swing.JPanel {
|
|||
session.leaveChat(chatId);
|
||||
}
|
||||
|
||||
public void receiveMessage(String message) {
|
||||
public void receiveMessage(String message, MessageColor color) {
|
||||
switch (color) {
|
||||
case BLACK:
|
||||
this.txtConversation.setForeground(Color.BLACK);
|
||||
break;
|
||||
case RED:
|
||||
this.txtConversation.setForeground(Color.RED);
|
||||
break;
|
||||
case GREEN:
|
||||
this.txtConversation.setForeground(Color.GREEN);
|
||||
break;
|
||||
case BLUE:
|
||||
this.txtConversation.setForeground(Color.BLUE);
|
||||
break;
|
||||
case ORANGE:
|
||||
this.txtConversation.setForeground(Color.ORANGE);
|
||||
break;
|
||||
}
|
||||
this.txtConversation.append(message + "\n");
|
||||
txtConversation.setCaretPosition(txtConversation.getText().length() - 1);
|
||||
}
|
||||
|
|
|
@ -37,11 +37,13 @@ package mage.client.deckeditor;
|
|||
import java.awt.Cursor;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.ComponentListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.swing.DefaultComboBoxModel;
|
||||
import mage.Constants.CardType;
|
||||
import mage.Constants.Zone;
|
||||
import mage.cards.Cards;
|
||||
import mage.cards.CardsImpl;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.ExpansionSet;
|
||||
import mage.client.cards.BigCard;
|
||||
import mage.client.cards.CardGrid;
|
||||
|
@ -56,8 +58,9 @@ import mage.view.CardsView;
|
|||
*/
|
||||
public class CardSelector extends javax.swing.JPanel implements ComponentListener {
|
||||
|
||||
private Cards cards = new CardsImpl(Zone.OUTSIDE);
|
||||
private FilterCard filter = new FilterCard();
|
||||
private final Set<Card> allCards = new LinkedHashSet<Card>();
|
||||
private final List<Card> cards = new ArrayList<Card>();
|
||||
private final FilterCard filter = new FilterCard();
|
||||
private BigCard bigCard;
|
||||
|
||||
/** Creates new form CardSelector */
|
||||
|
@ -68,12 +71,11 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
|
|||
|
||||
public void loadCards(BigCard bigCard) {
|
||||
this.bigCard = bigCard;
|
||||
this.cards.clear();
|
||||
cbExpansionSet.setModel(new DefaultComboBoxModel(Sets.getInstance().toArray()));
|
||||
cbExpansionSet.insertItemAt("All sets", 0);
|
||||
cbExpansionSet.setSelectedIndex(0);
|
||||
for (ExpansionSet set: Sets.getInstance()) {
|
||||
cards.addAll(set.createCards());
|
||||
allCards.addAll(set.createCards());
|
||||
}
|
||||
filter.setUseColor(true);
|
||||
filter.getColor().setBlack(true);
|
||||
|
@ -98,8 +100,13 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
|
|||
|
||||
private void filterCards() {
|
||||
try {
|
||||
cards.clear();
|
||||
for (Card card: allCards) {
|
||||
if (filter.match(card))
|
||||
cards.add(card);
|
||||
}
|
||||
setCursor(new Cursor(Cursor.WAIT_CURSOR));
|
||||
this.cardGrid.loadCards(new CardsView(cards.getCards(filter)), bigCard, null);
|
||||
this.cardGrid.loadCards(new CardsView(cards), bigCard, null);
|
||||
}
|
||||
finally {
|
||||
setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
|
||||
|
@ -110,7 +117,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene
|
|||
return this.cardGrid;
|
||||
}
|
||||
|
||||
public Cards getCards() {
|
||||
public List<Card> getCards() {
|
||||
return cards;
|
||||
}
|
||||
|
||||
|
|
|
@ -80,7 +80,12 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
@Override
|
||||
public void event(Event event) {
|
||||
if (event.getEventName().equals("double-click")) {
|
||||
deck.getCards().add(createCard(cardSelector.getCards().get((UUID)event.getSource()).getClass()));
|
||||
for (Card card: cardSelector.getCards()) {
|
||||
if (card.getId().equals((UUID)event.getSource())) {
|
||||
deck.getCards().add(createCard(card.getClass()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
refreshDeck();
|
||||
}
|
||||
}
|
||||
|
@ -92,7 +97,12 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
@Override
|
||||
public void event(Event event) {
|
||||
if (event.getEventName().equals("double-click")) {
|
||||
deck.getCards().remove((UUID)event.getSource());
|
||||
for (Card card: deck.getCards()) {
|
||||
if (card.getId().equals((UUID)event.getSource())) {
|
||||
deck.getCards().remove(card);
|
||||
break;
|
||||
}
|
||||
}
|
||||
refreshDeck();
|
||||
}
|
||||
}
|
||||
|
@ -272,8 +282,11 @@ public class DeckEditorPanel extends javax.swing.JPanel {
|
|||
if (ret == JFileChooser.APPROVE_OPTION) {
|
||||
File file = fcSelectDeck.getSelectedFile();
|
||||
try {
|
||||
String fileName = file.getPath();
|
||||
if (!fileName.endsWith(".dck"))
|
||||
fileName += ".dck";
|
||||
setCursor(new Cursor(Cursor.WAIT_CURSOR));
|
||||
deck.getDeckCardLists().save(file.getPath());
|
||||
deck.getDeckCardLists().save(fileName);
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(DeckEditorPanel.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
|
|
|
@ -33,6 +33,11 @@
|
|||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="mage.client.cards.Cards" name="cards">
|
||||
<Properties>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||
<Connection code="new java.awt.Dimension(Config.dimensions.frameWidth, Config.dimensions.frameHeight + 25)" type="code"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
|
|
|
@ -38,9 +38,8 @@ import java.beans.PropertyVetoException;
|
|||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.swing.JLayeredPane;
|
||||
import mage.client.MageFrame;
|
||||
import mage.client.cards.BigCard;
|
||||
import mage.client.util.Config;
|
||||
import mage.view.ExileView;
|
||||
|
||||
/**
|
||||
|
@ -57,17 +56,21 @@ public class ExileZoneDialog extends MageDialog {
|
|||
|
||||
public void loadCards(ExileView exile, BigCard bigCard, UUID gameId) {
|
||||
this.title = exile.getName();
|
||||
boolean changed = false;
|
||||
changed = cards.loadCards(exile, bigCard, gameId);
|
||||
if (exile.size() > 0) {
|
||||
cards.loadCards(exile, bigCard, gameId);
|
||||
if (getParent() != MageFrame.getDesktop() || this.isClosed)
|
||||
MageFrame.getDesktop().add(this, JLayeredPane.POPUP_LAYER);
|
||||
// try {
|
||||
// this.setIcon(false);
|
||||
// } catch (PropertyVetoException ex) {
|
||||
// Logger.getLogger(ShowCardsDialog.class.getName()).log(Level.SEVERE, null, ex);
|
||||
// }
|
||||
show();
|
||||
if (changed) {
|
||||
try {
|
||||
this.setIcon(false);
|
||||
} catch (PropertyVetoException ex) {
|
||||
Logger.getLogger(ExileZoneDialog.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
hide();
|
||||
}
|
||||
this.setVisible(exile.size() > 0);
|
||||
}
|
||||
|
||||
/** This method is called from within the constructor to
|
||||
|
@ -83,6 +86,8 @@ public class ExileZoneDialog extends MageDialog {
|
|||
|
||||
setIconifiable(true);
|
||||
|
||||
cards.setPreferredSize(new java.awt.Dimension(Config.dimensions.frameWidth, Config.dimensions.frameHeight + 25));
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
|
||||
getContentPane().setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
|
|
|
@ -21,22 +21,27 @@
|
|||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<EmptySpace pref="310" max="32767" attributes="0"/>
|
||||
<Component id="btnOK" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="btnCancel" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="newPlayerPanel" alignment="0" pref="414" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="newPlayerPanel" alignment="1" pref="438" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="newPlayerPanel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
<EmptySpace pref="10" max="32767" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="btnCancel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="btnOK" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
|
|
|
@ -103,17 +103,20 @@ public class JoinTableDialog extends MageDialog {
|
|||
getContentPane().setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addContainerGap(310, Short.MAX_VALUE)
|
||||
.addComponent(btnOK)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(btnCancel)
|
||||
.addComponent(btnCancel))
|
||||
.addComponent(newPlayerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 414, Short.MAX_VALUE))
|
||||
.addContainerGap())
|
||||
.addComponent(newPlayerPanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 438, Short.MAX_VALUE)
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(newPlayerPanel, 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)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
|
@ -133,7 +136,7 @@ public class JoinTableDialog extends MageDialog {
|
|||
private void btnOKActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnOKActionPerformed
|
||||
Session session = MageFrame.getSession();
|
||||
try {
|
||||
joined = session.joinTable(roomId, tableId, 1, this.newPlayerPanel.getPlayerName(), DeckCardLists.load(this.newPlayerPanel.getDeckFile()));
|
||||
joined = session.joinTable(roomId, tableId, this.newPlayerPanel.getPlayerName(), DeckCardLists.load(this.newPlayerPanel.getDeckFile()));
|
||||
} catch (Exception ex) {
|
||||
handleError(ex);
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<EmptySpace min="0" pref="302" max="32767" attributes="0"/>
|
||||
<EmptySpace min="0" pref="306" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
|
|
|
@ -64,6 +64,7 @@ public class MageDialog extends javax.swing.JInternalFrame {
|
|||
@Override
|
||||
public void show() {
|
||||
super.show();
|
||||
this.toFront();
|
||||
if (this.modal) {
|
||||
startModal();
|
||||
}
|
||||
|
@ -72,6 +73,7 @@ public class MageDialog extends javax.swing.JInternalFrame {
|
|||
@Override
|
||||
public void setVisible(boolean value) {
|
||||
super.setVisible(value);
|
||||
this.toFront();
|
||||
if (modal) {
|
||||
if (value) {
|
||||
startModal();
|
||||
|
|
|
@ -286,18 +286,16 @@ public class NewTableDialog extends MageDialog {
|
|||
(MultiplayerAttackOption)this.cbAttackOption.getSelectedItem(),
|
||||
(RangeOfInfluence)this.cbRange.getSelectedItem());
|
||||
try {
|
||||
if (session.joinTable(roomId, table.getTableId(), 0, this.player1Panel.getPlayerName(), DeckCardLists.load(this.player1Panel.getDeckFile()))) {
|
||||
int seatNum = 1;
|
||||
if (session.joinTable(roomId, table.getTableId(), this.player1Panel.getPlayerName(), DeckCardLists.load(this.player1Panel.getDeckFile()))) {
|
||||
for (TablePlayerPanel player: players) {
|
||||
if (!player.getPlayerType().equals("Human")) {
|
||||
if (!player.joinTable(roomId, table.getTableId(), seatNum)) {
|
||||
if (!player.joinTable(roomId, table.getTableId())) {
|
||||
JOptionPane.showMessageDialog(MageFrame.getDesktop(), "Error joining table.", "Error", JOptionPane.ERROR_MESSAGE);
|
||||
session.removeTable(roomId, table.getTableId());
|
||||
table = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
seatNum++;
|
||||
}
|
||||
this.setVisible(false);
|
||||
return;
|
||||
|
|
|
@ -20,23 +20,24 @@
|
|||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace pref="13" max="32767" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<Component id="btnOk" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="btnCancel" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="44" max="-2" attributes="0"/>
|
||||
<Component id="jScrollPane1" alignment="0" pref="146" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<Component id="spnAmount" min="-2" pref="52" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="lblMessage" pref="121" max="32767" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="54" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
|
@ -44,10 +45,10 @@
|
|||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="lblMessage" pref="30" max="32767" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="jScrollPane1" pref="64" max="32767" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="spnAmount" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="btnCancel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="btnOk" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
|
@ -81,10 +82,30 @@
|
|||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnOkActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="lblMessage">
|
||||
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
|
||||
<Properties>
|
||||
<Property name="horizontalAlignment" type="int" value="0"/>
|
||||
<Property name="horizontalScrollBarPolicy" type="int" value="31"/>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JTextPane" name="lblMessage">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="null"/>
|
||||
</Property>
|
||||
<Property name="editable" type="boolean" value="false"/>
|
||||
<Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||
<Connection code="null	" type="code"/>
|
||||
</Property>
|
||||
<Property name="focusable" type="boolean" value="false"/>
|
||||
<Property name="opaque" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
|
|
|
@ -53,7 +53,9 @@ public class PickNumberDialog extends MageDialog {
|
|||
public void showDialog(int min, int max, String message) {
|
||||
this.spnAmount.setModel(new SpinnerNumberModel(min, min, max, 1));
|
||||
this.lblMessage.setText(message);
|
||||
this.btnOk.setVisible(true);
|
||||
this.btnCancel.setVisible(false);
|
||||
this.pack();
|
||||
this.setVisible(true);
|
||||
}
|
||||
|
||||
|
@ -77,7 +79,8 @@ public class PickNumberDialog extends MageDialog {
|
|||
spnAmount = new javax.swing.JSpinner();
|
||||
btnCancel = new javax.swing.JButton();
|
||||
btnOk = new javax.swing.JButton();
|
||||
lblMessage = new javax.swing.JLabel();
|
||||
jScrollPane1 = new javax.swing.JScrollPane();
|
||||
lblMessage = new javax.swing.JTextPane();
|
||||
|
||||
spnAmount.setModel(new javax.swing.SpinnerNumberModel(Integer.valueOf(1), null, null, Integer.valueOf(1)));
|
||||
|
||||
|
@ -95,35 +98,42 @@ public class PickNumberDialog extends MageDialog {
|
|||
}
|
||||
});
|
||||
|
||||
lblMessage.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
|
||||
jScrollPane1.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
|
||||
lblMessage.setBorder(null);
|
||||
lblMessage.setEditable(false);
|
||||
lblMessage.setCursor(null );
|
||||
lblMessage.setFocusable(false);
|
||||
lblMessage.setOpaque(false);
|
||||
jScrollPane1.setViewportView(lblMessage);
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
|
||||
getContentPane().setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap(13, Short.MAX_VALUE)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addComponent(btnOk)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(btnCancel))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(44, 44, 44)
|
||||
.addComponent(spnAmount, javax.swing.GroupLayout.PREFERRED_SIZE, 52, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(lblMessage, javax.swing.GroupLayout.DEFAULT_SIZE, 121, Short.MAX_VALUE)))
|
||||
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 146, Short.MAX_VALUE))
|
||||
.addContainerGap())
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addComponent(spnAmount, javax.swing.GroupLayout.PREFERRED_SIZE, 52, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(54, 54, 54))))
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(lblMessage, javax.swing.GroupLayout.DEFAULT_SIZE, 30, Short.MAX_VALUE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 64, Short.MAX_VALUE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(spnAmount, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(btnCancel)
|
||||
.addComponent(btnOk))
|
||||
|
@ -146,7 +156,8 @@ public class PickNumberDialog extends MageDialog {
|
|||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JButton btnCancel;
|
||||
private javax.swing.JButton btnOk;
|
||||
private javax.swing.JLabel lblMessage;
|
||||
private javax.swing.JScrollPane jScrollPane1;
|
||||
private javax.swing.JTextPane lblMessage;
|
||||
private javax.swing.JSpinner spnAmount;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ public class ShowCardsDialog extends MageDialog implements MouseListener {
|
|||
|
||||
private void loadCardsFew(CardsView showCards, BigCard bigCard, CardDimensions dimension, UUID gameId) {
|
||||
Rectangle rectangle = new Rectangle(Config.dimensions.frameWidth, Config.dimensions.frameHeight);
|
||||
for (CardView card: showCards) {
|
||||
for (CardView card: showCards.values()) {
|
||||
Card cardImg = new Card(card, bigCard, dimension, gameId);
|
||||
cardImg.setBounds(rectangle);
|
||||
cardArea.add(cardImg);
|
||||
|
@ -95,7 +95,7 @@ public class ShowCardsDialog extends MageDialog implements MouseListener {
|
|||
if (showCards != null && showCards.size() > 0) {
|
||||
Rectangle rectangle = new Rectangle(Config.dimensions.frameWidth, Config.dimensions.frameHeight);
|
||||
int count = 0;
|
||||
for (CardView card: showCards) {
|
||||
for (CardView card: showCards.values()) {
|
||||
Card cardImg = new Card(card, bigCard, dimension, gameId);
|
||||
cardImg.setBounds(rectangle);
|
||||
cardArea.add(cardImg);
|
||||
|
|
|
@ -48,7 +48,6 @@ import mage.client.cards.BigCard;
|
|||
import mage.client.cards.Permanent;
|
||||
import mage.client.util.Config;
|
||||
import mage.view.PermanentView;
|
||||
import static mage.client.util.Constants.*;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="lblDefender" alignment="0" pref="142" max="32767" attributes="0"/>
|
||||
<Component id="blockers" alignment="0" pref="142" max="32767" attributes="2"/>
|
||||
<Component id="attackers" alignment="0" pref="142" max="32767" attributes="2"/>
|
||||
<Component id="lblDefender" alignment="0" pref="69" max="32767" attributes="0"/>
|
||||
<Component id="blockers" alignment="0" min="-2" max="-2" attributes="2"/>
|
||||
<Component id="attackers" alignment="0" min="-2" max="-2" attributes="2"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
|
@ -26,22 +26,32 @@
|
|||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="lblDefender" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="blockers" min="-2" pref="199" max="-2" attributes="0"/>
|
||||
<Component id="blockers" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
|
||||
<Component id="attackers" min="-2" pref="199" max="-2" attributes="0"/>
|
||||
<Component id="attackers" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="mage.client.cards.Cards" name="blockers">
|
||||
<Properties>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||
<Connection code="new java.awt.Dimension(Config.dimensions.frameWidth + 8, Config.dimensions.frameHeight + 25)" type="code"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="mage.client.cards.Cards" name="attackers">
|
||||
<Properties>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||
<Connection code="new java.awt.Dimension(Config.dimensions.frameWidth + 8, Config.dimensions.frameHeight + 25)" type="code"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="lblDefender">
|
||||
<Properties>
|
||||
<Property name="horizontalAlignment" type="int" value="0"/>
|
||||
<Property name="text" type="java.lang.String" value="jLabel1"/>
|
||||
<Property name="text" type="java.lang.String" value="Defender"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
|
|
|
@ -39,7 +39,6 @@ import java.util.UUID;
|
|||
import mage.client.cards.BigCard;
|
||||
import mage.client.util.Config;
|
||||
import mage.view.CombatGroupView;
|
||||
import static mage.client.util.Constants.*;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -53,7 +52,6 @@ public class CombatGroup extends javax.swing.JPanel {
|
|||
/** Creates new form CombatGroup */
|
||||
public CombatGroup() {
|
||||
initComponents();
|
||||
// setPreferredSize(new Dimension(160, 440));
|
||||
}
|
||||
|
||||
public void init(UUID gameId, BigCard bigCard) {
|
||||
|
@ -64,9 +62,9 @@ public class CombatGroup extends javax.swing.JPanel {
|
|||
public void update(CombatGroupView combatGroup) {
|
||||
this.lblDefender.setText(combatGroup.getDefenderName());
|
||||
this.attackers.loadCards(combatGroup.getAttackers(), bigCard, gameId);
|
||||
attackers.setPreferredSize(new Dimension(Config.dimensions.frameWidth + 6, Config.dimensions.frameHeight + 6));
|
||||
// attackers.setPreferredSize(new Dimension(Config.dimensions.frameWidth + 6, Config.dimensions.frameHeight + 6));
|
||||
this.blockers.loadCards(combatGroup.getBlockers(), bigCard, gameId);
|
||||
blockers.setPreferredSize(new Dimension(Config.dimensions.frameWidth + 6, Config.dimensions.frameHeight + 6));
|
||||
// blockers.setPreferredSize(new Dimension(Config.dimensions.frameWidth + 6, Config.dimensions.frameHeight + 6));
|
||||
this.attackers.setVisible(true);
|
||||
this.blockers.setVisible(true);
|
||||
}
|
||||
|
@ -84,25 +82,29 @@ public class CombatGroup extends javax.swing.JPanel {
|
|||
attackers = new mage.client.cards.Cards();
|
||||
lblDefender = new javax.swing.JLabel();
|
||||
|
||||
blockers.setPreferredSize(new java.awt.Dimension(Config.dimensions.frameWidth + 8, Config.dimensions.frameHeight + 25));
|
||||
|
||||
attackers.setPreferredSize(new java.awt.Dimension(Config.dimensions.frameWidth + 8, Config.dimensions.frameHeight + 25));
|
||||
|
||||
lblDefender.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
|
||||
lblDefender.setText("jLabel1");
|
||||
lblDefender.setText("Defender");
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(lblDefender, javax.swing.GroupLayout.DEFAULT_SIZE, 142, Short.MAX_VALUE)
|
||||
.addComponent(blockers, javax.swing.GroupLayout.DEFAULT_SIZE, 142, Short.MAX_VALUE)
|
||||
.addComponent(attackers, javax.swing.GroupLayout.DEFAULT_SIZE, 142, Short.MAX_VALUE)
|
||||
.addComponent(lblDefender, javax.swing.GroupLayout.DEFAULT_SIZE, 69, Short.MAX_VALUE)
|
||||
.addComponent(blockers, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(attackers, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(lblDefender)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(blockers, javax.swing.GroupLayout.PREFERRED_SIZE, 199, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(blockers, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(0, 0, 0)
|
||||
.addComponent(attackers, javax.swing.GroupLayout.PREFERRED_SIZE, 199, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addComponent(attackers, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
|
|
|
@ -108,9 +108,10 @@ public class FeedbackPanel extends javax.swing.JPanel {
|
|||
break;
|
||||
}
|
||||
this.btnSpecial.setVisible(special);
|
||||
this.revalidate();
|
||||
this.repaint();
|
||||
if (modal)
|
||||
startModal();
|
||||
this.revalidate();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
|
|
|
@ -36,6 +36,8 @@ package mage.client.game;
|
|||
|
||||
import mage.client.*;
|
||||
import java.util.UUID;
|
||||
import javax.swing.event.InternalFrameEvent;
|
||||
import javax.swing.event.InternalFrameListener;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -46,6 +48,33 @@ public class GamePane extends MagePane {
|
|||
/** Creates new form GamePane */
|
||||
public GamePane() {
|
||||
initComponents();
|
||||
addInternalFrameListener(new InternalFrameListener()
|
||||
{
|
||||
|
||||
@Override
|
||||
public void internalFrameOpened(InternalFrameEvent e) { }
|
||||
|
||||
@Override
|
||||
public void internalFrameClosing(InternalFrameEvent e) {
|
||||
gamePanel.cleanUp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void internalFrameClosed(InternalFrameEvent e) { }
|
||||
|
||||
@Override
|
||||
public void internalFrameIconified(InternalFrameEvent e) { }
|
||||
|
||||
@Override
|
||||
public void internalFrameDeiconified(InternalFrameEvent e) { }
|
||||
|
||||
@Override
|
||||
public void internalFrameActivated(InternalFrameEvent e) { }
|
||||
|
||||
@Override
|
||||
public void internalFrameDeactivated(InternalFrameEvent e) { }
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public void showGame(UUID gameId, UUID playerId) {
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="jSplitPane1" alignment="0" pref="847" max="32767" attributes="0"/>
|
||||
<Component id="jSplitPane1" alignment="0" pref="798" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
|
@ -62,8 +62,8 @@
|
|||
<Component id="pnlGameInfo" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="pnlHand" max="32767" attributes="0"/>
|
||||
<Component id="pnlBattlefield" alignment="0" pref="715" max="32767" attributes="0"/>
|
||||
<Component id="hand" pref="715" max="32767" attributes="0"/>
|
||||
<Component id="pnlBattlefield" pref="715" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
|
@ -71,9 +71,9 @@
|
|||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<Component id="pnlBattlefield" pref="634" max="32767" attributes="0"/>
|
||||
<Component id="pnlBattlefield" pref="794" max="32767" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
|
||||
<Component id="pnlHand" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="hand" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="pnlGameInfo" alignment="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
|
@ -116,9 +116,7 @@
|
|||
<Component id="btnConcede" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="btnStopWatching" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="btnCheat" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="19" max="32767" attributes="0"/>
|
||||
<EmptySpace pref="62" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="bigCard" alignment="0" pref="256" max="32767" attributes="0"/>
|
||||
<Component id="feedbackPanel" alignment="0" pref="256" max="32767" attributes="0"/>
|
||||
|
@ -160,16 +158,15 @@
|
|||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="feedbackPanel" min="-2" pref="109" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
|
||||
<Component id="stack" min="-2" pref="209" max="-2" attributes="0"/>
|
||||
<Component id="stack" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
|
||||
<Component id="bigCard" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="8" max="32767" attributes="0"/>
|
||||
<EmptySpace pref="164" max="32767" attributes="0"/>
|
||||
<Component id="pnlReplay" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="btnConcede" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="btnStopWatching" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="btnCheat" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
|
@ -325,14 +322,11 @@
|
|||
<Component class="mage.client.cards.BigCard" name="bigCard">
|
||||
</Component>
|
||||
<Component class="mage.client.cards.Cards" name="stack">
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="btnCheat">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="?"/>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||
<Connection code="new java.awt.Dimension(Config.dimensions.frameWidth, Config.dimensions.frameHeight + 25)" type="code"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnCheatActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Container class="javax.swing.JPanel" name="pnlReplay">
|
||||
|
||||
|
@ -387,44 +381,17 @@
|
|||
</Container>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Container class="javax.swing.JPanel" name="pnlHand">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
|
||||
<EtchetBorder/>
|
||||
</Border>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||
<Connection code="new java.awt.Dimension(Config.dimensions.frameWidth, Config.dimensions.frameHeight + 25)" type="code"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="hand" alignment="1" pref="711" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="hand" alignment="1" pref="209" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="mage.client.cards.Cards" name="hand">
|
||||
<Properties>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||
<Connection code="new java.awt.Dimension(Config.dimensions.frameWidth, Config.dimensions.frameHeight)" type="code"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Container class="javax.swing.JPanel" name="pnlBattlefield">
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||
</Container>
|
||||
<Component class="mage.client.cards.Cards" name="hand">
|
||||
<Properties>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||
<Connection code="new java.awt.Dimension(Config.dimensions.frameWidth, Config.dimensions.frameHeight + 25)" type="code"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Component class="mage.client.chat.ChatPanel" name="chatPanel">
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
package mage.client.game;
|
||||
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.util.logging.Level;
|
||||
import mage.client.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
@ -44,11 +43,8 @@ import java.util.logging.Logger;
|
|||
import javax.swing.JLayeredPane;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import mage.cards.decks.DeckCardLists;
|
||||
import mage.client.dialog.CombatDialog;
|
||||
import mage.client.dialog.ExileZoneDialog;
|
||||
import mage.client.dialog.PickChoiceDialog;
|
||||
import mage.client.dialog.PickNumberDialog;
|
||||
import mage.client.dialog.ShowCardsDialog;
|
||||
import mage.client.game.FeedbackPanel.FeedbackMode;
|
||||
import mage.client.remote.Session;
|
||||
|
@ -73,14 +69,20 @@ public class GamePanel extends javax.swing.JPanel {
|
|||
private UUID gameId;
|
||||
private UUID playerId;
|
||||
private Session session;
|
||||
private CombatDialog combat = new CombatDialog();
|
||||
private PickNumberDialog pickNumber = new PickNumberDialog();
|
||||
|
||||
/** Creates new form GamePanel */
|
||||
public GamePanel() {
|
||||
initComponents();
|
||||
}
|
||||
|
||||
public void cleanUp() {
|
||||
MageFrame.getCombatDialog().hideDialog();
|
||||
MageFrame.getPickNumberDialog().hide();
|
||||
for (ExileZoneDialog exile: exiles.values()) {
|
||||
exile.hide();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void showGame(UUID gameId, UUID playerId) {
|
||||
this.gameId = gameId;
|
||||
this.playerId = playerId;
|
||||
|
@ -108,7 +110,6 @@ public class GamePanel extends javax.swing.JPanel {
|
|||
this.feedbackPanel.clear();
|
||||
this.btnConcede.setVisible(false);
|
||||
this.btnStopWatching.setVisible(true);
|
||||
this.btnCheat.setVisible(false);
|
||||
this.pnlReplay.setVisible(false);
|
||||
this.setVisible(true);
|
||||
this.chatPanel.clear();
|
||||
|
@ -124,7 +125,6 @@ public class GamePanel extends javax.swing.JPanel {
|
|||
this.feedbackPanel.clear();
|
||||
this.btnConcede.setVisible(false);
|
||||
this.btnStopWatching.setVisible(false);
|
||||
this.btnCheat.setVisible(false);
|
||||
this.pnlReplay.setVisible(true);
|
||||
this.setVisible(true);
|
||||
this.chatPanel.clear();
|
||||
|
@ -136,16 +136,21 @@ public class GamePanel extends javax.swing.JPanel {
|
|||
this.chatPanel.disconnect();
|
||||
this.players.clear();
|
||||
this.pnlBattlefield.removeAll();
|
||||
this.combat.hideDialog();
|
||||
MageFrame.getDesktop().remove(combat);
|
||||
MageFrame.getCombatDialog().hideDialog();
|
||||
// MageFrame.getDesktop().remove(combat);
|
||||
this.setVisible(false);
|
||||
}
|
||||
|
||||
public synchronized void init(GameView game) {
|
||||
combat.init(gameId, bigCard);
|
||||
MageFrame.getDesktop().add(combat, JLayeredPane.POPUP_LAYER);
|
||||
combat.setLocation(500, 300);
|
||||
MageFrame.getDesktop().add(pickNumber, JLayeredPane.POPUP_LAYER);
|
||||
MageFrame.getCombatDialog().init(gameId, bigCard);
|
||||
// MageFrame.getDesktop().add(combat, JLayeredPane.POPUP_LAYER);
|
||||
MageFrame.getCombatDialog().setLocation(500, 300);
|
||||
// MageFrame.getDesktop().add(pickNumber, JLayeredPane.POPUP_LAYER);
|
||||
addPlayers(game);
|
||||
updateGame(game);
|
||||
}
|
||||
|
||||
private void addPlayers(GameView game) {
|
||||
this.players.clear();
|
||||
this.pnlBattlefield.removeAll();
|
||||
//arrange players in a circle with the session player at the bottom left
|
||||
|
@ -155,11 +160,13 @@ public class GamePanel extends javax.swing.JPanel {
|
|||
int col = 0;
|
||||
int row = 1;
|
||||
int playerSeat = 0;
|
||||
if (playerId != null) {
|
||||
for (PlayerView player: game.getPlayers()) {
|
||||
if (playerId.equals(player.getPlayerId()))
|
||||
break;
|
||||
playerSeat++;
|
||||
}
|
||||
}
|
||||
PlayerView player = game.getPlayers().get(playerSeat);
|
||||
PlayAreaPanel sessionPlayer = new PlayAreaPanel(player, bigCard, gameId);
|
||||
players.put(player.getPlayerId(), sessionPlayer);
|
||||
|
@ -176,6 +183,8 @@ public class GamePanel extends javax.swing.JPanel {
|
|||
if (oddNumber)
|
||||
col++;
|
||||
int playerNum = playerSeat + 1;
|
||||
if (playerNum >= numSeats)
|
||||
playerNum = 0;
|
||||
while (true) {
|
||||
if (row == 1)
|
||||
col++;
|
||||
|
@ -202,7 +211,6 @@ public class GamePanel extends javax.swing.JPanel {
|
|||
if (playerNum == playerSeat)
|
||||
break;
|
||||
}
|
||||
updateGame(game);
|
||||
}
|
||||
|
||||
public synchronized void updateGame(GameView game) {
|
||||
|
@ -229,20 +237,23 @@ public class GamePanel extends javax.swing.JPanel {
|
|||
if (!exiles.containsKey(exile.getId())) {
|
||||
ExileZoneDialog newExile = new ExileZoneDialog();
|
||||
exiles.put(exile.getId(), newExile);
|
||||
MageFrame.getDesktop().add(newExile, JLayeredPane.POPUP_LAYER);
|
||||
newExile.show();
|
||||
}
|
||||
exiles.get(exile.getId()).loadCards(exile, bigCard, gameId);
|
||||
}
|
||||
if (game.getCombat().size() > 0) {
|
||||
combat.showDialog(game.getCombat());
|
||||
MageFrame.getCombatDialog().showDialog(game.getCombat());
|
||||
}
|
||||
else {
|
||||
combat.hideDialog();
|
||||
MageFrame.getCombatDialog().hideDialog();
|
||||
}
|
||||
this.revalidate();
|
||||
this.repaint();
|
||||
}
|
||||
|
||||
public void ask(String question) {
|
||||
public void ask(String question, GameView gameView) {
|
||||
updateGame(gameView);
|
||||
this.feedbackPanel.getFeedback(FeedbackMode.QUESTION, question, true, false);
|
||||
}
|
||||
|
||||
|
@ -309,11 +320,11 @@ public class GamePanel extends javax.swing.JPanel {
|
|||
}
|
||||
|
||||
public void getAmount(int min, int max, String message) {
|
||||
pickNumber.showDialog(min, max, message);
|
||||
if (pickNumber.isCancel())
|
||||
MageFrame.getPickNumberDialog().showDialog(min, max, message);
|
||||
if (MageFrame.getPickNumberDialog().isCancel())
|
||||
session.sendPlayerBoolean(gameId, false);
|
||||
else
|
||||
session.sendPlayerInteger(gameId, pickNumber.getAmount());
|
||||
session.sendPlayerInteger(gameId, MageFrame.getPickNumberDialog().getAmount());
|
||||
}
|
||||
|
||||
public void getChoice(String message, String[] choices) {
|
||||
|
@ -350,14 +361,12 @@ public class GamePanel extends javax.swing.JPanel {
|
|||
btnStopWatching = new javax.swing.JButton();
|
||||
bigCard = new mage.client.cards.BigCard();
|
||||
stack = new mage.client.cards.Cards();
|
||||
btnCheat = new javax.swing.JButton();
|
||||
pnlReplay = new javax.swing.JPanel();
|
||||
btnStopReplay = new javax.swing.JButton();
|
||||
btnPreviousPlay = new javax.swing.JButton();
|
||||
btnNextPlay = new javax.swing.JButton();
|
||||
pnlHand = new javax.swing.JPanel();
|
||||
hand = new mage.client.cards.Cards();
|
||||
pnlBattlefield = new javax.swing.JPanel();
|
||||
hand = new mage.client.cards.Cards();
|
||||
chatPanel = new mage.client.chat.ChatPanel();
|
||||
|
||||
jSplitPane1.setBorder(null);
|
||||
|
@ -420,12 +429,7 @@ public class GamePanel extends javax.swing.JPanel {
|
|||
}
|
||||
});
|
||||
|
||||
btnCheat.setText("?");
|
||||
btnCheat.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
btnCheatActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
stack.setPreferredSize(new java.awt.Dimension(Config.dimensions.frameWidth, Config.dimensions.frameHeight + 25));
|
||||
|
||||
btnStopReplay.setText("Stop");
|
||||
btnStopReplay.addActionListener(new java.awt.event.ActionListener() {
|
||||
|
@ -492,9 +496,7 @@ public class GamePanel extends javax.swing.JPanel {
|
|||
.addComponent(btnConcede)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(btnStopWatching)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(btnCheat)
|
||||
.addContainerGap(19, Short.MAX_VALUE))
|
||||
.addContainerGap(62, Short.MAX_VALUE))
|
||||
.addComponent(bigCard, javax.swing.GroupLayout.DEFAULT_SIZE, 256, Short.MAX_VALUE)
|
||||
.addComponent(feedbackPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 256, Short.MAX_VALUE)
|
||||
.addComponent(stack, javax.swing.GroupLayout.DEFAULT_SIZE, 256, Short.MAX_VALUE)
|
||||
|
@ -528,36 +530,21 @@ public class GamePanel extends javax.swing.JPanel {
|
|||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(feedbackPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 109, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(0, 0, 0)
|
||||
.addComponent(stack, javax.swing.GroupLayout.PREFERRED_SIZE, 209, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(stack, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(0, 0, 0)
|
||||
.addComponent(bigCard, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 8, Short.MAX_VALUE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 164, Short.MAX_VALUE)
|
||||
.addComponent(pnlReplay, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(pnlGameInfoLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(btnConcede)
|
||||
.addComponent(btnStopWatching)
|
||||
.addComponent(btnCheat)))
|
||||
);
|
||||
|
||||
pnlHand.setBorder(javax.swing.BorderFactory.createEtchedBorder());
|
||||
pnlHand.setPreferredSize(new java.awt.Dimension(Config.dimensions.frameWidth, Config.dimensions.frameHeight + 25));
|
||||
|
||||
hand.setPreferredSize(new java.awt.Dimension(Config.dimensions.frameWidth, Config.dimensions.frameHeight));
|
||||
|
||||
javax.swing.GroupLayout pnlHandLayout = new javax.swing.GroupLayout(pnlHand);
|
||||
pnlHand.setLayout(pnlHandLayout);
|
||||
pnlHandLayout.setHorizontalGroup(
|
||||
pnlHandLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(hand, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 711, Short.MAX_VALUE)
|
||||
);
|
||||
pnlHandLayout.setVerticalGroup(
|
||||
pnlHandLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(hand, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 209, Short.MAX_VALUE)
|
||||
.addComponent(btnStopWatching)))
|
||||
);
|
||||
|
||||
pnlBattlefield.setLayout(new java.awt.GridBagLayout());
|
||||
|
||||
hand.setPreferredSize(new java.awt.Dimension(Config.dimensions.frameWidth, Config.dimensions.frameHeight + 25));
|
||||
|
||||
javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3);
|
||||
jPanel3.setLayout(jPanel3Layout);
|
||||
jPanel3Layout.setHorizontalGroup(
|
||||
|
@ -566,15 +553,15 @@ public class GamePanel extends javax.swing.JPanel {
|
|||
.addComponent(pnlGameInfo, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(0, 0, 0)
|
||||
.addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(pnlHand, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(hand, javax.swing.GroupLayout.DEFAULT_SIZE, 715, Short.MAX_VALUE)
|
||||
.addComponent(pnlBattlefield, javax.swing.GroupLayout.DEFAULT_SIZE, 715, Short.MAX_VALUE)))
|
||||
);
|
||||
jPanel3Layout.setVerticalGroup(
|
||||
jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel3Layout.createSequentialGroup()
|
||||
.addComponent(pnlBattlefield, javax.swing.GroupLayout.DEFAULT_SIZE, 634, Short.MAX_VALUE)
|
||||
.addComponent(pnlBattlefield, javax.swing.GroupLayout.DEFAULT_SIZE, 794, Short.MAX_VALUE)
|
||||
.addGap(0, 0, 0)
|
||||
.addComponent(pnlHand, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addComponent(hand, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addComponent(pnlGameInfo, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
);
|
||||
|
||||
|
@ -591,7 +578,7 @@ public class GamePanel extends javax.swing.JPanel {
|
|||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 847, Short.MAX_VALUE)
|
||||
.addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 798, Short.MAX_VALUE)
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
|
@ -621,18 +608,9 @@ public class GamePanel extends javax.swing.JPanel {
|
|||
session.previousPlay();
|
||||
}//GEN-LAST:event_btnPreviousPlayActionPerformed
|
||||
|
||||
private void btnCheatActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCheatActionPerformed
|
||||
try {
|
||||
session.cheat(gameId, DeckCardLists.load("cheat.dck"));
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}//GEN-LAST:event_btnCheatActionPerformed
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private mage.client.game.AbilityPicker abilityPicker;
|
||||
private mage.client.cards.BigCard bigCard;
|
||||
private javax.swing.JButton btnCheat;
|
||||
private javax.swing.JButton btnConcede;
|
||||
private javax.swing.JButton btnNextPlay;
|
||||
private javax.swing.JButton btnPreviousPlay;
|
||||
|
@ -650,7 +628,6 @@ public class GamePanel extends javax.swing.JPanel {
|
|||
private javax.swing.JLabel lblTurn;
|
||||
private javax.swing.JPanel pnlBattlefield;
|
||||
private javax.swing.JPanel pnlGameInfo;
|
||||
private javax.swing.JPanel pnlHand;
|
||||
private javax.swing.JPanel pnlReplay;
|
||||
private mage.client.cards.Cards stack;
|
||||
private javax.swing.JLabel txtActivePlayer;
|
||||
|
|
|
@ -25,8 +25,8 @@
|
|||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="jScrollPane1" alignment="1" pref="278" max="32767" attributes="0"/>
|
||||
<Component id="jPanel1" alignment="0" max="32767" attributes="0"/>
|
||||
<Component id="jScrollPane1" alignment="1" pref="252" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
|
@ -45,6 +45,7 @@
|
|||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="manaPool" alignment="0" pref="116" max="32767" attributes="1"/>
|
||||
<Component id="playerPanel" alignment="0" max="32767" attributes="1"/>
|
||||
<Component id="btnCheat" alignment="0" pref="116" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
|
@ -53,7 +54,8 @@
|
|||
<Component id="playerPanel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
|
||||
<Component id="manaPool" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="14" max="32767" attributes="0"/>
|
||||
<EmptySpace pref="17" max="32767" attributes="0"/>
|
||||
<Component id="btnCheat" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
|
@ -63,6 +65,14 @@
|
|||
</Component>
|
||||
<Component class="mage.client.game.ManaPool" name="manaPool">
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="btnCheat">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Cheat"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnCheatActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
|
||||
|
|
|
@ -34,7 +34,13 @@
|
|||
|
||||
package mage.client.game;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import mage.cards.decks.DeckCardLists;
|
||||
import mage.client.MageFrame;
|
||||
import mage.client.cards.BigCard;
|
||||
import mage.view.PlayerView;
|
||||
|
||||
|
@ -44,6 +50,8 @@ import mage.view.PlayerView;
|
|||
*/
|
||||
public class PlayAreaPanel extends javax.swing.JPanel {
|
||||
|
||||
UUID playerId;
|
||||
UUID gameId;
|
||||
|
||||
/** Creates new form PlayAreaPanel */
|
||||
public PlayAreaPanel() {
|
||||
|
@ -59,6 +67,14 @@ public class PlayAreaPanel extends javax.swing.JPanel {
|
|||
public void init(PlayerView player, BigCard bigCard, UUID gameId) {
|
||||
this.playerPanel.init(gameId, player.getPlayerId(), bigCard);
|
||||
this.battlefieldPanel.init(gameId, bigCard);
|
||||
if (MageFrame.getSession().isTestMode()) {
|
||||
this.playerId = player.getPlayerId();
|
||||
this.gameId = gameId;
|
||||
this.btnCheat.setVisible(true);
|
||||
}
|
||||
else {
|
||||
this.btnCheat.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void update(PlayerView player) {
|
||||
|
@ -80,17 +96,26 @@ public class PlayAreaPanel extends javax.swing.JPanel {
|
|||
jPanel1 = new javax.swing.JPanel();
|
||||
playerPanel = new mage.client.game.PlayerPanel();
|
||||
manaPool = new mage.client.game.ManaPool();
|
||||
btnCheat = new javax.swing.JButton();
|
||||
jScrollPane1 = new javax.swing.JScrollPane();
|
||||
battlefieldPanel = new mage.client.game.BattlefieldPanel();
|
||||
|
||||
jPanel1.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED));
|
||||
|
||||
btnCheat.setText("Cheat");
|
||||
btnCheat.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
btnCheatActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
|
||||
jPanel1.setLayout(jPanel1Layout);
|
||||
jPanel1Layout.setHorizontalGroup(
|
||||
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(manaPool, javax.swing.GroupLayout.DEFAULT_SIZE, 116, Short.MAX_VALUE)
|
||||
.addComponent(playerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(btnCheat, javax.swing.GroupLayout.DEFAULT_SIZE, 116, Short.MAX_VALUE)
|
||||
);
|
||||
jPanel1Layout.setVerticalGroup(
|
||||
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
|
@ -98,7 +123,8 @@ public class PlayAreaPanel extends javax.swing.JPanel {
|
|||
.addComponent(playerPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(0, 0, 0)
|
||||
.addComponent(manaPool, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap(14, Short.MAX_VALUE))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 17, Short.MAX_VALUE)
|
||||
.addComponent(btnCheat))
|
||||
);
|
||||
|
||||
jScrollPane1.setViewportView(battlefieldPanel);
|
||||
|
@ -114,14 +140,27 @@ public class PlayAreaPanel extends javax.swing.JPanel {
|
|||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 278, Short.MAX_VALUE)
|
||||
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 252, Short.MAX_VALUE)
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void btnCheatActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCheatActionPerformed
|
||||
try {
|
||||
MageFrame.getSession().cheat(gameId, playerId, DeckCardLists.load("cheat.dck"));
|
||||
} catch (FileNotFoundException ex) {
|
||||
Logger.getLogger(PlayAreaPanel.class.getName()).log(Level.SEVERE, null, ex);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(PlayAreaPanel.class.getName()).log(Level.SEVERE, null, ex);
|
||||
} catch (ClassNotFoundException ex) {
|
||||
Logger.getLogger(PlayAreaPanel.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}//GEN-LAST:event_btnCheatActionPerformed
|
||||
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private mage.client.game.BattlefieldPanel battlefieldPanel;
|
||||
private javax.swing.JButton btnCheat;
|
||||
private javax.swing.JPanel jPanel1;
|
||||
private javax.swing.JScrollPane jScrollPane1;
|
||||
private mage.client.game.ManaPool manaPool;
|
||||
|
|
|
@ -65,8 +65,6 @@ public class Client implements CallbackClient {
|
|||
|
||||
@Override
|
||||
public synchronized void processCallback(ClientCallback callback) {
|
||||
if (callback.getMessageId() > messageId) {
|
||||
messageId = callback.getMessageId();
|
||||
logger.info(callback.getMessageId() + " - " + callback.getMethod());
|
||||
if (callback.getMethod().equals("startGame")) {
|
||||
UUID[] data = (UUID[]) callback.getData();
|
||||
|
@ -80,7 +78,7 @@ public class Client implements CallbackClient {
|
|||
}
|
||||
else if (callback.getMethod().equals("chatMessage")) {
|
||||
ChatMessage message = (ChatMessage) callback.getData();
|
||||
session.getChats().get(message.getChatId()).receiveMessage(message.getMessage());
|
||||
session.getChats().get(message.getChatId()).receiveMessage(message.getMessage(), message.getColor());
|
||||
}
|
||||
else if (callback.getMethod().equals("replayInit")) {
|
||||
session.getGame().init((GameView) callback.getData());
|
||||
|
@ -95,21 +93,13 @@ public class Client implements CallbackClient {
|
|||
else if (callback.getMethod().equals("gameInit")) {
|
||||
session.getGame().init((GameView) callback.getData());
|
||||
}
|
||||
else if (callback.getMethod().equals("gameUpdate")) {
|
||||
session.getGame().updateGame((GameView) callback.getData());
|
||||
}
|
||||
else if (callback.getMethod().equals("gameInform")) {
|
||||
GameClientMessage message = (GameClientMessage) callback.getData();
|
||||
session.getGame().inform(message.getMessage(), null, message.getGameView());
|
||||
}
|
||||
else if (callback.getMethod().equals("gameOver")) {
|
||||
session.getGame().modalMessage((String) callback.getData());
|
||||
session.getGame().hideGame();
|
||||
}
|
||||
else if (callback.getMethod().equals("gameAsk")) {
|
||||
GameClientMessage message = (GameClientMessage) callback.getData();
|
||||
session.getGame().updateGame(message.getGameView());
|
||||
session.getGame().ask(message.getMessage());
|
||||
session.getGame().ask(message.getMessage(), message.getGameView());
|
||||
}
|
||||
else if (callback.getMethod().equals("gameTarget")) {
|
||||
GameClientMessage message = (GameClientMessage) callback.getData();
|
||||
|
@ -146,11 +136,20 @@ public class Client implements CallbackClient {
|
|||
GameClientMessage message = (GameClientMessage) callback.getData();
|
||||
session.getGame().revealCards(message.getMessage(), message.getCardsView());
|
||||
}
|
||||
else if (callback.getMethod().equals("gameUpdate")) {
|
||||
session.getGame().updateGame((GameView) callback.getData());
|
||||
}
|
||||
else if (callback.getMethod().equals("gameInform")) {
|
||||
if (callback.getMessageId() > messageId) {
|
||||
GameClientMessage message = (GameClientMessage) callback.getData();
|
||||
session.getGame().inform(message.getMessage(), null, message.getGameView());
|
||||
}
|
||||
else {
|
||||
logger.warning("message out of sequence - ignoring");
|
||||
}
|
||||
}
|
||||
messageId = callback.getMessageId();
|
||||
}
|
||||
|
||||
public UUID getId() throws RemoteException {
|
||||
return clientId;
|
||||
|
|
|
@ -50,6 +50,7 @@ import mage.client.util.Config;
|
|||
import mage.game.GameException;
|
||||
import mage.interfaces.MageException;
|
||||
import mage.interfaces.Server;
|
||||
import mage.interfaces.ServerState;
|
||||
import mage.interfaces.callback.CallbackClientDaemon;
|
||||
import mage.util.Logging;
|
||||
import mage.view.GameTypeView;
|
||||
|
@ -68,9 +69,10 @@ public class Session {
|
|||
private Client client;
|
||||
private String userName;
|
||||
private MageFrame frame;
|
||||
private String[] playerTypes;
|
||||
private List<GameTypeView> gameTypes;
|
||||
private String[] deckTypes;
|
||||
private ServerState serverState;
|
||||
// private String[] playerTypes;
|
||||
// private List<GameTypeView> gameTypes;
|
||||
// private String[] deckTypes;
|
||||
private Map<UUID, ChatPanel> chats = new HashMap<UUID, ChatPanel>();
|
||||
private GamePanel game;
|
||||
private CallbackClientDaemon callbackDaemon;
|
||||
|
@ -91,9 +93,7 @@ public class Session {
|
|||
this.client = new Client(this, frame, userName);
|
||||
sessionId = server.registerClient(userName, client.getId());
|
||||
callbackDaemon = new CallbackClientDaemon(sessionId, client, server);
|
||||
playerTypes = server.getPlayerTypes();
|
||||
gameTypes = server.getGameTypes();
|
||||
deckTypes = server.getDeckTypes();
|
||||
serverState = server.getServerState();
|
||||
logger.info("Connected to RMI server at " + serverName + ":" + port);
|
||||
frame.setStatusText("Connected to " + serverName + ":" + port + " ");
|
||||
frame.enableButtons();
|
||||
|
@ -127,15 +127,19 @@ public class Session {
|
|||
}
|
||||
|
||||
public String[] getPlayerTypes() {
|
||||
return playerTypes;
|
||||
return serverState.getPlayerTypes();
|
||||
}
|
||||
|
||||
public List<GameTypeView> getGameTypes() {
|
||||
return gameTypes;
|
||||
return serverState.getGameTypes();
|
||||
}
|
||||
|
||||
public String[] getDeckTypes() {
|
||||
return deckTypes;
|
||||
return serverState.getDeckTypes();
|
||||
}
|
||||
|
||||
public boolean isTestMode() {
|
||||
return serverState.isTestMode();
|
||||
}
|
||||
|
||||
public Map<UUID, ChatPanel> getChats() {
|
||||
|
@ -229,9 +233,9 @@ public class Session {
|
|||
return false;
|
||||
}
|
||||
|
||||
public boolean joinTable(UUID roomId, UUID tableId, int seat, String playerName, DeckCardLists deckList) {
|
||||
public boolean joinTable(UUID roomId, UUID tableId, String playerName, DeckCardLists deckList) {
|
||||
try {
|
||||
return server.joinTable(sessionId, roomId, tableId, seat, playerName, deckList);
|
||||
return server.joinTable(sessionId, roomId, tableId, playerName, deckList);
|
||||
} catch (RemoteException ex) {
|
||||
handleRemoteException(ex);
|
||||
} catch (MageException ex) {
|
||||
|
@ -506,9 +510,9 @@ public class Session {
|
|||
return false;
|
||||
}
|
||||
|
||||
public boolean cheat(UUID gameId, DeckCardLists deckList) {
|
||||
public boolean cheat(UUID gameId, UUID playerId, DeckCardLists deckList) {
|
||||
try {
|
||||
server.cheat(gameId, sessionId, deckList);
|
||||
server.cheat(gameId, sessionId, playerId, deckList);
|
||||
return true;
|
||||
} catch (RemoteException ex) {
|
||||
handleRemoteException(ex);
|
||||
|
|
|
@ -72,9 +72,9 @@ public class TablePlayerPanel extends javax.swing.JPanel {
|
|||
this.lblPlayerNum.setText("Player " + playerNum);
|
||||
}
|
||||
|
||||
public boolean joinTable(UUID roomId, UUID tableId, int seatNum) throws FileNotFoundException, IOException, ClassNotFoundException {
|
||||
public boolean joinTable(UUID roomId, UUID tableId) throws FileNotFoundException, IOException, ClassNotFoundException {
|
||||
if (!this.cbPlayerType.getSelectedItem().equals("Human")) {
|
||||
return session.joinTable(roomId, tableId, seatNum, this.newPlayerPanel.getPlayerName(), DeckCardLists.load(this.newPlayerPanel.getDeckFile()));
|
||||
return session.joinTable(roomId, tableId, this.newPlayerPanel.getPlayerName(), DeckCardLists.load(this.newPlayerPanel.getDeckFile()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -266,14 +266,12 @@ public class TablesPanel extends javax.swing.JPanel implements Observer {
|
|||
session.joinTable(
|
||||
roomId,
|
||||
table.getTableId(),
|
||||
0,
|
||||
"Human",
|
||||
DeckCardLists.load("test.dck")
|
||||
);
|
||||
session.joinTable(
|
||||
roomId,
|
||||
table.getTableId(),
|
||||
1,
|
||||
"Computer",
|
||||
DeckCardLists.load("test.dck")
|
||||
);
|
||||
|
|
|
@ -46,17 +46,14 @@ import mage.view.TableView;
|
|||
*/
|
||||
public interface Server extends Remote, CallbackServer {
|
||||
|
||||
// public String getClientIp() throws RemoteException, MageException;
|
||||
public UUID registerClient(String userName, UUID clientId) throws RemoteException, MageException;
|
||||
public void deregisterClient(UUID sessionId) throws RemoteException, MageException;
|
||||
|
||||
public List<GameTypeView> getGameTypes() throws RemoteException, MageException;
|
||||
public String[] getPlayerTypes() throws RemoteException, MageException;
|
||||
public String[] getDeckTypes() throws RemoteException, MageException;
|
||||
public ServerState getServerState() throws RemoteException, MageException;
|
||||
|
||||
//table methods
|
||||
public TableView createTable(UUID sessionId, UUID roomId, String gameType, String deckType, List<String> playerTypes, MultiplayerAttackOption attackOption, RangeOfInfluence range) throws RemoteException, MageException;
|
||||
public boolean joinTable(UUID sessionId, UUID roomId, UUID tableId, int seatNum, String name, DeckCardLists deckList) throws RemoteException, MageException, GameException;
|
||||
public boolean joinTable(UUID sessionId, UUID roomId, UUID tableId, String name, DeckCardLists deckList) throws RemoteException, MageException, GameException;
|
||||
public boolean watchTable(UUID sessionId, UUID roomId, UUID tableId) throws RemoteException, MageException;
|
||||
public boolean replayTable(UUID sessionId, UUID roomId, UUID tableId) throws RemoteException, MageException;
|
||||
public void leaveTable(UUID sessionId, UUID roomId, UUID tableId) throws RemoteException, MageException;
|
||||
|
@ -95,6 +92,6 @@ public interface Server extends Remote, CallbackServer {
|
|||
public void previousPlay(UUID sessionId) throws RemoteException, MageException;
|
||||
|
||||
//test methods
|
||||
public void cheat(UUID gameId, UUID sessionId, DeckCardLists deckList) throws RemoteException, MageException;
|
||||
public void cheat(UUID gameId, UUID sessionId, UUID playerId, DeckCardLists deckList) throws RemoteException, MageException;
|
||||
|
||||
}
|
||||
|
|
69
Mage.Common/src/mage/interfaces/ServerState.java
Normal file
69
Mage.Common/src/mage/interfaces/ServerState.java
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.interfaces;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import mage.view.GameTypeView;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class ServerState implements Serializable {
|
||||
|
||||
private List<GameTypeView> gameTypes;
|
||||
private String[] playerTypes;
|
||||
private String[] deckTypes;
|
||||
private boolean testMode;
|
||||
|
||||
public ServerState(List<GameTypeView> gameTypes, String[] playerTypes, String[] deckTypes, boolean testMode) {
|
||||
this.gameTypes = gameTypes;
|
||||
this.playerTypes = playerTypes;
|
||||
this.deckTypes = deckTypes;
|
||||
this.testMode = testMode;
|
||||
}
|
||||
|
||||
public List<GameTypeView> getGameTypes() {
|
||||
return gameTypes;
|
||||
}
|
||||
|
||||
public String[] getPlayerTypes() {
|
||||
return playerTypes;
|
||||
}
|
||||
|
||||
public String[] getDeckTypes() {
|
||||
return deckTypes;
|
||||
}
|
||||
|
||||
public boolean isTestMode() {
|
||||
return testMode;
|
||||
}
|
||||
|
||||
}
|
|
@ -28,40 +28,39 @@
|
|||
|
||||
package mage.view;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import mage.MageObject;
|
||||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.Cards;
|
||||
import mage.game.Game;
|
||||
import mage.game.GameState;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class CardsView extends ArrayList<CardView> {
|
||||
public class CardsView extends HashMap<UUID, CardView> {
|
||||
|
||||
|
||||
public CardsView() {}
|
||||
|
||||
public CardsView(Collection<Card> cards) {
|
||||
for (Card card: cards) {
|
||||
this.add(new CardView(card));
|
||||
this.put(card.getId(), new CardView(card));
|
||||
}
|
||||
}
|
||||
|
||||
public CardsView(Cards cards) {
|
||||
if (cards != null)
|
||||
for (Card card: cards.values()) {
|
||||
this.add(new CardView(card));
|
||||
}
|
||||
}
|
||||
// public CardsView(Cards cards) {
|
||||
// if (cards != null)
|
||||
// for (Card card: cards.values()) {
|
||||
// this.add(new CardView(card));
|
||||
// }
|
||||
// }
|
||||
|
||||
public CardsView(Collection<? extends Ability> abilities, Game game) {
|
||||
public CardsView(Collection<? extends Ability> abilities, GameState state) {
|
||||
for (Ability ability: abilities) {
|
||||
String sourceName = game.getPermanent(ability.getSourceId()).getName();
|
||||
this.add(new AbilityView(ability, sourceName));
|
||||
String sourceName = state.getPermanent(ability.getSourceId()).getName();
|
||||
this.put(ability.getId(), new AbilityView(ability, sourceName));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,10 +39,16 @@ public class ChatMessage implements Serializable {
|
|||
|
||||
private UUID chatId;
|
||||
private String message;
|
||||
private MessageColor color;
|
||||
|
||||
public ChatMessage(UUID chatId, String message) {
|
||||
public enum MessageColor {
|
||||
BLACK, RED, GREEN, BLUE, ORANGE;
|
||||
}
|
||||
|
||||
public ChatMessage(UUID chatId, String message, MessageColor color) {
|
||||
this.chatId = chatId;
|
||||
this.message = message;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
|
@ -52,4 +58,8 @@ public class ChatMessage implements Serializable {
|
|||
public UUID getChatId() {
|
||||
return chatId;
|
||||
}
|
||||
|
||||
public MessageColor getColor() {
|
||||
return color;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ package mage.view;
|
|||
|
||||
import java.io.Serializable;
|
||||
import java.util.UUID;
|
||||
import mage.game.Game;
|
||||
import mage.game.GameState;
|
||||
import mage.game.combat.CombatGroup;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
@ -45,20 +46,24 @@ public class CombatGroupView implements Serializable {
|
|||
private CardsView blockers = new CardsView();
|
||||
private String defenderName;
|
||||
|
||||
public CombatGroupView(CombatGroup combatGroup, GameState game) {
|
||||
Player player = game.getPlayer(combatGroup.getDefenderId());
|
||||
public CombatGroupView(CombatGroup combatGroup, GameState state) {
|
||||
Player player = state.getPlayer(combatGroup.getDefenderId());
|
||||
if (player != null) {
|
||||
this.defenderName = player.getName();
|
||||
}
|
||||
else {
|
||||
Permanent perm = game.getPermanent(combatGroup.getDefenderId());
|
||||
Permanent perm = state.getPermanent(combatGroup.getDefenderId());
|
||||
this.defenderName = perm.getName();
|
||||
}
|
||||
for (UUID id: combatGroup.getAttackers()) {
|
||||
attackers.add(new PermanentView(game.getPermanent(id)));
|
||||
Permanent attacker = state.getPermanent(id);
|
||||
if (attacker != null)
|
||||
attackers.put(id, new PermanentView(attacker));
|
||||
}
|
||||
for (UUID id: combatGroup.getBlockers()) {
|
||||
blockers.add(new PermanentView(game.getPermanent(id)));
|
||||
Permanent blocker = state.getPermanent(id);
|
||||
if (blocker != null)
|
||||
blockers.put(id, new PermanentView(blocker));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ package mage.view;
|
|||
import java.util.UUID;
|
||||
import mage.cards.Card;
|
||||
import mage.game.ExileZone;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -41,11 +42,11 @@ public class ExileView extends CardsView {
|
|||
private String name;
|
||||
private UUID id;
|
||||
|
||||
public ExileView(ExileZone exileZone) {
|
||||
public ExileView(ExileZone exileZone, Game game) {
|
||||
this.name = exileZone.getName();
|
||||
this.id = exileZone.getId();
|
||||
for (Card card: exileZone.values()) {
|
||||
this.add(new CardView(card));
|
||||
for (Card card: exileZone.getCards(game)) {
|
||||
this.put(card.getId(), new CardView(card));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ import mage.Constants.PhaseStep;
|
|||
import mage.Constants.TurnPhase;
|
||||
import mage.MageObject;
|
||||
import mage.game.ExileZone;
|
||||
import mage.game.Game;
|
||||
import mage.game.GameState;
|
||||
import mage.game.combat.CombatGroup;
|
||||
import mage.game.stack.Spell;
|
||||
|
@ -60,40 +61,40 @@ public class GameView implements Serializable {
|
|||
private int turn;
|
||||
private boolean special = false;
|
||||
|
||||
public GameView(GameState game) {
|
||||
for (Player player: game.getPlayers().values()) {
|
||||
players.add(new PlayerView(player, game));
|
||||
public GameView(GameState state, Game game) {
|
||||
for (Player player: state.getPlayers().values()) {
|
||||
players.add(new PlayerView(player, state, game));
|
||||
}
|
||||
for (StackObject stackObject: game.getStack()) {
|
||||
for (StackObject stackObject: state.getStack()) {
|
||||
if (stackObject instanceof StackAbility) {
|
||||
MageObject object = game.getObject(stackObject.getSourceId());
|
||||
if (object != null)
|
||||
stack.add(new StackAbilityView((StackAbility)stackObject, object.getName()));
|
||||
stack.put(stackObject.getId(), new StackAbilityView((StackAbility)stackObject, object.getName()));
|
||||
else
|
||||
stack.add(new StackAbilityView((StackAbility)stackObject, ""));
|
||||
stack.put(null, new StackAbilityView((StackAbility)stackObject, ""));
|
||||
}
|
||||
else {
|
||||
stack.add(new CardView((Spell)stackObject));
|
||||
stack.put(stackObject.getId(), new CardView((Spell)stackObject));
|
||||
}
|
||||
}
|
||||
for (ExileZone exileZone: game.getExile().getExileZones()) {
|
||||
exiles.add(new ExileView(exileZone));
|
||||
for (ExileZone exileZone: state.getExile().getExileZones()) {
|
||||
exiles.add(new ExileView(exileZone, game));
|
||||
}
|
||||
this.phase = game.getTurn().getPhaseType();
|
||||
this.step = game.getTurn().getStepType();
|
||||
this.turn = game.getTurnNum();
|
||||
if (game.getActivePlayerId() != null)
|
||||
this.activePlayerName = game.getPlayer(game.getActivePlayerId()).getName();
|
||||
this.phase = state.getTurn().getPhaseType();
|
||||
this.step = state.getTurn().getStepType();
|
||||
this.turn = state.getTurnNum();
|
||||
if (state.getActivePlayerId() != null)
|
||||
this.activePlayerName = state.getPlayer(state.getActivePlayerId()).getName();
|
||||
else
|
||||
this.activePlayerName = "";
|
||||
if (game.getPriorityPlayerId() != null)
|
||||
this.priorityPlayerName = game.getPlayer(game.getPriorityPlayerId()).getName();
|
||||
if (state.getPriorityPlayerId() != null)
|
||||
this.priorityPlayerName = state.getPlayer(state.getPriorityPlayerId()).getName();
|
||||
else
|
||||
this.priorityPlayerName = "";
|
||||
for (CombatGroup combatGroup: game.getCombat().getGroups()) {
|
||||
combat.add(new CombatGroupView(combatGroup, game));
|
||||
for (CombatGroup combatGroup: state.getCombat().getGroups()) {
|
||||
combat.add(new CombatGroupView(combatGroup, state));
|
||||
}
|
||||
this.special = game.getSpecialActions().getControlledBy(game.getPriorityPlayerId()).size() > 0;
|
||||
this.special = state.getSpecialActions().getControlledBy(state.getPriorityPlayerId()).size() > 0;
|
||||
}
|
||||
|
||||
public List<PlayerView> getPlayers() {
|
||||
|
|
|
@ -33,6 +33,7 @@ import java.util.HashMap;
|
|||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import mage.cards.Card;
|
||||
import mage.game.Game;
|
||||
import mage.game.GameState;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
|
@ -54,33 +55,33 @@ public class PlayerView implements Serializable {
|
|||
private CardsView graveyard = new CardsView();
|
||||
private Map<UUID, PermanentView> battlefield = new HashMap<UUID, PermanentView>();
|
||||
|
||||
public PlayerView(Player player, GameState game) {
|
||||
public PlayerView(Player player, GameState state, Game game) {
|
||||
this.playerId = player.getId();
|
||||
this.name = player.getName();
|
||||
this.life = player.getLife();
|
||||
this.libraryCount = player.getLibrary().size();
|
||||
this.handCount = player.getHand().size();
|
||||
this.manaPool = new ManaPoolView(player.getManaPool());
|
||||
this.isActive = (player.getId().equals(game.getActivePlayerId()));
|
||||
this.isActive = (player.getId().equals(state.getActivePlayerId()));
|
||||
this.hasLeft = player.hasLeft();
|
||||
for (Card card: player.getGraveyard().values()) {
|
||||
graveyard.add(new CardView(card));
|
||||
for (Card card: player.getGraveyard().getCards(game)) {
|
||||
graveyard.put(card.getId(), new CardView(card));
|
||||
}
|
||||
for (Permanent permanent: game.getBattlefield().getAllPermanents()) {
|
||||
if (showInBattlefield(permanent, game)) {
|
||||
for (Permanent permanent: state.getBattlefield().getAllPermanents()) {
|
||||
if (showInBattlefield(permanent, state)) {
|
||||
PermanentView view = new PermanentView(permanent);
|
||||
battlefield.put(view.getId(), view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean showInBattlefield(Permanent permanent, GameState game) {
|
||||
private boolean showInBattlefield(Permanent permanent, GameState state) {
|
||||
|
||||
//show permanents controlled by player or attachments to permanents controlled by player
|
||||
if (permanent.getAttachedTo() == null)
|
||||
return permanent.getControllerId().equals(playerId);
|
||||
else
|
||||
return game.getPermanent(permanent.getAttachedTo()).getControllerId().equals(playerId);
|
||||
return state.getPermanent(permanent.getAttachedTo()).getControllerId().equals(playerId);
|
||||
}
|
||||
|
||||
public int getLife() {
|
||||
|
|
|
@ -58,8 +58,8 @@ public class Constructed extends DeckValidatorImpl {
|
|||
|
||||
List<String> basicLandNames = new ArrayList<String>(Arrays.asList("Forest", "Island", "Mountain", "Swamp", "Plains"));
|
||||
Map<String, Integer> counts = new HashMap<String, Integer>();
|
||||
countCards(counts, deck.getCards().values());
|
||||
countCards(counts, deck.getSideboard().values());
|
||||
countCards(counts, deck.getCards());
|
||||
countCards(counts, deck.getSideboard());
|
||||
for (Entry<String, Integer> entry: counts.entrySet()) {
|
||||
if (entry.getValue() > 4) {
|
||||
if (!basicLandNames.contains(entry.getKey())) {
|
||||
|
|
|
@ -41,7 +41,7 @@ import mage.players.Player;
|
|||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class FreeForAll extends GameImpl {
|
||||
public class FreeForAll extends GameImpl<FreeForAll> {
|
||||
|
||||
private int numPlayers;
|
||||
private List<UUID> mulliganed = new ArrayList<UUID>();
|
||||
|
@ -50,6 +50,14 @@ public class FreeForAll extends GameImpl {
|
|||
super(attackOption, range);
|
||||
}
|
||||
|
||||
public FreeForAll(final FreeForAll game) {
|
||||
super(game);
|
||||
this.numPlayers = game.numPlayers;
|
||||
for (UUID playerId: game.mulliganed) {
|
||||
mulliganed.add(playerId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameType getGameType() {
|
||||
return new FreeForAllType();
|
||||
|
@ -88,11 +96,16 @@ public class FreeForAll extends GameImpl {
|
|||
numCards += 1;
|
||||
mulliganed.add(playerId);
|
||||
}
|
||||
player.getLibrary().addAll(player.getHand());
|
||||
player.getLibrary().addAll(player.getHand().getCards(this));
|
||||
player.getHand().clear();
|
||||
player.shuffleLibrary(this);
|
||||
player.drawCards(numCards - 1, this);
|
||||
fireInformEvent(player.getName() + " mulligans down to " + Integer.toString(numCards - 1) + " cards");
|
||||
}
|
||||
|
||||
@Override
|
||||
public FreeForAll copy() {
|
||||
return new FreeForAll(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -36,12 +36,16 @@ import mage.Constants.PhaseStep;
|
|||
import mage.Constants.RangeOfInfluence;
|
||||
import mage.game.turn.TurnMod;
|
||||
|
||||
public class TwoPlayerDuel extends GameImpl {
|
||||
public class TwoPlayerDuel extends GameImpl<TwoPlayerDuel> {
|
||||
|
||||
public TwoPlayerDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range) {
|
||||
super(MultiplayerAttackOption.LEFT, RangeOfInfluence.ALL);
|
||||
}
|
||||
|
||||
public TwoPlayerDuel(final TwoPlayerDuel game) {
|
||||
super(game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameType getGameType() {
|
||||
return new TwoPlayerDuelType();
|
||||
|
@ -88,4 +92,9 @@ public class TwoPlayerDuel extends GameImpl {
|
|||
return opponents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TwoPlayerDuel copy() {
|
||||
return new TwoPlayerDuel(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ debug.test.classpath=\
|
|||
dist.dir=dist
|
||||
dist.jar=${dist.dir}/Mage.Player.AI.jar
|
||||
dist.javadoc.dir=${dist.dir}/javadoc
|
||||
endorsed.classpath=
|
||||
excludes=
|
||||
file.reference.Mage.AI-src=src
|
||||
file.reference.Mage.AI-test=test
|
||||
|
|
|
@ -40,14 +40,18 @@ import java.util.LinkedList;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import mage.Constants.CardType;
|
||||
import mage.Constants.Outcome;
|
||||
import mage.Constants.RangeOfInfluence;
|
||||
import mage.Constants.Zone;
|
||||
import mage.MageObject;
|
||||
import mage.Mana;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.ActivatedAbility;
|
||||
import mage.abilities.TriggeredAbilities;
|
||||
import mage.abilities.TriggeredAbility;
|
||||
|
@ -103,10 +107,10 @@ import mage.util.TreeNode;
|
|||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class ComputerPlayer extends PlayerImpl implements Player {
|
||||
public class ComputerPlayer<T extends ComputerPlayer<T>> extends PlayerImpl<T> implements Player {
|
||||
|
||||
private final static transient Logger logger = Logging.getLogger(ComputerPlayer.class.getName());
|
||||
private boolean abort = false;
|
||||
private boolean abort;
|
||||
private transient Map<Mana, Card> unplayable = new TreeMap<Mana, Card>();
|
||||
private transient List<Card> playableNonInstant = new ArrayList<Card>();
|
||||
private transient List<Card> playableInstant = new ArrayList<Card>();
|
||||
|
@ -121,31 +125,37 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
super(id);
|
||||
}
|
||||
|
||||
public ComputerPlayer(final ComputerPlayer player) {
|
||||
super(player);
|
||||
this.abort = player.abort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean chooseMulligan(Game game) {
|
||||
logger.fine("chooseMulligan");
|
||||
if (hand.size() < 6)
|
||||
return false;
|
||||
List<Card> lands = hand.getCards(new FilterLandCard());
|
||||
Set<Card> lands = hand.getCards(new FilterLandCard(), game);
|
||||
if (lands.size() < 2 || lands.size() > hand.size() - 2)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean chooseTarget(Outcome outcome, Target target, Game game) {
|
||||
public boolean chooseTarget(Outcome outcome, Target target, Ability source, Game game) {
|
||||
if (logger.isLoggable(Level.FINE))
|
||||
logger.fine("chooseTarget: " + outcome.toString() + ":" + target.toString());
|
||||
UUID opponentId = game.getOpponents(playerId).iterator().next();
|
||||
if (target instanceof TargetPlayer) {
|
||||
if (outcome.isGood()) {
|
||||
if (target.canTarget(playerId, game)) {
|
||||
target.addTarget(playerId, game);
|
||||
if (target.canTarget(playerId, source, game)) {
|
||||
target.addTarget(playerId, source, game);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (target.canTarget(playerId, game)) {
|
||||
target.addTarget(opponentId, game);
|
||||
if (target.canTarget(playerId, source, game)) {
|
||||
target.addTarget(opponentId, source, game);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -154,15 +164,15 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
findPlayables(game);
|
||||
if (unplayable.size() > 0) {
|
||||
for (int i = unplayable.size() - 1; i >= 0; i--) {
|
||||
if (target.canTarget(unplayable.values().toArray(new Card[0])[i].getId(), game)) {
|
||||
target.addTarget(unplayable.values().toArray(new Card[0])[i].getId(), game);
|
||||
if (target.canTarget(unplayable.values().toArray(new Card[0])[i].getId(), source, game)) {
|
||||
target.addTarget(unplayable.values().toArray(new Card[0])[i].getId(), source, game);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hand.size() > 0) {
|
||||
if (target.canTarget(hand.keySet().toArray(new UUID[0])[0], game)) {
|
||||
target.addTarget(hand.keySet().toArray(new UUID[0])[0], game);
|
||||
if (target.canTarget(hand.toArray(new UUID[0])[0], source, game)) {
|
||||
target.addTarget(hand.toArray(new UUID[0])[0], source, game);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -173,8 +183,8 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
if (!outcome.isGood())
|
||||
Collections.reverse(targets);
|
||||
for (Permanent permanent: targets) {
|
||||
if (target.canTarget(permanent.getId(), game)) {
|
||||
target.addTarget(permanent.getId(), game);
|
||||
if (target.canTarget(permanent.getId(), source, game)) {
|
||||
target.addTarget(permanent.getId(), source, game);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -188,8 +198,8 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
targets = threats(opponentId, ((TargetPermanent)target).getFilter(), game);
|
||||
}
|
||||
for (Permanent permanent: targets) {
|
||||
if (target.canTarget(permanent.getId(), game)) {
|
||||
target.addTarget(permanent.getId(), game);
|
||||
if (target.canTarget(permanent.getId(), source, game)) {
|
||||
target.addTarget(permanent.getId(), source, game);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -198,12 +208,13 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean chooseTargetAmount(Outcome outcome, TargetAmount target, Game game) {
|
||||
public boolean chooseTargetAmount(Outcome outcome, TargetAmount target, Ability source, Game game) {
|
||||
if (logger.isLoggable(Level.FINE))
|
||||
logger.fine("chooseTarget: " + outcome.toString() + ":" + target.toString());
|
||||
UUID opponentId = game.getOpponents(playerId).iterator().next();
|
||||
if (target instanceof TargetCreatureOrPlayerAmount) {
|
||||
if (game.getPlayer(opponentId).getLife() <= target.getAmountRemaining()) {
|
||||
target.addTarget(opponentId, target.getAmountRemaining(), game);
|
||||
target.addTarget(opponentId, target.getAmountRemaining(), source, game);
|
||||
return true;
|
||||
}
|
||||
List<Permanent> targets;
|
||||
|
@ -214,9 +225,9 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
targets = threats(opponentId, new FilterCreaturePermanent(), game);
|
||||
}
|
||||
for (Permanent permanent: targets) {
|
||||
if (target.canTarget(permanent.getId(), game)) {
|
||||
if (target.canTarget(permanent.getId(), source, game)) {
|
||||
if (permanent.getToughness().getValue() <= target.getAmountRemaining()) {
|
||||
target.addTarget(permanent.getId(), permanent.getToughness().getValue(), game);
|
||||
target.addTarget(permanent.getId(), permanent.getToughness().getValue(), source, game);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -304,17 +315,17 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
|
||||
protected void playLand(Game game) {
|
||||
logger.fine("playLand");
|
||||
List<Card> lands = hand.getCards(new FilterLandCard());
|
||||
Set<Card> lands = hand.getCards(new FilterLandCard(), game);
|
||||
while (lands.size() > 0 && this.landsPlayed < this.landsPerTurn) {
|
||||
if (lands.size() == 1)
|
||||
this.playLand(lands.get(0), game);
|
||||
this.playLand(lands.iterator().next(), game);
|
||||
else {
|
||||
playALand(lands, game);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void playALand(List<Card> lands, Game game) {
|
||||
protected void playALand(Set<Card> lands, Game game) {
|
||||
logger.fine("playALand");
|
||||
//play a land that will allow us to play an unplayable
|
||||
for (Mana mana: unplayable.keySet()) {
|
||||
|
@ -341,8 +352,8 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
}
|
||||
}
|
||||
//play first available land
|
||||
this.playLand(lands.get(0), game);
|
||||
lands.remove(0);
|
||||
this.playLand(lands.iterator().next(), game);
|
||||
lands.remove(lands.iterator().next());
|
||||
}
|
||||
|
||||
protected void findPlayables(Game game) {
|
||||
|
@ -350,7 +361,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
playableNonInstant.clear();
|
||||
unplayable.clear();
|
||||
playableAbilities.clear();
|
||||
List<Card> nonLands = hand.getCards(new FilterNonlandCard());
|
||||
Set<Card> nonLands = hand.getCards(new FilterNonlandCard(), game);
|
||||
ManaOptions available = getManaAvailable(game);
|
||||
available.addMana(manaPool.getMana());
|
||||
|
||||
|
@ -402,6 +413,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (logger.isLoggable(Level.FINE))
|
||||
logger.fine("findPlayables: " + playableInstant.toString() + "---" + playableNonInstant.toString() + "---" + playableAbilities.toString() );
|
||||
}
|
||||
|
||||
|
@ -417,7 +429,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
ManaCost cost;
|
||||
List<Permanent> producers;
|
||||
if (unpaid instanceof ManaCosts) {
|
||||
cost = ((ManaCosts)unpaid).get(0);
|
||||
cost = ((ManaCosts<ManaCost>)unpaid).get(0);
|
||||
producers = getSortedProducers((ManaCosts)unpaid, game);
|
||||
}
|
||||
else {
|
||||
|
@ -477,7 +489,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
* @param game
|
||||
* @return List<Permanent>
|
||||
*/
|
||||
private List<Permanent> getSortedProducers(ManaCosts unpaid, Game game) {
|
||||
private List<Permanent> getSortedProducers(ManaCosts<ManaCost> unpaid, Game game) {
|
||||
List<Permanent> unsorted = this.getAvailableManaProducers(game);
|
||||
Map<Permanent, Integer> scored = new HashMap<Permanent, Integer>();
|
||||
for (Permanent permanent: unsorted) {
|
||||
|
@ -490,6 +502,8 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (score > 0) // score mana producers that produce other types higher
|
||||
score += permanent.getAbilities().getManaAbilities(Zone.BATTLEFIELD).size();
|
||||
scored.put(permanent, score);
|
||||
}
|
||||
return sortByValue(scored);
|
||||
|
@ -546,16 +560,20 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean chooseTarget(Cards cards, TargetCard target, Game game) {
|
||||
public boolean chooseTarget(Cards cards, TargetCard target, Ability source, Game game) {
|
||||
logger.fine("chooseTarget");
|
||||
//TODO: improve this
|
||||
//return first match
|
||||
for (Card card: cards.getCards(target.getFilter())) {
|
||||
target.addTarget(card.getId(), game);
|
||||
if (!target.doneChosing()) {
|
||||
for (Card card: cards.getCards(target.getFilter(), game)) {
|
||||
target.addTarget(card.getId(), source, game);
|
||||
if (target.doneChosing())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectAttackers(Game game) {
|
||||
|
@ -665,12 +683,12 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
return potential;
|
||||
}
|
||||
|
||||
protected List<Permanent> getAvailableBlockers(Game game) {
|
||||
logger.fine("getAvailableBlockers");
|
||||
FilterCreatureForCombat blockFilter = new FilterCreatureForCombat();
|
||||
List<Permanent> blockers = game.getBattlefield().getAllActivePermanents(blockFilter, playerId);
|
||||
return blockers;
|
||||
}
|
||||
// protected List<Permanent> getAvailableBlockers(Game game) {
|
||||
// logger.fine("getAvailableBlockers");
|
||||
// FilterCreatureForCombat blockFilter = new FilterCreatureForCombat();
|
||||
// List<Permanent> blockers = game.getBattlefield().getAllActivePermanents(blockFilter, playerId);
|
||||
// return blockers;
|
||||
// }
|
||||
|
||||
protected List<Permanent> getOpponentBlockers(UUID opponentId, Game game) {
|
||||
logger.fine("getOpponentBlockers");
|
||||
|
@ -784,10 +802,24 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
}
|
||||
|
||||
protected void logState(Game game) {
|
||||
if (logger.isLoggable(Level.FINE))
|
||||
logList("computer player hand: ", new ArrayList(hand.getCards(game)));
|
||||
}
|
||||
|
||||
protected void logList(String message, List<MageObject> list) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("computer player hand: ");
|
||||
for (Card card: hand.values()) {
|
||||
sb.append(card.getName()).append(",");
|
||||
sb.append(message).append(": ");
|
||||
for (MageObject object: list) {
|
||||
sb.append(object.getName()).append(",");
|
||||
}
|
||||
logger.fine(sb.toString());
|
||||
}
|
||||
|
||||
protected void logAbilityList(String message, List<Ability> list) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(message).append(": ");
|
||||
for (Ability ability: list) {
|
||||
sb.append(ability.getRule()).append(",");
|
||||
}
|
||||
logger.fine(sb.toString());
|
||||
}
|
||||
|
@ -798,7 +830,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
if (card.getSpellAbility().canActivate(playerId, game)) {
|
||||
for (Effect effect: card.getSpellAbility().getEffects()) {
|
||||
if (effect.getOutcome().equals(Outcome.DestroyPermanent)) {
|
||||
if (card.getSpellAbility().getTargets().get(0).canTarget(creatureId, game)) {
|
||||
if (card.getSpellAbility().getTargets().get(0).canTarget(creatureId, card.getSpellAbility(), game)) {
|
||||
if (this.activateAbility(card.getSpellAbility(), game))
|
||||
return;
|
||||
}
|
||||
|
@ -816,7 +848,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
if (card.getSpellAbility().canActivate(playerId, game)) {
|
||||
for (Effect effect: card.getSpellAbility().getEffects()) {
|
||||
if (effect instanceof DamageTargetEffect) {
|
||||
if (card.getSpellAbility().getTargets().get(0).canTarget(creatureId, game)) {
|
||||
if (card.getSpellAbility().getTargets().get(0).canTarget(creatureId, card.getSpellAbility(), game)) {
|
||||
if (((DamageTargetEffect)effect).getAmount() > (creature.getPower().getValue() - creature.getDamage())) {
|
||||
if (this.activateAbility(card.getSpellAbility(), game))
|
||||
return;
|
||||
|
@ -837,5 +869,10 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
|||
playableAbilities = new ArrayList<ActivatedAbility>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T copy() {
|
||||
return (T)new ComputerPlayer(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
7
Mage.Player.AIMinimax/config/AIMinimax.properties
Normal file
7
Mage.Player.AIMinimax/config/AIMinimax.properties
Normal file
|
@ -0,0 +1,7 @@
|
|||
maxDepth=10
|
||||
maxNodes=5000
|
||||
evaluatorLifeFactor=2
|
||||
evaluatorPermanentFactor=1
|
||||
evaluatorCreatureFactor=1
|
||||
evaluatorHandFactor=1
|
||||
maxThinkSeconds=30
|
75
Mage.Player.AIMinimax/nbproject/project.properties
Normal file
75
Mage.Player.AIMinimax/nbproject/project.properties
Normal file
|
@ -0,0 +1,75 @@
|
|||
application.title=Mage.Player.AIMinimax
|
||||
application.vendor=BetaSteward_at_googlemail.com
|
||||
build.classes.dir=${build.dir}/classes
|
||||
build.classes.excludes=**/*.java,**/*.form
|
||||
# This directory is removed when the project is cleaned:
|
||||
build.dir=build
|
||||
build.generated.dir=${build.dir}/generated
|
||||
build.generated.sources.dir=${build.dir}/generated-sources
|
||||
# Only compile against the classpath explicitly listed here:
|
||||
build.sysclasspath=ignore
|
||||
build.test.classes.dir=${build.dir}/test/classes
|
||||
build.test.results.dir=${build.dir}/test/results
|
||||
# Uncomment to specify the preferred debugger connection transport:
|
||||
#debug.transport=dt_socket
|
||||
debug.classpath=\
|
||||
${run.classpath}
|
||||
debug.test.classpath=\
|
||||
${run.test.classpath}
|
||||
# This directory is removed when the project is cleaned:
|
||||
dist.dir=dist
|
||||
dist.jar=${dist.dir}/Mage.Player.AIMinimax.jar
|
||||
dist.javadoc.dir=${dist.dir}/javadoc
|
||||
endorsed.classpath=
|
||||
excludes=
|
||||
includes=**
|
||||
jar.compress=false
|
||||
javac.classpath=\
|
||||
${reference.Mage.jar}:\
|
||||
${reference.Mage_Player_AI.jar}
|
||||
# Space-separated list of extra javac options
|
||||
javac.compilerargs=
|
||||
javac.deprecation=false
|
||||
javac.source=1.5
|
||||
javac.target=1.5
|
||||
javac.test.classpath=\
|
||||
${javac.classpath}:\
|
||||
${build.classes.dir}:\
|
||||
${libs.junit.classpath}:\
|
||||
${libs.junit_4.classpath}
|
||||
javadoc.additionalparam=
|
||||
javadoc.author=false
|
||||
javadoc.encoding=${source.encoding}
|
||||
javadoc.noindex=false
|
||||
javadoc.nonavbar=false
|
||||
javadoc.notree=false
|
||||
javadoc.private=false
|
||||
javadoc.splitindex=true
|
||||
javadoc.use=true
|
||||
javadoc.version=false
|
||||
javadoc.windowtitle=
|
||||
jnlp.codebase.type=local
|
||||
jnlp.descriptor=application
|
||||
jnlp.enabled=false
|
||||
jnlp.offline-allowed=false
|
||||
jnlp.signed=false
|
||||
meta.inf.dir=${src.dir}/META-INF
|
||||
platform.active=default_platform
|
||||
project.license=bsd
|
||||
project.Mage=../Mage
|
||||
project.Mage_Player_AI=../Mage.Player.AI
|
||||
reference.Mage.jar=${project.Mage}/dist/Mage.jar
|
||||
reference.Mage_Player_AI.jar=${project.Mage_Player_AI}/dist/Mage.Player.AI.jar
|
||||
run.classpath=\
|
||||
${javac.classpath}:\
|
||||
${build.classes.dir}
|
||||
# Space-separated list of JVM arguments used when running the project
|
||||
# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
|
||||
# or test-sys-prop.name=value to set system properties for unit tests):
|
||||
run.jvmargs=
|
||||
run.test.classpath=\
|
||||
${javac.test.classpath}:\
|
||||
${build.test.classes.dir}
|
||||
source.encoding=UTF-8
|
||||
src.dir=src
|
||||
test.src.dir=test
|
33
Mage.Player.AIMinimax/nbproject/project.xml
Normal file
33
Mage.Player.AIMinimax/nbproject/project.xml
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://www.netbeans.org/ns/project/1">
|
||||
<type>org.netbeans.modules.java.j2seproject</type>
|
||||
<configuration>
|
||||
<data xmlns="http://www.netbeans.org/ns/j2se-project/3">
|
||||
<name>Mage.Player.AIMinimax</name>
|
||||
<source-roots>
|
||||
<root id="src.dir"/>
|
||||
</source-roots>
|
||||
<test-roots>
|
||||
<root id="test.src.dir"/>
|
||||
</test-roots>
|
||||
</data>
|
||||
<references xmlns="http://www.netbeans.org/ns/ant-project-references/1">
|
||||
<reference>
|
||||
<foreign-project>Mage</foreign-project>
|
||||
<artifact-type>jar</artifact-type>
|
||||
<script>build.xml</script>
|
||||
<target>jar</target>
|
||||
<clean-target>clean</clean-target>
|
||||
<id>jar</id>
|
||||
</reference>
|
||||
<reference>
|
||||
<foreign-project>Mage_Player_AI</foreign-project>
|
||||
<artifact-type>jar</artifact-type>
|
||||
<script>build.xml</script>
|
||||
<target>jar</target>
|
||||
<clean-target>clean</clean-target>
|
||||
<id>jar</id>
|
||||
</reference>
|
||||
</references>
|
||||
</configuration>
|
||||
</project>
|
52
Mage.Player.AIMinimax/src/mage/player/ai/Attackers.java
Normal file
52
Mage.Player.AIMinimax/src/mage/player/ai/Attackers.java
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.player.ai;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.TreeMap;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class Attackers extends TreeMap<Integer, List<Permanent>> {
|
||||
|
||||
public List<Permanent> getAttackers() {
|
||||
List<Permanent> attackers = new ArrayList<Permanent>();
|
||||
for (List<Permanent> l: this.values()) {
|
||||
for (Permanent permanent: l) {
|
||||
attackers.add(permanent);
|
||||
}
|
||||
}
|
||||
return attackers;
|
||||
}
|
||||
|
||||
}
|
631
Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer2.java
Normal file
631
Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer2.java
Normal file
|
@ -0,0 +1,631 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.player.ai;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import mage.Constants.Outcome;
|
||||
import mage.Constants.PhaseStep;
|
||||
import mage.Constants.RangeOfInfluence;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.ActivatedAbility;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.SearchEffect;
|
||||
import mage.cards.Cards;
|
||||
import mage.cards.decks.Deck;
|
||||
import mage.choices.Choice;
|
||||
import mage.filter.FilterAbility;
|
||||
import mage.game.Game;
|
||||
import mage.game.combat.Combat;
|
||||
import mage.game.combat.CombatGroup;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.stack.StackAbility;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.game.turn.BeginCombatStep;
|
||||
import mage.game.turn.BeginningPhase;
|
||||
import mage.game.turn.CleanupStep;
|
||||
import mage.game.turn.CombatDamageStep;
|
||||
import mage.game.turn.CombatPhase;
|
||||
import mage.game.turn.DeclareAttackersStep;
|
||||
import mage.game.turn.DeclareBlockersStep;
|
||||
import mage.game.turn.DrawStep;
|
||||
import mage.game.turn.EndOfCombatStep;
|
||||
import mage.game.turn.EndPhase;
|
||||
import mage.game.turn.EndStep;
|
||||
import mage.game.turn.Phase;
|
||||
import mage.game.turn.PostCombatMainPhase;
|
||||
import mage.game.turn.PostCombatMainStep;
|
||||
import mage.game.turn.PreCombatMainPhase;
|
||||
import mage.game.turn.PreCombatMainStep;
|
||||
import mage.game.turn.UntapStep;
|
||||
import mage.game.turn.UpkeepStep;
|
||||
import mage.players.Player;
|
||||
import mage.target.Target;
|
||||
import mage.target.TargetCard;
|
||||
import mage.util.Logging;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class ComputerPlayer2 extends ComputerPlayer<ComputerPlayer2> implements Player {
|
||||
|
||||
private static final transient Logger logger = Logging.getLogger(ComputerPlayer2.class.getName());
|
||||
private static final ExecutorService pool = Executors.newFixedThreadPool(1);
|
||||
|
||||
protected int maxDepth;
|
||||
protected int maxNodes;
|
||||
protected LinkedList<Ability> actions = new LinkedList<Ability>();
|
||||
protected List<UUID> targets = new ArrayList<UUID>();
|
||||
protected List<String> choices = new ArrayList<String>();
|
||||
protected Combat combat;
|
||||
protected int currentScore;
|
||||
protected SimulationNode root;
|
||||
|
||||
public ComputerPlayer2(String name, Deck deck, RangeOfInfluence range) {
|
||||
super(name, deck, range);
|
||||
maxDepth = Config.maxDepth;
|
||||
maxNodes = Config.maxNodes;
|
||||
}
|
||||
|
||||
public ComputerPlayer2(final ComputerPlayer2 player) {
|
||||
super(player);
|
||||
this.maxDepth = player.maxDepth;
|
||||
this.currentScore = player.currentScore;
|
||||
if (player.combat != null)
|
||||
this.combat = player.combat.copy();
|
||||
for (Ability ability: player.actions) {
|
||||
actions.add(ability);
|
||||
}
|
||||
for (UUID targetId: player.targets) {
|
||||
targets.add(targetId);
|
||||
}
|
||||
for (String choice: player.choices) {
|
||||
choices.add(choice);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComputerPlayer2 copy() {
|
||||
return new ComputerPlayer2(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void priority(Game game) {
|
||||
logState(game);
|
||||
game.firePriorityEvent(playerId);
|
||||
switch (game.getTurn().getStepType()) {
|
||||
case UPKEEP:
|
||||
case DRAW:
|
||||
pass();
|
||||
break;
|
||||
case PRECOMBAT_MAIN:
|
||||
case BEGIN_COMBAT:
|
||||
case DECLARE_ATTACKERS:
|
||||
case DECLARE_BLOCKERS:
|
||||
case COMBAT_DAMAGE:
|
||||
case END_COMBAT:
|
||||
case POSTCOMBAT_MAIN:
|
||||
if (actions.size() == 0) {
|
||||
calculateActions(game);
|
||||
}
|
||||
act(game);
|
||||
break;
|
||||
case END_TURN:
|
||||
case CLEANUP:
|
||||
pass();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected void act(Game game) {
|
||||
if (actions == null || actions.size() == 0)
|
||||
pass();
|
||||
else {
|
||||
boolean usedStack = false;
|
||||
while (actions.peek() != null) {
|
||||
Ability ability = actions.poll();
|
||||
this.activateAbility((ActivatedAbility) ability, game);
|
||||
if (ability.isUsesStack())
|
||||
usedStack = true;
|
||||
}
|
||||
if (usedStack)
|
||||
pass();
|
||||
}
|
||||
}
|
||||
|
||||
protected void calculateActions(Game game) {
|
||||
currentScore = GameStateEvaluator.evaluate(playerId, game);
|
||||
if (!getNextAction(game)) {
|
||||
Game sim = createSimulation(game);
|
||||
SimulationNode.resetCount();
|
||||
root = new SimulationNode(sim, maxDepth, playerId);
|
||||
logger.fine("simulating actions");
|
||||
addActionsTimed(new FilterAbility());
|
||||
if (root.children.size() > 0) {
|
||||
root = root.children.get(0);
|
||||
actions = new LinkedList<Ability>(root.abilities);
|
||||
combat = root.combat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean getNextAction(Game game) {
|
||||
if (root != null && root.children.size() > 0) {
|
||||
SimulationNode test = root;
|
||||
root = root.children.get(0);
|
||||
while (root.children.size() > 0 && !root.playerId.equals(playerId)) {
|
||||
test = root;
|
||||
root = root.children.get(0);
|
||||
}
|
||||
logger.fine("simlating -- game value:" + game.getState().getValue() + " test value:" + test.gameValue);
|
||||
if (root.playerId.equals(playerId) && root.abilities != null && game.getState().getValue() == test.gameValue) {
|
||||
logger.fine("simulating -- continuing previous action chain");
|
||||
actions = new LinkedList<Ability>(root.abilities);
|
||||
combat = root.combat;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected int minimaxAB(SimulationNode node, FilterAbility filter, int depth, int alpha, int beta) {
|
||||
UUID currentPlayerId = node.getGame().getPlayerList().get();
|
||||
SimulationNode bestChild = null;
|
||||
for (SimulationNode child: node.getChildren()) {
|
||||
if (alpha >= beta) {
|
||||
logger.fine("alpha beta pruning");
|
||||
break;
|
||||
}
|
||||
if (SimulationNode.nodeCount > maxNodes) {
|
||||
logger.fine("simulating -- reached end-state");
|
||||
break;
|
||||
}
|
||||
int val = addActions(child, filter, depth-1, alpha, beta);
|
||||
if (!currentPlayerId.equals(playerId)) {
|
||||
if (val < beta) {
|
||||
beta = val;
|
||||
bestChild = child;
|
||||
if (node.getCombat() == null)
|
||||
node.setCombat(child.getCombat());
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (val > alpha) {
|
||||
alpha = val;
|
||||
bestChild = child;
|
||||
if (node.getCombat() == null)
|
||||
node.setCombat(child.getCombat());
|
||||
}
|
||||
}
|
||||
}
|
||||
node.children.clear();
|
||||
if (bestChild != null)
|
||||
node.children.add(bestChild);
|
||||
if (!currentPlayerId.equals(playerId)) {
|
||||
logger.fine("returning minimax beta: " + beta);
|
||||
return beta;
|
||||
}
|
||||
else {
|
||||
logger.fine("returning minimax alpha: " + alpha);
|
||||
return alpha;
|
||||
}
|
||||
}
|
||||
|
||||
protected SearchEffect getSearchEffect(StackAbility ability) {
|
||||
for (Effect effect: ability.getEffects()) {
|
||||
if (effect instanceof SearchEffect) {
|
||||
return (SearchEffect) effect;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void resolve(SimulationNode node, int depth, Game game) {
|
||||
StackObject ability = game.getStack().pop();
|
||||
if (ability instanceof StackAbility) {
|
||||
SearchEffect effect = getSearchEffect((StackAbility) ability);
|
||||
if (effect != null && ability.getControllerId().equals(playerId)) {
|
||||
Target target = effect.getTarget();
|
||||
if (!target.doneChosing()) {
|
||||
for (UUID targetId: target.possibleTargets(ability.getSourceId(), ability.getControllerId(), game)) {
|
||||
Game sim = game.copy();
|
||||
StackAbility newAbility = (StackAbility) ability.copy();
|
||||
SearchEffect newEffect = getSearchEffect((StackAbility) newAbility);
|
||||
newEffect.getTarget().addTarget(targetId, newAbility, sim);
|
||||
sim.getStack().push(newAbility);
|
||||
SimulationNode newNode = new SimulationNode(sim, depth, ability.getControllerId());
|
||||
node.children.add(newNode);
|
||||
newNode.getTargets().add(targetId);
|
||||
logger.fine("simulating search -- node#: " + SimulationNode.getCount() + "for player: " + sim.getPlayer(ability.getControllerId()).getName());
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.fine("simulating resolve ");
|
||||
ability.resolve(game);
|
||||
game.applyEffects();
|
||||
game.getPlayers().resetPassed();
|
||||
game.getPlayerList().setCurrent(game.getActivePlayerId());
|
||||
}
|
||||
|
||||
protected void addActionsTimed(final FilterAbility filter) {
|
||||
FutureTask<Integer> task = new FutureTask<Integer>(new Callable<Integer>() {
|
||||
public Integer call() throws Exception
|
||||
{
|
||||
return addActions(root, filter, maxDepth, Integer.MIN_VALUE, Integer.MAX_VALUE);
|
||||
}
|
||||
});
|
||||
pool.execute(task);
|
||||
try {
|
||||
task.get(Config.maxThinkSeconds, TimeUnit.SECONDS);
|
||||
} catch (TimeoutException e) {
|
||||
logger.fine("simulating - timed out");
|
||||
task.cancel(true);
|
||||
} catch (ExecutionException e) {
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
protected int addActions(SimulationNode node, FilterAbility filter, int depth, int alpha, int beta) {
|
||||
Game game = node.getGame();
|
||||
int val;
|
||||
if (Thread.interrupted()) {
|
||||
Thread.currentThread().interrupt();
|
||||
logger.fine("interrupted");
|
||||
return GameStateEvaluator.evaluate(playerId, game);
|
||||
}
|
||||
if (depth <= 0 || SimulationNode.nodeCount > maxNodes || game.isGameOver()) {
|
||||
logger.fine("simulating -- reached end state");
|
||||
val = GameStateEvaluator.evaluate(playerId, game);
|
||||
}
|
||||
else if (node.getChildren().size() > 0) {
|
||||
logger.fine("simulating -- somthing added children:" + node.getChildren().size());
|
||||
val = minimaxAB(node, filter, depth-1, alpha, beta);
|
||||
}
|
||||
else {
|
||||
if (logger.isLoggable(Level.FINE))
|
||||
logger.fine("simulating -- alpha: " + alpha + " beta: " + beta + " depth:" + depth + " step:" + game.getTurn().getStepType() + " for player:" + (node.getPlayerId().equals(playerId)?"yes":"no"));
|
||||
if (allPassed(game)) {
|
||||
if (!game.getStack().isEmpty()) {
|
||||
resolve(node, depth, game);
|
||||
}
|
||||
else {
|
||||
// int testScore = GameStateEvaluator.evaluate(playerId, game);
|
||||
// if (testScore < currentScore) {
|
||||
// // if score at end of step is worse than original score don't check any further
|
||||
// logger.fine("simulating -- abandoning current check, no immediate benefit");
|
||||
// return testScore;
|
||||
// }
|
||||
game.getPlayers().resetPassed();
|
||||
playNext(game, game.getActivePlayerId(), node);
|
||||
}
|
||||
}
|
||||
|
||||
if (game.isGameOver()) {
|
||||
val = GameStateEvaluator.evaluate(playerId, game);
|
||||
}
|
||||
else if (node.getChildren().size() > 0) {
|
||||
//declared attackers or blockers or triggered abilities
|
||||
logger.fine("simulating -- attack/block/trigger added children:" + node.getChildren().size());
|
||||
val = minimaxAB(node, filter, depth-1, alpha, beta);
|
||||
}
|
||||
else {
|
||||
val = simulatePriority(node, game, filter, depth, alpha, beta);
|
||||
}
|
||||
}
|
||||
|
||||
if (logger.isLoggable(Level.FINE))
|
||||
logger.fine("returning -- score: " + val + " depth:" + depth + " step:" + game.getTurn().getStepType() + " for player:" + game.getPlayer(node.getPlayerId()).getName());
|
||||
return val;
|
||||
|
||||
}
|
||||
|
||||
protected int simulatePriority(SimulationNode node, Game game, FilterAbility filter, int depth, int alpha, int beta) {
|
||||
if (Thread.interrupted()) {
|
||||
Thread.currentThread().interrupt();
|
||||
logger.fine("interrupted");
|
||||
return GameStateEvaluator.evaluate(playerId, game);
|
||||
}
|
||||
node.setGameValue(game.getState().getValue());
|
||||
SimulatedPlayer currentPlayer = (SimulatedPlayer) game.getPlayer(game.getPlayerList().get());
|
||||
SimulationNode bestNode = null;
|
||||
List<Ability> allActions = currentPlayer.simulatePriority(game, filter);
|
||||
if (logger.isLoggable(Level.FINE))
|
||||
logger.fine("simulating -- adding " + allActions.size() + " children:" + allActions);
|
||||
for (Ability action: allActions) {
|
||||
Game sim = game.copy();
|
||||
if (sim.getPlayer(playerId).activateAbility((ActivatedAbility) action.copy(), sim)) {
|
||||
sim.applyEffects();
|
||||
if (!sim.isGameOver() && action.isUsesStack()) {
|
||||
// only pass if the last action uses the stack
|
||||
sim.getPlayer(currentPlayer.getId()).pass();
|
||||
sim.getPlayerList().getNext();
|
||||
}
|
||||
SimulationNode newNode = new SimulationNode(sim, action, depth, currentPlayer.getId());
|
||||
if (logger.isLoggable(Level.FINE))
|
||||
logger.fine("simulating -- node #:" + SimulationNode.getCount() + " actions:" + action);
|
||||
sim.checkStateAndTriggered();
|
||||
int val = addActions(newNode, filter, depth-1, alpha, beta);
|
||||
if (!currentPlayer.getId().equals(playerId)) {
|
||||
if (val < beta) {
|
||||
beta = val;
|
||||
bestNode = newNode;
|
||||
node.setCombat(newNode.getCombat());
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (val > alpha) {
|
||||
alpha = val;
|
||||
bestNode = newNode;
|
||||
node.setCombat(newNode.getCombat());
|
||||
if (node.getTargets().size() > 0)
|
||||
targets = node.getTargets();
|
||||
if (node.getChoices().size() > 0)
|
||||
choices = node.getChoices();
|
||||
}
|
||||
}
|
||||
if (alpha >= beta) {
|
||||
logger.fine("simulating -- pruning");
|
||||
break;
|
||||
}
|
||||
if (SimulationNode.nodeCount > maxNodes) {
|
||||
logger.fine("simulating -- reached end-state");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bestNode != null) {
|
||||
node.children.clear();
|
||||
node.children.add(bestNode);
|
||||
}
|
||||
if (!currentPlayer.getId().equals(playerId)) {
|
||||
logger.fine("returning priority beta: " + beta);
|
||||
return beta;
|
||||
}
|
||||
else {
|
||||
logger.fine("returning priority alpha: " + alpha);
|
||||
return alpha;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean allPassed(Game game) {
|
||||
for (Player player: game.getPlayers().values()) {
|
||||
if (!player.isPassed() && !player.hasLost() && !player.hasLeft())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean choose(Outcome outcome, Choice choice, Game game) {
|
||||
if (choices.size() == 0)
|
||||
return super.choose(outcome, choice, game);
|
||||
if (!choice.isChosen()) {
|
||||
for (String achoice: choices) {
|
||||
choice.setChoice(achoice);
|
||||
if (choice.isChosen()) {
|
||||
choices.clear();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean chooseTarget(Cards cards, TargetCard target, Ability source, Game game) {
|
||||
if (targets.size() == 0)
|
||||
return super.chooseTarget(cards, target, source, game);
|
||||
if (!target.doneChosing()) {
|
||||
for (UUID targetId: targets) {
|
||||
target.addTarget(targetId, source, game);
|
||||
if (target.doneChosing()) {
|
||||
targets.clear();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void playNext(Game game, UUID activePlayerId, SimulationNode node) {
|
||||
boolean skip = false;
|
||||
while (true) {
|
||||
Phase currentPhase = game.getPhase();
|
||||
if (!skip)
|
||||
currentPhase.getStep().endStep(game, activePlayerId);
|
||||
game.applyEffects();
|
||||
switch (currentPhase.getStep().getType()) {
|
||||
case UNTAP:
|
||||
game.getPhase().setStep(new UpkeepStep());
|
||||
break;
|
||||
case UPKEEP:
|
||||
game.getPhase().setStep(new DrawStep());
|
||||
break;
|
||||
case DRAW:
|
||||
game.getTurn().setPhase(new PreCombatMainPhase());
|
||||
game.getPhase().setStep(new PreCombatMainStep());
|
||||
break;
|
||||
case PRECOMBAT_MAIN:
|
||||
game.getTurn().setPhase(new CombatPhase());
|
||||
game.getPhase().setStep(new BeginCombatStep());
|
||||
break;
|
||||
case BEGIN_COMBAT:
|
||||
game.getPhase().setStep(new DeclareAttackersStep());
|
||||
break;
|
||||
case DECLARE_ATTACKERS:
|
||||
game.getPhase().setStep(new DeclareBlockersStep());
|
||||
break;
|
||||
case DECLARE_BLOCKERS:
|
||||
game.getPhase().setStep(new CombatDamageStep(true));
|
||||
break;
|
||||
case COMBAT_DAMAGE:
|
||||
if (((CombatDamageStep)currentPhase.getStep()).getFirst())
|
||||
game.getPhase().setStep(new CombatDamageStep(false));
|
||||
else
|
||||
game.getPhase().setStep(new EndOfCombatStep());
|
||||
break;
|
||||
case END_COMBAT:
|
||||
game.getTurn().setPhase(new PostCombatMainPhase());
|
||||
game.getPhase().setStep(new PostCombatMainStep());
|
||||
break;
|
||||
case POSTCOMBAT_MAIN:
|
||||
game.getTurn().setPhase(new EndPhase());
|
||||
game.getPhase().setStep(new EndStep());
|
||||
break;
|
||||
case END_TURN:
|
||||
game.getPhase().setStep(new CleanupStep());
|
||||
break;
|
||||
case CLEANUP:
|
||||
game.getPhase().getStep().beginStep(game, activePlayerId);
|
||||
if (!game.checkStateAndTriggered() && !game.isGameOver()) {
|
||||
game.getState().setActivePlayerId(game.getState().getPlayerList(game.getActivePlayerId()).getNext());
|
||||
game.getTurn().setPhase(new BeginningPhase());
|
||||
game.getPhase().setStep(new UntapStep());
|
||||
}
|
||||
}
|
||||
if (!game.getStep().skipStep(game, game.getActivePlayerId())) {
|
||||
if (game.getTurn().getStepType() == PhaseStep.DECLARE_ATTACKERS) {
|
||||
game.fireEvent(new GameEvent(GameEvent.EventType.DECLARE_ATTACKERS_STEP_PRE, null, null, activePlayerId));
|
||||
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DECLARING_ATTACKERS, activePlayerId, activePlayerId))) {
|
||||
for (Combat engagement: ((SimulatedPlayer)game.getPlayer(activePlayerId)).addAttackers(game)) {
|
||||
Game sim = game.copy();
|
||||
UUID defenderId = game.getOpponents(playerId).iterator().next();
|
||||
for (CombatGroup group: engagement.getGroups()) {
|
||||
for (UUID attackerId: group.getAttackers()) {
|
||||
sim.getPlayer(activePlayerId).declareAttacker(attackerId, defenderId, sim);
|
||||
}
|
||||
}
|
||||
sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_ATTACKERS, playerId, playerId));
|
||||
SimulationNode newNode = new SimulationNode(sim, node.getDepth()-1, activePlayerId);
|
||||
logger.fine("simulating -- node #:" + SimulationNode.getCount() + " declare attakers");
|
||||
newNode.setCombat(sim.getCombat());
|
||||
node.children.add(newNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (game.getTurn().getStepType() == PhaseStep.DECLARE_BLOCKERS) {
|
||||
game.fireEvent(new GameEvent(GameEvent.EventType.DECLARE_BLOCKERS_STEP_PRE, null, null, activePlayerId));
|
||||
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DECLARING_BLOCKERS, activePlayerId, activePlayerId))) {
|
||||
for (UUID defenderId: game.getCombat().getDefenders()) {
|
||||
//check if defender is being attacked
|
||||
if (game.getCombat().isAttacked(defenderId, game)) {
|
||||
for (Combat engagement: ((SimulatedPlayer)game.getPlayer(defenderId)).addBlockers(game)) {
|
||||
Game sim = game.copy();
|
||||
for (CombatGroup group: engagement.getGroups()) {
|
||||
for (UUID blockerId: group.getBlockers()) {
|
||||
group.addBlocker(blockerId, defenderId, sim);
|
||||
}
|
||||
}
|
||||
sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_BLOCKERS, playerId, playerId));
|
||||
SimulationNode newNode = new SimulationNode(sim, node.getDepth()-1, defenderId);
|
||||
logger.fine("simulating -- node #:" + SimulationNode.getCount() + " declare blockers");
|
||||
newNode.setCombat(sim.getCombat());
|
||||
node.children.add(newNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
game.getStep().beginStep(game, activePlayerId);
|
||||
}
|
||||
if (game.getStep().getHasPriority())
|
||||
break;
|
||||
}
|
||||
else {
|
||||
skip = true;
|
||||
}
|
||||
}
|
||||
game.checkStateAndTriggered();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectAttackers(Game game) {
|
||||
logger.fine("selectAttackers");
|
||||
if (combat != null) {
|
||||
UUID opponentId = game.getCombat().getDefenders().iterator().next();
|
||||
for (UUID attackerId: combat.getAttackers()) {
|
||||
this.declareAttacker(attackerId, opponentId, game);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectBlockers(Game game) {
|
||||
logger.fine("selectBlockers");
|
||||
if (combat != null && combat.getGroups().size() > 0) {
|
||||
List<CombatGroup> groups = game.getCombat().getGroups();
|
||||
for (int i = 0; i< groups.size(); i++) {
|
||||
for (UUID blockerId: combat.getGroups().get(i).getBlockers()) {
|
||||
this.declareBlocker(blockerId, groups.get(i).getAttackers().get(0), game);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies game and replaces all players in copy with simulated players
|
||||
*
|
||||
* @param game
|
||||
* @return a new game object with simulated players
|
||||
*/
|
||||
protected Game createSimulation(Game game) {
|
||||
Game sim = game.copy();
|
||||
|
||||
for (Player copyPlayer: sim.getState().getPlayers().values()) {
|
||||
Player origPlayer = game.getState().getPlayers().get(copyPlayer.getId());
|
||||
SimulatedPlayer newPlayer = new SimulatedPlayer(copyPlayer.getId(), copyPlayer.getId().equals(playerId));
|
||||
newPlayer.restore(origPlayer);
|
||||
sim.getState().getPlayers().put(copyPlayer.getId(), newPlayer);
|
||||
}
|
||||
return sim;
|
||||
}
|
||||
|
||||
}
|
540
Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer3.java
Normal file
540
Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer3.java
Normal file
|
@ -0,0 +1,540 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.player.ai;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import mage.Constants.AbilityType;
|
||||
import mage.Constants.PhaseStep;
|
||||
import mage.Constants.RangeOfInfluence;
|
||||
import mage.Constants.Zone;
|
||||
import mage.abilities.Ability;
|
||||
import mage.cards.decks.Deck;
|
||||
import mage.filter.FilterAbility;
|
||||
import mage.game.Game;
|
||||
import mage.game.combat.Combat;
|
||||
import mage.game.combat.CombatGroup;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.turn.BeginCombatStep;
|
||||
import mage.game.turn.BeginningPhase;
|
||||
import mage.game.turn.CleanupStep;
|
||||
import mage.game.turn.CombatDamageStep;
|
||||
import mage.game.turn.CombatPhase;
|
||||
import mage.game.turn.DeclareAttackersStep;
|
||||
import mage.game.turn.DeclareBlockersStep;
|
||||
import mage.game.turn.DrawStep;
|
||||
import mage.game.turn.EndOfCombatStep;
|
||||
import mage.game.turn.EndPhase;
|
||||
import mage.game.turn.EndStep;
|
||||
import mage.game.turn.PostCombatMainPhase;
|
||||
import mage.game.turn.PostCombatMainStep;
|
||||
import mage.game.turn.Step;
|
||||
import mage.game.turn.UntapStep;
|
||||
import mage.game.turn.UpkeepStep;
|
||||
import mage.players.Player;
|
||||
import mage.util.Logging;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class ComputerPlayer3 extends ComputerPlayer2 implements Player {
|
||||
|
||||
private static final transient Logger logger = Logging.getLogger(ComputerPlayer3.class.getName());
|
||||
|
||||
private static FilterAbility filterLand = new FilterAbility();
|
||||
private static FilterAbility filterNotLand = new FilterAbility();
|
||||
|
||||
static {
|
||||
filterLand.getTypes().add(AbilityType.PLAY_LAND);
|
||||
filterLand.setZone(Zone.HAND);
|
||||
|
||||
filterNotLand.getTypes().add(AbilityType.PLAY_LAND);
|
||||
filterNotLand.setZone(Zone.HAND);
|
||||
filterNotLand.setNotFilter(true);
|
||||
|
||||
}
|
||||
|
||||
public ComputerPlayer3(String name, Deck deck, RangeOfInfluence range) {
|
||||
super(name, deck, range);
|
||||
maxDepth = Config.maxDepth;
|
||||
maxNodes = Config.maxNodes;
|
||||
}
|
||||
|
||||
public ComputerPlayer3(final ComputerPlayer3 player) {
|
||||
super(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComputerPlayer3 copy() {
|
||||
return new ComputerPlayer3(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void priority(Game game) {
|
||||
logState(game);
|
||||
game.firePriorityEvent(playerId);
|
||||
switch (game.getTurn().getStepType()) {
|
||||
case UPKEEP:
|
||||
case DRAW:
|
||||
pass();
|
||||
break;
|
||||
case PRECOMBAT_MAIN:
|
||||
if (game.getActivePlayerId().equals(playerId)) {
|
||||
if (actions.size() == 0) {
|
||||
calculatePreCombatActions(game);
|
||||
}
|
||||
act(game);
|
||||
}
|
||||
else
|
||||
pass();
|
||||
break;
|
||||
case BEGIN_COMBAT:
|
||||
pass();
|
||||
break;
|
||||
case DECLARE_ATTACKERS:
|
||||
if (!game.getActivePlayerId().equals(playerId)) {
|
||||
if (actions.size() == 0) {
|
||||
calculatePreCombatActions(game);
|
||||
}
|
||||
act(game);
|
||||
}
|
||||
else
|
||||
pass();
|
||||
break;
|
||||
case DECLARE_BLOCKERS:
|
||||
case COMBAT_DAMAGE:
|
||||
case END_COMBAT:
|
||||
pass();
|
||||
break;
|
||||
case POSTCOMBAT_MAIN:
|
||||
if (game.getActivePlayerId().equals(playerId)) {
|
||||
if (actions.size() == 0) {
|
||||
calculatePostCombatActions(game);
|
||||
}
|
||||
act(game);
|
||||
}
|
||||
else
|
||||
pass();
|
||||
break;
|
||||
case END_TURN:
|
||||
case CLEANUP:
|
||||
pass();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected void calculatePreCombatActions(Game game) {
|
||||
if (!getNextAction(game)) {
|
||||
currentScore = GameStateEvaluator.evaluate(playerId, game);
|
||||
Game sim = createSimulation(game);
|
||||
SimulationNode.resetCount();
|
||||
root = new SimulationNode(sim, maxDepth, playerId);
|
||||
logger.fine("simulating pre combat actions -----------------------------------------------------------------------------------------");
|
||||
|
||||
addActionsTimed(new FilterAbility());
|
||||
if (root.children.size() > 0) {
|
||||
root = root.children.get(0);
|
||||
actions = new LinkedList<Ability>(root.abilities);
|
||||
combat = root.combat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void calculatePostCombatActions(Game game) {
|
||||
if (!getNextAction(game)) {
|
||||
currentScore = GameStateEvaluator.evaluate(playerId, game);
|
||||
Game sim = createSimulation(game);
|
||||
SimulationNode.resetCount();
|
||||
root = new SimulationNode(sim, maxDepth, playerId);
|
||||
logger.fine("simulating post combat actions ----------------------------------------------------------------------------------------");
|
||||
addActionsTimed(new FilterAbility());
|
||||
if (root.children.size() > 0) {
|
||||
root = root.children.get(0);
|
||||
actions = new LinkedList<Ability>(root.abilities);
|
||||
combat = root.combat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int addActions(SimulationNode node, FilterAbility filter, int depth, int alpha, int beta) {
|
||||
boolean stepFinished = false;
|
||||
int val;
|
||||
Game game = node.getGame();
|
||||
if (Thread.interrupted()) {
|
||||
Thread.currentThread().interrupt();
|
||||
logger.fine("interrupted");
|
||||
return GameStateEvaluator.evaluate(playerId, game);
|
||||
}
|
||||
if (depth <= 0 || SimulationNode.nodeCount > maxNodes || game.isGameOver()) {
|
||||
logger.fine("simulating -- reached end state");
|
||||
val = GameStateEvaluator.evaluate(playerId, game);
|
||||
}
|
||||
else if (node.getChildren().size() > 0) {
|
||||
logger.fine("simulating -- somthing added children:" + node.getChildren().size());
|
||||
val = minimaxAB(node, filter, depth-1, alpha, beta);
|
||||
}
|
||||
else {
|
||||
if (logger.isLoggable(Level.FINE))
|
||||
logger.fine("simulating -- alpha: " + alpha + " beta: " + beta + " depth:" + depth + " step:" + game.getTurn().getStepType() + " for player:" + game.getPlayer(game.getPlayerList().get()).getName());
|
||||
if (allPassed(game)) {
|
||||
if (!game.getStack().isEmpty()) {
|
||||
resolve(node, depth, game);
|
||||
}
|
||||
else {
|
||||
stepFinished = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (game.isGameOver()) {
|
||||
val = GameStateEvaluator.evaluate(playerId, game);
|
||||
}
|
||||
else if (stepFinished) {
|
||||
logger.fine("step finished");
|
||||
int testScore = GameStateEvaluator.evaluate(playerId, game);
|
||||
if (game.getActivePlayerId().equals(playerId)) {
|
||||
if (testScore < currentScore) {
|
||||
// if score at end of step is worse than original score don't check further
|
||||
logger.fine("simulating -- abandoning check, no immediate benefit");
|
||||
val = testScore;
|
||||
}
|
||||
else {
|
||||
switch (game.getTurn().getStepType()) {
|
||||
case PRECOMBAT_MAIN:
|
||||
val = simulateCombat(game, node, depth-1, alpha, beta, false);
|
||||
break;
|
||||
case POSTCOMBAT_MAIN:
|
||||
val = simulateCounterAttack(game, node, depth-1, alpha, beta);
|
||||
break;
|
||||
default:
|
||||
val = GameStateEvaluator.evaluate(playerId, game);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (game.getTurn().getStepType() == PhaseStep.DECLARE_ATTACKERS)
|
||||
val = simulateBlockers(game, node, playerId, depth-1, alpha, beta, true);
|
||||
else
|
||||
val = GameStateEvaluator.evaluate(playerId, game);
|
||||
}
|
||||
}
|
||||
else if (node.getChildren().size() > 0) {
|
||||
logger.fine("simulating -- trigger added children:" + node.getChildren().size());
|
||||
val = minimaxAB(node, filter, depth, alpha, beta);
|
||||
}
|
||||
else {
|
||||
val = simulatePriority(node, game, filter, depth, alpha, beta);
|
||||
}
|
||||
}
|
||||
|
||||
if (logger.isLoggable(Level.FINE))
|
||||
logger.fine("returning -- score: " + val + " depth:" + depth + " step:" + game.getTurn().getStepType() + " for player:" + game.getPlayer(node.getPlayerId()).getName());
|
||||
return val;
|
||||
|
||||
}
|
||||
|
||||
protected int simulateCombat(Game game, SimulationNode node, int depth, int alpha, int beta, boolean counter) {
|
||||
Integer val = null;
|
||||
if (Thread.interrupted()) {
|
||||
Thread.currentThread().interrupt();
|
||||
logger.fine("interrupted");
|
||||
return GameStateEvaluator.evaluate(playerId, game);
|
||||
}
|
||||
if (game.getTurn().getStepType() != PhaseStep.DECLARE_BLOCKERS) {
|
||||
game.getTurn().setPhase(new CombatPhase());
|
||||
if (game.getPhase().beginPhase(game, game.getActivePlayerId())) {
|
||||
simulateStep(game, new BeginCombatStep());
|
||||
game.getPhase().setStep(new DeclareAttackersStep());
|
||||
if (!game.getStep().skipStep(game, game.getActivePlayerId())) {
|
||||
game.fireEvent(new GameEvent(GameEvent.EventType.DECLARE_ATTACKERS_STEP_PRE, null, null, game.getActivePlayerId()));
|
||||
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DECLARING_ATTACKERS, game.getActivePlayerId(), game.getActivePlayerId()))) {
|
||||
val = simulateAttackers(game, node, game.getActivePlayerId(), depth, alpha, beta, counter);
|
||||
}
|
||||
}
|
||||
else if (!counter) {
|
||||
simulateToEnd(game);
|
||||
val = simulatePostCombatMain(game, node, depth, alpha, beta);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!game.getStep().skipStep(game, game.getActivePlayerId())) {
|
||||
game.fireEvent(new GameEvent(GameEvent.EventType.DECLARE_BLOCKERS_STEP_PRE, null, null, game.getActivePlayerId()));
|
||||
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DECLARING_BLOCKERS, game.getActivePlayerId(), game.getActivePlayerId()))) {
|
||||
//only suitable for two player games - only simulates blocks for 1st defender
|
||||
val = simulateBlockers(game, node, game.getCombat().getDefenders().iterator().next(), depth, alpha, beta, counter);
|
||||
}
|
||||
}
|
||||
else if (!counter) {
|
||||
finishCombat(game);
|
||||
val = GameStateEvaluator.evaluate(playerId, game);
|
||||
// val = simulateCounterAttack(game, node, depth, alpha, beta);
|
||||
}
|
||||
}
|
||||
if (val == null)
|
||||
val = GameStateEvaluator.evaluate(playerId, game);
|
||||
if (logger.isLoggable(Level.FINE))
|
||||
logger.fine("returning -- combat score: " + val + " depth:" + depth + " for player:" + game.getPlayer(node.getPlayerId()).getName());
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
protected int simulateAttackers(Game game, SimulationNode node, UUID attackerId, int depth, int alpha, int beta, boolean counter) {
|
||||
if (Thread.interrupted()) {
|
||||
Thread.currentThread().interrupt();
|
||||
logger.fine("interrupted");
|
||||
return GameStateEvaluator.evaluate(playerId, game);
|
||||
}
|
||||
Integer val = null;
|
||||
SimulationNode bestNode = null;
|
||||
SimulatedPlayer attacker = (SimulatedPlayer) game.getPlayer(attackerId);
|
||||
|
||||
for (Combat engagement: attacker.addAttackers(game)) {
|
||||
if (alpha >= beta) {
|
||||
logger.fine("simulating -- pruning attackers");
|
||||
break;
|
||||
}
|
||||
Game sim = game.copy();
|
||||
UUID defenderId = game.getOpponents(playerId).iterator().next();
|
||||
for (CombatGroup group: engagement.getGroups()) {
|
||||
for (UUID attackId: group.getAttackers()) {
|
||||
sim.getPlayer(attackerId).declareAttacker(attackId, defenderId, sim);
|
||||
}
|
||||
}
|
||||
sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_ATTACKERS, playerId, playerId));
|
||||
SimulationNode newNode = new SimulationNode(sim, depth, game.getActivePlayerId());
|
||||
if (logger.isLoggable(Level.FINE))
|
||||
logger.fine("simulating attack -- node#: " + SimulationNode.getCount());
|
||||
sim.checkStateAndTriggered();
|
||||
while (!sim.getStack().isEmpty()) {
|
||||
sim.getStack().resolve(sim);
|
||||
logger.fine("resolving triggered abilities");
|
||||
sim.applyEffects();
|
||||
}
|
||||
sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARE_ATTACKERS_STEP_POST, sim.getActivePlayerId(), sim.getActivePlayerId()));
|
||||
Combat simCombat = sim.getCombat().copy();
|
||||
sim.getPhase().setStep(new DeclareBlockersStep());
|
||||
val = simulateCombat(sim, newNode, depth-1, alpha, beta, counter);
|
||||
if (!attackerId.equals(playerId)) {
|
||||
if (val < beta) {
|
||||
beta = val;
|
||||
bestNode = newNode;
|
||||
node.setCombat(simCombat);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (val > alpha) {
|
||||
alpha = val;
|
||||
bestNode = newNode;
|
||||
node.setCombat(simCombat);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (val == null)
|
||||
val = GameStateEvaluator.evaluate(playerId, game);
|
||||
if (bestNode != null) {
|
||||
node.children.clear();
|
||||
node.children.add(bestNode);
|
||||
}
|
||||
if (logger.isLoggable(Level.FINE))
|
||||
logger.fine("returning -- combat attacker score: " + val + " depth:" + depth + " for player:" + game.getPlayer(node.getPlayerId()).getName());
|
||||
return val;
|
||||
}
|
||||
|
||||
protected int simulateBlockers(Game game, SimulationNode node, UUID defenderId, int depth, int alpha, int beta, boolean counter) {
|
||||
if (Thread.interrupted()) {
|
||||
Thread.currentThread().interrupt();
|
||||
logger.fine("interrupted");
|
||||
return GameStateEvaluator.evaluate(playerId, game);
|
||||
}
|
||||
Integer val = null;
|
||||
SimulationNode bestNode = null;
|
||||
//check if defender is being attacked
|
||||
if (game.getCombat().isAttacked(defenderId, game)) {
|
||||
SimulatedPlayer defender = (SimulatedPlayer) game.getPlayer(defenderId);
|
||||
for (Combat engagement: defender.addBlockers(game)) {
|
||||
if (alpha >= beta) {
|
||||
logger.fine("simulating -- pruning blockers");
|
||||
break;
|
||||
}
|
||||
Game sim = game.copy();
|
||||
for (CombatGroup group: engagement.getGroups()) {
|
||||
UUID attackerId = group.getAttackers().get(0);
|
||||
for (UUID blockerId: group.getBlockers()) {
|
||||
sim.getPlayer(defenderId).declareBlocker(blockerId, attackerId, sim);
|
||||
}
|
||||
}
|
||||
sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_BLOCKERS, playerId, playerId));
|
||||
SimulationNode newNode = new SimulationNode(sim, depth, defenderId);
|
||||
if (logger.isLoggable(Level.FINE))
|
||||
logger.fine("simulating block -- node#: " + SimulationNode.getCount());
|
||||
sim.checkStateAndTriggered();
|
||||
while (!sim.getStack().isEmpty()) {
|
||||
sim.getStack().resolve(sim);
|
||||
logger.fine("resolving triggered abilities");
|
||||
sim.applyEffects();
|
||||
}
|
||||
sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARE_BLOCKERS_STEP_POST, sim.getActivePlayerId(), sim.getActivePlayerId()));
|
||||
Combat simCombat = sim.getCombat().copy();
|
||||
finishCombat(sim);
|
||||
if (!counter) {
|
||||
int testScore = GameStateEvaluator.evaluate(playerId, sim);
|
||||
if (testScore < currentScore) {
|
||||
// if score at end of combat is worse than original score don't check counterattack
|
||||
logger.fine("simulating -- abandoning counterattack check, no immediate benefit");
|
||||
val = testScore;
|
||||
}
|
||||
else
|
||||
val = simulatePostCombatMain(sim, newNode, depth-1, alpha, beta);
|
||||
}
|
||||
else
|
||||
val = GameStateEvaluator.evaluate(playerId, sim);
|
||||
if (!defenderId.equals(playerId)) {
|
||||
if (val < beta) {
|
||||
beta = val;
|
||||
bestNode = newNode;
|
||||
node.setCombat(simCombat);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (val > alpha) {
|
||||
alpha = val;
|
||||
bestNode = newNode;
|
||||
node.setCombat(simCombat);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (val == null)
|
||||
val = GameStateEvaluator.evaluate(playerId, game);
|
||||
if (bestNode != null) {
|
||||
node.children.clear();
|
||||
node.children.add(bestNode);
|
||||
}
|
||||
if (logger.isLoggable(Level.FINE))
|
||||
logger.fine("returning -- combat blocker score: " + val + " depth:" + depth + " for player:" + game.getPlayer(node.getPlayerId()).getName());
|
||||
return val;
|
||||
}
|
||||
|
||||
protected int simulateCounterAttack(Game game, SimulationNode node, int depth, int alpha, int beta) {
|
||||
if (Thread.interrupted()) {
|
||||
Thread.currentThread().interrupt();
|
||||
logger.fine("interrupted");
|
||||
return GameStateEvaluator.evaluate(playerId, game);
|
||||
}
|
||||
Integer val = null;
|
||||
if (!game.isGameOver()) {
|
||||
logger.fine("simulating -- counter attack");
|
||||
simulateToEnd(game);
|
||||
game.getState().setActivePlayerId(game.getState().getPlayerList(game.getActivePlayerId()).getNext());
|
||||
game.getTurn().setPhase(new BeginningPhase());
|
||||
if (game.getPhase().beginPhase(game, game.getActivePlayerId())) {
|
||||
simulateStep(game, new UntapStep());
|
||||
simulateStep(game, new UpkeepStep());
|
||||
simulateStep(game, new DrawStep());
|
||||
game.getPhase().endPhase(game, game.getActivePlayerId());
|
||||
}
|
||||
val = simulateCombat(game, node, depth-1, alpha, beta, true);
|
||||
if (logger.isLoggable(Level.FINE))
|
||||
logger.fine("returning -- counter attack score: " + val + " depth:" + depth + " for player:" + game.getPlayer(node.getPlayerId()).getName());
|
||||
}
|
||||
if (val == null)
|
||||
val = GameStateEvaluator.evaluate(playerId, game);
|
||||
return val;
|
||||
}
|
||||
|
||||
protected void simulateStep(Game game, Step step) {
|
||||
if (Thread.interrupted()) {
|
||||
Thread.currentThread().interrupt();
|
||||
logger.fine("interrupted");
|
||||
return;
|
||||
}
|
||||
if (!game.isGameOver()) {
|
||||
game.getPhase().setStep(step);
|
||||
if (!step.skipStep(game, game.getActivePlayerId())) {
|
||||
step.beginStep(game, game.getActivePlayerId());
|
||||
game.checkStateAndTriggered();
|
||||
while (!game.getStack().isEmpty()) {
|
||||
game.getStack().resolve(game);
|
||||
game.applyEffects();
|
||||
}
|
||||
step.endStep(game, game.getActivePlayerId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void finishCombat(Game game) {
|
||||
if (Thread.interrupted()) {
|
||||
Thread.currentThread().interrupt();
|
||||
logger.fine("interrupted");
|
||||
return;
|
||||
}
|
||||
simulateStep(game, new CombatDamageStep(true));
|
||||
simulateStep(game, new CombatDamageStep(false));
|
||||
simulateStep(game, new EndOfCombatStep());
|
||||
}
|
||||
|
||||
protected int simulatePostCombatMain(Game game, SimulationNode node, int depth, int alpha, int beta) {
|
||||
if (Thread.interrupted()) {
|
||||
Thread.currentThread().interrupt();
|
||||
logger.fine("interrupted");
|
||||
return GameStateEvaluator.evaluate(playerId, game);
|
||||
}
|
||||
logger.fine("simulating -- post combat main");
|
||||
game.getTurn().setPhase(new PostCombatMainPhase());
|
||||
if (game.getPhase().beginPhase(game, game.getActivePlayerId())) {
|
||||
game.getPhase().setStep(new PostCombatMainStep());
|
||||
game.getStep().beginStep(game, playerId);
|
||||
game.getPlayers().resetPassed();
|
||||
return addActions(node, new FilterAbility(), depth, alpha, beta);
|
||||
}
|
||||
return simulateCounterAttack(game, node, depth, alpha, beta);
|
||||
}
|
||||
|
||||
protected void simulateToEnd(Game game) {
|
||||
if (Thread.interrupted()) {
|
||||
Thread.currentThread().interrupt();
|
||||
logger.fine("interrupted");
|
||||
return;
|
||||
}
|
||||
if (!game.isGameOver()) {
|
||||
game.getTurn().getPhase().endPhase(game, game.getActivePlayerId());
|
||||
game.getTurn().setPhase(new EndPhase());
|
||||
if (game.getTurn().getPhase().beginPhase(game, game.getActivePlayerId())) {
|
||||
simulateStep(game, new EndStep());
|
||||
simulateStep(game, new CleanupStep());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
75
Mage.Player.AIMinimax/src/mage/player/ai/Config.java
Normal file
75
Mage.Player.AIMinimax/src/mage/player/ai/Config.java
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.player.ai;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Properties;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import mage.util.Logging;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class Config {
|
||||
|
||||
private final static Logger logger = Logging.getLogger(Config.class.getName());
|
||||
|
||||
public static final int maxDepth;
|
||||
public static final int maxNodes;
|
||||
public static final int evaluatorLifeFactor;
|
||||
public static final int evaluatorPermanentFactor;
|
||||
public static final int evaluatorCreatureFactor;
|
||||
public static final int evaluatorHandFactor;
|
||||
public static final int maxThinkSeconds;
|
||||
|
||||
static {
|
||||
Properties p = new Properties();
|
||||
try {
|
||||
File file = new File(Config.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath());
|
||||
p.load(new FileInputStream(new File(file.getParent() + File.separator + "AIMinimax.properties")));
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.SEVERE, null, ex);
|
||||
} catch (URISyntaxException ex) {
|
||||
Logger.getLogger(Config.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
maxDepth = Integer.parseInt(p.getProperty("maxDepth"));
|
||||
maxNodes = Integer.parseInt(p.getProperty("maxNodes"));
|
||||
evaluatorLifeFactor = Integer.parseInt(p.getProperty("evaluatorLifeFactor"));
|
||||
evaluatorPermanentFactor = Integer.parseInt(p.getProperty("evaluatorPermanentFactor"));
|
||||
evaluatorCreatureFactor = Integer.parseInt(p.getProperty("evaluatorCreatureFactor"));
|
||||
evaluatorHandFactor = Integer.parseInt(p.getProperty("evaluatorHandFactor"));
|
||||
maxThinkSeconds = Integer.parseInt(p.getProperty("maxThinkSeconds"));
|
||||
}
|
||||
|
||||
}
|
102
Mage.Player.AIMinimax/src/mage/player/ai/GameStateEvaluator.java
Normal file
102
Mage.Player.AIMinimax/src/mage/player/ai/GameStateEvaluator.java
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
package mage.player.ai;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import mage.Constants.CardType;
|
||||
import mage.Constants.Zone;
|
||||
import mage.abilities.ActivatedAbility;
|
||||
import mage.abilities.keyword.DoubleStrikeAbility;
|
||||
import mage.abilities.keyword.FirstStrikeAbility;
|
||||
import mage.abilities.keyword.TrampleAbility;
|
||||
import mage.abilities.mana.ManaAbility;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.util.Logging;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*
|
||||
* this evaluator is only good for two player games
|
||||
*
|
||||
*/
|
||||
public class GameStateEvaluator {
|
||||
|
||||
private final static transient Logger logger = Logging.getLogger(GameStateEvaluator.class.getName());
|
||||
|
||||
private static final int LIFE_FACTOR = Config.evaluatorLifeFactor;
|
||||
private static final int PERMANENT_FACTOR = Config.evaluatorPermanentFactor;
|
||||
private static final int CREATURE_FACTOR = Config.evaluatorCreatureFactor;
|
||||
private static final int HAND_FACTOR = Config.evaluatorHandFactor;
|
||||
|
||||
public static int evaluate(UUID playerId, Game game) {
|
||||
Player player = game.getPlayer(playerId);
|
||||
Player opponent = game.getPlayer(game.getOpponents(playerId).iterator().next());
|
||||
if (game.isGameOver()) {
|
||||
if (player.hasLost() || opponent.hasWon())
|
||||
return Integer.MIN_VALUE;
|
||||
if (opponent.hasLost() || player.hasWon())
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
int lifeScore = (player.getLife() - opponent.getLife()) * LIFE_FACTOR;
|
||||
int permanentScore = 0;
|
||||
for (Permanent permanent: game.getBattlefield().getAllActivePermanents(playerId)) {
|
||||
permanentScore += evaluatePermanent(permanent, game);
|
||||
}
|
||||
for (Permanent permanent: game.getBattlefield().getAllActivePermanents(opponent.getId())) {
|
||||
permanentScore -= evaluatePermanent(permanent, game);
|
||||
}
|
||||
permanentScore *= PERMANENT_FACTOR;
|
||||
|
||||
int handScore = 0;
|
||||
handScore = 7 - opponent.getHand().size();
|
||||
handScore = Math.min(7, player.getHand().size());
|
||||
handScore *= HAND_FACTOR;
|
||||
|
||||
int score = lifeScore + permanentScore + handScore;
|
||||
if (logger.isLoggable(Level.FINE))
|
||||
logger.fine("game state evaluated to- lifeScore:" + lifeScore + " permanentScore:" + permanentScore + " handScore:" + handScore + " total:" + score);
|
||||
return score;
|
||||
}
|
||||
|
||||
public static int evaluatePermanent(Permanent permanent, Game game) {
|
||||
int value = permanent.isTapped()?1:2;
|
||||
if (permanent.getCardType().contains(CardType.CREATURE)) {
|
||||
value += evaluateCreature(permanent, game) * CREATURE_FACTOR;
|
||||
}
|
||||
value += permanent.getAbilities().getManaAbilities(Zone.BATTLEFIELD).size();
|
||||
for (ActivatedAbility ability: permanent.getAbilities().getActivatedAbilities(Zone.BATTLEFIELD)) {
|
||||
if (!(ability instanceof ManaAbility) && ability.canActivate(ability.getControllerId(), game))
|
||||
value += ability.getEffects().getOutcomeTotal();
|
||||
}
|
||||
value += permanent.getAbilities().getStaticAbilities(Zone.BATTLEFIELD).getOutcomeTotal();
|
||||
value += permanent.getAbilities().getTriggeredAbilities(Zone.BATTLEFIELD).getOutcomeTotal();
|
||||
value += permanent.getManaCost().convertedManaCost();
|
||||
//TODO: add a difficulty to calculation to ManaCost - sort permanents by difficulty for casting when evaluating game states
|
||||
return value;
|
||||
}
|
||||
|
||||
public static int evaluateCreature(Permanent creature, Game game) {
|
||||
int value = 0;
|
||||
value += creature.getPower().getValue();
|
||||
value += creature.getToughness().getValue();
|
||||
// if (creature.canAttack(game))
|
||||
// value += creature.getPower().getValue();
|
||||
// if (!creature.isTapped())
|
||||
// value += 2;
|
||||
value += creature.getAbilities().getEvasionAbilities().getOutcomeTotal();
|
||||
value += creature.getAbilities().getProtectionAbilities().getOutcomeTotal();
|
||||
value += creature.getAbilities().containsKey(FirstStrikeAbility.getInstance().getId())?1:0;
|
||||
value += creature.getAbilities().containsKey(DoubleStrikeAbility.getInstance().getId())?2:0;
|
||||
value += creature.getAbilities().containsKey(TrampleAbility.getInstance().getId())?1:0;
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.player.ai;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import mage.game.Game;
|
||||
import mage.util.Logging;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class SimulateBlockWorker implements Callable {
|
||||
|
||||
private final static Logger logger = Logging.getLogger(SimulationWorker.class.getName());
|
||||
|
||||
private SimulationNode node;
|
||||
private ComputerPlayer3 player;
|
||||
|
||||
public SimulateBlockWorker(ComputerPlayer3 player, SimulationNode node) {
|
||||
this.player = player;
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object call() {
|
||||
try {
|
||||
// player.simulateBlock(node);
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.SEVERE, null, ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.player.ai;
|
||||
|
||||
import java.util.List;
|
||||
import mage.abilities.Ability;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class SimulatedAction {
|
||||
|
||||
private Game game;
|
||||
private List<Ability> abilities;
|
||||
|
||||
public SimulatedAction(Game game, List<Ability> abilities) {
|
||||
this.game = game;
|
||||
this.abilities = abilities;
|
||||
}
|
||||
|
||||
public Game getGame() {
|
||||
return this.game;
|
||||
}
|
||||
|
||||
public List<Ability> getAbilities() {
|
||||
return this.abilities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.abilities.toString();
|
||||
}
|
||||
|
||||
public boolean usesStack() {
|
||||
if (abilities != null && abilities.size() > 0) {
|
||||
return abilities.get(abilities.size() -1).isUsesStack();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
250
Mage.Player.AIMinimax/src/mage/player/ai/SimulatedPlayer.java
Normal file
250
Mage.Player.AIMinimax/src/mage/player/ai/SimulatedPlayer.java
Normal file
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.player.ai;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.ActivatedAbility;
|
||||
import mage.abilities.TriggeredAbility;
|
||||
import mage.abilities.common.PassAbility;
|
||||
import mage.abilities.mana.ManaOptions;
|
||||
import mage.choices.Choice;
|
||||
import mage.filter.FilterAbility;
|
||||
import mage.game.Game;
|
||||
import mage.game.combat.Combat;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.StackAbility;
|
||||
import mage.target.Target;
|
||||
import mage.util.Copier;
|
||||
import mage.util.Logging;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class SimulatedPlayer extends ComputerPlayer<SimulatedPlayer> {
|
||||
|
||||
private final static transient Logger logger = Logging.getLogger(SimulatedPlayer.class.getName());
|
||||
private boolean isSimulatedPlayer;
|
||||
private FilterAbility filter;
|
||||
private transient ConcurrentLinkedQueue<Ability> allActions;
|
||||
private static PassAbility pass = new PassAbility();
|
||||
|
||||
public SimulatedPlayer(UUID id, boolean isSimulatedPlayer) {
|
||||
super(id);
|
||||
pass.setControllerId(playerId);
|
||||
this.isSimulatedPlayer = isSimulatedPlayer;
|
||||
}
|
||||
|
||||
public SimulatedPlayer(final SimulatedPlayer player) {
|
||||
super(player);
|
||||
this.isSimulatedPlayer = player.isSimulatedPlayer;
|
||||
if (player.filter != null)
|
||||
this.filter = player.filter.copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimulatedPlayer copy() {
|
||||
return new SimulatedPlayer(this);
|
||||
}
|
||||
|
||||
public List<Ability> simulatePriority(Game game, FilterAbility filter) {
|
||||
allActions = new ConcurrentLinkedQueue<Ability>();
|
||||
Game sim = game.copy();
|
||||
this.filter = filter;
|
||||
|
||||
simulateOptions(sim, pass);
|
||||
|
||||
ArrayList<Ability> list = new ArrayList<Ability>(allActions);
|
||||
Collections.reverse(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
protected void simulateOptions(Game game, Ability previousActions) {
|
||||
allActions.add(previousActions);
|
||||
ManaOptions available = getManaAvailable(game);
|
||||
available.addMana(manaPool.getMana());
|
||||
List<Ability> playables = game.getPlayer(playerId).getPlayable(game, filter, available, isSimulatedPlayer);
|
||||
for (Ability ability: playables) {
|
||||
List<Ability> options = game.getPlayer(playerId).getPlayableOptions(ability, game);
|
||||
if (options.size() == 0) {
|
||||
allActions.add(ability);
|
||||
// simulateAction(game, previousActions, ability);
|
||||
}
|
||||
else {
|
||||
// ExecutorService simulationExecutor = Executors.newFixedThreadPool(4);
|
||||
for (Ability option: options) {
|
||||
allActions.add(option);
|
||||
// SimulationWorker worker = new SimulationWorker(game, this, previousActions, option);
|
||||
// simulationExecutor.submit(worker);
|
||||
}
|
||||
// simulationExecutor.shutdown();
|
||||
// while(!simulationExecutor.isTerminated()) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// protected void simulateAction(Game game, SimulatedAction previousActions, Ability action) {
|
||||
// List<Ability> actions = new ArrayList<Ability>(previousActions.getAbilities());
|
||||
// actions.add(action);
|
||||
// Game sim = game.copy();
|
||||
// if (sim.getPlayer(playerId).activateAbility((ActivatedAbility) action.copy(), sim)) {
|
||||
// sim.applyEffects();
|
||||
// sim.getPlayers().resetPassed();
|
||||
// allActions.add(new SimulatedAction(sim, actions));
|
||||
// }
|
||||
// }
|
||||
|
||||
public List<Combat> addAttackers(Game game) {
|
||||
Map<Integer, Combat> engagements = new HashMap<Integer, Combat>();
|
||||
//useful only for two player games - will only attack first opponent
|
||||
UUID defenderId = game.getOpponents(playerId).iterator().next();
|
||||
List<Permanent> attackersList = super.getAvailableAttackers(game);
|
||||
//use binary digits to calculate powerset of attackers
|
||||
int powerElements = (int) Math.pow(2, attackersList.size());
|
||||
StringBuilder binary = new StringBuilder();
|
||||
for (int i = powerElements - 1; i >= 0; i--) {
|
||||
Game sim = game.copy();
|
||||
binary.setLength(0);
|
||||
binary.append(Integer.toBinaryString(i));
|
||||
while (binary.length() < attackersList.size()) {
|
||||
binary.insert(0, "0");
|
||||
}
|
||||
for (int j = 0; j < attackersList.size(); j++) {
|
||||
if (binary.charAt(j) == '1')
|
||||
sim.getCombat().declareAttacker(attackersList.get(j).getId(), defenderId, sim);
|
||||
}
|
||||
if (engagements.put(sim.getCombat().getValue(sim), sim.getCombat()) != null) {
|
||||
logger.fine("simulating -- found redundant attack combination");
|
||||
}
|
||||
else if (logger.isLoggable(Level.FINE)) {
|
||||
logger.fine("simulating -- attack:" + sim.getCombat().getGroups().size());
|
||||
}
|
||||
}
|
||||
return new ArrayList<Combat>(engagements.values());
|
||||
}
|
||||
|
||||
public List<Combat> addBlockers(Game game) {
|
||||
Map<Integer, Combat> engagements = new HashMap<Integer, Combat>();
|
||||
int numGroups = game.getCombat().getGroups().size();
|
||||
if (numGroups == 0) return new ArrayList<Combat>();
|
||||
|
||||
//add a node with no blockers
|
||||
Game sim = game.copy();
|
||||
engagements.put(sim.getCombat().getValue(sim), sim.getCombat());
|
||||
sim.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_BLOCKERS, playerId, playerId));
|
||||
|
||||
List<Permanent> blockers = getAvailableBlockers(game);
|
||||
addBlocker(game, blockers, engagements);
|
||||
|
||||
return new ArrayList<Combat>(engagements.values());
|
||||
}
|
||||
|
||||
protected void addBlocker(Game game, List<Permanent> blockers, Map<Integer, Combat> engagements) {
|
||||
if (blockers.size() == 0)
|
||||
return;
|
||||
int numGroups = game.getCombat().getGroups().size();
|
||||
//try to block each attacker with each potential blocker
|
||||
Permanent blocker = blockers.get(0);
|
||||
if (logger.isLoggable(Level.FINE))
|
||||
logger.fine("simulating -- block:" + blocker);
|
||||
List<Permanent> remaining = remove(blockers, blocker);
|
||||
for (int i = 0; i < numGroups; i++) {
|
||||
if (game.getCombat().getGroups().get(i).canBlock(blocker, game)) {
|
||||
Game sim = game.copy();
|
||||
sim.getCombat().getGroups().get(i).addBlocker(blocker.getId(), playerId, sim);
|
||||
if (engagements.put(sim.getCombat().getValue(sim), sim.getCombat()) != null)
|
||||
logger.fine("simulating -- found redundant block combination");
|
||||
addBlocker(sim, remaining, engagements); // and recurse minus the used blocker
|
||||
}
|
||||
}
|
||||
addBlocker(game, remaining, engagements);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean triggerAbility(TriggeredAbility source, Game game) {
|
||||
Ability ability = source.copy();
|
||||
List<Ability> options = getPlayableOptions(ability, game);
|
||||
if (options.size() == 0) {
|
||||
if (logger.isLoggable(Level.FINE))
|
||||
logger.fine("simulating -- triggered ability:" + ability);
|
||||
game.getStack().push(new StackAbility(ability, playerId));
|
||||
ability.activate(game, false);
|
||||
game.applyEffects();
|
||||
game.getPlayers().resetPassed();
|
||||
}
|
||||
else {
|
||||
SimulationNode parent = (SimulationNode) game.getCustomData();
|
||||
int depth = parent.getDepth() - 1;
|
||||
if (depth == 0) return true;
|
||||
logger.fine("simulating -- triggered ability - adding children:" + options.size());
|
||||
for (Ability option: options) {
|
||||
addAbilityNode(parent, option, depth, game);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void addAbilityNode(SimulationNode parent, Ability ability, int depth, Game game) {
|
||||
Game sim = game.copy();
|
||||
sim.getStack().push(new StackAbility(ability, playerId));
|
||||
ability.activate(sim, false);
|
||||
sim.applyEffects();
|
||||
SimulationNode newNode = new SimulationNode(sim, depth, playerId);
|
||||
logger.fine("simulating -- node #:" + SimulationNode.getCount() + " triggered ability option");
|
||||
for (Target target: ability.getTargets()) {
|
||||
for (UUID targetId: target.getTargets()) {
|
||||
newNode.getTargets().add(targetId);
|
||||
}
|
||||
}
|
||||
for (Choice choice: ability.getChoices()) {
|
||||
newNode.getChoices().add(choice.getChoice());
|
||||
}
|
||||
parent.children.add(newNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void priority(Game game) {
|
||||
//should never get here
|
||||
}
|
||||
|
||||
}
|
127
Mage.Player.AIMinimax/src/mage/player/ai/SimulationNode.java
Normal file
127
Mage.Player.AIMinimax/src/mage/player/ai/SimulationNode.java
Normal file
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.player.ai;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.game.Game;
|
||||
import mage.game.combat.Combat;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class SimulationNode implements Serializable {
|
||||
|
||||
protected static int nodeCount;
|
||||
|
||||
protected Game game;
|
||||
protected int gameValue;
|
||||
protected List<Ability> abilities;
|
||||
protected int depth;
|
||||
protected List<SimulationNode> children = new ArrayList<SimulationNode>();
|
||||
protected List<UUID> targets = new ArrayList<UUID>();
|
||||
protected List<String> choices = new ArrayList<String>();
|
||||
protected UUID playerId;
|
||||
protected Combat combat;
|
||||
|
||||
public SimulationNode(Game game, int depth, UUID playerId) {
|
||||
this.game = game;
|
||||
this.depth = depth;
|
||||
this.playerId = playerId;
|
||||
game.setCustomData(this);
|
||||
nodeCount++;
|
||||
}
|
||||
|
||||
public SimulationNode(Game game, List<Ability> abilities, int depth, UUID playerId) {
|
||||
this(game, depth, playerId);
|
||||
this.abilities = abilities;
|
||||
}
|
||||
|
||||
public SimulationNode(Game game, Ability ability, int depth, UUID playerId) {
|
||||
this(game, depth, playerId);
|
||||
this.abilities = new ArrayList<Ability>();
|
||||
abilities.add(ability);
|
||||
}
|
||||
|
||||
public static void resetCount() {
|
||||
nodeCount = 0;
|
||||
}
|
||||
|
||||
public static int getCount() {
|
||||
return nodeCount;
|
||||
}
|
||||
|
||||
public Game getGame() {
|
||||
return this.game;
|
||||
}
|
||||
|
||||
public int getGameValue() {
|
||||
return this.gameValue;
|
||||
}
|
||||
|
||||
public void setGameValue(int value) {
|
||||
this.gameValue = value;
|
||||
}
|
||||
|
||||
public List<Ability> getAbilities() {
|
||||
return this.abilities;
|
||||
}
|
||||
|
||||
public List<SimulationNode> getChildren() {
|
||||
return this.children;
|
||||
}
|
||||
|
||||
public int getDepth() {
|
||||
return this.depth;
|
||||
}
|
||||
|
||||
public UUID getPlayerId() {
|
||||
return this.playerId;
|
||||
}
|
||||
|
||||
public Combat getCombat() {
|
||||
return this.combat;
|
||||
}
|
||||
|
||||
public void setCombat(Combat combat) {
|
||||
this.combat = combat;
|
||||
}
|
||||
|
||||
public List<UUID> getTargets() {
|
||||
return this.targets;
|
||||
}
|
||||
|
||||
public List<String> getChoices() {
|
||||
return this.choices;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
|
||||
package mage.player.ai;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import mage.abilities.Ability;
|
||||
import mage.game.Game;
|
||||
import mage.util.Logging;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class SimulationWorker implements Callable {
|
||||
|
||||
private final static Logger logger = Logging.getLogger(SimulationWorker.class.getName());
|
||||
|
||||
private Game game;
|
||||
private SimulatedAction previousActions;
|
||||
private Ability action;
|
||||
private SimulatedPlayer player;
|
||||
|
||||
public SimulationWorker(Game game, SimulatedPlayer player, SimulatedAction previousActions, Ability action) {
|
||||
this.game = game;
|
||||
this.player = player;
|
||||
this.previousActions = previousActions;
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object call() {
|
||||
try {
|
||||
// player.simulateAction(game, previousActions, action);
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.SEVERE, null, ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -43,6 +43,7 @@ import mage.Constants.RangeOfInfluence;
|
|||
import mage.Constants.TargetController;
|
||||
import mage.Constants.Zone;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.ActivatedAbility;
|
||||
import mage.abilities.SpecialAction;
|
||||
import mage.abilities.costs.mana.ManaCost;
|
||||
|
@ -63,11 +64,11 @@ import mage.target.common.TargetDefender;
|
|||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class HumanPlayer extends PlayerImpl {
|
||||
public class HumanPlayer extends PlayerImpl<HumanPlayer> {
|
||||
|
||||
final transient PlayerResponse response = new PlayerResponse();
|
||||
|
||||
private boolean abort = false;
|
||||
private boolean abort;
|
||||
|
||||
protected transient TargetPermanent targetCombat = new TargetPermanent(new FilterCreatureForCombat(), TargetController.YOU);
|
||||
|
||||
|
@ -76,6 +77,11 @@ public class HumanPlayer extends PlayerImpl {
|
|||
human = true;
|
||||
}
|
||||
|
||||
public HumanPlayer(final HumanPlayer player) {
|
||||
super(player);
|
||||
this.abort = player.abort;
|
||||
}
|
||||
|
||||
protected void waitForResponse() {
|
||||
response.clear();
|
||||
synchronized(response) {
|
||||
|
@ -135,23 +141,27 @@ public class HumanPlayer extends PlayerImpl {
|
|||
|
||||
@Override
|
||||
public boolean choose(Outcome outcome, Choice choice, Game game) {
|
||||
game.fireChooseEvent(playerId, choice);
|
||||
while (!abort) {
|
||||
waitForStringResponse();
|
||||
game.fireChooseEvent(playerId, choice);
|
||||
waitForResponse();
|
||||
if (response.getString() != null) {
|
||||
choice.setChoice(response.getString());
|
||||
return true;
|
||||
} else if (!choice.isRequired()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean chooseTarget(Outcome outcome, Target target, Game game) {
|
||||
game.fireSelectTargetEvent(playerId, target.getMessage(), target.isRequired());
|
||||
public boolean chooseTarget(Outcome outcome, Target target, Ability source, Game game) {
|
||||
while (!abort) {
|
||||
game.fireSelectTargetEvent(playerId, target.getMessage(), target.isRequired());
|
||||
waitForResponse();
|
||||
if (response.getUUID() != null) {
|
||||
if (target.canTarget(response.getUUID(), game)) {
|
||||
target.addTarget(response.getUUID(), game);
|
||||
if (target.canTarget(response.getUUID(), source, game)) {
|
||||
target.addTarget(response.getUUID(), source, game);
|
||||
return true;
|
||||
}
|
||||
} else if (!target.isRequired()) {
|
||||
|
@ -162,13 +172,13 @@ public class HumanPlayer extends PlayerImpl {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean chooseTarget(Cards cards, TargetCard target, Game game) {
|
||||
public boolean chooseTarget(Cards cards, TargetCard target, Ability source, Game game) {
|
||||
game.fireSelectTargetEvent(playerId, target.getMessage(), cards, target.isRequired());
|
||||
while (!abort) {
|
||||
waitForResponse();
|
||||
if (response.getUUID() != null) {
|
||||
if (target.canTarget(response.getUUID(), cards, game)) {
|
||||
target.addTarget(response.getUUID(), game);
|
||||
target.addTarget(response.getUUID(), source, game);
|
||||
return true;
|
||||
}
|
||||
} else if (!target.isRequired()) {
|
||||
|
@ -180,15 +190,15 @@ public class HumanPlayer extends PlayerImpl {
|
|||
|
||||
|
||||
@Override
|
||||
public boolean chooseTargetAmount(Outcome outcome, TargetAmount target, Game game) {
|
||||
public boolean chooseTargetAmount(Outcome outcome, TargetAmount target, Ability source, Game game) {
|
||||
game.fireSelectTargetEvent(playerId, target.getMessage() + "\n Amount remaining:" + target.getAmountRemaining(), target.isRequired());
|
||||
while (!abort) {
|
||||
waitForResponse();
|
||||
if (response.getUUID() != null) {
|
||||
if (target.canTarget(response.getUUID(), game)) {
|
||||
if (target.canTarget(response.getUUID(), source, game)) {
|
||||
UUID targetId = response.getUUID();
|
||||
int amountSelected = getAmount(1, target.getAmountRemaining(), "Select amount", game);
|
||||
target.addTarget(targetId, amountSelected, game);
|
||||
target.addTarget(targetId, amountSelected, source, game);
|
||||
return true;
|
||||
}
|
||||
} else if (!target.isRequired()) {
|
||||
|
@ -313,7 +323,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
if (response.getBoolean() != null) {
|
||||
return;
|
||||
} else if (response.getUUID() != null) {
|
||||
if (targetCombat.canTarget(playerId, response.getUUID(), game)) {
|
||||
if (targetCombat.canTarget(playerId, response.getUUID(), null, game)) {
|
||||
selectDefender(game.getCombat().getDefenders(), response.getUUID(), game);
|
||||
}
|
||||
}
|
||||
|
@ -321,11 +331,17 @@ public class HumanPlayer extends PlayerImpl {
|
|||
}
|
||||
|
||||
protected boolean selectDefender(Set<UUID> defenders, UUID attackerId, Game game) {
|
||||
if (defenders.size() == 1) {
|
||||
declareAttacker(attackerId, defenders.iterator().next(), game);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
TargetDefender target = new TargetDefender(defenders, attackerId);
|
||||
if (chooseTarget(Outcome.Damage, target, game)) {
|
||||
if (chooseTarget(Outcome.Damage, target, null, game)) {
|
||||
declareAttacker(attackerId, response.getUUID(), game);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -338,7 +354,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
if (response.getBoolean() != null) {
|
||||
return;
|
||||
} else if (response.getUUID() != null) {
|
||||
if (targetCombat.canTarget(playerId, response.getUUID(), game)) {
|
||||
if (targetCombat.canTarget(playerId, response.getUUID(), null, game)) {
|
||||
selectCombatGroup(response.getUUID(), game);
|
||||
}
|
||||
}
|
||||
|
@ -361,7 +377,7 @@ public class HumanPlayer extends PlayerImpl {
|
|||
int remainingDamage = damage;
|
||||
while (remainingDamage > 0) {
|
||||
Target target = new TargetCreatureOrPlayer();
|
||||
chooseTarget(Outcome.Damage, target, game);
|
||||
chooseTarget(Outcome.Damage, target, null, game);
|
||||
if (targets.size() == 0 || targets.contains(target.getFirstTarget())) {
|
||||
int damageAmount = getAmount(0, remainingDamage, "Select amount", game);
|
||||
Permanent permanent = game.getPermanent(target.getFirstTarget());
|
||||
|
@ -449,4 +465,9 @@ public class HumanPlayer extends PlayerImpl {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HumanPlayer copy() {
|
||||
return new HumanPlayer(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
<playerTypes>
|
||||
<playerType name="Human" jar="Mage.Player.Human.jar" className="mage.player.human.HumanPlayer"/>
|
||||
<playerType name="Computer - default" jar="Mage.Player.AI.jar" className="mage.player.ai.ComputerPlayer"/>
|
||||
<playerType name="Computer - minimax" jar="Mage.Player.AIMinimax.jar" className="mage.player.ai.ComputerPlayer2"/>
|
||||
<playerType name="Computer - minimax hybrid" jar="Mage.Player.AIMinimax.jar" className="mage.player.ai.ComputerPlayer3"/>
|
||||
</playerTypes>
|
||||
<gameTypes>
|
||||
<gameType name="Two Player Duel" jar="Mage.Game.TwoPlayerDuel.jar" className="mage.game.TwoPlayerDuel" typeName="mage.game.TwoPlayerDuelType"/>
|
||||
|
|
|
@ -20,6 +20,7 @@ debug.test.classpath=\
|
|||
dist.dir=dist
|
||||
dist.jar=${dist.dir}/Mage.Server.jar
|
||||
dist.javadoc.dir=${dist.dir}/javadoc
|
||||
endorsed.classpath=
|
||||
excludes=
|
||||
includes=**
|
||||
jar.compress=false
|
||||
|
@ -27,7 +28,9 @@ javac.classpath=\
|
|||
${reference.Mage.jar}:\
|
||||
${reference.Mage_Common.jar}:\
|
||||
${reference.Mage_Sets.jar}:\
|
||||
${reference.Mage_Player_AI.jar}
|
||||
${reference.Mage_Player_AI.jar}:\
|
||||
${reference.Mage_Player_Human.jar}:\
|
||||
${reference.Mage_Player_AIMinimax.jar}
|
||||
# Space-separated list of extra javac options
|
||||
javac.compilerargs=
|
||||
javac.deprecation=false
|
||||
|
@ -56,15 +59,19 @@ jaxbwiz.xjcrun.classpath=${libs.jaxb.classpath}
|
|||
main.class=mage.server.Main
|
||||
manifest.file=manifest.mf
|
||||
meta.inf.dir=${src.dir}/META-INF
|
||||
platform.active=default_platform
|
||||
platform.active=JDK_1.6_21
|
||||
project.license=bsd
|
||||
project.Mage=../Mage
|
||||
project.Mage_Common=../Mage.Common
|
||||
project.Mage_Player_AI=../Mage.Player.AI
|
||||
project.Mage_Player_AIMinimax=../Mage.Player.AIMinimax
|
||||
project.Mage_Player_Human=../Mage.Player.Human
|
||||
project.Mage_Sets=../Mage.Sets
|
||||
reference.Mage.jar=${project.Mage}/dist/Mage.jar
|
||||
reference.Mage_Common.jar=${project.Mage_Common}/dist/Mage.Common.jar
|
||||
reference.Mage_Player_AI.jar=${project.Mage_Player_AI}/dist/Mage.Player.AI.jar
|
||||
reference.Mage_Player_AIMinimax.jar=${project.Mage_Player_AIMinimax}/dist/Mage.Player.AIMinimax.jar
|
||||
reference.Mage_Player_Human.jar=${project.Mage_Player_Human}/dist/Mage.Player.Human.jar
|
||||
reference.Mage_Sets.jar=${project.Mage_Sets}/dist/Mage.Sets.jar
|
||||
run-sys-prop.java.endorsed.dirs=${jaxbwiz.endorsed.dirs}
|
||||
run.classpath=\
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
</buildExtensions>
|
||||
<data xmlns="http://www.netbeans.org/ns/j2se-project/3">
|
||||
<name>Mage.Server</name>
|
||||
<explicit-platform explicit-source-supported="true"/>
|
||||
<source-roots>
|
||||
<root id="src.dir"/>
|
||||
</source-roots>
|
||||
|
@ -41,6 +42,22 @@
|
|||
<clean-target>clean</clean-target>
|
||||
<id>jar</id>
|
||||
</reference>
|
||||
<reference>
|
||||
<foreign-project>Mage_Player_AIMinimax</foreign-project>
|
||||
<artifact-type>jar</artifact-type>
|
||||
<script>build.xml</script>
|
||||
<target>jar</target>
|
||||
<clean-target>clean</clean-target>
|
||||
<id>jar</id>
|
||||
</reference>
|
||||
<reference>
|
||||
<foreign-project>Mage_Player_Human</foreign-project>
|
||||
<artifact-type>jar</artifact-type>
|
||||
<script>build.xml</script>
|
||||
<target>jar</target>
|
||||
<clean-target>clean</clean-target>
|
||||
<id>jar</id>
|
||||
</reference>
|
||||
<reference>
|
||||
<foreign-project>Mage_Sets</foreign-project>
|
||||
<artifact-type>jar</artifact-type>
|
||||
|
|
7
Mage.Server/plugins/AIMinimax.properties
Normal file
7
Mage.Server/plugins/AIMinimax.properties
Normal file
|
@ -0,0 +1,7 @@
|
|||
maxDepth=10
|
||||
maxNodes=5000
|
||||
evaluatorLifeFactor=2
|
||||
evaluatorPermanentFactor=1
|
||||
evaluatorCreatureFactor=1
|
||||
evaluatorHandFactor=1
|
||||
maxThinkSeconds=30
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Mage.Server/plugins/Mage.Player.AIMinimax.jar
Normal file
BIN
Mage.Server/plugins/Mage.Player.AIMinimax.jar
Normal file
Binary file not shown.
Binary file not shown.
|
@ -3,13 +3,16 @@
|
|||
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../Config.xsd">
|
||||
<server serverAddress="localhost" serverName="mage-server" port="17171" maxGameThreads="10" maxSecondsIdle="600"/>
|
||||
<playerTypes>
|
||||
<plugin name="Human" jar="Mage.Player.Human.jar" className="mage.player.human.HumanPlayer"/>
|
||||
<plugin name="Computer - default" jar="Mage.Player.AI.jar" className="mage.player.ai.ComputerPlayer"/>
|
||||
<playerType name="Human" jar="Mage.Player.Human.jar" className="mage.player.human.HumanPlayer"/>
|
||||
<playerType name="Computer - default" jar="Mage.Player.AI.jar" className="mage.player.ai.ComputerPlayer"/>
|
||||
<playerType name="Computer - minimax" jar="Mage.Player.AIMinimax.jar" className="mage.player.ai.ComputerPlayer2"/>
|
||||
<playerType name="Computer - minimax hybrid" jar="Mage.Player.AIMinimax.jar" className="mage.player.ai.ComputerPlayer3"/>
|
||||
</playerTypes>
|
||||
<gameTypes>
|
||||
<plugin name="Two Player Duel" jar="Mage.Game.TwoPlayerDuel.jar" className="mage.game.TwoPlayerGame"/>
|
||||
<gameType name="Two Player Duel" jar="Mage.Game.TwoPlayerDuel.jar" className="mage.game.TwoPlayerDuel" typeName="mage.game.TwoPlayerDuelType"/>
|
||||
<gameType name="Free For All" jar="Mage.Game.FreeForAll.jar" className="mage.game.FreeForAll" typeName="mage.game.FreeForAllType"/>
|
||||
</gameTypes>
|
||||
<deckTypes>
|
||||
<plugin name="Constructed" jar="Mage.Deck.Constructed.jar" className="mage.deck.Constructed"/>
|
||||
<deckType name="Constructed" jar="Mage.Deck.Constructed.jar" className="mage.deck.Constructed"/>
|
||||
</deckTypes>
|
||||
</config>
|
||||
|
|
|
@ -30,6 +30,7 @@ package mage.server;
|
|||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import mage.view.ChatMessage.MessageColor;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -65,8 +66,8 @@ public class ChatManager {
|
|||
chatSessions.remove(chatId);
|
||||
}
|
||||
|
||||
public void broadcast(UUID chatId, String userName, String message) {
|
||||
chatSessions.get(chatId).broadcast(userName, message);
|
||||
public void broadcast(UUID chatId, String userName, String message, MessageColor color) {
|
||||
chatSessions.get(chatId).broadcast(userName, message, color);
|
||||
}
|
||||
|
||||
void removeSession(UUID sessionId) {
|
||||
|
|
|
@ -39,6 +39,7 @@ import java.util.logging.Logger;
|
|||
import mage.interfaces.callback.ClientCallback;
|
||||
import mage.util.Logging;
|
||||
import mage.view.ChatMessage;
|
||||
import mage.view.ChatMessage.MessageColor;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -59,7 +60,7 @@ public class ChatSession {
|
|||
|
||||
public void join(String userName, UUID sessionId) {
|
||||
clients.put(sessionId, userName);
|
||||
broadcast(userName, " has joined");
|
||||
broadcast(userName, " has joined", MessageColor.BLACK);
|
||||
logger.info(userName + " joined chat " + chatId);
|
||||
}
|
||||
|
||||
|
@ -67,18 +68,18 @@ public class ChatSession {
|
|||
if (clients.containsKey(sessionId)) {
|
||||
String userName = clients.get(sessionId);
|
||||
clients.remove(sessionId);
|
||||
broadcast(userName, " has left");
|
||||
broadcast(userName, " has left", MessageColor.BLACK);
|
||||
logger.info(userName + " has left chat " + chatId);
|
||||
}
|
||||
}
|
||||
|
||||
public void broadcast(String userName, String message) {
|
||||
public void broadcast(String userName, String message, MessageColor color) {
|
||||
Calendar cal = new GregorianCalendar();
|
||||
final String msg = timeFormatter.format(cal.getTime()) + " " + userName + ":" + message;
|
||||
for (UUID sessionId: clients.keySet()) {
|
||||
Session session = SessionManager.getInstance().getSession(sessionId);
|
||||
if (session != null)
|
||||
session.fireCallback(new ClientCallback("chatMessage", new ChatMessage(chatId, msg)));
|
||||
session.fireCallback(new ClientCallback("chatMessage", new ChatMessage(chatId, msg, color)));
|
||||
else
|
||||
kill(sessionId);
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ import mage.cards.decks.DeckCardLists;
|
|||
import mage.game.GameException;
|
||||
import mage.interfaces.MageException;
|
||||
import mage.interfaces.Server;
|
||||
import mage.interfaces.ServerState;
|
||||
import mage.interfaces.callback.ClientCallback;
|
||||
import mage.server.game.DeckValidatorFactory;
|
||||
import mage.server.game.GameFactory;
|
||||
|
@ -52,6 +53,7 @@ import mage.server.game.PlayerFactory;
|
|||
import mage.server.game.ReplayManager;
|
||||
import mage.server.game.TableManager;
|
||||
import mage.util.Logging;
|
||||
import mage.view.ChatMessage.MessageColor;
|
||||
import mage.view.GameTypeView;
|
||||
import mage.view.TableView;
|
||||
|
||||
|
@ -126,9 +128,9 @@ public class ServerImpl extends RemoteServer implements Server {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean joinTable(UUID sessionId, UUID roomId, UUID tableId, int seatNum, String name, DeckCardLists deckList) throws MageException, GameException {
|
||||
public boolean joinTable(UUID sessionId, UUID roomId, UUID tableId, String name, DeckCardLists deckList) throws MageException, GameException {
|
||||
try {
|
||||
boolean ret = GamesRoomManager.getInstance().getRoom(roomId).joinTable(sessionId, tableId, seatNum, name, deckList);
|
||||
boolean ret = GamesRoomManager.getInstance().getRoom(roomId).joinTable(sessionId, tableId, name, deckList);
|
||||
logger.info("Session " + sessionId + " joined table " + tableId);
|
||||
return ret;
|
||||
}
|
||||
|
@ -186,7 +188,7 @@ public class ServerImpl extends RemoteServer implements Server {
|
|||
@Override
|
||||
public void sendChatMessage(UUID chatId, String userName, String message) throws MageException {
|
||||
try {
|
||||
ChatManager.getInstance().broadcast(chatId, userName, message);
|
||||
ChatManager.getInstance().broadcast(chatId, userName, message, MessageColor.BLUE);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
handleException(ex);
|
||||
|
@ -431,9 +433,13 @@ public class ServerImpl extends RemoteServer implements Server {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<GameTypeView> getGameTypes() throws MageException {
|
||||
public ServerState getServerState() throws RemoteException, MageException {
|
||||
try {
|
||||
return GameFactory.getInstance().getGameTypes();
|
||||
return new ServerState(
|
||||
GameFactory.getInstance().getGameTypes(),
|
||||
PlayerFactory.getInstance().getPlayerTypes().toArray(new String[0]),
|
||||
DeckValidatorFactory.getInstance().getDeckTypes().toArray(new String[0]),
|
||||
testMode);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
handleException(ex);
|
||||
|
@ -441,33 +447,44 @@ public class ServerImpl extends RemoteServer implements Server {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getPlayerTypes() throws MageException {
|
||||
try {
|
||||
return PlayerFactory.getInstance().getPlayerTypes().toArray(new String[0]);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
handleException(ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
// @Override
|
||||
// public List<GameTypeView> getGameTypes() throws MageException {
|
||||
// try {
|
||||
// return GameFactory.getInstance().getGameTypes();
|
||||
// }
|
||||
// catch (Exception ex) {
|
||||
// handleException(ex);
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String[] getPlayerTypes() throws MageException {
|
||||
// try {
|
||||
// return PlayerFactory.getInstance().getPlayerTypes().toArray(new String[0]);
|
||||
// }
|
||||
// catch (Exception ex) {
|
||||
// handleException(ex);
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String[] getDeckTypes() throws MageException {
|
||||
// try {
|
||||
// return DeckValidatorFactory.getInstance().getDeckTypes().toArray(new String[0]);
|
||||
// }
|
||||
// catch (Exception ex) {
|
||||
// handleException(ex);
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public String[] getDeckTypes() throws MageException {
|
||||
try {
|
||||
return DeckValidatorFactory.getInstance().getDeckTypes().toArray(new String[0]);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
handleException(ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cheat(UUID gameId, UUID sessionId, DeckCardLists deckList) throws MageException {
|
||||
public void cheat(UUID gameId, UUID sessionId, UUID playerId, DeckCardLists deckList) throws MageException {
|
||||
try {
|
||||
if (testMode)
|
||||
GameManager.getInstance().cheat(gameId, sessionId, deckList);
|
||||
GameManager.getInstance().cheat(gameId, sessionId, playerId, deckList);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
handleException(ex);
|
||||
|
|
|
@ -77,10 +77,11 @@ public class Session {
|
|||
return null;
|
||||
}
|
||||
|
||||
public void fireCallback(ClientCallback call) {
|
||||
public synchronized void fireCallback(ClientCallback call) {
|
||||
try {
|
||||
call.setMessageId(messageId++);
|
||||
logger.info(sessionId + " - " + call.getMessageId() + " - " + call.getMethod());
|
||||
if (logger.isLoggable(Level.FINE))
|
||||
logger.fine(sessionId + " - " + call.getMessageId() + " - " + call.getMethod());
|
||||
callback.setCallback(call);
|
||||
} catch (InterruptedException ex) {
|
||||
logger.log(Level.SEVERE, null, ex);
|
||||
|
|
|
@ -50,6 +50,7 @@ import mage.players.Player;
|
|||
import mage.util.Logging;
|
||||
import mage.view.AbilityPickerView;
|
||||
import mage.view.CardsView;
|
||||
import mage.view.ChatMessage.MessageColor;
|
||||
import mage.view.GameView;
|
||||
|
||||
/**
|
||||
|
@ -90,7 +91,7 @@ public class GameController implements GameCallback {
|
|||
updateGame();
|
||||
break;
|
||||
case INFO:
|
||||
ChatManager.getInstance().broadcast(chatId, "", event.getMessage());
|
||||
ChatManager.getInstance().broadcast(chatId, "", event.getMessage(), MessageColor.BLACK);
|
||||
logger.finest(game.getId() + " " + event.getMessage());
|
||||
break;
|
||||
case REVEAL:
|
||||
|
@ -152,7 +153,7 @@ public class GameController implements GameCallback {
|
|||
gameSessions.put(playerId, gameSession);
|
||||
logger.info("player " + playerId + " has joined game " + game.getId());
|
||||
// gameSession.init(getGameView(playerId));
|
||||
ChatManager.getInstance().broadcast(chatId, "", game.getPlayer(playerId).getName() + " has joined the game");
|
||||
ChatManager.getInstance().broadcast(chatId, "", game.getPlayer(playerId).getName() + " has joined the game", MessageColor.BLACK);
|
||||
if (allJoined()) {
|
||||
startGame();
|
||||
}
|
||||
|
@ -181,12 +182,12 @@ public class GameController implements GameCallback {
|
|||
GameWatcher gameWatcher = new GameWatcher(sessionId, game.getId());
|
||||
watchers.put(sessionId, gameWatcher);
|
||||
gameWatcher.init(getGameView());
|
||||
ChatManager.getInstance().broadcast(chatId, "", " has started watching");
|
||||
ChatManager.getInstance().broadcast(chatId, "", " has started watching", MessageColor.BLACK);
|
||||
}
|
||||
|
||||
public void stopWatching(UUID sessionId) {
|
||||
watchers.remove(sessionId);
|
||||
ChatManager.getInstance().broadcast(chatId, "", " has stopped watching");
|
||||
ChatManager.getInstance().broadcast(chatId, "", " has stopped watching", MessageColor.BLACK);
|
||||
}
|
||||
|
||||
public void concede(UUID sessionId) {
|
||||
|
@ -197,11 +198,11 @@ public class GameController implements GameCallback {
|
|||
game.quit(getPlayerId(sessionId));
|
||||
}
|
||||
|
||||
public void cheat(UUID sessionId, DeckCardLists deckList) {
|
||||
Player player = game.getPlayer(getPlayerId(sessionId));
|
||||
public void cheat(UUID sessionId, UUID playerId, DeckCardLists deckList) {
|
||||
Player player = game.getPlayer(playerId);
|
||||
Deck deck = Deck.load(deckList);
|
||||
deck.setOwnerId(player.getId());
|
||||
for (Card card: deck.getCards().values()) {
|
||||
game.loadCards(deck.getCards(), playerId);
|
||||
for (Card card: deck.getCards()) {
|
||||
player.putOntoBattlefield(card, game);
|
||||
}
|
||||
updateGame();
|
||||
|
@ -222,7 +223,7 @@ public class GameController implements GameCallback {
|
|||
|
||||
public void timeout(UUID sessionId) {
|
||||
if (sessionPlayerMap.containsKey(sessionId)) {
|
||||
ChatManager.getInstance().broadcast(chatId, "", game.getPlayer(sessionPlayerMap.get(sessionId)).getName() + " has timed out. Auto concede.");
|
||||
ChatManager.getInstance().broadcast(chatId, "", game.getPlayer(sessionPlayerMap.get(sessionId)).getName() + " has timed out. Auto concede.", MessageColor.BLACK);
|
||||
concede(sessionId);
|
||||
}
|
||||
}
|
||||
|
@ -272,68 +273,72 @@ public class GameController implements GameCallback {
|
|||
}
|
||||
|
||||
private synchronized void ask(UUID playerId, String question) {
|
||||
informOthers(playerId);
|
||||
if (gameSessions.containsKey(playerId))
|
||||
gameSessions.get(playerId).ask(question, getGameView(playerId));
|
||||
informOthers(playerId);
|
||||
}
|
||||
|
||||
private synchronized void chooseAbility(UUID playerId, Collection<? extends Ability> choices) {
|
||||
informOthers(playerId);
|
||||
if (gameSessions.containsKey(playerId))
|
||||
gameSessions.get(playerId).chooseAbility(new AbilityPickerView(choices));
|
||||
informOthers(playerId);
|
||||
}
|
||||
|
||||
private synchronized void choose(UUID playerId, String message, String[] choices) {
|
||||
informOthers(playerId);
|
||||
if (gameSessions.containsKey(playerId))
|
||||
gameSessions.get(playerId).choose(message, choices);
|
||||
informOthers(playerId);
|
||||
}
|
||||
|
||||
private synchronized void target(UUID playerId, String question, Cards cards, boolean required) {
|
||||
if (gameSessions.containsKey(playerId)) {
|
||||
if (cards != null)
|
||||
gameSessions.get(playerId).target(question, new CardsView(cards.getCards(game)), required, getGameView(playerId));
|
||||
else
|
||||
gameSessions.get(playerId).target(question, new CardsView(), required, getGameView(playerId));
|
||||
}
|
||||
informOthers(playerId);
|
||||
if (gameSessions.containsKey(playerId))
|
||||
gameSessions.get(playerId).target(question, new CardsView(cards), required, getGameView(playerId));
|
||||
}
|
||||
|
||||
private synchronized void target(UUID playerId, String question, Collection<? extends Ability> abilities, boolean required) {
|
||||
informOthers(playerId);
|
||||
if (gameSessions.containsKey(playerId))
|
||||
gameSessions.get(playerId).target(question, new CardsView(abilities, game), required, getGameView(playerId));
|
||||
gameSessions.get(playerId).target(question, new CardsView(abilities, game.getState()), required, getGameView(playerId));
|
||||
informOthers(playerId);
|
||||
}
|
||||
|
||||
private synchronized void select(UUID playerId, String message) {
|
||||
informOthers(playerId);
|
||||
if (gameSessions.containsKey(playerId))
|
||||
gameSessions.get(playerId).select(message, getGameView(playerId));
|
||||
informOthers(playerId);
|
||||
}
|
||||
|
||||
private synchronized void playMana(UUID playerId, String message) {
|
||||
informOthers(playerId);
|
||||
if (gameSessions.containsKey(playerId))
|
||||
gameSessions.get(playerId).playMana(message, getGameView(playerId));
|
||||
informOthers(playerId);
|
||||
}
|
||||
|
||||
private synchronized void playXMana(UUID playerId, String message) {
|
||||
informOthers(playerId);
|
||||
if (gameSessions.containsKey(playerId))
|
||||
gameSessions.get(playerId).playXMana(message, getGameView(playerId));
|
||||
informOthers(playerId);
|
||||
}
|
||||
|
||||
private synchronized void amount(UUID playerId, String message, int min, int max) {
|
||||
informOthers(playerId);
|
||||
if (gameSessions.containsKey(playerId))
|
||||
gameSessions.get(playerId).getAmount(message, min, max);
|
||||
informOthers(playerId);
|
||||
}
|
||||
|
||||
private synchronized void revealCards(String name, Cards cards) {
|
||||
for (GameSession session: gameSessions.values()) {
|
||||
session.revealCards(name, new CardsView(cards));
|
||||
session.revealCards(name, new CardsView(cards.getCards(game)));
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void lookAtCards(UUID playerId, String name, Cards cards) {
|
||||
if (gameSessions.containsKey(playerId))
|
||||
gameSessions.get(playerId).revealCards(name, new CardsView(cards));
|
||||
gameSessions.get(playerId).revealCards(name, new CardsView(cards.getCards(game)));
|
||||
}
|
||||
|
||||
private void informOthers(UUID playerId) {
|
||||
|
@ -349,12 +354,12 @@ public class GameController implements GameCallback {
|
|||
}
|
||||
|
||||
private GameView getGameView() {
|
||||
return new GameView(game.getState());
|
||||
return new GameView(game.getState(), game);
|
||||
}
|
||||
|
||||
private GameView getGameView(UUID playerId) {
|
||||
GameView gameView = new GameView(game.getState());
|
||||
gameView.setHand(new CardsView(game.getPlayer(playerId).getHand()));
|
||||
GameView gameView = new GameView(game.getState(), game);
|
||||
gameView.setHand(new CardsView(game.getPlayer(playerId).getHand().getCards(game)));
|
||||
return gameView;
|
||||
}
|
||||
|
||||
|
|
|
@ -108,8 +108,8 @@ public class GameManager {
|
|||
// return gameControllers.get(gameId).createReplay();
|
||||
// }
|
||||
|
||||
public void cheat(UUID gameId, UUID sessionId, DeckCardLists deckList) {
|
||||
gameControllers.get(gameId).cheat(sessionId, deckList);
|
||||
public void cheat(UUID gameId, UUID sessionId, UUID playerId, DeckCardLists deckList) {
|
||||
gameControllers.get(gameId).cheat(sessionId, playerId, deckList);
|
||||
}
|
||||
|
||||
void timeout(UUID gameId, UUID sessionId) {
|
||||
|
|
|
@ -37,10 +37,12 @@ import mage.game.*;
|
|||
public class GameReplay {
|
||||
|
||||
private GameStates savedGame;
|
||||
private Game game;
|
||||
private int stateIndex;
|
||||
|
||||
public GameReplay(GameStates savedGame) {
|
||||
this.savedGame = savedGame;
|
||||
public GameReplay(Game game) {
|
||||
this.savedGame = game.getGameStates();
|
||||
this.game = game;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
|
@ -61,4 +63,7 @@ public class GameReplay {
|
|||
return null;
|
||||
}
|
||||
|
||||
public Game getGame() {
|
||||
return this.game;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,6 +63,7 @@ public class GameSession extends GameWatcher {
|
|||
|
||||
public void ask(final String question, final GameView gameView) {
|
||||
if (!killed) {
|
||||
setupTimeout();
|
||||
Session session = SessionManager.getInstance().getSession(sessionId);
|
||||
if (session != null)
|
||||
session.fireCallback(new ClientCallback("gameAsk", new GameClientMessage(gameView, question)));
|
||||
|
@ -71,6 +72,7 @@ public class GameSession extends GameWatcher {
|
|||
|
||||
public void target(final String question, final CardsView cardView, final boolean required, final GameView gameView) {
|
||||
if (!killed) {
|
||||
setupTimeout();
|
||||
Session session = SessionManager.getInstance().getSession(sessionId);
|
||||
if (session != null)
|
||||
session.fireCallback(new ClientCallback("gameTarget", new GameClientMessage(gameView, question, cardView, required)));
|
||||
|
@ -79,6 +81,7 @@ public class GameSession extends GameWatcher {
|
|||
|
||||
public void select(final String message, final GameView gameView) {
|
||||
if (!killed) {
|
||||
setupTimeout();
|
||||
Session session = SessionManager.getInstance().getSession(sessionId);
|
||||
if (session != null)
|
||||
session.fireCallback(new ClientCallback("gameSelect", new GameClientMessage(gameView, message)));
|
||||
|
@ -87,6 +90,7 @@ public class GameSession extends GameWatcher {
|
|||
|
||||
public void chooseAbility(final AbilityPickerView abilities) {
|
||||
if (!killed) {
|
||||
setupTimeout();
|
||||
Session session = SessionManager.getInstance().getSession(sessionId);
|
||||
if (session != null)
|
||||
session.fireCallback(new ClientCallback("gameChooseAbility", abilities));
|
||||
|
@ -95,6 +99,7 @@ public class GameSession extends GameWatcher {
|
|||
|
||||
public void choose(final String message, final String[] choices) {
|
||||
if (!killed) {
|
||||
setupTimeout();
|
||||
Session session = SessionManager.getInstance().getSession(sessionId);
|
||||
if (session != null)
|
||||
session.fireCallback(new ClientCallback("gameChoose", new GameClientMessage(choices, message)));
|
||||
|
@ -103,6 +108,7 @@ public class GameSession extends GameWatcher {
|
|||
|
||||
public void playMana(final String message, final GameView gameView) {
|
||||
if (!killed) {
|
||||
setupTimeout();
|
||||
Session session = SessionManager.getInstance().getSession(sessionId);
|
||||
if (session != null)
|
||||
session.fireCallback(new ClientCallback("gamePlayMana", new GameClientMessage(gameView, message)));
|
||||
|
@ -111,6 +117,7 @@ public class GameSession extends GameWatcher {
|
|||
|
||||
public void playXMana(final String message, final GameView gameView) {
|
||||
if (!killed) {
|
||||
setupTimeout();
|
||||
Session session = SessionManager.getInstance().getSession(sessionId);
|
||||
if (session != null)
|
||||
session.fireCallback(new ClientCallback("gamePlayXMana", new GameClientMessage(gameView, message)));
|
||||
|
@ -119,6 +126,7 @@ public class GameSession extends GameWatcher {
|
|||
|
||||
public void getAmount(final String message, final int min, final int max) {
|
||||
if (!killed) {
|
||||
setupTimeout();
|
||||
Session session = SessionManager.getInstance().getSession(sessionId);
|
||||
if (session != null)
|
||||
session.fireCallback(new ClientCallback("gameSelectAmount", new GameClientMessage(message, min, max)));
|
||||
|
|
|
@ -43,7 +43,7 @@ import mage.view.TableView;
|
|||
public interface GamesRoom extends Room {
|
||||
|
||||
public List<TableView> getTables();
|
||||
public boolean joinTable(UUID sessionId, UUID tableId, int seatNum, String name, DeckCardLists deckList) throws GameException;
|
||||
public boolean joinTable(UUID sessionId, UUID tableId, String name, DeckCardLists deckList) throws GameException;
|
||||
public TableView createTable(UUID sessionId, String gameType, String deckType, List<String> playerTypes, MultiplayerAttackOption attackOption, RangeOfInfluence range);
|
||||
public void removeTable(UUID sessionId, UUID tableId);
|
||||
public TableView getTable(UUID tableId);
|
||||
|
|
|
@ -62,9 +62,9 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean joinTable(UUID sessionId, UUID tableId, int seatNum, String name, DeckCardLists deckList) throws GameException {
|
||||
public boolean joinTable(UUID sessionId, UUID tableId, String name, DeckCardLists deckList) throws GameException {
|
||||
if (tables.containsKey(tableId)) {
|
||||
return TableManager.getInstance().joinTable(sessionId, tableId, seatNum, name, deckList);
|
||||
return TableManager.getInstance().joinTable(sessionId, tableId, name, deckList);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ package mage.server.game;
|
|||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
|
@ -48,7 +49,7 @@ public class PlayerFactory {
|
|||
private final static PlayerFactory INSTANCE = new PlayerFactory();
|
||||
private final static Logger logger = Logging.getLogger(PlayerFactory.class.getName());
|
||||
|
||||
private Map<String, Class> playerTypes = new HashMap<String, Class>();
|
||||
private Map<String, Class> playerTypes = new LinkedHashMap<String, Class>();
|
||||
|
||||
public static PlayerFactory getInstance() {
|
||||
return INSTANCE;
|
||||
|
|
|
@ -30,6 +30,7 @@ package mage.server.game;
|
|||
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Logger;
|
||||
import mage.game.Game;
|
||||
import mage.game.GameState;
|
||||
import mage.interfaces.callback.ClientCallback;
|
||||
import mage.server.Session;
|
||||
|
@ -45,19 +46,19 @@ public class ReplaySession implements GameCallback {
|
|||
|
||||
private final static Logger logger = Logging.getLogger(ReplaySession.class.getName());
|
||||
|
||||
private GameReplay game;
|
||||
private GameReplay replay;
|
||||
protected UUID sessionId;
|
||||
|
||||
ReplaySession(UUID tableId, UUID sessionId) {
|
||||
this.game = TableManager.getInstance().createReplay(tableId);
|
||||
this.replay = TableManager.getInstance().createReplay(tableId);
|
||||
this.sessionId = sessionId;
|
||||
}
|
||||
|
||||
public void replay() {
|
||||
game.start();
|
||||
replay.start();
|
||||
Session session = SessionManager.getInstance().getSession(sessionId);
|
||||
if (session != null)
|
||||
session.fireCallback(new ClientCallback("replayInit", new GameView(game.next())));
|
||||
session.fireCallback(new ClientCallback("replayInit", new GameView(replay.next(), replay.getGame())));
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
|
@ -65,11 +66,11 @@ public class ReplaySession implements GameCallback {
|
|||
}
|
||||
|
||||
public synchronized void next() {
|
||||
updateGame(game.next());
|
||||
updateGame(replay.next(), replay.getGame());
|
||||
}
|
||||
|
||||
public synchronized void previous() {
|
||||
updateGame(game.previous());
|
||||
updateGame(replay.previous(), replay.getGame());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -79,14 +80,14 @@ public class ReplaySession implements GameCallback {
|
|||
session.fireCallback(new ClientCallback("replayDone", result));
|
||||
}
|
||||
|
||||
private void updateGame(final GameState state) {
|
||||
private void updateGame(final GameState state, Game game) {
|
||||
if (state == null) {
|
||||
gameResult("game ended");
|
||||
}
|
||||
else {
|
||||
Session session = SessionManager.getInstance().getSession(sessionId);
|
||||
if (session != null)
|
||||
session.fireCallback(new ClientCallback("replayUpdate", new GameView(state)));
|
||||
session.fireCallback(new ClientCallback("replayUpdate", new GameView(state, game)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -86,21 +86,26 @@ public class TableController {
|
|||
table = new Table(gameType, DeckValidatorFactory.getInstance().createDeckValidator(deckType), playerTypes);
|
||||
}
|
||||
|
||||
public synchronized boolean joinTable(UUID sessionId, int seatNum, String name, DeckCardLists deckList) throws GameException {
|
||||
public synchronized boolean joinTable(UUID sessionId, String name, DeckCardLists deckList) throws GameException {
|
||||
if (table.getState() != TableState.WAITING) {
|
||||
return false;
|
||||
}
|
||||
Seat seat = table.getSeats()[seatNum];
|
||||
Seat seat = table.getNextAvailableSeat();
|
||||
if (seat == null) {
|
||||
throw new GameException("No available seats.");
|
||||
}
|
||||
Deck deck = Deck.load(deckList);
|
||||
if (!Main.server.isTestMode() && !validDeck(deck)) {
|
||||
throw new GameException(name + " has an invalid deck for this format");
|
||||
}
|
||||
|
||||
Player player = createPlayer(name, deck, seat.getPlayerType());
|
||||
table.joinTable(player, seatNum);
|
||||
game.loadCards(deck.getCards(), player.getId());
|
||||
game.loadCards(deck.getSideboard(), player.getId());
|
||||
table.joinTable(player, seat);
|
||||
logger.info("player joined " + player.getId());
|
||||
//only add human players to sessionPlayerMap
|
||||
if (table.getSeats()[seatNum].getPlayer().isHuman()) {
|
||||
if (seat.getPlayer().isHuman()) {
|
||||
sessionPlayerMap.put(sessionId, player.getId());
|
||||
}
|
||||
|
||||
|
@ -183,11 +188,11 @@ public class TableController {
|
|||
|
||||
private void saveGame() {
|
||||
try {
|
||||
//use buffering
|
||||
OutputStream file = new FileOutputStream("saved/" + game.getId().toString() + ".game");
|
||||
OutputStream buffer = new BufferedOutputStream(file);
|
||||
ObjectOutput output = new ObjectOutputStream(new GZIPOutputStream(buffer));
|
||||
try {
|
||||
output.writeObject(game);
|
||||
output.writeObject(game.getGameStates());
|
||||
}
|
||||
finally {
|
||||
|
@ -200,17 +205,16 @@ public class TableController {
|
|||
}
|
||||
}
|
||||
|
||||
private GameStates loadGame() {
|
||||
private Game loadGame() {
|
||||
try{
|
||||
//use buffering
|
||||
InputStream file = new FileInputStream("saved/" + gameId.toString() + ".game");
|
||||
InputStream buffer = new BufferedInputStream(file);
|
||||
ObjectInput input = new CopierObjectInputStream(Main.classLoader, new GZIPInputStream(buffer));
|
||||
//ObjectInput input = new ObjectInputStream(buffer);
|
||||
try {
|
||||
//deserialize the List
|
||||
GameStates gameStates = (GameStates)input.readObject();
|
||||
return gameStates;
|
||||
Game game = (Game)input.readObject();
|
||||
GameStates states = (GameStates)input.readObject();
|
||||
game.loadGameStates(states);
|
||||
return game;
|
||||
}
|
||||
finally {
|
||||
input.close();
|
||||
|
|
|
@ -71,8 +71,8 @@ public class TableManager {
|
|||
return tables.values();
|
||||
}
|
||||
|
||||
public boolean joinTable(UUID sessionId, UUID tableId, int seatNum, String name, DeckCardLists deckList) throws GameException {
|
||||
return controllers.get(tableId).joinTable(sessionId, seatNum, name, deckList);
|
||||
public boolean joinTable(UUID sessionId, UUID tableId, String name, DeckCardLists deckList) throws GameException {
|
||||
return controllers.get(tableId).joinTable(sessionId, name, deckList);
|
||||
}
|
||||
|
||||
public void removeSession(UUID sessionId) {
|
||||
|
|
102
Mage.Sets/src/mage/sets/Magic2011.java
Normal file
102
Mage.Sets/src/mage/sets/Magic2011.java
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import mage.sets.magic2011.*;
|
||||
import mage.cards.ExpansionSet;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class Magic2011 extends ExpansionSet {
|
||||
|
||||
private static final Magic2011 fINSTANCE = new Magic2011();
|
||||
|
||||
public static Magic2011 getInstance() {
|
||||
return fINSTANCE;
|
||||
}
|
||||
|
||||
private Magic2011() {
|
||||
this.name = "Magic 2011";
|
||||
this.cards.add(AcidicSlime.class);
|
||||
this.cards.add(ActOfTreason.class);
|
||||
this.cards.add(AetherAdept.class);
|
||||
this.cards.add(AirServant.class);
|
||||
this.cards.add(AjaniGoldmane.class);
|
||||
// this.cards.add(AlluringSiren.class);
|
||||
// this.cards.add(AngelsFeather.class);
|
||||
// this.cards.add(AngelsMercy.class);
|
||||
// this.cards.add(AntQueen.class);
|
||||
// this.cards.add(ArmoredAscension.class);
|
||||
// this.cards.add(Assassinate.class);
|
||||
// this.cards.add(AwakenerDruid.class);
|
||||
// this.cards.add(BallLightning.class);
|
||||
// this.cards.add(BaneslayerAngel.class);
|
||||
// this.cards.add(BirdsOfParadise.class);
|
||||
// this.cards.add(BerserkersOfBloodRidge.class);
|
||||
// this.cards.add(BlackKnight.class);
|
||||
// this.cards.add(BlindingMage.class);
|
||||
// this.cards.add(BogWraith.class);
|
||||
// this.cards.add(BogardanHellkite.class);
|
||||
// this.cards.add(Cancel.class);
|
||||
// this.cards.add(CelestialPurge.class);
|
||||
// this.cards.add(DiabolicTutor.class);
|
||||
// this.cards.add(DoomBlade.class);
|
||||
// this.cards.add(DragonskullSummit.class);
|
||||
// this.cards.add(Earthquake.class);
|
||||
// this.cards.add(EliteVanguard.class);
|
||||
// this.cards.add(Flashfreeze.class);
|
||||
// this.cards.add(GargoyleCastle.class);
|
||||
// this.cards.add(GarrukWildspeaker.class);
|
||||
// this.cards.add(GiantGrowth.class);
|
||||
// this.cards.add(GlacialFortress.class);
|
||||
// this.cards.add(GreatSableStag.class);
|
||||
// this.cards.add(HonorOfThePure.class);
|
||||
// this.cards.add(HowlingMine.class);
|
||||
// this.cards.add(JaceBeleren.class);
|
||||
// this.cards.add(LlanowarElves.class);
|
||||
// this.cards.add(LightningBolt.class);
|
||||
// this.cards.add(MasterOfTheWildHunt.class);
|
||||
// this.cards.add(MightOfOaks.class);
|
||||
// this.cards.add(MindRot.class);
|
||||
// this.cards.add(Naturalize.class);
|
||||
// this.cards.add(Overrun.class);
|
||||
// this.cards.add(RampantGrowth.class);
|
||||
// this.cards.add(MindSpring.class);
|
||||
// this.cards.add(Negate.class);
|
||||
// this.cards.add(RootboundCrag.class);
|
||||
// this.cards.add(RoyalAssassin.class);
|
||||
// this.cards.add(SafePassage.class);
|
||||
// this.cards.add(SunpetalGrove.class);
|
||||
// this.cards.add(TerramorphicExpanse.class);
|
||||
// this.cards.add(TimeWarp.class);
|
||||
// this.cards.add(WhiteKnight.class);
|
||||
}
|
||||
}
|
|
@ -47,7 +47,11 @@ public class RiseOfTheEldrazi extends ExpansionSet {
|
|||
this.name = "Rise Of The Eldrazi";
|
||||
this.cards.add(Deprive.class);
|
||||
this.cards.add(GideonJura.class);
|
||||
this.cards.add(JoragaTreespeaker.class);
|
||||
this.cards.add(KarganDragonlord.class);
|
||||
this.cards.add(KozileksPredator.class);
|
||||
this.cards.add(NestInvader.class);
|
||||
this.cards.add(Vengevine.class);
|
||||
this.cards.add(WallOfOmens.class);
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ public class Sets extends ArrayList<ExpansionSet> {
|
|||
this.add(AlaraReborn.getInstance());
|
||||
this.add(Conflux.getInstance());
|
||||
this.add(Magic2010.getInstance());
|
||||
this.add(Magic2011.getInstance());
|
||||
this.add(Planechase.getInstance());
|
||||
this.add(RiseOfTheEldrazi.getInstance());
|
||||
this.add(ShardsOfAlara.getInstance());
|
||||
|
|
|
@ -45,10 +45,13 @@ public class Worldwake extends ExpansionSet {
|
|||
|
||||
private Worldwake() {
|
||||
this.name = "Worldwake";
|
||||
this.cards.add(ArborElf.class);
|
||||
this.cards.add(BasiliskCollar.class);
|
||||
this.cards.add(CelestialColonnade.class);
|
||||
this.cards.add(DreadStatuary.class);
|
||||
this.cards.add(EverflowingChalice.class);
|
||||
this.cards.add(JaceTheMindSculptor.class);
|
||||
this.cards.add(KhalniGarden.class);
|
||||
this.cards.add(LavaclawReaches.class);
|
||||
this.cards.add(RagingRavine.class);
|
||||
this.cards.add(SearingBlaze.class);
|
||||
|
@ -56,6 +59,7 @@ public class Worldwake extends ExpansionSet {
|
|||
this.cards.add(StirringWildwood.class);
|
||||
this.cards.add(StoneforgeMystic.class);
|
||||
this.cards.add(TectonicEdge.class);
|
||||
this.cards.add(WolfbriarElemental.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -45,12 +45,16 @@ public class Zendikar extends ExpansionSet {
|
|||
|
||||
private Zendikar() {
|
||||
this.name = "Zendikar";
|
||||
this.cards.add(AdventuringGear.class);
|
||||
this.cards.add(AetherFigment.class);
|
||||
this.cards.add(ArchiveTrap.class);
|
||||
this.cards.add(AridMesa.class);
|
||||
this.cards.add(BeastmasterAscension.class);
|
||||
this.cards.add(BraveTheElements.class);
|
||||
this.cards.add(BurstLightning.class);
|
||||
this.cards.add(ConquerorsPledge.class);
|
||||
this.cards.add(DayOfJudgment.class);
|
||||
this.cards.add(EldraziMonument.class);
|
||||
this.cards.add(EmeriaAngel.class);
|
||||
this.cards.add(GoblinGuide.class);
|
||||
this.cards.add(GoblinRuinblaster.class);
|
||||
|
@ -60,6 +64,7 @@ public class Zendikar extends ExpansionSet {
|
|||
this.cards.add(MistyRainforest.class);
|
||||
this.cards.add(OranRiefTheVastwood.class);
|
||||
this.cards.add(RampagingBaloths.class);
|
||||
this.cards.add(RiverBoa.class);
|
||||
this.cards.add(ScaldingTarn.class);
|
||||
this.cards.add(ScuteMob.class);
|
||||
this.cards.add(SpreadingSeas.class);
|
||||
|
|
|
@ -32,6 +32,7 @@ import java.util.UUID;
|
|||
import mage.Constants.CardType;
|
||||
import mage.Constants.Outcome;
|
||||
import mage.Constants.Zone;
|
||||
import mage.MageObjectImpl;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.effects.common.BoostEquippedEffect;
|
||||
|
@ -46,12 +47,11 @@ import mage.sets.AlaraReborn;
|
|||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class BehemothSledge extends CardImpl {
|
||||
public class BehemothSledge extends CardImpl<BehemothSledge> {
|
||||
|
||||
public BehemothSledge(UUID ownerId) {
|
||||
super(ownerId, "Behemoth Sledge", new CardType[]{CardType.ARTIFACT}, "{1}{G}{W}");
|
||||
this.expansionSetId = AlaraReborn.getInstance().getId();
|
||||
this.art = "120963_typ_reg_sty_010.jpg";
|
||||
this.subtype.add("Equipment");
|
||||
this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(3)));
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(LifelinkAbility.getInstance())));
|
||||
|
@ -59,4 +59,18 @@ public class BehemothSledge extends CardImpl {
|
|||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(2, 2)));
|
||||
}
|
||||
|
||||
protected BehemothSledge(BehemothSledge me) {
|
||||
super(me);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BehemothSledge copy() {
|
||||
return new BehemothSledge(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArt() {
|
||||
return "120963_typ_reg_sty_010.jpg";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -40,17 +40,30 @@ import mage.target.common.TargetCreaturePermanent;
|
|||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class BituminousBlast extends CardImpl {
|
||||
public class BituminousBlast extends CardImpl<BituminousBlast> {
|
||||
|
||||
public BituminousBlast(UUID ownerId) {
|
||||
super(ownerId, "Bituminous Blast", new CardType[]{CardType.INSTANT}, "{3}{B}{R}");
|
||||
this.expansionSetId = AlaraReborn.getInstance().getId();
|
||||
this.color.setBlack(true);
|
||||
this.color.setRed(true);
|
||||
this.art = "121045_typ_reg_sty_010.jpg";
|
||||
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
|
||||
this.getSpellAbility().addEffect(new DamageTargetEffect(4));
|
||||
this.addAbility(new CascadeAbility());
|
||||
}
|
||||
|
||||
public BituminousBlast(final BituminousBlast card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BituminousBlast copy() {
|
||||
return new BituminousBlast(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArt() {
|
||||
return "121045_typ_reg_sty_010.jpg";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ import mage.sets.AlaraReborn;
|
|||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class BloodbraidElf extends CardImpl {
|
||||
public class BloodbraidElf extends CardImpl<BloodbraidElf> {
|
||||
|
||||
public BloodbraidElf(UUID ownerId) {
|
||||
super(ownerId, "Bloodbraid Elf", new CardType[]{CardType.CREATURE}, "{2}{R}{G}");
|
||||
|
@ -49,10 +49,23 @@ public class BloodbraidElf extends CardImpl {
|
|||
this.color.setGreen(true);
|
||||
this.subtype.add("Elf");
|
||||
this.subtype.add("Berserker");
|
||||
this.art = "121042_typ_reg_sty_010.jpg";
|
||||
this.power = new MageInt(3);
|
||||
this.toughness = new MageInt(2);
|
||||
this.addAbility(HasteAbility.getInstance());
|
||||
this.addAbility(new CascadeAbility());
|
||||
}
|
||||
|
||||
public BloodbraidElf(final BloodbraidElf card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BloodbraidElf copy() {
|
||||
return new BloodbraidElf(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArt() {
|
||||
return "121042_typ_reg_sty_010.jpg";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ import mage.Constants.CardType;
|
|||
import mage.Constants.Outcome;
|
||||
import mage.Constants.TurnPhase;
|
||||
import mage.Constants.Zone;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.keyword.ExaltedAbility;
|
||||
|
@ -49,7 +50,7 @@ import mage.target.common.TargetCreaturePermanent;
|
|||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class FinestHour extends CardImpl {
|
||||
public class FinestHour extends CardImpl<FinestHour> {
|
||||
|
||||
public FinestHour(UUID ownerId) {
|
||||
super(ownerId, "Finest Hour", new CardType[]{CardType.ENCHANTMENT}, "{2}{G}{W}{U}");
|
||||
|
@ -57,26 +58,48 @@ public class FinestHour extends CardImpl {
|
|||
this.color.setWhite(true);
|
||||
this.color.setGreen(true);
|
||||
this.color.setBlue(true);
|
||||
this.art = "121018_typ_reg_sty_010.jpg";
|
||||
this.addAbility(new ExaltedAbility());
|
||||
this.addAbility(new FinestHourAbility());
|
||||
}
|
||||
|
||||
public FinestHour(final FinestHour card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FinestHour copy() {
|
||||
return new FinestHour(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getArt() {
|
||||
return "121018_typ_reg_sty_010.jpg";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class FinestHourAbility extends TriggeredAbilityImpl {
|
||||
class FinestHourAbility extends TriggeredAbilityImpl<FinestHourAbility> {
|
||||
|
||||
public FinestHourAbility() {
|
||||
super(Zone.BATTLEFIELD, new FinestHourEffect());
|
||||
}
|
||||
|
||||
public FinestHourAbility(final FinestHourAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FinestHourAbility copy() {
|
||||
return new FinestHourAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (checkIfClause(game) && game.getActivePlayerId().equals(this.controllerId)) {
|
||||
if (event.getType() == EventType.DECLARED_ATTACKERS) {
|
||||
if (game.getCombat().attacksAlone()) {
|
||||
this.addTarget(new TargetCreaturePermanent());
|
||||
this.targets.get(0).getTargets().add(game.getCombat().getAttackers().get(0));
|
||||
this.targets.get(0).addTarget(game.getCombat().getAttackers().get(0), this, game);
|
||||
trigger(game, event.getPlayerId());
|
||||
return true;
|
||||
}
|
||||
|
@ -97,18 +120,27 @@ class FinestHourAbility extends TriggeredAbilityImpl {
|
|||
|
||||
}
|
||||
|
||||
class FinestHourEffect extends OneShotEffect {
|
||||
class FinestHourEffect extends OneShotEffect<FinestHourEffect> {
|
||||
|
||||
public FinestHourEffect() {
|
||||
super(Outcome.Benefit);
|
||||
}
|
||||
|
||||
public FinestHourEffect(final FinestHourEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game) {
|
||||
Permanent permanent = game.getPermanent(this.source.getFirstTarget());
|
||||
public FinestHourEffect copy() {
|
||||
return new FinestHourEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = game.getPermanent(source.getFirstTarget());
|
||||
if (permanent != null) {
|
||||
permanent.setTapped(false);
|
||||
game.getState().getTurnMods().add(new TurnMod(this.source.getControllerId(), TurnPhase.COMBAT, null, false));
|
||||
game.getState().getTurnMods().add(new TurnMod(source.getControllerId(), TurnPhase.COMBAT, null, false));
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue