1
0
Fork 0
mirror of https://github.com/correl/mage.git synced 2025-04-04 01:06:04 -09:00

Merge pull request from magefree/master

merge
This commit is contained in:
Sarah Souders 2019-12-26 15:33:52 -05:00 committed by GitHub
commit df4524f43c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
589 changed files with 9538 additions and 3884 deletions
Mage.Client
Mage.Common
Mage.Plugins
Mage.Counter.Plugin
pom.xml
Mage.Server.Console
Mage.Server.Plugins
Mage.Deck.Constructed
Mage.Deck.Limited
Mage.Game.BrawlDuel
Mage.Game.BrawlFreeForAll
Mage.Game.CanadianHighlanderDuel
Mage.Game.CommanderDuel
Mage.Game.CommanderFreeForAll
Mage.Game.FreeForAll
Mage.Game.FreeformCommanderDuel
Mage.Game.FreeformCommanderFreeForAll
Mage.Game.MomirDuel
Mage.Game.MomirGame
Mage.Game.OathbreakerDuel
Mage.Game.OathbreakerFreeForAll
Mage.Game.PennyDreadfulCommanderFreeForAll
Mage.Game.TinyLeadersDuel
Mage.Game.TwoPlayerDuel
Mage.Player.AI.DraftBot
Mage.Player.AI.MA
Mage.Player.AI
pom.xml
src/main/java/mage/player/ai
Mage.Player.AIMCTS
Mage.Player.AIMinimax
Mage.Player.Human
pom.xml
src/mage/player/human
Mage.Tournament.BoosterDraft
pom.xml
src/mage/tournament/cubes
Mage.Tournament.Constructed
Mage.Tournament.Sealed
pom.xml
Mage.Server
config
pom.xml
release/config
src/main/java/mage/server/util
Mage.Sets

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-client</artifactId>

View file

@ -517,7 +517,7 @@ public class Card extends MagePermanent implements MouseMotionListener, MouseLis
}
@Override
public void setSelected(boolean selected) {
public void setSelected(boolean isSelected) {
}
@Override

View file

@ -1,5 +1,10 @@
package mage.client.dialog;
import java.awt.*;
import java.io.File;
import java.util.*;
import java.util.stream.Collectors;
import javax.swing.*;
import mage.cards.decks.Deck;
import mage.cards.decks.DeckFileFilter;
import mage.cards.decks.importer.DeckImporter;
@ -26,13 +31,6 @@ import mage.view.TableView;
import mage.view.TournamentTypeView;
import org.apache.log4j.Logger;
import javax.swing.*;
import java.awt.*;
import java.io.File;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author BetaSteward_at_googlemail.com, JayDi85
*/
@ -41,13 +39,13 @@ public class NewTournamentDialog extends MageDialog {
private static final Logger logger = Logger.getLogger(NewTournamentDialog.class);
private TableView table;
private UUID playerId;
// private UUID playerId;
private UUID roomId;
private String lastSessionId;
private RandomPacksSelectorDialog randomPackSelector;
private JTextArea txtRandomPacks;
private final List<TournamentPlayerPanel> players = new ArrayList<>();
private final List<JPanel> packPanels = new ArrayList<>();
private final java.util.List<TournamentPlayerPanel> players = new ArrayList<>();
private final java.util.List<JPanel> packPanels = new ArrayList<>();
private static final int CONSTRUCTION_TIME_MIN = 6;
private static final int CONSTRUCTION_TIME_MAX = 30;
private boolean isRandom = false;
@ -709,12 +707,12 @@ public class NewTournamentDialog extends MageDialog {
private void btnCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCancelActionPerformed
this.table = null;
this.playerId = null;
// this.playerId = null;
this.hideDialog();
}//GEN-LAST:event_btnCancelActionPerformed
private void updateNumSeats() {
int numPlayers = (Integer) this.spnNumPlayers.getValue();
// int numPlayers = (Integer) this.spnNumPlayers.getValue();
int numSeats = (Integer) this.spnNumSeats.getValue();
if (numSeats > 2) {
@ -966,11 +964,6 @@ public class NewTournamentDialog extends MageDialog {
}
randomPackSelector.setSelectedPacks(packList);
txtRandomPacks.setText(packNames);
// workaround to apply field's auto-size
this.pack();
this.revalidate();
this.repaint();
}
private void createRandomPacks() {
@ -993,6 +986,7 @@ public class NewTournamentDialog extends MageDialog {
btnSelectRandomPacks.setToolTipText(RandomPacksSelectorDialog.randomDraftDescription);
btnSelectRandomPacks.addActionListener(evt -> showRandomPackSelectorDialog());
pnlRandomPacks.add(btnSelectRandomPacks);
this.pnlRandomPacks.setMinimumSize(new Dimension(784, 150));
}
txtRandomPacks.setText(txtRandomPacks.getText()); // workaround to apply field's auto-size
this.pack();
@ -1154,7 +1148,7 @@ public class NewTournamentDialog extends MageDialog {
int packNumber = 0;
for (String pack : packsArray) {
packNumber++;
if (this.packPanels.size() >= packNumber - 1) {
if (!packPanels.isEmpty() && this.packPanels.size() >= packNumber - 1) {
JPanel panel = packPanels.get(packNumber - 1);
JComboBox comboBox = findComboInComponent(panel);
@ -1466,4 +1460,4 @@ public class NewTournamentDialog extends MageDialog {
private org.jdesktop.beansbinding.BindingGroup bindingGroup;
// End of variables declaration//GEN-END:variables
}
}

View file

@ -36,12 +36,17 @@
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="pnlSelect" min="-2" pref="241" max="-2" attributes="0"/>
<EmptySpace pref="300" max="32767" attributes="0"/>
<Component id="pnlApply" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Component id="pnlPacks" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="pnlSelect" min="-2" pref="196" max="-2" attributes="0"/>
<EmptySpace pref="402" max="32767" attributes="0"/>
<Component id="pnlApply" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="btnApply" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="pnlPacks" max="32767" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
@ -49,11 +54,13 @@
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="pnlPacks" min="-2" pref="372" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="pnlPacks" min="-2" pref="362" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="pnlApply" min="-2" pref="32" max="-2" attributes="0"/>
<Component id="pnlSelect" min="-2" pref="32" max="-2" attributes="0"/>
<Component id="btnApply" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
</Group>
@ -64,8 +71,8 @@
<Container class="java.awt.Panel" name="pnlPacks">
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridLayout">
<Property name="columns" type="int" value="12"/>
<Property name="rows" type="int" value="11"/>
<Property name="columns" type="int" value="13"/>
<Property name="rows" type="int" value="12"/>
</Layout>
</Container>
<Container class="javax.swing.JPanel" name="pnlSelect">
@ -94,17 +101,15 @@
<Container class="javax.swing.JPanel" name="pnlApply">
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout"/>
<SubComponents>
<Component class="javax.swing.JButton" name="btnApply">
<Properties>
<Property name="text" type="java.lang.String" value="Apply"/>
<Property name="toolTipText" type="java.lang.String" value="At least two packs must be selected"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnApplyActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JButton" name="btnApply">
<Properties>
<Property name="text" type="java.lang.String" value="Apply"/>
<Property name="toolTipText" type="java.lang.String" value="At least two packs must be selected"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnApplyActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Form>

View file

@ -58,25 +58,25 @@ public class RandomPacksSelectorDialog extends javax.swing.JDialog {
this.setModal(true);
}
public void setSelectedPacks(ArrayList<String> packs){
if (!boxesCreated){
createCheckboxes();
}
for (Component pack : pnlPacks.getComponents()) {
JCheckBox thePack = (JCheckBox) pack;
if (packs.contains(thePack.getText())) {
thePack.setSelected(true);
} else{
thePack.setSelected(false);
}
}
}
public void setSelectedPacks(ArrayList<String> packs) {
if (!boxesCreated) {
createCheckboxes();
}
for (Component pack : pnlPacks.getComponents()) {
JCheckBox thePack = (JCheckBox) pack;
if (packs.contains(thePack.getText())) {
thePack.setSelected(true);
} else {
thePack.setSelected(false);
}
}
}
public ArrayList<String> getSelectedPacks() {
ArrayList<String> returnVal = new ArrayList<>();
for (Component pack: pnlPacks.getComponents()){
for (Component pack : pnlPacks.getComponents()) {
JCheckBox thePack = (JCheckBox) pack;
if (thePack.isSelected()){
if (thePack.isSelected()) {
returnVal.add(thePack.getText());
}
}
@ -100,7 +100,6 @@ public class RandomPacksSelectorDialog extends javax.swing.JDialog {
}
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
@ -118,7 +117,7 @@ public class RandomPacksSelectorDialog extends javax.swing.JDialog {
btnApply = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
setTitle(title);
setTitle("Random Booster Draft Packs Selector");
setModal(true);
setModalExclusionType(java.awt.Dialog.ModalExclusionType.APPLICATION_EXCLUDE);
setPreferredSize(new java.awt.Dimension(600, 450));
@ -129,50 +128,63 @@ public class RandomPacksSelectorDialog extends javax.swing.JDialog {
}
});
pnlPacks.setLayout(new java.awt.GridLayout(11, 12));
pnlPacks.setLayout(new java.awt.GridLayout(12, 13));
pnlSelect.setLayout(new javax.swing.BoxLayout(pnlSelect, javax.swing.BoxLayout.LINE_AXIS));
btnNone.setText("Select none");
btnNone.setActionCommand("none");
btnNone.addActionListener(evt -> btnNoneActionPerformed(evt));
btnNone.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnNoneActionPerformed(evt);
}
});
pnlSelect.add(btnNone);
btnAll.setText("Select all");
btnAll.addActionListener(evt -> btnAllActionPerformed(evt));
btnAll.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnAllActionPerformed(evt);
}
});
pnlSelect.add(btnAll);
pnlApply.setLayout(new javax.swing.BoxLayout(pnlApply, javax.swing.BoxLayout.LINE_AXIS));
btnApply.setText("Apply");
if (isRandomDraft) {
btnApply.setToolTipText("At least 2 packs must be selected");
} else if (isRichManDraft) {
btnApply.setToolTipText("At least 1 pack must be selected");
}
btnApply.addActionListener(evt -> btnApplyActionPerformed(evt));
pnlApply.add(btnApply);
btnApply.setToolTipText("At least two packs must be selected");
btnApply.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
btnApplyActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(pnlSelect, javax.swing.GroupLayout.PREFERRED_SIZE, 241, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 300, Short.MAX_VALUE)
.addComponent(pnlApply, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createSequentialGroup()
.addComponent(pnlPacks, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(pnlSelect, javax.swing.GroupLayout.PREFERRED_SIZE, 196, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 402, Short.MAX_VALUE)
.addComponent(pnlApply, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(btnApply))
.addComponent(pnlPacks, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(pnlPacks, javax.swing.GroupLayout.PREFERRED_SIZE, 372, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap()
.addComponent(pnlPacks, javax.swing.GroupLayout.PREFERRED_SIZE, 362, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(pnlApply, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(pnlSelect, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(pnlSelect, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(btnApply))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
@ -220,4 +232,4 @@ public class RandomPacksSelectorDialog extends javax.swing.JDialog {
private java.awt.Panel pnlPacks;
private javax.swing.JPanel pnlSelect;
// End of variables declaration//GEN-END:variables
}
}

View file

@ -1205,11 +1205,11 @@ public final class GamePanel extends javax.swing.JPanel {
needSelectable = new HashSet<>();
}
Set<UUID> needPlayable;
Map<UUID, Integer> needPlayable;
if (showPlayable && gameView.getCanPlayObjects() != null) {
needPlayable = gameView.getCanPlayObjects();
} else {
needPlayable = new HashSet<>();
needPlayable = new HashMap<>();
}
if (needChoosen.isEmpty() && needSelectable.isEmpty() && needPlayable.isEmpty()) {
@ -1225,8 +1225,9 @@ public final class GamePanel extends javax.swing.JPanel {
if (needChoosen.contains(card.getId())) {
card.setSelected(true);
}
if (needPlayable.contains(card.getId())) {
if (needPlayable.containsKey(card.getId())) {
card.setPlayable(true);
card.setPlayableAmount(needPlayable.get(card.getId()));
}
}
}
@ -1254,8 +1255,9 @@ public final class GamePanel extends javax.swing.JPanel {
if (needChoosen.contains(perm.getKey())) {
perm.getValue().setSelected(true);
}
if (needPlayable.contains(perm.getKey())) {
if (needPlayable.containsKey(perm.getKey())) {
perm.getValue().setPlayable(true);
perm.getValue().setPlayableAmount(needPlayable.get(perm.getKey()));
}
}
}
@ -1271,8 +1273,9 @@ public final class GamePanel extends javax.swing.JPanel {
if (needChoosen.contains(card.getKey())) {
card.getValue().setSelected(true);
}
if (needPlayable.contains(card.getKey())) {
if (needPlayable.containsKey(card.getKey())) {
card.getValue().setPlayable(true);
card.getValue().setPlayableAmount(needPlayable.get(card.getKey()));
}
}
}
@ -1288,8 +1291,9 @@ public final class GamePanel extends javax.swing.JPanel {
if (needChoosen.contains(card.getKey())) {
card.getValue().setSelected(true);
}
if (needPlayable.contains(card.getKey())) {
if (needPlayable.containsKey(card.getKey())) {
card.getValue().setPlayable(true);
card.getValue().setPlayableAmount(needPlayable.get(card.getKey()));
}
}
}
@ -1305,8 +1309,9 @@ public final class GamePanel extends javax.swing.JPanel {
if (needChoosen.contains(com.getId())) {
com.setSelected(true);
}
if (needPlayable.contains(com.getId())) {
if (needPlayable.containsKey(com.getId())) {
com.setPlayable(true);
com.setPlayableAmount(needPlayable.get(com.getId()));
}
}
}
@ -1321,8 +1326,19 @@ public final class GamePanel extends javax.swing.JPanel {
if (needChoosen.contains(card.getKey())) {
card.getValue().setSelected(true);
}
if (needPlayable.contains(card.getKey())) {
if (needPlayable.containsKey(card.getKey())) {
card.getValue().setPlayable(true);
card.getValue().setPlayableAmount(needPlayable.get(card.getKey()));
}
}
}
// looked at
for (LookedAtView look : gameView.getLookedAt()) {
for (Map.Entry<UUID, SimpleCardView> card : look.getCards().entrySet()) {
if (needPlayable.containsKey(card.getKey())) {
card.getValue().setPlayable(true);
card.getValue().setPlayableAmount(needPlayable.get(card.getKey()));
}
}
}

View file

@ -142,7 +142,7 @@ public class PlayerPanelExt extends javax.swing.JPanel {
// can play
if (gameView != null && gameView.getCanPlayObjects() != null && !gameView.getCanPlayObjects().isEmpty()) {
for (CardView card : cards) {
if (gameView.getCanPlayObjects().contains(card.getId())) {
if (gameView.getCanPlayObjects().containsKey(card.getId())) {
return true;
}
}
@ -239,7 +239,7 @@ public class PlayerPanelExt extends javax.swing.JPanel {
Color commandColor = Color.BLACK;
for (CommandObjectView com : player.getCommandObjectList()) {
if (game != null && game.getCanPlayObjects() != null && game.getCanPlayObjects().contains(com.getId())) {
if (game != null && game.getCanPlayObjects() != null && game.getCanPlayObjects().containsKey(com.getId())) {
commandColor = activeValueColor;
break;
}
@ -269,7 +269,7 @@ public class PlayerPanelExt extends javax.swing.JPanel {
if (!MageFrame.isLite()) {
int id = player.getUserData().getAvatarId();
if (!(id >= 1000) && (id <= 0 || (id <= MIN_AVATAR_ID && id > MAX_AVATAR_ID))) {
if (!(id > 1000) && (id != 64) && (id < MIN_AVATAR_ID || id > MAX_AVATAR_ID)) {
id = DEFAULT_AVATAR_ID;
}
if (id != avatarId) {

View file

@ -20,7 +20,7 @@ public final class CardsViewUtil {
CardInfo cardInfo = CardRepository.instance.findCard(simple.getExpansionSetCode(), simple.getCardNumber());
Card card = cardInfo != null ? cardInfo.getMockCard() : null;
if (card != null) {
cards.put(simple.getId(), new CardView(card, simple.getId()));
cards.put(simple.getId(), new CardView(card, simple));
}
}
@ -39,7 +39,7 @@ public final class CardsViewUtil {
loadedCards.put(key, card);
}
if (card != null) {
cards.put(simple.getId(), new CardView(card, simple.getId()));
cards.put(simple.getId(), new CardView(card, simple));
}
}

View file

@ -28,10 +28,10 @@ public final class ConstructedFormats {
public static final Standard STANDARD_CARDS = new Standard();
// Attention -Month is 0 Based so Feb = 1 for example. //
private static final Date extendedDate = new GregorianCalendar(2009, 7, 20).getTime();
private static final Date frontierDate = new GregorianCalendar(2014, 6, 17).getTime();
private static final Date pioneerDate = new GregorianCalendar(2012, 10, 5).getTime();
private static final Date modernDate = new GregorianCalendar(2003, 6, 20).getTime();
private static final Date extendedDate = new GregorianCalendar(2009, Calendar.AUGUST, 20).getTime();
private static final Date frontierDate = new GregorianCalendar(2014, Calendar.JULY, 17).getTime();
private static final Date pioneerDate = new GregorianCalendar(2012, Calendar.NOVEMBER, 5).getTime();
private static final Date modernDate = new GregorianCalendar(2003, Calendar.JULY, 20).getTime();
// for all sets just return empty list
private static final List<String> all = new ArrayList<>();

View file

@ -243,6 +243,7 @@ public class ScryfallImageSupportCards {
add("C19");
add("ELD");
add("CELD");
add("THB");
//
add("EURO");
add("GPX");

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-common</artifactId>

View file

@ -11,9 +11,9 @@ public class MageVersion implements Serializable, Comparable<MageVersion> {
public static final int MAGE_VERSION_MAJOR = 1;
public static final int MAGE_VERSION_MINOR = 4;
public static final int MAGE_VERSION_PATCH = 40;
public static final int MAGE_VERSION_PATCH = 41;
public static final String MAGE_EDITION_INFO = ""; // set "-beta" for 1.4.32-betaV0
public static final String MAGE_VERSION_MINOR_PATCH = "V0"; // default
public static final String MAGE_VERSION_MINOR_PATCH = "V1"; // default
// strict mode
private static final boolean MAGE_VERSION_MINOR_PATCH_MUST_BE_SAME = false; // set true on uncompatible github changes, set false after new major release (after MAGE_VERSION_PATCH changes)

View file

@ -32,7 +32,7 @@ import java.util.stream.Collectors;
/**
* @author BetaSteward_at_googlemail.com
*/
public class CardView extends SimpleCardView implements SelectableObjectView {
public class CardView extends SimpleCardView {
private static final long serialVersionUID = 1L;
@ -104,9 +104,6 @@ public class CardView extends SimpleCardView implements SelectableObjectView {
protected boolean rotate;
protected boolean hideInfo; // controls if the tooltip window is shown (eg. controlled face down morph card)
protected boolean isPlayable;
protected boolean isChoosable;
protected boolean selected;
protected boolean canAttack;
protected boolean canBlock;
protected boolean inViewerOnly;
@ -117,9 +114,13 @@ public class CardView extends SimpleCardView implements SelectableObjectView {
this(card, null, false);
}
public CardView(Card card, UUID cardId) {
public CardView(Card card, SimpleCardView simpleCardView) {
this(card, null, false);
this.id = cardId;
this.id = simpleCardView.getId();
this.isPlayable = simpleCardView.isPlayable;
this.isChoosable = simpleCardView.isChoosable;
this.isSelected = simpleCardView.isSelected;
}
public CardView(Card card, Game game, UUID cardId) {
@ -128,10 +129,12 @@ public class CardView extends SimpleCardView implements SelectableObjectView {
}
public CardView(CardView cardView) {
super(cardView.id, cardView.expansionSetCode, cardView.cardNumber, cardView.usesVariousArt, cardView.tokenSetCode, cardView.gameObject, cardView.tokenDescriptor);
super(cardView);
this.originalCard = cardView.originalCard;
// generetate new ID
this.id = UUID.randomUUID();
this.parentId = cardView.parentId;
this.name = cardView.name;
this.displayName = cardView.displayName;
@ -198,9 +201,6 @@ public class CardView extends SimpleCardView implements SelectableObjectView {
this.rotate = cardView.rotate;
this.hideInfo = cardView.hideInfo;
this.isPlayable = cardView.isPlayable;
this.isChoosable = cardView.isChoosable;
this.selected = cardView.selected;
this.canAttack = cardView.canAttack;
this.canBlock = cardView.canBlock;
this.inViewerOnly = cardView.inViewerOnly;
@ -468,8 +468,6 @@ public class CardView extends SimpleCardView implements SelectableObjectView {
// Get starting loyalty
this.startingLoyalty = "" + card.getStartingLoyalty();
}
public CardView(MageObject object) {
@ -964,30 +962,6 @@ public class CardView extends SimpleCardView implements SelectableObjectView {
return hideInfo;
}
public boolean isPlayable() {
return isPlayable;
}
public void setPlayable(boolean isPlayable) {
this.isPlayable = isPlayable;
}
public boolean isChoosable() {
return isChoosable;
}
public void setChoosable(boolean isChoosable) {
this.isChoosable = isChoosable;
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
public boolean isCanAttack() {
return canAttack;
}

View file

@ -17,6 +17,7 @@ public class EmblemView implements CommandObjectView, Serializable {
protected String expansionSetCode;
protected List<String> rules;
protected boolean isPlayable = false;
protected int playableAmount = 0;
public EmblemView(Emblem emblem, Card sourceCard) {
this.id = emblem.getId();
@ -67,6 +68,16 @@ public class EmblemView implements CommandObjectView, Serializable {
this.isPlayable = isPlayable;
}
@Override
public void setPlayableAmount(int playableAmount) {
this.playableAmount = playableAmount;
}
@Override
public int getPlayableAmount() {
return playableAmount;
}
@Override
public boolean isChoosable() {
// unsupported
@ -85,7 +96,7 @@ public class EmblemView implements CommandObjectView, Serializable {
}
@Override
public void setSelected(boolean selected) {
public void setSelected(boolean isSelected) {
// unsupported
}
}

View file

@ -26,7 +26,10 @@ import mage.watchers.common.CastSpellLastTurnWatcher;
import org.apache.log4j.Logger;
import java.io.Serializable;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
* @author BetaSteward_at_googlemail.com
@ -39,7 +42,7 @@ public class GameView implements Serializable {
private final int priorityTime;
private final List<PlayerView> players = new ArrayList<>();
private CardsView hand;
private Set<UUID> canPlayObjects;
private Map<UUID, Integer> canPlayObjects;
private Map<String, SimpleCardsView> opponentHands;
private Map<String, SimpleCardsView> watchedHands;
private final CardsView stack = new CardsView();
@ -300,11 +303,11 @@ public class GameView implements Serializable {
return isPlayer;
}
public Set<UUID> getCanPlayObjects() {
public Map<UUID, Integer> getCanPlayObjects() {
return canPlayObjects;
}
public void setCanPlayObjects(Set<UUID> canPlayObjects) {
public void setCanPlayObjects(Map<UUID, Integer> canPlayObjects) {
this.canPlayObjects = canPlayObjects;
}

View file

@ -18,6 +18,7 @@ public class PlaneView implements CommandObjectView, Serializable {
protected List<String> rules;
protected boolean isPlayable = false;
protected int playableAmount = 0;
public PlaneView(Plane plane, Card sourceCard) {
this.id = plane.getId();
@ -67,6 +68,16 @@ public class PlaneView implements CommandObjectView, Serializable {
this.isPlayable = isPlayable;
}
@Override
public void setPlayableAmount(int playableAmount) {
this.playableAmount = playableAmount;
}
@Override
public int getPlayableAmount() {
return playableAmount;
}
@Override
public boolean isChoosable() {
// unsupported
@ -85,7 +96,7 @@ public class PlaneView implements CommandObjectView, Serializable {
}
@Override
public void setSelected(boolean selected) {
public void setSelected(boolean isSelected) {
// unsupported
}
}

View file

@ -9,11 +9,15 @@ public interface SelectableObjectView {
void setPlayable(boolean isPlayable);
void setPlayableAmount(int playableAmount);
int getPlayableAmount();
boolean isChoosable();
void setChoosable(boolean isChoosable);
boolean isSelected();
void setSelected(boolean selected);
void setSelected(boolean isSelected);
}

View file

@ -1,5 +1,3 @@
package mage.view;
import com.google.gson.annotations.Expose;
@ -8,10 +6,9 @@ import java.io.Serializable;
import java.util.UUID;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public class SimpleCardView implements Serializable {
public class SimpleCardView implements Serializable, SelectableObjectView {
@Expose
protected UUID id;
protected String expansionSetCode;
@ -21,9 +18,30 @@ public class SimpleCardView implements Serializable {
protected boolean usesVariousArt;
protected boolean gameObject;
protected boolean isPlayable;
protected boolean isChoosable;
protected boolean isSelected;
protected int playableAmount; // playable abilities count on object
public SimpleCardView(final SimpleCardView view) {
this.id = view.id;
this.expansionSetCode = view.expansionSetCode;
this.tokenSetCode = view.tokenSetCode;
this.tokenDescriptor = view.tokenDescriptor;
this.cardNumber = view.cardNumber;
this.usesVariousArt = view.usesVariousArt;
this.gameObject = view.gameObject;
this.isPlayable = view.isPlayable;
this.isChoosable = view.isChoosable;
this.isSelected = view.isSelected;
this.playableAmount = view.playableAmount;
}
public SimpleCardView(UUID id, String expansionSetCode, String cardNumber, boolean usesVariousArt, String tokenSetCode, String tokenDescriptor) {
this(id, expansionSetCode, cardNumber, usesVariousArt, tokenSetCode, false, tokenDescriptor);
}
public SimpleCardView(UUID id, String expansionSetCode, String cardNumber, boolean usesVariousArt, String tokenSetCode, boolean isGameObject, String tokenDescriptor) {
this.id = id;
this.expansionSetCode = expansionSetCode;
@ -53,12 +71,52 @@ public class SimpleCardView implements Serializable {
public String getTokenSetCode() {
return tokenSetCode;
}
public String getTokenDescriptor() {
return tokenDescriptor;
}
public boolean isGameObject() {
return gameObject;
}
}
@Override
public boolean isPlayable() {
return isPlayable;
}
@Override
public void setPlayable(boolean isPlayable) {
this.isPlayable = isPlayable;
}
@Override
public void setPlayableAmount(int playableAmount) {
this.playableAmount = playableAmount;
}
@Override
public int getPlayableAmount() {
return playableAmount;
}
@Override
public boolean isChoosable() {
return isChoosable;
}
@Override
public void setChoosable(boolean isChoosable) {
this.isChoosable = isChoosable;
}
@Override
public boolean isSelected() {
return isSelected;
}
@Override
public void setSelected(boolean isSelected) {
this.isSelected = isSelected;
}
}

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-plugins</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-counter-plugin</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-plugins</artifactId>

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage.server.console</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-deck-constructed</artifactId>

View file

@ -12,7 +12,7 @@ public class AmonkhetBlock extends Constructed {
public AmonkhetBlock() {
super("Constructed - Amonkhet Block");
setCodes.add("AKH");
setCodes.add("HOU");
setCodes.add(mage.sets.Amonkhet.getInstance().getCode());
setCodes.add(mage.sets.HourOfDevastation.getInstance().getCode());
}
}

View file

@ -12,7 +12,7 @@ public class BattleForZendikarBlock extends Constructed {
public BattleForZendikarBlock() {
super("Constructed - Battle for Zendikar Block");
setCodes.add("BFZ");
setCodes.add("OGW");
setCodes.add(mage.sets.BattleForZendikar.getInstance().getCode());
setCodes.add(mage.sets.OathOfTheGatewatch.getInstance().getCode());
}
}

View file

@ -4,6 +4,7 @@ import mage.cards.ExpansionSet;
import mage.cards.Sets;
import mage.cards.decks.Constructed;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
@ -15,7 +16,7 @@ public class Frontier extends Constructed {
public Frontier() {
super("Constructed - Frontier");
Date cutoff = new GregorianCalendar(2014, 6, 18).getTime(); // M15 release date
Date cutoff = new GregorianCalendar(2014, Calendar.JULY, 18).getTime(); // M15 release date
for (ExpansionSet set : Sets.getInstance().values()) {
if (set.getSetType().isStandardLegal() && (set.getReleaseDate().after(cutoff) || set.getReleaseDate().equals(cutoff))) {
setCodes.add(set.getCode());

View file

@ -12,9 +12,9 @@ public class InnistradBlock extends Constructed {
public InnistradBlock() {
super("Constructed - Innistrad Block");
setCodes.add("ISD");
setCodes.add("DKA");
setCodes.add("AVR");
setCodes.add(mage.sets.Innistrad.getInstance().getCode());
setCodes.add(mage.sets.DarkAscension.getInstance().getCode());
setCodes.add(mage.sets.AvacynRestored.getInstance().getCode());
}
}

View file

@ -11,7 +11,7 @@ public class IxalanBlock extends Constructed {
public IxalanBlock() {
super("Constructed - Ixalan Block");
setCodes.add("XLN");
setCodes.add("RIX");
setCodes.add(mage.sets.Ixalan.getInstance().getCode());
setCodes.add(mage.sets.RivalsOfIxalan.getInstance().getCode());
}
}

View file

@ -12,7 +12,7 @@ public class KaladeshBlock extends Constructed {
public KaladeshBlock() {
super("Constructed - Kaladesh Block");
setCodes.add("KLD");
setCodes.add("AER");
setCodes.add(mage.sets.Kaladesh.getInstance().getCode());
setCodes.add(mage.sets.AetherRevolt.getInstance().getCode());
}
}

View file

@ -12,9 +12,9 @@ public class KamigawaBlock extends Constructed {
public KamigawaBlock() {
super("Constructed - Kamigawa Block");
setCodes.add("CHK");
setCodes.add("BOK");
setCodes.add("SOK");
setCodes.add(mage.sets.ChampionsOfKamigawa.getInstance().getCode());
setCodes.add(mage.sets.BetrayersOfKamigawa.getInstance().getCode());
setCodes.add(mage.sets.SaviorsOfKamigawa.getInstance().getCode());
}
}

View file

@ -12,9 +12,9 @@ public class KhansOfTarkirBlock extends Constructed {
public KhansOfTarkirBlock() {
super("Constructed - Khans of Tarkir Block");
setCodes.add("KTK");
setCodes.add("FRF");
setCodes.add("DTK");
setCodes.add(mage.sets.KhansOfTarkir.getInstance().getCode());
setCodes.add(mage.sets.FateReforged.getInstance().getCode());
setCodes.add(mage.sets.DragonsOfTarkir.getInstance().getCode());
}
}

View file

@ -11,7 +11,7 @@ public class LorwynBlock extends Constructed {
public LorwynBlock() {
super("Constructed - Lorwyn Block");
setCodes.add("LRW");
setCodes.add("MOR");
setCodes.add(mage.sets.Lorwyn.getInstance().getCode());
setCodes.add(mage.sets.Morningtide.getInstance().getCode());
}
}

View file

@ -4,6 +4,7 @@ import mage.cards.ExpansionSet;
import mage.cards.Sets;
import mage.cards.decks.Constructed;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
@ -15,7 +16,7 @@ public class Modern extends Constructed {
public Modern() {
super("Constructed - Modern");
Date cutoff = new GregorianCalendar(2003, 6, 28).getTime(); // Eight edition release date
Date cutoff = new GregorianCalendar(2003, Calendar.JULY, 28).getTime(); // Eight edition release date
for (ExpansionSet set : Sets.getInstance().values()) {
if (set.getSetType().isModernLegal() && (set.getReleaseDate().after(cutoff) || set.getReleaseDate().equals(cutoff))) {
setCodes.add(set.getCode());

View file

@ -4,6 +4,7 @@ import mage.cards.ExpansionSet;
import mage.cards.Sets;
import mage.cards.decks.Constructed;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
@ -15,7 +16,7 @@ public class ModernNoBannedList extends Constructed {
public ModernNoBannedList() {
super("Constructed - Modern - No Banned List");
Date cutoff = new GregorianCalendar(2003, 6, 28).getTime(); // Eight edition release date
Date cutoff = new GregorianCalendar(2003, Calendar.JULY, 28).getTime(); // Eight edition release date
for (ExpansionSet set : Sets.getInstance().values()) {
if (set.getSetType().isModernLegal() && (set.getReleaseDate().after(cutoff) || set.getReleaseDate().equals(cutoff))) {
setCodes.add(set.getCode());

View file

@ -4,6 +4,7 @@ import mage.cards.ExpansionSet;
import mage.cards.Sets;
import mage.cards.decks.Constructed;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
@ -15,7 +16,7 @@ public class Pioneer extends Constructed {
public Pioneer() {
super("Constructed - Pioneer");
Date cutoff = new GregorianCalendar(2012, 10, 5).getTime(); // RTR release date
Date cutoff = new GregorianCalendar(2012, Calendar.OCTOBER, 5).getTime(); // RTR release date
for (ExpansionSet set : Sets.getInstance().values()) {
if (set.getSetType().isStandardLegal() && (set.getReleaseDate().after(cutoff) || set.getReleaseDate().equals(cutoff))) {
setCodes.add(set.getCode());
@ -30,7 +31,9 @@ public class Pioneer extends Constructed {
banned.add("Felidar Guardian");
banned.add("Field of the Dead");
banned.add("Leyline of Abundance");
banned.add("Nexus of Fate");
banned.add("Oath of Nissa");
banned.add("Oko, Thief of Crowns");
banned.add("Once Upon a Time");
banned.add("Smuggler's Copter");
banned.add("Veil of Summer");

View file

@ -12,9 +12,9 @@ public class ReturnToRavnicaBlock extends Constructed {
public ReturnToRavnicaBlock() {
super("Constructed - Return to Ravnica Block");
setCodes.add("RTR");
setCodes.add("GTC");
setCodes.add("DGM");
setCodes.add(mage.sets.ReturnToRavnica.getInstance().getCode());
setCodes.add(mage.sets.Gatecrash.getInstance().getCode());
setCodes.add(mage.sets.DragonsMaze.getInstance().getCode());
}
}

View file

@ -12,9 +12,9 @@ public class ScarsOfMirrodinBlock extends Constructed {
public ScarsOfMirrodinBlock() {
super("Constructed - Scars of Mirrodin Block");
setCodes.add("SOM");
setCodes.add("MBS");
setCodes.add("NPH");
setCodes.add(mage.sets.ScarsOfMirrodin.getInstance().getCode());
setCodes.add(mage.sets.MirrodinBesieged.getInstance().getCode());
setCodes.add(mage.sets.NewPhyrexia.getInstance().getCode());
}
}

View file

@ -12,8 +12,8 @@ public class ShadowmoorBlock extends Constructed {
public ShadowmoorBlock() {
super("Constructed - Shadowmoor Block");
setCodes.add("SHM");
setCodes.add("EVE");
setCodes.add(mage.sets.Shadowmoor.getInstance().getCode());
setCodes.add(mage.sets.Eventide.getInstance().getCode());
}
}

View file

@ -12,7 +12,7 @@ public class ShadowsOverInnistradBlock extends Constructed {
public ShadowsOverInnistradBlock() {
super("Constructed - Shadows over Innistrad Block");
setCodes.add("SOI");
setCodes.add("EDM");
setCodes.add(mage.sets.ShadowsOverInnistrad.getInstance().getCode());
setCodes.add(mage.sets.EldritchMoon.getInstance().getCode());
}
}

View file

@ -12,9 +12,9 @@ public class ShardsOfAlaraBlock extends Constructed {
public ShardsOfAlaraBlock() {
super("Constructed - Shards of Alara Block");
setCodes.add("ALA");
setCodes.add("CON");
setCodes.add("ARB");
setCodes.add(mage.sets.ShardsOfAlara.getInstance().getCode());
setCodes.add(mage.sets.Conflux.getInstance().getCode());
setCodes.add(mage.sets.AlaraReborn.getInstance().getCode());
}
}

View file

@ -15,7 +15,7 @@ public class StarWarsBlock extends Constructed {
public StarWarsBlock() {
super("Constructed Custom - Star Wars Block");
setCodes.add("SWS");
setCodes.add(mage.sets.StarWars.getInstance().getCode());
}
}

View file

@ -26,7 +26,7 @@ public class SuperType2 extends Constructed {
* Kamigawa/Ravnica standard, where rotation stabilized.
* Data taken from http://thattournament.website/historic-tournament.php
*/
protected static final String[][] standards = {
private static final String[][] standards = {
// 11th Standard
{"7ED", "INV", "APC", "PLS", "ODY", "TOR", "JUD"},
// 12th Standard
@ -72,7 +72,7 @@ public class SuperType2 extends Constructed {
* regular validation function to test validity.
*
* @param deck - the deck to validate.
* @return
* @return boolean if valid deck
*/
@Override
public boolean validate(Deck deck) {

View file

@ -12,9 +12,9 @@ public class TherosBlock extends Constructed {
public TherosBlock() {
super("Constructed - Theros Block");
setCodes.add("THS");
setCodes.add("BNG");
setCodes.add("JOU");
setCodes.add(mage.sets.Theros.getInstance().getCode());
setCodes.add(mage.sets.BornOfTheGods.getInstance().getCode());
setCodes.add(mage.sets.JourneyIntoNyx.getInstance().getCode());
}
}

View file

@ -76,6 +76,10 @@ public class TinyLeaders extends Constructed {
banned.add("Wheel of Fortune");
banned.add("Yawgmoth's Will");
// TODO: Karn Liberated can't be used in TinyLeaders game (wrong commanders init like missing watchers)
// GameTinyLeadersImpl must extends GameCommanderImpl, not GameImpl
banned.add("Karn Liberated");
//Additionally, these Legendary creatures cannot be used as Commanders
bannedCommander.add("Erayo, Soratami Ascendant");
bannedCommander.add("Rofellos, Llanowar Emissary");

View file

@ -15,9 +15,9 @@ public class ZendikarBlock extends Constructed {
public ZendikarBlock() {
super("Constructed - Zendikar Block");
setCodes.add("ZEN");
setCodes.add("WWK");
setCodes.add("ROE");
setCodes.add(mage.sets.Zendikar.getInstance().getCode());
setCodes.add(mage.sets.Worldwake.getInstance().getCode());
setCodes.add(mage.sets.RiseOfTheEldrazi.getInstance().getCode());
}
}

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-deck-limited</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-game-brawlduel</artifactId>

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-game-brawlfreeforall</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-game-canadianhighlanderduel</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-game-commanderduel</artifactId>

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-game-commanderfreeforall</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-game-freeforall</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-game-freeformcommanderduel</artifactId>

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-game-freeformcommanderfreeforall</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-game-momirduel</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-game-momirfreeforall</artifactId>

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-game-oathbreakerduel</artifactId>
@ -22,7 +22,7 @@
<dependency>
<groupId>org.mage</groupId>
<artifactId>mage-game-oathbreakerfreeforall</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
<scope>compile</scope>
</dependency>
</dependencies>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-game-oathbreakerfreeforall</artifactId>

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-game-pennydreadfulcommanderfreeforall</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-game-tinyleadersduel</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-game-twoplayerduel</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-player-ai-draftbot</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-player-ai-ma</artifactId>

View file

@ -227,7 +227,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
}
val = minimaxAB(node, depth - 1, alpha, beta);
} else {
logger.trace("Add Action -- alpha: " + alpha + " beta: " + beta + " depth:" + depth + " step:" + game.getTurn().getStepType() + " for player:" + game.getPlayer(game.getPlayerList().get()).getName());
logger.trace("Add Action -- alpha: " + alpha + " beta: " + beta + " depth:" + depth + " step:" + game.getTurn().getStepType() + " for player:" + game.getPlayer(game.getActivePlayerId()).getName());
if (allPassed(game)) {
if (!game.getStack().isEmpty()) {
resolve(node, depth, game);

View file

@ -1,14 +1,14 @@
package mage.player.ai;
import java.util.LinkedList;
import mage.abilities.Ability;
import mage.constants.RangeOfInfluence;
import mage.game.Game;
import org.apache.log4j.Logger;
import java.util.Date;
import java.util.LinkedList;
/**
*
* @author ayratn
*/
public class ComputerPlayer7 extends ComputerPlayer6 {
@ -107,6 +107,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 {
protected void calculateActions(Game game) {
if (!getNextAction(game)) {
Date startTime = new Date();
currentScore = GameStateEvaluator2.evaluate(playerId, game);
Game sim = createSimulation(game);
SimulationNode2.resetCount();
@ -137,6 +138,15 @@ public class ComputerPlayer7 extends ComputerPlayer6 {
} else {
logger.info('[' + game.getPlayer(playerId).getName() + "][pre] Action: skip");
}
Date endTime = new Date();
this.setLastThinkTime((endTime.getTime() - startTime.getTime()));
/*
logger.warn("Last think time: " + this.getLastThinkTime()
+ "; actions: " + actions.size()
+ "; hand: " + this.getHand().size()
+ "; permanents: " + game.getBattlefield().getAllPermanents().size());
*/
} else {
logger.debug("Next Action exists!");
}

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-player-ai</artifactId>

View file

@ -70,6 +70,7 @@ import java.util.Map.Entry;
public class ComputerPlayer extends PlayerImpl implements Player {
private static final Logger log = Logger.getLogger(ComputerPlayer.class);
private long lastThinkTime = 0; // msecs for last AI actions calc
protected int PASSIVITY_PENALTY = 5; // Penalty value for doing nothing if some actions are available
protected boolean ALLOW_INTERRUPT = true; // change this for test to false / debugging purposes to false to switch off interrupts while debugging
@ -127,10 +128,17 @@ public class ComputerPlayer extends PlayerImpl implements Player {
@Override
public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game, Map<String, Serializable> options) {
if (log.isDebugEnabled()) {
log.debug("chooseTarget: " + outcome.toString() + ':' + target.toString());
}
// controller hints:
// - target.getTargetController(), this.getId() -- player that must makes choices (must be same with this.getId)
// - target.getAbilityController(), abilityControllerId -- affected player/controller for all actions/filters
// - affected controler can be different from target controller (another player makes choices for controller)
// sometimes a target selection can be made from a player that does not control the ability
UUID abilityControllerId = playerId;
if (target.getTargetController() != null
@ -138,6 +146,12 @@ public class ComputerPlayer extends PlayerImpl implements Player {
abilityControllerId = target.getAbilityController();
}
boolean required = target.isRequired(sourceId, game);
Set<UUID> possibleTargets = target.possibleTargets(sourceId, abilityControllerId, game);
if (possibleTargets.isEmpty() || target.getTargets().size() >= target.getNumberOfTargets()) {
required = false;
}
UUID randomOpponentId;
if (target.getTargetController() != null) {
randomOpponentId = getRandomOpponent(target.getTargetController(), game);
@ -148,14 +162,14 @@ public class ComputerPlayer extends PlayerImpl implements Player {
}
if (target.getOriginalTarget() instanceof TargetPlayer) {
return setTargetPlayer(outcome, target, null, sourceId, abilityControllerId, randomOpponentId, game);
return setTargetPlayer(outcome, target, null, sourceId, abilityControllerId, randomOpponentId, game, required);
}
if (target.getOriginalTarget() instanceof TargetDiscard) {
findPlayables(game);
if (!unplayable.isEmpty()) {
for (int i = unplayable.size() - 1; i >= 0; i--) {
if (target.canTarget(unplayable.values().toArray(new Card[0])[i].getId(), game)) {
if (target.canTarget(abilityControllerId, unplayable.values().toArray(new Card[0])[i].getId(), null, game)) {
target.add(unplayable.values().toArray(new Card[0])[i].getId(), game);
if (target.isChosen()) {
return true;
@ -165,7 +179,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
}
if (!hand.isEmpty()) {
for (int i = 0; i < hand.size(); i++) {
if (target.canTarget(hand.toArray(new UUID[0])[i], game)) {
if (target.canTarget(abilityControllerId, hand.toArray(new UUID[0])[i], null, game)) {
target.add(hand.toArray(new UUID[0])[i], game);
if (target.isChosen()) {
return true;
@ -244,7 +258,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
}
while ((outcome.isGood() ? target.getTargets().size() < target.getMaxNumberOfTargets() : !target.isChosen())
&& !cards.isEmpty()) {
Card pick = pickTarget(cards, outcome, target, null, game);
Card pick = pickTarget(abilityControllerId, cards, outcome, target, null, game);
if (pick != null) {
target.addTarget(pick.getId(), null, game);
cards.remove(pick);
@ -271,15 +285,15 @@ public class ComputerPlayer extends PlayerImpl implements Player {
}
}
if (outcome.isGood()) {
if (target.canTarget(abilityControllerId, null, game)) {
if (target.canTarget(abilityControllerId, abilityControllerId, null, game)) {
target.add(abilityControllerId, game);
return true;
}
} else if (target.canTarget(randomOpponentId, null, game)) {
} else if (target.canTarget(abilityControllerId, randomOpponentId, null, game)) {
target.add(randomOpponentId, game);
return true;
}
if (!target.isRequired(sourceId, game)) {
if (!required) {
return false;
}
}
@ -302,15 +316,15 @@ public class ComputerPlayer extends PlayerImpl implements Player {
}
}
if (outcome.isGood()) {
if (target.canTarget(abilityControllerId, null, game)) {
if (target.canTarget(abilityControllerId, abilityControllerId, null, game)) {
target.add(abilityControllerId, game);
return true;
}
} else if (target.canTarget(randomOpponentId, null, game)) {
} else if (target.canTarget(abilityControllerId, randomOpponentId, null, game)) {
target.add(randomOpponentId, game);
return true;
}
if (!target.isRequired(sourceId, game)) {
if (!required) {
return false;
}
}
@ -327,7 +341,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
}
for (Permanent permanent : targets) {
List<UUID> alreadyTargeted = target.getTargets();
if (target.canTarget(permanent.getId(), game)) {
if (target.canTarget(abilityControllerId, permanent.getId(), null, game)) {
if (alreadyTargeted != null && !alreadyTargeted.contains(permanent.getId())) {
target.add(permanent.getId(), game);
return true;
@ -335,22 +349,22 @@ public class ComputerPlayer extends PlayerImpl implements Player {
}
}
if (outcome.isGood()) {
if (target.canTarget(abilityControllerId, null, game)) {
if (target.canTarget(abilityControllerId, abilityControllerId, null, game)) {
target.add(abilityControllerId, game);
return true;
}
} else if (target.canTarget(randomOpponentId, null, game)) {
} else if (target.canTarget(abilityControllerId, randomOpponentId, null, game)) {
target.add(randomOpponentId, game);
return true;
}
if (!target.isRequired(sourceId, game) || target.getNumberOfTargets() == 0) {
return false;
}
if (target.canTarget(randomOpponentId, null, game)) {
if (target.canTarget(abilityControllerId, randomOpponentId, null, game)) {
target.add(randomOpponentId, game);
return true;
}
if (target.canTarget(abilityControllerId, null, game)) {
if (target.canTarget(abilityControllerId, abilityControllerId, null, game)) {
target.add(abilityControllerId, game);
return true;
}
@ -361,7 +375,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
}
for (Permanent permanent : targets) {
List<UUID> alreadyTargeted = target.getTargets();
if (target.canTarget(permanent.getId(), game)) {
if (target.canTarget(abilityControllerId, permanent.getId(), null, game)) {
if (alreadyTargeted != null && !alreadyTargeted.contains(permanent.getId())) {
target.add(permanent.getId(), game);
return true;
@ -371,30 +385,36 @@ public class ComputerPlayer extends PlayerImpl implements Player {
return false;
}
if (target.getOriginalTarget() instanceof TargetCardInGraveyard) {
if (target.getOriginalTarget() instanceof TargetCardInGraveyard
|| (target.getZone() == Zone.GRAVEYARD && (target.getOriginalTarget() instanceof TargetCard))) {
List<Card> cards = new ArrayList<>();
for (Player player : game.getPlayers().values()) {
for (Card card : player.getGraveyard().getCards(game)) {
if (target.canTarget(card.getId(), game)) {
if (target.canTarget(abilityControllerId, card.getId(), null, game)) {
cards.add(card);
}
}
}
for (Card card : cards) {
target.add(card.getId(), game);
if (target.isChosen()) {
return true;
while ((outcome.isGood() ? target.getTargets().size() < target.getMaxNumberOfTargets() : !target.isChosen())
&& !cards.isEmpty()) {
Card pick = pickTarget(abilityControllerId, cards, outcome, target, null, game);
if (pick != null) {
target.addTarget(pick.getId(), null, game);
cards.remove(pick);
}
}
return target.isChosen();
}
if (target.getOriginalTarget() instanceof TargetCardInYourGraveyard
|| target.getOriginalTarget() instanceof TargetCardInASingleGraveyard) {
List<UUID> alreadyTargeted = target.getTargets();
List<Card> cards = new ArrayList<>(game.getPlayer(abilityControllerId).getGraveyard().getCards((FilterCard) target.getFilter(), game));
TargetCard originalTarget = (TargetCard) target.getOriginalTarget();
List<Card> cards = new ArrayList<>(game.getPlayer(abilityControllerId).getGraveyard().getCards(originalTarget.getFilter(), game));
while (!cards.isEmpty()) {
Card card = pickTarget(cards, outcome, target, null, game);
Card card = pickTarget(abilityControllerId, cards, outcome, target, null, game);
if (card != null && alreadyTargeted != null && !alreadyTargeted.contains(card.getId())) {
target.add(card.getId(), game);
if (target.isChosen()) {
@ -412,7 +432,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
MageObject targetObject = game.getObject(targetId);
if (targetObject != null) {
List<UUID> alreadyTargeted = target.getTargets();
if (target.canTarget(targetObject.getId(), game)) {
if (target.canTarget(abilityControllerId, targetObject.getId(), null, game)) {
if (alreadyTargeted != null && !alreadyTargeted.contains(targetObject.getId())) {
target.add(targetObject.getId(), game);
return true;
@ -420,13 +440,13 @@ public class ComputerPlayer extends PlayerImpl implements Player {
}
}
}
if (!target.isRequired(sourceId, game)) {
if (!required) {
return false;
}
throw new IllegalStateException("TargetSource wasn't handled. class:" + target.getClass().toString());
throw new IllegalStateException("TargetSource wasn't handled. class: " + target.getClass().toString());
}
throw new IllegalStateException("Target wasn't handled. class:" + target.getClass().toString());
throw new IllegalStateException("Target wasn't handled. class: " + target.getClass().toString());
} //end of choose method
@Override
@ -434,12 +454,34 @@ public class ComputerPlayer extends PlayerImpl implements Player {
if (log.isDebugEnabled()) {
log.debug("chooseTarget: " + outcome.toString() + ':' + target.toString());
}
// target - real target, make all changes and add targets to it
// target.getOriginalTarget() - copy spell effect replaces original target with TargetWithAdditionalFilter
// use originalTarget to get filters and target class info
// source can be null (as example: legendary rule permanent selection)
UUID sourceId = source != null ? source.getSourceId() : null;
// sometimes a target selection can be made from a player that does not control the ability
UUID abilityControllerId = playerId;
if (target.getAbilityController() != null) {
abilityControllerId = target.getAbilityController();
}
boolean required = target.isRequired(sourceId, game);
Set<UUID> possibleTargets = target.possibleTargets(sourceId, abilityControllerId, game);
if (possibleTargets.isEmpty() || target.getTargets().size() >= target.getNumberOfTargets()) {
required = false;
}
// temp lists
List<Permanent> goodList = new ArrayList<>();
List<Permanent> badList = new ArrayList<>();
List<Permanent> allList = new ArrayList<>();
List<Permanent> goodList2 = new ArrayList<>();
List<Permanent> badList2 = new ArrayList<>();
List<Permanent> allList2 = new ArrayList<>();
// TODO: improve to process multiple opponents instead random
UUID randomOpponentId;
if (target.getTargetController() != null) {
@ -451,21 +493,21 @@ public class ComputerPlayer extends PlayerImpl implements Player {
}
if (target.getOriginalTarget() instanceof TargetPlayer) {
return setTargetPlayer(outcome, target, source, source.getSourceId(), abilityControllerId, randomOpponentId, game);
return setTargetPlayer(outcome, target, source, sourceId, abilityControllerId, randomOpponentId, game, required);
}
if (target.getOriginalTarget() instanceof TargetDiscard
|| target.getOriginalTarget() instanceof TargetCardInHand) {
if (outcome.isGood()) {
// good
Cards cards = new CardsImpl(target.possibleTargets(source.getSourceId(), getId(), game));
Cards cards = new CardsImpl(target.possibleTargets(sourceId, getId(), game));
ArrayList<Card> cardsInHand = new ArrayList<>(cards.getCards(game));
while (!target.isChosen()
&& !target.possibleTargets(source.getSourceId(), getId(), game).isEmpty()
&& !target.possibleTargets(sourceId, getId(), game).isEmpty()
&& target.getMaxNumberOfTargets() > target.getTargets().size()) {
Card card = pickBestCard(cardsInHand, null, target, source, game);
if (card != null) {
if (target.canTarget(getId(), card.getId(), source, game)) {
if (target.canTarget(abilityControllerId, card.getId(), source, game)) {
target.addTarget(card.getId(), source, game);
cardsInHand.remove(card);
if (target.isChosen()) {
@ -479,7 +521,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
findPlayables(game);
if (!unplayable.isEmpty()) {
for (int i = unplayable.size() - 1; i >= 0; i--) {
if (target.canTarget(getId(), unplayable.values().toArray(new Card[0])[i].getId(), source, game)) {
if (target.canTarget(abilityControllerId, unplayable.values().toArray(new Card[0])[i].getId(), source, game)) {
target.addTarget(unplayable.values().toArray(new Card[0])[i].getId(), source, game);
if (target.isChosen()) {
return true;
@ -489,7 +531,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
}
if (!hand.isEmpty()) {
for (int i = 0; i < hand.size(); i++) {
if (target.canTarget(getId(), hand.toArray(new UUID[0])[i], source, game)) {
if (target.canTarget(abilityControllerId, hand.toArray(new UUID[0])[i], source, game)) {
target.addTarget(hand.toArray(new UUID[0])[i], source, game);
if (target.isChosen()) {
return true;
@ -504,7 +546,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
if (target.getOriginalTarget() instanceof TargetControlledPermanent) {
TargetControlledPermanent origTarget = (TargetControlledPermanent) target.getOriginalTarget();
List<Permanent> targets;
targets = threats(abilityControllerId, source.getSourceId(), origTarget.getFilter(), game, target.getTargets());
targets = threats(abilityControllerId, sourceId, origTarget.getFilter(), game, target.getTargets());
if (!outcome.isGood()) {
Collections.reverse(targets);
}
@ -520,30 +562,30 @@ public class ComputerPlayer extends PlayerImpl implements Player {
}
// TODO: implemented findBestPlayerTargets
// TODO: add findBest*Targets for all target types
if (target.getOriginalTarget() instanceof TargetPermanent) {
List<Permanent> targets;
TargetPermanent origTarget = (TargetPermanent) target.getOriginalTarget();
boolean outcomeTargets = true;
if (outcome.isGood()) {
targets = threats(abilityControllerId, source == null ? null : source.getSourceId(), ((TargetPermanent) target).getFilter(), game, target.getTargets());
} else {
targets = threats(randomOpponentId, source == null ? null : source.getSourceId(), ((TargetPermanent) target).getFilter(), game, target.getTargets());
}
if (targets.isEmpty() && target.isRequired(source)) {
targets = threats(null, source == null ? null : source.getSourceId(), ((TargetPermanent) target).getFilter(), game, target.getTargets());
Collections.reverse(targets);
outcomeTargets = false;
//targets = game.getBattlefield().getActivePermanents(((TargetPermanent)target).getFilter(), playerId, game);
}
if (targets.isEmpty() && target.isRequired()) {
targets = game.getBattlefield().getActivePermanents(origTarget.getFilter(), playerId, game);
}
for (Permanent permanent : targets) {
findBestPermanentTargets(outcome, abilityControllerId, sourceId, origTarget.getFilter(),
game, target, goodList, badList, allList);
// use good list all the time and add maximum targets
for (Permanent permanent : goodList) {
if (target.canTarget(abilityControllerId, permanent.getId(), source, game)) {
target.addTarget(permanent.getId(), source, game);
if (!outcomeTargets || target.getMaxNumberOfTargets() <= target.getTargets().size()) {
return true;
if (target.getTargets().size() >= target.getMaxNumberOfTargets()) {
break;
}
target.addTarget(permanent.getId(), source, game);
}
}
// use bad list only on required target and add minimum targets
if (required) {
for (Permanent permanent : badList) {
if (target.getTargets().size() >= target.getMinNumberOfTargets()) {
break;
}
target.addTarget(permanent.getId(), source, game);
}
}
return target.isChosen();
@ -551,19 +593,19 @@ public class ComputerPlayer extends PlayerImpl implements Player {
if (target.getOriginalTarget() instanceof TargetCreatureOrPlayer) {
List<Permanent> targets;
TargetCreatureOrPlayer origTarget = ((TargetCreatureOrPlayer) target);
TargetCreatureOrPlayer origTarget = ((TargetCreatureOrPlayer) target.getOriginalTarget());
if (outcome.isGood()) {
targets = threats(abilityControllerId, source.getSourceId(), ((FilterCreatureOrPlayer) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets());
targets = threats(abilityControllerId, sourceId, ((FilterCreatureOrPlayer) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets());
} else {
targets = threats(randomOpponentId, source.getSourceId(), ((FilterCreatureOrPlayer) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets());
targets = threats(randomOpponentId, sourceId, ((FilterCreatureOrPlayer) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets());
}
if (targets.isEmpty()) {
if (outcome.isGood()) {
if (target.canTarget(getId(), abilityControllerId, source, game)) {
if (target.canTarget(abilityControllerId, abilityControllerId, source, game)) {
return tryAddTarget(target, abilityControllerId, source, game);
}
} else if (target.canTarget(getId(), randomOpponentId, source, game)) {
} else if (target.canTarget(abilityControllerId, randomOpponentId, source, game)) {
return tryAddTarget(target, randomOpponentId, source, game);
}
}
@ -581,37 +623,36 @@ public class ComputerPlayer extends PlayerImpl implements Player {
}
if (outcome.isGood()) {
if (target.canTarget(getId(), abilityControllerId, source, game)) {
if (target.canTarget(abilityControllerId, abilityControllerId, source, game)) {
return tryAddTarget(target, abilityControllerId, source, game);
}
} else if (target.canTarget(getId(), randomOpponentId, source, game)) {
} else if (target.canTarget(abilityControllerId, randomOpponentId, source, game)) {
return tryAddTarget(target, randomOpponentId, source, game);
}
//if (!target.isRequired())
return false;
}
if (target.getOriginalTarget() instanceof TargetAnyTarget) {
List<Permanent> targets;
TargetAnyTarget origTarget = ((TargetAnyTarget) target);
TargetAnyTarget origTarget = ((TargetAnyTarget) target.getOriginalTarget());
if (outcome.isGood()) {
targets = threats(abilityControllerId, source.getSourceId(), ((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets());
targets = threats(abilityControllerId, sourceId, ((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets());
} else {
targets = threats(randomOpponentId, source.getSourceId(), ((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets());
targets = threats(randomOpponentId, sourceId, ((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets());
}
if (targets.isEmpty()) {
if (outcome.isGood()) {
if (target.canTarget(getId(), abilityControllerId, source, game)) {
if (target.canTarget(abilityControllerId, abilityControllerId, source, game)) {
return tryAddTarget(target, abilityControllerId, source, game);
}
} else if (target.canTarget(getId(), randomOpponentId, source, game)) {
} else if (target.canTarget(abilityControllerId, randomOpponentId, source, game)) {
return tryAddTarget(target, randomOpponentId, source, game);
}
}
if (targets.isEmpty() && target.isRequired(source)) {
if (targets.isEmpty() && required) {
targets = game.getBattlefield().getActivePermanents(((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getCreatureFilter(), playerId, game);
}
for (Permanent permanent : targets) {
@ -624,10 +665,10 @@ public class ComputerPlayer extends PlayerImpl implements Player {
}
if (outcome.isGood()) {
if (target.canTarget(getId(), abilityControllerId, source, game)) {
if (target.canTarget(abilityControllerId, abilityControllerId, source, game)) {
return tryAddTarget(target, abilityControllerId, source, game);
}
} else if (target.canTarget(getId(), randomOpponentId, source, game)) {
} else if (target.canTarget(abilityControllerId, randomOpponentId, source, game)) {
return tryAddTarget(target, randomOpponentId, source, game);
}
@ -637,7 +678,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
if (target.getOriginalTarget() instanceof TargetPermanentOrPlayer) {
List<Permanent> targets;
TargetPermanentOrPlayer origTarget = ((TargetPermanentOrPlayer) target);
TargetPermanentOrPlayer origTarget = ((TargetPermanentOrPlayer) target.getOriginalTarget());
if (outcome.isGood()) {
targets = threats(abilityControllerId, source.getSourceId(), ((FilterPermanentOrPlayer) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets());
} else {
@ -646,10 +687,10 @@ public class ComputerPlayer extends PlayerImpl implements Player {
if (targets.isEmpty()) {
if (outcome.isGood()) {
if (target.canTarget(getId(), abilityControllerId, source, game)) {
if (target.canTarget(abilityControllerId, abilityControllerId, source, game)) {
return tryAddTarget(target, abilityControllerId, source, game);
}
} else if (target.canTarget(getId(), randomOpponentId, source, game)) {
} else if (target.canTarget(abilityControllerId, randomOpponentId, source, game)) {
return tryAddTarget(target, randomOpponentId, source, game);
}
}
@ -669,7 +710,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
if (target.getOriginalTarget() instanceof TargetPlayerOrPlaneswalker) {
List<Permanent> targets;
TargetPlayerOrPlaneswalker origTarget = ((TargetPlayerOrPlaneswalker) target);
TargetPlayerOrPlaneswalker origTarget = ((TargetPlayerOrPlaneswalker) target.getOriginalTarget());
// TODO: if effect is bad and no opponent's targets available then AI can't target yourself but must by rules
/*
@ -692,16 +733,16 @@ public class ComputerPlayer extends PlayerImpl implements Player {
// possible good/bad players
if (targets.isEmpty()) {
if (outcome.isGood()) {
if (target.canTarget(getId(), abilityControllerId, source, game)) {
if (target.canTarget(abilityControllerId, abilityControllerId, source, game)) {
return tryAddTarget(target, abilityControllerId, source, game);
}
} else if (target.canTarget(getId(), randomOpponentId, source, game)) {
} else if (target.canTarget(abilityControllerId, randomOpponentId, source, game)) {
return tryAddTarget(target, randomOpponentId, source, game);
}
}
// can't find targets (e.g. effect is bad, but you need take targets from yourself)
if (targets.isEmpty() && target.isRequired(source)) {
if (targets.isEmpty() && required) {
targets = game.getBattlefield().getActivePermanents(origTarget.getFilterPermanent(), playerId, game);
}
@ -717,14 +758,13 @@ public class ComputerPlayer extends PlayerImpl implements Player {
// try target player as normal
if (outcome.isGood()) {
if (target.canTarget(getId(), abilityControllerId, source, game)) {
if (target.canTarget(abilityControllerId, abilityControllerId, source, game)) {
return tryAddTarget(target, abilityControllerId, source, game);
}
} else if (target.canTarget(getId(), randomOpponentId, source, game)) {
} else if (target.canTarget(abilityControllerId, randomOpponentId, source, game)) {
return tryAddTarget(target, randomOpponentId, source, game);
}
//if (!target.isRequired())
return false;
}
@ -733,7 +773,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
for (Player player : game.getPlayers().values()) {
cards.addAll(player.getGraveyard().getCards(game));
}
Card card = pickTarget(cards, outcome, target, source, game);
Card card = pickTarget(abilityControllerId, cards, outcome, target, source, game);
if (card != null) {
return tryAddTarget(target, card.getId(), source, game);
}
@ -743,7 +783,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
if (target.getOriginalTarget() instanceof TargetCardInLibrary) {
List<Card> cards = new ArrayList<>(game.getPlayer(abilityControllerId).getLibrary().getCards(game));
Card card = pickTarget(cards, outcome, target, source, game);
Card card = pickTarget(abilityControllerId, cards, outcome, target, source, game);
if (card != null) {
return tryAddTarget(target, card.getId(), source, game);
}
@ -753,7 +793,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
if (target.getOriginalTarget() instanceof TargetCardInYourGraveyard) {
List<Card> cards = new ArrayList<>(game.getPlayer(abilityControllerId).getGraveyard().getCards((FilterCard) target.getFilter(), game));
while (!target.isChosen() && !cards.isEmpty()) {
Card card = pickTarget(cards, outcome, target, source, game);
Card card = pickTarget(abilityControllerId, cards, outcome, target, source, game);
if (card != null) {
target.addTarget(card.getId(), source, game);
cards.remove(card); // pickTarget don't remove cards (only on second+ tries)
@ -783,7 +823,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
} else {
targets = threats(randomOpponentId, source == null ? null : source.getSourceId(), origTarget.getPermanentFilter(), game, target.getTargets());
}
if (targets.isEmpty() && target.isRequired(source)) {
if (targets.isEmpty() && required) {
targets = threats(null, source == null ? null : source.getSourceId(), origTarget.getPermanentFilter(), game, target.getTargets());
Collections.reverse(targets);
outcomeTargets = false;
@ -816,7 +856,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
cards.addAll(player.getGraveyard().getCards(game));
}
}
Card card = pickTarget(cards, outcome, target, source, game);
Card card = pickTarget(abilityControllerId, cards, outcome, target, source, game);
if (card != null) {
return tryAddTarget(target, card.getId(), source, game);
}
@ -830,7 +870,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
targets = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_PLANESWALKER, randomOpponentId, game);
if (targets != null && !targets.isEmpty()) {
for (Permanent planeswalker : targets) {
if (target.canTarget(getId(), planeswalker.getId(), source, game)) {
if (target.canTarget(abilityControllerId, planeswalker.getId(), source, game)) {
target.addTarget(planeswalker.getId(), source, game);
}
if (target.isChosen()) {
@ -839,7 +879,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
}
}
if (!target.isChosen()) {
if (target.canTarget(getId(), randomOpponentId, source, game)) {
if (target.canTarget(abilityControllerId, randomOpponentId, source, game)) {
target.addTarget(randomOpponentId, source, game);
}
}
@ -852,7 +892,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
cards.addAll(player.getGraveyard().getCards(game));
}
while (!target.isChosen() && !cards.isEmpty()) {
Card pick = pickTarget(cards, outcome, target, source, game);
Card pick = pickTarget(abilityControllerId, cards, outcome, target, source, game);
if (pick != null) {
target.addTarget(pick.getId(), source, game);
cards.remove(pick); // pickTarget don't remove cards (only on second+ tries)
@ -870,7 +910,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
}
}
while (!target.isChosen() && !cards.isEmpty()) {
Card pick = pickTarget(cards, outcome, target, source, game);
Card pick = pickTarget(abilityControllerId, cards, outcome, target, source, game);
if (pick != null) {
target.addTarget(pick.getId(), source, game);
cards.remove(pick); // pickTarget don't remove cards (only on second+ tries)
@ -903,7 +943,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
cards.addAll(player.getGraveyard().getCards(game));
cards.addAll(game.getBattlefield().getAllActivePermanents(new FilterPermanent(), player.getId(), game));
}
Card card = pickTarget(cards, outcome, target, source, game);
Card card = pickTarget(abilityControllerId, cards, outcome, target, source, game);
if (card != null) {
return tryAddTarget(target, card.getId(), source, game);
}
@ -912,7 +952,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
throw new IllegalStateException("Target wasn't handled. class:" + target.getClass().toString());
} //end of chooseTarget method
protected Card pickTarget(List<Card> cards, Outcome outcome, Target target, Ability source, Game game) {
protected Card pickTarget(UUID abilityControllerId, List<Card> cards, Outcome outcome, Target target, Ability source, Game game) {
Card card;
while (!cards.isEmpty()) {
@ -923,7 +963,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
}
if (!target.getTargets().contains(card.getId())) {
if (source != null) {
if (target.canTarget(getId(), card.getId(), source, game)) {
if (target.canTarget(abilityControllerId, card.getId(), source, game)) {
return card;
}
} else {
@ -1277,6 +1317,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
}
}
}
// TODO: wtf?! change to player.getPlayable
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(playerId)) {
for (ActivatedAbility ability : permanent.getAbilities().getActivatedAbilities(Zone.BATTLEFIELD)) {
if (!(ability instanceof ActivatedManaAbilityImpl) && ability.canActivate(playerId, game).canActivate()) {
@ -1728,9 +1769,16 @@ public class ComputerPlayer extends PlayerImpl implements Player {
return target.isRequired(source);
}
// sometimes a target selection can be made from a player that does not control the ability
UUID abilityControllerId = playerId;
if (target.getTargetController() != null
&& target.getAbilityController() != null) {
abilityControllerId = target.getAbilityController();
}
ArrayList<Card> cardChoices = new ArrayList<>(cards.getCards(target.getFilter(), game));
while (!target.doneChosing()) {
Card card = pickTarget(cardChoices, outcome, target, source, game);
Card card = pickTarget(abilityControllerId, cardChoices, outcome, target, source, game);
if (card != null) {
target.addTarget(card.getId(), source, game);
cardChoices.remove(card);
@ -1752,9 +1800,16 @@ public class ComputerPlayer extends PlayerImpl implements Player {
return true;
}
// sometimes a target selection can be made from a player that does not control the ability
UUID abilityControllerId = playerId;
if (target.getTargetController() != null
&& target.getAbilityController() != null) {
abilityControllerId = target.getAbilityController();
}
ArrayList<Card> cardChoices = new ArrayList<>(cards.getCards(target.getFilter(), game));
while (!target.doneChosing()) {
Card card = pickTarget(cardChoices, outcome, target, null, game);
Card card = pickTarget(abilityControllerId, cardChoices, outcome, target, null, game);
if (card != null) {
target.add(card.getId(), game);
cardChoices.remove(card);
@ -2421,6 +2476,58 @@ public class ComputerPlayer extends PlayerImpl implements Player {
return worst;
}
protected void findBestPermanentTargets(Outcome outcome, UUID abilityControllerId, UUID sourceId, FilterPermanent filter, Game game, Target target,
List<Permanent> goodList, List<Permanent> badList, List<Permanent> allList) {
// searching for most valuable/powerfull permanents
goodList.clear();
badList.clear();
allList.clear();
List<UUID> usedTargets = target.getTargets();
// search all
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, abilityControllerId, sourceId, game)) {
if (usedTargets.contains(permanent.getId())) {
continue;
}
if (outcome.isGood()) {
// good effect
if (permanent.isControlledBy(abilityControllerId)) {
goodList.add(permanent);
} else {
badList.add(permanent);
}
} else {
// bad effect
if (permanent.isControlledBy(abilityControllerId)) {
badList.add(permanent);
} else {
goodList.add(permanent);
}
}
}
// sort from tiny to big (more valuable)
PermanentComparator comparator = new PermanentComparator(game);
goodList.sort(comparator);
badList.sort(comparator);
// real sort
if (outcome.isGood()) {
// good effect -- most valueable goes first
Collections.reverse(goodList);
// Collections.reverse(badList);
} else {
// bad effect - most weakest goes first, no need in reverse
// Collections.reverse(goodList);
Collections.reverse(badList);
}
allList.addAll(goodList);
allList.addAll(badList);
}
protected List<Permanent> threats(UUID playerId, UUID sourceId, FilterPermanent filter, Game game, List<UUID> targets) {
return threats(playerId, sourceId, filter, game, targets, true);
}
@ -2550,7 +2657,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
/**
* Sets a possible target player
*/
private boolean setTargetPlayer(Outcome outcome, Target target, Ability source, UUID sourceId, UUID abilityControllerId, UUID randomOpponentId, Game game) {
private boolean setTargetPlayer(Outcome outcome, Target target, Ability source, UUID sourceId, UUID abilityControllerId, UUID randomOpponentId, Game game, boolean required) {
if (target.getOriginalTarget() instanceof TargetOpponent) {
if (source == null) {
if (target.canTarget(randomOpponentId, game)) {
@ -2617,7 +2724,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
target.add(randomOpponentId, game);
return true;
}
if (target.isRequired(sourceId, game)) {
if (required) {
if (target.canTarget(abilityControllerId, game)) {
target.add(abilityControllerId, game);
return true;
@ -2689,4 +2796,12 @@ public class ComputerPlayer extends PlayerImpl implements Player {
// all human players converted to computer and analyse
this.human = false;
}
public long getLastThinkTime() {
return lastThinkTime;
}
public void setLastThinkTime(long lastThinkTime) {
this.lastThinkTime = lastThinkTime;
}
}

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-player-ai-mcts</artifactId>
@ -25,6 +25,11 @@
<artifactId>mage</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>mage-sets</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>mage-player-ai</artifactId>
@ -33,7 +38,6 @@
</dependencies>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@ -49,10 +53,9 @@
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
<finalName>mage-player-aimcts</finalName>
<finalName>mage-player-ai-mcts</finalName>
</build>
<properties/>

View file

@ -1,4 +1,3 @@
package mage.player.ai;
import mage.constants.PhaseStep;

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-player-aiminimax</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-player-human</artifactId>

View file

@ -1,7 +1,28 @@
package mage.player.human;
import java.awt.Color;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Queue;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import mage.MageObject;
import mage.abilities.*;
import mage.abilities.Ability;
import mage.abilities.ActivatedAbility;
import mage.abilities.Mode;
import mage.abilities.Modes;
import mage.abilities.PlayLandAbility;
import mage.abilities.SpecialAction;
import mage.abilities.SpellAbility;
import mage.abilities.TriggeredAbility;
import mage.abilities.costs.VariableCost;
import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.costs.common.TapSourceCost;
@ -16,6 +37,11 @@ import mage.cards.decks.Deck;
import mage.choices.Choice;
import mage.choices.ChoiceImpl;
import mage.constants.*;
import static mage.constants.PlayerAction.REQUEST_AUTO_ANSWER_RESET_ALL;
import static mage.constants.PlayerAction.TRIGGER_AUTO_ORDER_RESET_ALL;
import static mage.constants.SpellAbilityType.SPLIT;
import static mage.constants.SpellAbilityType.SPLIT_AFTERMATH;
import static mage.constants.SpellAbilityType.SPLIT_FUSED;
import mage.filter.StaticFilters;
import mage.filter.common.FilterAttackingCreature;
import mage.filter.common.FilterBlockingCreature;
@ -46,16 +72,6 @@ import mage.util.ManaUtil;
import mage.util.MessageToClient;
import org.apache.log4j.Logger;
import java.awt.*;
import java.io.Serializable;
import java.util.List;
import java.util.Queue;
import java.util.*;
import java.util.stream.Collectors;
import static mage.constants.PlayerAction.REQUEST_AUTO_ANSWER_RESET_ALL;
import static mage.constants.PlayerAction.TRIGGER_AUTO_ORDER_RESET_ALL;
/**
* @author BetaSteward_at_googlemail.com
*/
@ -268,6 +284,9 @@ public class HumanPlayer extends PlayerImpl {
@Override
public boolean chooseUse(Outcome outcome, String message, String secondMessage, String trueText, String falseText, Ability source, Game game) {
if (game.inCheckPlayableState()) {
return true;
}
MessageToClient messageToClient = new MessageToClient(message, secondMessage);
Map<String, Serializable> options = new HashMap<>(2);
if (trueText != null) {
@ -334,6 +353,14 @@ public class HumanPlayer extends PlayerImpl {
@Override
public int chooseReplacementEffect(Map<String, String> rEffects, Game game) {
if (game.inCheckPlayableState()) {
logger.warn("player interaction in checkPlayableState.");
if (rEffects.size() <= 1) {
return 0;
} else {
return 1;
}
}
updateGameStatePriority("chooseEffect", game);
if (rEffects.size() <= 1) {
return 0;
@ -394,6 +421,11 @@ public class HumanPlayer extends PlayerImpl {
@Override
public boolean choose(Outcome outcome, Choice choice, Game game) {
if (game.inCheckPlayableState()) {
logger.warn("player interaction in checkPlayableState. Choice: " + choice.getMessage());
choice.setChoice(choice.getChoices().iterator().next());
return true;
}
if (Outcome.PutManaInPool == outcome) {
if (currentlyUnpaidMana != null
&& ManaUtil.tryToAutoSelectAManaColor(choice, currentlyUnpaidMana)) {
@ -429,6 +461,11 @@ public class HumanPlayer extends PlayerImpl {
@Override
public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game, Map<String, Serializable> options) {
if (game.inCheckPlayableState()) {
logger.warn("player interaction in checkPlayableState. Target: " + target.getMessage());
// TODO: set default choice
return true;
}
// choose one or multiple permanents
updateGameStatePriority("choose(5)", game);
UUID abilityControllerId = playerId;
@ -520,6 +557,11 @@ public class HumanPlayer extends PlayerImpl {
@Override
public boolean chooseTarget(Outcome outcome, Target target, Ability source, Game game) {
if (game.inCheckPlayableState()) {
logger.warn("player interaction in checkPlayableState. Target: " + target.getMessage());
// TODO: set default choice
return true;
}
// choose one or multiple targets
updateGameStatePriority("chooseTarget", game);
UUID abilityControllerId = playerId;
@ -582,6 +624,11 @@ public class HumanPlayer extends PlayerImpl {
@Override
public boolean choose(Outcome outcome, Cards cards, TargetCard target, Game game) {
if (game.inCheckPlayableState()) {
logger.warn("player interaction in checkPlayableState. Target: " + target.getMessage());
// TODO: set default choice
return true;
}
// choose one or multiple cards
if (cards == null) {
return false;
@ -710,9 +757,9 @@ public class HumanPlayer extends PlayerImpl {
if (!isExecutingMacro()) {
String selectedNames = target.getTargetedName(game);
game.fireSelectTargetEvent(playerId, new MessageToClient(target.getMessage()
+ "<br> Amount remaining: " + target.getAmountRemaining()
+ (selectedNames.isEmpty() ? "" : ", selected: " + selectedNames),
getRelatedObjectName(source, game)),
+ "<br> Amount remaining: " + target.getAmountRemaining()
+ (selectedNames.isEmpty() ? "" : ", selected: " + selectedNames),
getRelatedObjectName(source, game)),
target.possibleTargets(source == null ? null : source.getSourceId(), playerId, game),
target.isRequired(source),
getOptions(target, null));
@ -725,7 +772,7 @@ public class HumanPlayer extends PlayerImpl {
boolean removeMode = target.getTargets().contains(targetId)
&& chooseUse(outcome, "What do you want to do with " + (targetObject != null ? targetObject.getLogName() : "target") + "?", "",
"Remove from selected", "Add extra amount", source, game);
"Remove from selected", "Add extra amount", source, game);
if (removeMode) {
target.remove(targetId);
@ -862,9 +909,9 @@ public class HumanPlayer extends PlayerImpl {
if (!skippedAtLeastOnce
|| (playerId.equals(game.getActivePlayerId())
&& !controllingPlayer
.getUserData()
.getUserSkipPrioritySteps()
.isStopOnAllEndPhases())) {
.getUserData()
.getUserSkipPrioritySteps()
.isStopOnAllEndPhases())) {
skippedAtLeastOnce = true;
if (passWithManaPoolCheck(game)) {
return false;
@ -896,9 +943,9 @@ public class HumanPlayer extends PlayerImpl {
if (haveNewObjectsOnStack
&& (playerId.equals(game.getActivePlayerId())
&& controllingPlayer
.getUserData()
.getUserSkipPrioritySteps()
.isStopOnStackNewObjects())) {
.getUserData()
.getUserSkipPrioritySteps()
.isStopOnStackNewObjects())) {
// new objects on stack -- disable "pass until stack resolved"
passedUntilStackResolved = false;
} else {
@ -1235,8 +1282,8 @@ public class HumanPlayer extends PlayerImpl {
if (passedAllTurns
|| passedUntilEndStepBeforeMyTurn
|| (!getControllingPlayersUserData(game)
.getUserSkipPrioritySteps()
.isStopOnDeclareAttackers()
.getUserSkipPrioritySteps()
.isStopOnDeclareAttackers()
&& (passedTurn
|| passedTurnSkipStack
|| passedUntilEndOfTurn
@ -1419,7 +1466,7 @@ public class HumanPlayer extends PlayerImpl {
/**
* Selects a defender for an attacker and adds the attacker to combat
*
* @param defenders - list of possible defender
* @param defenders - list of possible defender
* @param attackerId - UUID of attacker
* @param game
* @return
@ -1742,7 +1789,7 @@ public class HumanPlayer extends PlayerImpl {
if (ability instanceof PlayLandAbility) {
return true;
}
if (!ability.getSourceId().equals(getCastSourceIdWithAlternateMana())
if (!getCastSourceIdWithAlternateMana().contains(ability.getSourceId())
&& ability.getManaCostsToPay().convertedManaCost() > 0) {
return true;
}

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-tournament-boosterdraft</artifactId>

View file

@ -0,0 +1,556 @@
package mage.tournament.cubes;
import mage.game.draft.DraftCube;
/**
*
* @author phulin
*/
public class VintageCubeDecember2019 extends DraftCube {
public VintageCubeDecember2019() {
super("MTGO Vintage Cube December 2019");
cubeCards.add(new DraftCube.CardIdentity("Kytheon, Hero of Akros", ""));
cubeCards.add(new DraftCube.CardIdentity("Mother of Runes", ""));
cubeCards.add(new DraftCube.CardIdentity("Student of Warfare", ""));
cubeCards.add(new DraftCube.CardIdentity("Adanto Vanguard", ""));
cubeCards.add(new DraftCube.CardIdentity("Containment Priest", ""));
cubeCards.add(new DraftCube.CardIdentity("Leonin Relic-Warder", ""));
cubeCards.add(new DraftCube.CardIdentity("Porcelain Legionnaire", ""));
cubeCards.add(new DraftCube.CardIdentity("Selfless Spirit", ""));
cubeCards.add(new DraftCube.CardIdentity("Soulfire Grand Master", ""));
cubeCards.add(new DraftCube.CardIdentity("Stoneforge Mystic", ""));
cubeCards.add(new DraftCube.CardIdentity("Thalia, Guardian of Thraben", ""));
cubeCards.add(new DraftCube.CardIdentity("Tithe Taker", ""));
cubeCards.add(new DraftCube.CardIdentity("Wall of Omens", ""));
cubeCards.add(new DraftCube.CardIdentity("Blade Splicer", ""));
cubeCards.add(new DraftCube.CardIdentity("Brightling", ""));
cubeCards.add(new DraftCube.CardIdentity("Brimaz, King of Oreskos", ""));
cubeCards.add(new DraftCube.CardIdentity("Fairgrounds Warden", ""));
cubeCards.add(new DraftCube.CardIdentity("Flickerwisp", ""));
cubeCards.add(new DraftCube.CardIdentity("Monastery Mentor", ""));
cubeCards.add(new DraftCube.CardIdentity("Recruiter of the Guard", ""));
cubeCards.add(new DraftCube.CardIdentity("Silverblade Paladin", ""));
cubeCards.add(new DraftCube.CardIdentity("Emeria Angel", ""));
cubeCards.add(new DraftCube.CardIdentity("Hero of Bladehold", ""));
cubeCards.add(new DraftCube.CardIdentity("Linvala, Keeper of Silence", ""));
cubeCards.add(new DraftCube.CardIdentity("Restoration Angel", ""));
cubeCards.add(new DraftCube.CardIdentity("Angel of Invention", ""));
cubeCards.add(new DraftCube.CardIdentity("Angel of Sanctions", ""));
cubeCards.add(new DraftCube.CardIdentity("Archangel Avacyn", ""));
cubeCards.add(new DraftCube.CardIdentity("Baneslayer Angel", ""));
cubeCards.add(new DraftCube.CardIdentity("Lyra Dawnbringer", ""));
cubeCards.add(new DraftCube.CardIdentity("Reveillark", ""));
cubeCards.add(new DraftCube.CardIdentity("Sun Titan", ""));
cubeCards.add(new DraftCube.CardIdentity("Angel of Serenity", ""));
cubeCards.add(new DraftCube.CardIdentity("Elesh Norn, Grand Cenobite", ""));
cubeCards.add(new DraftCube.CardIdentity("Iona, Shield of Emeria", ""));
cubeCards.add(new DraftCube.CardIdentity("Gideon Blackblade", ""));
cubeCards.add(new DraftCube.CardIdentity("Elspeth, Knight-Errant", ""));
cubeCards.add(new DraftCube.CardIdentity("Gideon, Ally of Zendikar", ""));
cubeCards.add(new DraftCube.CardIdentity("Gideon Jura", ""));
cubeCards.add(new DraftCube.CardIdentity("Elspeth, Sun's Champion", ""));
cubeCards.add(new DraftCube.CardIdentity("Condemn", ""));
cubeCards.add(new DraftCube.CardIdentity("Enlightened Tutor", ""));
cubeCards.add(new DraftCube.CardIdentity("Mana Tithe", ""));
cubeCards.add(new DraftCube.CardIdentity("Path to Exile", ""));
cubeCards.add(new DraftCube.CardIdentity("Swords to Plowshares", ""));
cubeCards.add(new DraftCube.CardIdentity("Disenchant", ""));
cubeCards.add(new DraftCube.CardIdentity("Unexpectedly Absent", ""));
cubeCards.add(new DraftCube.CardIdentity("Balance", ""));
cubeCards.add(new DraftCube.CardIdentity("Council's Judgment", ""));
cubeCards.add(new DraftCube.CardIdentity("Spectral Procession", ""));
cubeCards.add(new DraftCube.CardIdentity("Armageddon", ""));
cubeCards.add(new DraftCube.CardIdentity("Day of Judgment", ""));
cubeCards.add(new DraftCube.CardIdentity("Ravages of War", ""));
cubeCards.add(new DraftCube.CardIdentity("Wrath of God", ""));
cubeCards.add(new DraftCube.CardIdentity("Terminus", ""));
cubeCards.add(new DraftCube.CardIdentity("Land Tax", ""));
cubeCards.add(new DraftCube.CardIdentity("Legion's Landing", ""));
cubeCards.add(new DraftCube.CardIdentity("Honor of the Pure", ""));
cubeCards.add(new DraftCube.CardIdentity("Banishing Light", ""));
cubeCards.add(new DraftCube.CardIdentity("Oblivion Ring", ""));
cubeCards.add(new DraftCube.CardIdentity("Faith's Fetters", ""));
cubeCards.add(new DraftCube.CardIdentity("Moat", ""));
cubeCards.add(new DraftCube.CardIdentity("Parallax Wave", ""));
cubeCards.add(new DraftCube.CardIdentity("Spear of Heliod", ""));
cubeCards.add(new DraftCube.CardIdentity("Karakas", ""));
cubeCards.add(new DraftCube.CardIdentity("Pteramander", ""));
cubeCards.add(new DraftCube.CardIdentity("Baral, Chief of Compliance", ""));
cubeCards.add(new DraftCube.CardIdentity("Jace, Vryn's Prodigy", ""));
cubeCards.add(new DraftCube.CardIdentity("Looter il-Kor", ""));
cubeCards.add(new DraftCube.CardIdentity("Phantasmal Image", ""));
cubeCards.add(new DraftCube.CardIdentity("Snapcaster Mage", ""));
cubeCards.add(new DraftCube.CardIdentity("Thing in the Ice", ""));
cubeCards.add(new DraftCube.CardIdentity("Arcane Artisan", ""));
cubeCards.add(new DraftCube.CardIdentity("Deceiver Exarch", ""));
cubeCards.add(new DraftCube.CardIdentity("Pestermite", ""));
cubeCards.add(new DraftCube.CardIdentity("Spellseeker", ""));
cubeCards.add(new DraftCube.CardIdentity("Trinket Mage", ""));
cubeCards.add(new DraftCube.CardIdentity("Vendilion Clique", ""));
cubeCards.add(new DraftCube.CardIdentity("Glen Elendra Archmage", ""));
cubeCards.add(new DraftCube.CardIdentity("Phyrexian Metamorph", ""));
cubeCards.add(new DraftCube.CardIdentity("Sower of Temptation", ""));
cubeCards.add(new DraftCube.CardIdentity("Venser, Shaper Savant", ""));
cubeCards.add(new DraftCube.CardIdentity("Mulldrifter", ""));
cubeCards.add(new DraftCube.CardIdentity("Riftwing Cloudskate", ""));
cubeCards.add(new DraftCube.CardIdentity("Consecrated Sphinx", ""));
cubeCards.add(new DraftCube.CardIdentity("Frost Titan", ""));
cubeCards.add(new DraftCube.CardIdentity("Torrential Gearhulk", ""));
cubeCards.add(new DraftCube.CardIdentity("Palinchron", ""));
cubeCards.add(new DraftCube.CardIdentity("Inkwell Leviathan", ""));
cubeCards.add(new DraftCube.CardIdentity("Jace Beleren", ""));
cubeCards.add(new DraftCube.CardIdentity("Jace, the Mind Sculptor", ""));
cubeCards.add(new DraftCube.CardIdentity("Tezzeret the Seeker", ""));
cubeCards.add(new DraftCube.CardIdentity("Ancestral Recall", ""));
cubeCards.add(new DraftCube.CardIdentity("Brainstorm", ""));
cubeCards.add(new DraftCube.CardIdentity("High Tide", ""));
cubeCards.add(new DraftCube.CardIdentity("Mystical Tutor", ""));
cubeCards.add(new DraftCube.CardIdentity("Spell Pierce", ""));
cubeCards.add(new DraftCube.CardIdentity("Brain Freeze", ""));
cubeCards.add(new DraftCube.CardIdentity("Counterspell", ""));
cubeCards.add(new DraftCube.CardIdentity("Daze", ""));
cubeCards.add(new DraftCube.CardIdentity("Impulse", ""));
cubeCards.add(new DraftCube.CardIdentity("Mana Drain", ""));
cubeCards.add(new DraftCube.CardIdentity("Mana Leak", ""));
cubeCards.add(new DraftCube.CardIdentity("Miscalculation", ""));
cubeCards.add(new DraftCube.CardIdentity("Remand", ""));
cubeCards.add(new DraftCube.CardIdentity("Frantic Search", ""));
cubeCards.add(new DraftCube.CardIdentity("Thirst for Knowledge", ""));
cubeCards.add(new DraftCube.CardIdentity("Cryptic Command", ""));
cubeCards.add(new DraftCube.CardIdentity("Fact or Fiction", ""));
cubeCards.add(new DraftCube.CardIdentity("Gifts Ungiven", ""));
cubeCards.add(new DraftCube.CardIdentity("Turnabout", ""));
cubeCards.add(new DraftCube.CardIdentity("Force of Will", ""));
cubeCards.add(new DraftCube.CardIdentity("Gush", ""));
cubeCards.add(new DraftCube.CardIdentity("Mystic Confluence", ""));
cubeCards.add(new DraftCube.CardIdentity("Repeal", ""));
cubeCards.add(new DraftCube.CardIdentity("Dig Through Time", ""));
cubeCards.add(new DraftCube.CardIdentity("Ancestral Vision", ""));
cubeCards.add(new DraftCube.CardIdentity("Gitaxian Probe", ""));
cubeCards.add(new DraftCube.CardIdentity("Ponder", ""));
cubeCards.add(new DraftCube.CardIdentity("Preordain", ""));
cubeCards.add(new DraftCube.CardIdentity("Chart a Course", ""));
cubeCards.add(new DraftCube.CardIdentity("Time Walk", ""));
cubeCards.add(new DraftCube.CardIdentity("Show and Tell", ""));
cubeCards.add(new DraftCube.CardIdentity("Timetwister", ""));
cubeCards.add(new DraftCube.CardIdentity("Tinker", ""));
cubeCards.add(new DraftCube.CardIdentity("Bribery", ""));
cubeCards.add(new DraftCube.CardIdentity("Time Warp", ""));
cubeCards.add(new DraftCube.CardIdentity("Mind's Desire", ""));
cubeCards.add(new DraftCube.CardIdentity("Time Spiral", ""));
cubeCards.add(new DraftCube.CardIdentity("Upheaval", ""));
cubeCards.add(new DraftCube.CardIdentity("Treasure Cruise", ""));
cubeCards.add(new DraftCube.CardIdentity("Search for Azcanta", ""));
cubeCards.add(new DraftCube.CardIdentity("Control Magic", ""));
cubeCards.add(new DraftCube.CardIdentity("Opposition", ""));
cubeCards.add(new DraftCube.CardIdentity("Treachery", ""));
cubeCards.add(new DraftCube.CardIdentity("Shelldock Isle", ""));
cubeCards.add(new DraftCube.CardIdentity("Tolarian Academy", ""));
cubeCards.add(new DraftCube.CardIdentity("Putrid Imp", ""));
cubeCards.add(new DraftCube.CardIdentity("Dark Confidant", ""));
cubeCards.add(new DraftCube.CardIdentity("Kitesail Freebooter", ""));
cubeCards.add(new DraftCube.CardIdentity("Mesmeric Fiend", ""));
cubeCards.add(new DraftCube.CardIdentity("Oona's Prowler", ""));
cubeCards.add(new DraftCube.CardIdentity("Pack Rat", ""));
cubeCards.add(new DraftCube.CardIdentity("Vampire Hexmage", ""));
cubeCards.add(new DraftCube.CardIdentity("Bone Shredder", ""));
cubeCards.add(new DraftCube.CardIdentity("Hypnotic Specter", ""));
cubeCards.add(new DraftCube.CardIdentity("Ophiomancer", ""));
cubeCards.add(new DraftCube.CardIdentity("Plaguecrafter", ""));
cubeCards.add(new DraftCube.CardIdentity("Vampire Nighthawk", ""));
cubeCards.add(new DraftCube.CardIdentity("Gonti, Lord of Luxury", ""));
cubeCards.add(new DraftCube.CardIdentity("Nekrataal", ""));
cubeCards.add(new DraftCube.CardIdentity("Ravenous Chupacabra", ""));
cubeCards.add(new DraftCube.CardIdentity("Shriekmaw", ""));
cubeCards.add(new DraftCube.CardIdentity("Grave Titan", ""));
cubeCards.add(new DraftCube.CardIdentity("Ink-Eyes, Servant of Oni", ""));
cubeCards.add(new DraftCube.CardIdentity("Massacre Wurm", ""));
cubeCards.add(new DraftCube.CardIdentity("Tasigur, the Golden Fang", ""));
cubeCards.add(new DraftCube.CardIdentity("Sheoldred, Whispering One", ""));
cubeCards.add(new DraftCube.CardIdentity("Griselbrand", ""));
cubeCards.add(new DraftCube.CardIdentity("Liliana of the Veil", ""));
cubeCards.add(new DraftCube.CardIdentity("Liliana, Death's Majesty", ""));
cubeCards.add(new DraftCube.CardIdentity("Dark Ritual", ""));
cubeCards.add(new DraftCube.CardIdentity("Entomb", ""));
cubeCards.add(new DraftCube.CardIdentity("Fatal Push", ""));
cubeCards.add(new DraftCube.CardIdentity("Vampiric Tutor", ""));
cubeCards.add(new DraftCube.CardIdentity("Cabal Ritual", ""));
cubeCards.add(new DraftCube.CardIdentity("Go for the Throat", ""));
cubeCards.add(new DraftCube.CardIdentity("Liliana's Triumph", ""));
cubeCards.add(new DraftCube.CardIdentity("Shallow Grave", ""));
cubeCards.add(new DraftCube.CardIdentity("Ultimate Price", ""));
cubeCards.add(new DraftCube.CardIdentity("Corpse Dance", ""));
cubeCards.add(new DraftCube.CardIdentity("Dismember", ""));
cubeCards.add(new DraftCube.CardIdentity("Hero's Downfall", ""));
cubeCards.add(new DraftCube.CardIdentity("Makeshift Mannequin", ""));
cubeCards.add(new DraftCube.CardIdentity("Duress", ""));
cubeCards.add(new DraftCube.CardIdentity("Imperial Seal", ""));
cubeCards.add(new DraftCube.CardIdentity("Inquisition of Kozilek", ""));
cubeCards.add(new DraftCube.CardIdentity("Reanimate", ""));
cubeCards.add(new DraftCube.CardIdentity("Thoughtseize", ""));
cubeCards.add(new DraftCube.CardIdentity("Collective Brutality", ""));
cubeCards.add(new DraftCube.CardIdentity("Demonic Tutor", ""));
cubeCards.add(new DraftCube.CardIdentity("Exhume", ""));
cubeCards.add(new DraftCube.CardIdentity("Hymn to Tourach", ""));
cubeCards.add(new DraftCube.CardIdentity("Night's Whisper", ""));
cubeCards.add(new DraftCube.CardIdentity("Buried Alive", ""));
cubeCards.add(new DraftCube.CardIdentity("Toxic Deluge", ""));
cubeCards.add(new DraftCube.CardIdentity("Yawgmoth's Will", ""));
cubeCards.add(new DraftCube.CardIdentity("Damnation", ""));
cubeCards.add(new DraftCube.CardIdentity("Languish", ""));
cubeCards.add(new DraftCube.CardIdentity("Mastermind's Acquisition", ""));
cubeCards.add(new DraftCube.CardIdentity("Tendrils of Agony", ""));
cubeCards.add(new DraftCube.CardIdentity("Dark Petition", ""));
cubeCards.add(new DraftCube.CardIdentity("Living Death", ""));
cubeCards.add(new DraftCube.CardIdentity("Mind Twist", ""));
cubeCards.add(new DraftCube.CardIdentity("Animate Dead", ""));
cubeCards.add(new DraftCube.CardIdentity("Bitterblossom", ""));
cubeCards.add(new DraftCube.CardIdentity("Necromancy", ""));
cubeCards.add(new DraftCube.CardIdentity("Phyrexian Arena", ""));
cubeCards.add(new DraftCube.CardIdentity("Recurring Nightmare", ""));
cubeCards.add(new DraftCube.CardIdentity("Yawgmoth's Bargain", ""));
cubeCards.add(new DraftCube.CardIdentity("Goblin Guide", ""));
cubeCards.add(new DraftCube.CardIdentity("Goblin Welder", ""));
cubeCards.add(new DraftCube.CardIdentity("Grim Lavamancer", ""));
cubeCards.add(new DraftCube.CardIdentity("Jackal Pup", ""));
cubeCards.add(new DraftCube.CardIdentity("Monastery Swiftspear", ""));
cubeCards.add(new DraftCube.CardIdentity("Zurgo Bellstriker", ""));
cubeCards.add(new DraftCube.CardIdentity("Abbot of Keral Keep", ""));
cubeCards.add(new DraftCube.CardIdentity("Dire Fleet Daredevil", ""));
cubeCards.add(new DraftCube.CardIdentity("Eidolon of the Great Revel", ""));
cubeCards.add(new DraftCube.CardIdentity("Runaway Steam-Kin", ""));
cubeCards.add(new DraftCube.CardIdentity("Young Pyromancer", ""));
cubeCards.add(new DraftCube.CardIdentity("Goblin Rabblemaster", ""));
cubeCards.add(new DraftCube.CardIdentity("Imperial Recruiter", ""));
cubeCards.add(new DraftCube.CardIdentity("Magus of the Moon", ""));
cubeCards.add(new DraftCube.CardIdentity("Avalanche Riders", ""));
cubeCards.add(new DraftCube.CardIdentity("Flametongue Kavu", ""));
cubeCards.add(new DraftCube.CardIdentity("Hazoret the Fervent", ""));
cubeCards.add(new DraftCube.CardIdentity("Hellrider", ""));
cubeCards.add(new DraftCube.CardIdentity("Pia and Kiran Nalaar", ""));
cubeCards.add(new DraftCube.CardIdentity("Rekindling Phoenix", ""));
cubeCards.add(new DraftCube.CardIdentity("Glorybringer", ""));
cubeCards.add(new DraftCube.CardIdentity("Goblin Dark-Dwellers", ""));
cubeCards.add(new DraftCube.CardIdentity("Kiki-Jiki, Mirror Breaker", ""));
cubeCards.add(new DraftCube.CardIdentity("Siege-Gang Commander", ""));
cubeCards.add(new DraftCube.CardIdentity("Thundermaw Hellkite", ""));
cubeCards.add(new DraftCube.CardIdentity("Zealous Conscripts", ""));
cubeCards.add(new DraftCube.CardIdentity("Inferno Titan", ""));
cubeCards.add(new DraftCube.CardIdentity("Chandra, Torch of Defiance", ""));
cubeCards.add(new DraftCube.CardIdentity("Daretti, Scrap Savant", ""));
cubeCards.add(new DraftCube.CardIdentity("Koth of the Hammer", ""));
cubeCards.add(new DraftCube.CardIdentity("Burst Lightning", ""));
cubeCards.add(new DraftCube.CardIdentity("Lightning Bolt", ""));
cubeCards.add(new DraftCube.CardIdentity("Abrade", ""));
cubeCards.add(new DraftCube.CardIdentity("Ancient Grudge", ""));
cubeCards.add(new DraftCube.CardIdentity("Desperate Ritual", ""));
cubeCards.add(new DraftCube.CardIdentity("Fire // Ice", ""));
cubeCards.add(new DraftCube.CardIdentity("Incinerate", ""));
cubeCards.add(new DraftCube.CardIdentity("Lightning Strike", ""));
cubeCards.add(new DraftCube.CardIdentity("Pyretic Ritual", ""));
cubeCards.add(new DraftCube.CardIdentity("Char", ""));
cubeCards.add(new DraftCube.CardIdentity("Seething Song", ""));
cubeCards.add(new DraftCube.CardIdentity("Through the Breach", ""));
cubeCards.add(new DraftCube.CardIdentity("Fireblast", ""));
cubeCards.add(new DraftCube.CardIdentity("Chain Lightning", ""));
cubeCards.add(new DraftCube.CardIdentity("Faithless Looting", ""));
cubeCards.add(new DraftCube.CardIdentity("Firebolt", ""));
cubeCards.add(new DraftCube.CardIdentity("Flame Slash", ""));
cubeCards.add(new DraftCube.CardIdentity("Mizzium Mortars", ""));
cubeCards.add(new DraftCube.CardIdentity("Pyroclasm", ""));
cubeCards.add(new DraftCube.CardIdentity("Light Up the Stage", ""));
cubeCards.add(new DraftCube.CardIdentity("Sweltering Suns", ""));
cubeCards.add(new DraftCube.CardIdentity("Wheel of Fortune", ""));
cubeCards.add(new DraftCube.CardIdentity("Empty the Warrens", ""));
cubeCards.add(new DraftCube.CardIdentity("Fiery Confluence", ""));
cubeCards.add(new DraftCube.CardIdentity("Past in Flames", ""));
cubeCards.add(new DraftCube.CardIdentity("Banefire", ""));
cubeCards.add(new DraftCube.CardIdentity("Burning of Xinye", ""));
cubeCards.add(new DraftCube.CardIdentity("Wildfire", ""));
cubeCards.add(new DraftCube.CardIdentity("Bonfire of the Damned", ""));
cubeCards.add(new DraftCube.CardIdentity("Mana Flare", ""));
cubeCards.add(new DraftCube.CardIdentity("Sulfuric Vortex", ""));
cubeCards.add(new DraftCube.CardIdentity("Sneak Attack", ""));
cubeCards.add(new DraftCube.CardIdentity("Splinter Twin", ""));
cubeCards.add(new DraftCube.CardIdentity("Arbor Elf", ""));
cubeCards.add(new DraftCube.CardIdentity("Avacyn's Pilgrim", ""));
cubeCards.add(new DraftCube.CardIdentity("Birds of Paradise", ""));
cubeCards.add(new DraftCube.CardIdentity("Elves of Deep Shadow", ""));
cubeCards.add(new DraftCube.CardIdentity("Elvish Mystic", ""));
cubeCards.add(new DraftCube.CardIdentity("Fyndhorn Elves", ""));
cubeCards.add(new DraftCube.CardIdentity("Joraga Treespeaker", ""));
cubeCards.add(new DraftCube.CardIdentity("Llanowar Elves", ""));
cubeCards.add(new DraftCube.CardIdentity("Noble Hierarch", ""));
cubeCards.add(new DraftCube.CardIdentity("Den Protector", ""));
cubeCards.add(new DraftCube.CardIdentity("Devoted Druid", ""));
cubeCards.add(new DraftCube.CardIdentity("Fauna Shaman", ""));
cubeCards.add(new DraftCube.CardIdentity("Incubation Druid", ""));
cubeCards.add(new DraftCube.CardIdentity("Lotus Cobra", ""));
cubeCards.add(new DraftCube.CardIdentity("Rofellos, Llanowar Emissary", ""));
cubeCards.add(new DraftCube.CardIdentity("Sakura-Tribe Elder", ""));
cubeCards.add(new DraftCube.CardIdentity("Scavenging Ooze", ""));
cubeCards.add(new DraftCube.CardIdentity("Sylvan Caryatid", ""));
cubeCards.add(new DraftCube.CardIdentity("Wall of Blossoms", ""));
cubeCards.add(new DraftCube.CardIdentity("Wall of Roots", ""));
cubeCards.add(new DraftCube.CardIdentity("Courser of Kruphix", ""));
cubeCards.add(new DraftCube.CardIdentity("Eternal Witness", ""));
cubeCards.add(new DraftCube.CardIdentity("Ramunap Excavator", ""));
cubeCards.add(new DraftCube.CardIdentity("Reclamation Sage", ""));
cubeCards.add(new DraftCube.CardIdentity("Tireless Tracker", ""));
cubeCards.add(new DraftCube.CardIdentity("Yavimaya Elder", ""));
cubeCards.add(new DraftCube.CardIdentity("Master of the Wild Hunt", ""));
cubeCards.add(new DraftCube.CardIdentity("Oracle of Mul Daya", ""));
cubeCards.add(new DraftCube.CardIdentity("Polukranos, World Eater", ""));
cubeCards.add(new DraftCube.CardIdentity("Acidic Slime", ""));
cubeCards.add(new DraftCube.CardIdentity("Biogenic Ooze", ""));
cubeCards.add(new DraftCube.CardIdentity("Deranged Hermit", ""));
cubeCards.add(new DraftCube.CardIdentity("Thragtusk", ""));
cubeCards.add(new DraftCube.CardIdentity("Whisperwood Elemental", ""));
cubeCards.add(new DraftCube.CardIdentity("Carnage Tyrant", ""));
cubeCards.add(new DraftCube.CardIdentity("Primeval Titan", ""));
cubeCards.add(new DraftCube.CardIdentity("Avenger of Zendikar", ""));
cubeCards.add(new DraftCube.CardIdentity("Craterhoof Behemoth", ""));
cubeCards.add(new DraftCube.CardIdentity("Terastodon", ""));
cubeCards.add(new DraftCube.CardIdentity("Woodfall Primus", ""));
cubeCards.add(new DraftCube.CardIdentity("Vivien, Champion of the Wilds", ""));
cubeCards.add(new DraftCube.CardIdentity("Garruk Relentless", ""));
cubeCards.add(new DraftCube.CardIdentity("Garruk Wildspeaker", ""));
cubeCards.add(new DraftCube.CardIdentity("Garruk, Primal Hunter", ""));
cubeCards.add(new DraftCube.CardIdentity("Vivien Reid", ""));
cubeCards.add(new DraftCube.CardIdentity("Nature's Claim", ""));
cubeCards.add(new DraftCube.CardIdentity("Beast Within", ""));
cubeCards.add(new DraftCube.CardIdentity("Channel", ""));
cubeCards.add(new DraftCube.CardIdentity("Regrowth", ""));
cubeCards.add(new DraftCube.CardIdentity("Kodama's Reach", ""));
cubeCards.add(new DraftCube.CardIdentity("Search for Tomorrow", ""));
cubeCards.add(new DraftCube.CardIdentity("Eureka", ""));
cubeCards.add(new DraftCube.CardIdentity("Harmonize", ""));
cubeCards.add(new DraftCube.CardIdentity("Natural Order", ""));
cubeCards.add(new DraftCube.CardIdentity("Plow Under", ""));
cubeCards.add(new DraftCube.CardIdentity("Primal Command", ""));
cubeCards.add(new DraftCube.CardIdentity("Green Sun's Zenith", ""));
cubeCards.add(new DraftCube.CardIdentity("Finale of Devastation", ""));
cubeCards.add(new DraftCube.CardIdentity("Tooth and Nail", ""));
cubeCards.add(new DraftCube.CardIdentity("Fastbond", ""));
cubeCards.add(new DraftCube.CardIdentity("Oath of Druids", ""));
cubeCards.add(new DraftCube.CardIdentity("Survival of the Fittest", ""));
cubeCards.add(new DraftCube.CardIdentity("Sylvan Library", ""));
cubeCards.add(new DraftCube.CardIdentity("Heartbeat of Spring", ""));
cubeCards.add(new DraftCube.CardIdentity("Wilderness Reclamation", ""));
cubeCards.add(new DraftCube.CardIdentity("Gaea's Cradle", ""));
cubeCards.add(new DraftCube.CardIdentity("Geist of Saint Traft", ""));
cubeCards.add(new DraftCube.CardIdentity("Teferi, Hero of Dominaria", ""));
cubeCards.add(new DraftCube.CardIdentity("Sphinx's Revelation", ""));
cubeCards.add(new DraftCube.CardIdentity("Fractured Identity", ""));
cubeCards.add(new DraftCube.CardIdentity("Celestial Colonnade", ""));
cubeCards.add(new DraftCube.CardIdentity("Flooded Strand", ""));
cubeCards.add(new DraftCube.CardIdentity("Hallowed Fountain", ""));
cubeCards.add(new DraftCube.CardIdentity("Seachrome Coast", ""));
cubeCards.add(new DraftCube.CardIdentity("Tundra", ""));
cubeCards.add(new DraftCube.CardIdentity("Thief of Sanity", ""));
cubeCards.add(new DraftCube.CardIdentity("The Scarab God", ""));
cubeCards.add(new DraftCube.CardIdentity("Ashiok, Nightmare Weaver", ""));
cubeCards.add(new DraftCube.CardIdentity("Baleful Strix", ""));
cubeCards.add(new DraftCube.CardIdentity("Creeping Tar Pit", ""));
cubeCards.add(new DraftCube.CardIdentity("Darkslick Shores", ""));
cubeCards.add(new DraftCube.CardIdentity("Polluted Delta", ""));
cubeCards.add(new DraftCube.CardIdentity("Underground Sea", ""));
cubeCards.add(new DraftCube.CardIdentity("Watery Grave", ""));
cubeCards.add(new DraftCube.CardIdentity("Daretti, Ingenious Iconoclast", ""));
cubeCards.add(new DraftCube.CardIdentity("Terminate", ""));
cubeCards.add(new DraftCube.CardIdentity("Kolaghan's Command", ""));
cubeCards.add(new DraftCube.CardIdentity("Rakdos's Return", ""));
cubeCards.add(new DraftCube.CardIdentity("Badlands", ""));
cubeCards.add(new DraftCube.CardIdentity("Blackcleave Cliffs", ""));
cubeCards.add(new DraftCube.CardIdentity("Blood Crypt", ""));
cubeCards.add(new DraftCube.CardIdentity("Bloodstained Mire", ""));
cubeCards.add(new DraftCube.CardIdentity("Lavaclaw Reaches", ""));
cubeCards.add(new DraftCube.CardIdentity("Bloodbraid Elf", ""));
cubeCards.add(new DraftCube.CardIdentity("Huntmaster of the Fells", ""));
cubeCards.add(new DraftCube.CardIdentity("Dragonlord Atarka", ""));
cubeCards.add(new DraftCube.CardIdentity("Manamorphose", ""));
cubeCards.add(new DraftCube.CardIdentity("Copperline Gorge", ""));
cubeCards.add(new DraftCube.CardIdentity("Raging Ravine", ""));
cubeCards.add(new DraftCube.CardIdentity("Stomping Ground", ""));
cubeCards.add(new DraftCube.CardIdentity("Taiga", ""));
cubeCards.add(new DraftCube.CardIdentity("Wooded Foothills", ""));
cubeCards.add(new DraftCube.CardIdentity("Kitchen Finks", ""));
cubeCards.add(new DraftCube.CardIdentity("Knight of Autumn", ""));
cubeCards.add(new DraftCube.CardIdentity("Knight of the Reliquary", ""));
cubeCards.add(new DraftCube.CardIdentity("Trostani Discordant", ""));
cubeCards.add(new DraftCube.CardIdentity("Mirari's Wake", ""));
cubeCards.add(new DraftCube.CardIdentity("Razorverge Thicket", ""));
cubeCards.add(new DraftCube.CardIdentity("Savannah", ""));
cubeCards.add(new DraftCube.CardIdentity("Stirring Wildwood", ""));
cubeCards.add(new DraftCube.CardIdentity("Temple Garden", ""));
cubeCards.add(new DraftCube.CardIdentity("Windswept Heath", ""));
cubeCards.add(new DraftCube.CardIdentity("Ashen Rider", ""));
cubeCards.add(new DraftCube.CardIdentity("Kaya, Orzhov Usurper", ""));
cubeCards.add(new DraftCube.CardIdentity("Tidehollow Sculler", ""));
cubeCards.add(new DraftCube.CardIdentity("Anguished Unmaking", ""));
cubeCards.add(new DraftCube.CardIdentity("Lingering Souls", ""));
cubeCards.add(new DraftCube.CardIdentity("Vindicate", ""));
cubeCards.add(new DraftCube.CardIdentity("Unburial Rites", ""));
cubeCards.add(new DraftCube.CardIdentity("Concealed Courtyard", ""));
cubeCards.add(new DraftCube.CardIdentity("Godless Shrine", ""));
cubeCards.add(new DraftCube.CardIdentity("Marsh Flats", ""));
cubeCards.add(new DraftCube.CardIdentity("Scrubland", ""));
cubeCards.add(new DraftCube.CardIdentity("Shambling Vent", ""));
cubeCards.add(new DraftCube.CardIdentity("Vraska, Golgari Queen", ""));
cubeCards.add(new DraftCube.CardIdentity("Assassin's Trophy", ""));
cubeCards.add(new DraftCube.CardIdentity("Maelstrom Pulse", ""));
cubeCards.add(new DraftCube.CardIdentity("Pernicious Deed", ""));
cubeCards.add(new DraftCube.CardIdentity("Bayou", ""));
cubeCards.add(new DraftCube.CardIdentity("Blooming Marsh", ""));
cubeCards.add(new DraftCube.CardIdentity("Hissing Quagmire", ""));
cubeCards.add(new DraftCube.CardIdentity("Overgrown Tomb", ""));
cubeCards.add(new DraftCube.CardIdentity("Verdant Catacombs", ""));
cubeCards.add(new DraftCube.CardIdentity("Edric, Spymaster of Trest", ""));
cubeCards.add(new DraftCube.CardIdentity("Trygon Predator", ""));
cubeCards.add(new DraftCube.CardIdentity("Hydroid Krasis", ""));
cubeCards.add(new DraftCube.CardIdentity("Shardless Agent", ""));
cubeCards.add(new DraftCube.CardIdentity("Botanical Sanctum", ""));
cubeCards.add(new DraftCube.CardIdentity("Breeding Pool", ""));
cubeCards.add(new DraftCube.CardIdentity("Lumbering Falls", ""));
cubeCards.add(new DraftCube.CardIdentity("Misty Rainforest", ""));
cubeCards.add(new DraftCube.CardIdentity("Tropical Island", ""));
cubeCards.add(new DraftCube.CardIdentity("Goblin Electromancer", ""));
cubeCards.add(new DraftCube.CardIdentity("Dack Fayden", ""));
cubeCards.add(new DraftCube.CardIdentity("Thousand-Year Storm", ""));
cubeCards.add(new DraftCube.CardIdentity("Scalding Tarn", ""));
cubeCards.add(new DraftCube.CardIdentity("Spirebluff Canal", ""));
cubeCards.add(new DraftCube.CardIdentity("Steam Vents", ""));
cubeCards.add(new DraftCube.CardIdentity("Volcanic Island", ""));
cubeCards.add(new DraftCube.CardIdentity("Wandering Fumarole", ""));
cubeCards.add(new DraftCube.CardIdentity("Figure of Destiny", ""));
cubeCards.add(new DraftCube.CardIdentity("Ajani Vengeant", ""));
cubeCards.add(new DraftCube.CardIdentity("Nahiri, the Harbinger", ""));
cubeCards.add(new DraftCube.CardIdentity("Wear // Tear", ""));
cubeCards.add(new DraftCube.CardIdentity("Lightning Helix", ""));
cubeCards.add(new DraftCube.CardIdentity("Arid Mesa", ""));
cubeCards.add(new DraftCube.CardIdentity("Inspiring Vantage", ""));
cubeCards.add(new DraftCube.CardIdentity("Needle Spires", ""));
cubeCards.add(new DraftCube.CardIdentity("Plateau", ""));
cubeCards.add(new DraftCube.CardIdentity("Sacred Foundry", ""));
cubeCards.add(new DraftCube.CardIdentity("Sphinx of the Steel Wind", ""));
cubeCards.add(new DraftCube.CardIdentity("Nicol Bolas, Dragon-God", ""));
cubeCards.add(new DraftCube.CardIdentity("Leovold, Emissary of Trest", ""));
cubeCards.add(new DraftCube.CardIdentity("Progenitus", ""));
cubeCards.add(new DraftCube.CardIdentity("Kozilek, Butcher of Truth", ""));
cubeCards.add(new DraftCube.CardIdentity("Ulamog, the Ceaseless Hunger", ""));
cubeCards.add(new DraftCube.CardIdentity("Ulamog, the Infinite Gyre", ""));
cubeCards.add(new DraftCube.CardIdentity("Emrakul, the Promised End", ""));
cubeCards.add(new DraftCube.CardIdentity("Emrakul, the Aeons Torn", ""));
cubeCards.add(new DraftCube.CardIdentity("Karn, Scion of Urza", ""));
cubeCards.add(new DraftCube.CardIdentity("Karn Liberated", ""));
cubeCards.add(new DraftCube.CardIdentity("Ugin, the Spirit Dragon", ""));
cubeCards.add(new DraftCube.CardIdentity("Bomat Courier", ""));
cubeCards.add(new DraftCube.CardIdentity("Hangarback Walker", ""));
cubeCards.add(new DraftCube.CardIdentity("Phyrexian Revoker", ""));
cubeCards.add(new DraftCube.CardIdentity("Metalworker", ""));
cubeCards.add(new DraftCube.CardIdentity("Lodestone Golem", ""));
cubeCards.add(new DraftCube.CardIdentity("Solemn Simulacrum", ""));
cubeCards.add(new DraftCube.CardIdentity("Kuldotha Forgemaster", ""));
cubeCards.add(new DraftCube.CardIdentity("Wurmcoil Engine", ""));
cubeCards.add(new DraftCube.CardIdentity("Myr Battlesphere", ""));
cubeCards.add(new DraftCube.CardIdentity("Sundering Titan", ""));
cubeCards.add(new DraftCube.CardIdentity("Walking Ballista", ""));
cubeCards.add(new DraftCube.CardIdentity("Blightsteel Colossus", ""));
cubeCards.add(new DraftCube.CardIdentity("Black Lotus", ""));
cubeCards.add(new DraftCube.CardIdentity("Chrome Mox", ""));
cubeCards.add(new DraftCube.CardIdentity("Everflowing Chalice", ""));
cubeCards.add(new DraftCube.CardIdentity("Lion's Eye Diamond", ""));
cubeCards.add(new DraftCube.CardIdentity("Lotus Bloom", ""));
cubeCards.add(new DraftCube.CardIdentity("Mana Crypt", ""));
cubeCards.add(new DraftCube.CardIdentity("Mox Diamond", ""));
cubeCards.add(new DraftCube.CardIdentity("Mox Emerald", ""));
cubeCards.add(new DraftCube.CardIdentity("Mox Jet", ""));
cubeCards.add(new DraftCube.CardIdentity("Mox Pearl", ""));
cubeCards.add(new DraftCube.CardIdentity("Mox Ruby", ""));
cubeCards.add(new DraftCube.CardIdentity("Mox Sapphire", ""));
cubeCards.add(new DraftCube.CardIdentity("Mana Vault", ""));
cubeCards.add(new DraftCube.CardIdentity("Relic of Progenitus", ""));
cubeCards.add(new DraftCube.CardIdentity("Sensei's Divining Top", ""));
cubeCards.add(new DraftCube.CardIdentity("Skullclamp", ""));
cubeCards.add(new DraftCube.CardIdentity("Sol Ring", ""));
cubeCards.add(new DraftCube.CardIdentity("Azorius Signet", ""));
cubeCards.add(new DraftCube.CardIdentity("Boros Signet", ""));
cubeCards.add(new DraftCube.CardIdentity("Dimir Signet", ""));
cubeCards.add(new DraftCube.CardIdentity("Golgari Signet", ""));
cubeCards.add(new DraftCube.CardIdentity("Grim Monolith", ""));
cubeCards.add(new DraftCube.CardIdentity("Gruul Signet", ""));
cubeCards.add(new DraftCube.CardIdentity("Izzet Signet", ""));
cubeCards.add(new DraftCube.CardIdentity("Lightning Greaves", ""));
cubeCards.add(new DraftCube.CardIdentity("Orzhov Signet", ""));
cubeCards.add(new DraftCube.CardIdentity("Rakdos Signet", ""));
cubeCards.add(new DraftCube.CardIdentity("Selesnya Signet", ""));
cubeCards.add(new DraftCube.CardIdentity("Shrine of Burning Rage", ""));
cubeCards.add(new DraftCube.CardIdentity("Simic Signet", ""));
cubeCards.add(new DraftCube.CardIdentity("Smuggler's Copter", ""));
cubeCards.add(new DraftCube.CardIdentity("Umezawa's Jitte", ""));
cubeCards.add(new DraftCube.CardIdentity("Winter Orb", ""));
cubeCards.add(new DraftCube.CardIdentity("Basalt Monolith", ""));
cubeCards.add(new DraftCube.CardIdentity("Coalition Relic", ""));
cubeCards.add(new DraftCube.CardIdentity("Crucible of Worlds", ""));
cubeCards.add(new DraftCube.CardIdentity("Oblivion Stone", ""));
cubeCards.add(new DraftCube.CardIdentity("Sword of Body and Mind", ""));
cubeCards.add(new DraftCube.CardIdentity("Sword of Feast and Famine", ""));
cubeCards.add(new DraftCube.CardIdentity("Sword of Fire and Ice", ""));
cubeCards.add(new DraftCube.CardIdentity("Sword of Light and Shadow", ""));
cubeCards.add(new DraftCube.CardIdentity("Sword of War and Peace", ""));
cubeCards.add(new DraftCube.CardIdentity("Tangle Wire", ""));
cubeCards.add(new DraftCube.CardIdentity("Worn Powerstone", ""));
cubeCards.add(new DraftCube.CardIdentity("Coercive Portal", ""));
cubeCards.add(new DraftCube.CardIdentity("Smokestack", ""));
cubeCards.add(new DraftCube.CardIdentity("Thran Dynamo", ""));
cubeCards.add(new DraftCube.CardIdentity("Batterskull", ""));
cubeCards.add(new DraftCube.CardIdentity("Memory Jar", ""));
cubeCards.add(new DraftCube.CardIdentity("Mindslaver", ""));
cubeCards.add(new DraftCube.CardIdentity("Academy Ruins", ""));
cubeCards.add(new DraftCube.CardIdentity("Ancient Tomb", ""));
cubeCards.add(new DraftCube.CardIdentity("Bazaar of Baghdad", ""));
cubeCards.add(new DraftCube.CardIdentity("Blast Zone", ""));
cubeCards.add(new DraftCube.CardIdentity("Field of Ruin", ""));
cubeCards.add(new DraftCube.CardIdentity("Library of Alexandria", ""));
cubeCards.add(new DraftCube.CardIdentity("Maze of Ith", ""));
cubeCards.add(new DraftCube.CardIdentity("Mishra's Factory", ""));
cubeCards.add(new DraftCube.CardIdentity("Mishra's Workshop", ""));
cubeCards.add(new DraftCube.CardIdentity("Mutavault", ""));
cubeCards.add(new DraftCube.CardIdentity("Nykthos, Shrine to Nyx", ""));
cubeCards.add(new DraftCube.CardIdentity("Rishadan Port", ""));
cubeCards.add(new DraftCube.CardIdentity("Strip Mine", ""));
cubeCards.add(new DraftCube.CardIdentity("Wasteland", ""));
cubeCards.add(new DraftCube.CardIdentity("Expansion // Explosion", ""));
cubeCards.add(new DraftCube.CardIdentity("Giver of Runes", ""));
cubeCards.add(new DraftCube.CardIdentity("Winds of Abandon", ""));
cubeCards.add(new DraftCube.CardIdentity("Hallowed Spiritkeeper", ""));
cubeCards.add(new DraftCube.CardIdentity("Thraben Inspector", ""));
cubeCards.add(new DraftCube.CardIdentity("Narset, Parter of Veils", ""));
cubeCards.add(new DraftCube.CardIdentity("Force of Negation", ""));
cubeCards.add(new DraftCube.CardIdentity("Urza, Lord High Artificer", ""));
cubeCards.add(new DraftCube.CardIdentity("Emry, Lurker of the Loch", ""));
cubeCards.add(new DraftCube.CardIdentity("Brazen Borrower", ""));
cubeCards.add(new DraftCube.CardIdentity("Bolas's Citadel", ""));
cubeCards.add(new DraftCube.CardIdentity("Yawgmoth, Thran Physician", ""));
cubeCards.add(new DraftCube.CardIdentity("Rotting Regisaur", ""));
cubeCards.add(new DraftCube.CardIdentity("Murderous Rider", ""));
cubeCards.add(new DraftCube.CardIdentity("Wishclaw Talisman", ""));
cubeCards.add(new DraftCube.CardIdentity("Dreadhorde Arcanist", ""));
cubeCards.add(new DraftCube.CardIdentity("Seasoned Pyromancer", ""));
cubeCards.add(new DraftCube.CardIdentity("Embereth Shieldbreaker", ""));
cubeCards.add(new DraftCube.CardIdentity("Nissa, Who Shakes the World", ""));
cubeCards.add(new DraftCube.CardIdentity("Questing Beast", ""));
cubeCards.add(new DraftCube.CardIdentity("Teferi, Time Raveler", ""));
cubeCards.add(new DraftCube.CardIdentity("Angrath's Rampage", ""));
cubeCards.add(new DraftCube.CardIdentity("Fallen Shinobi", ""));
cubeCards.add(new DraftCube.CardIdentity("Wrenn and Six", ""));
cubeCards.add(new DraftCube.CardIdentity("Oko, Thief of Crowns", ""));
cubeCards.add(new DraftCube.CardIdentity("Garruk, Cursed Huntsman", ""));
cubeCards.add(new DraftCube.CardIdentity("Prismatic Vista", ""));
cubeCards.add(new DraftCube.CardIdentity("Golos, Tireless Pilgrim", ""));
cubeCards.add(new DraftCube.CardIdentity("Stonecoil Serpent", ""));
}
}

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-tournament-constructed</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-tournament-sealed</artifactId>

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-server-plugins</artifactId>

View file

@ -140,6 +140,7 @@
<draftCube name="MTGO Vintage Cube June 2018" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeJune2018"/>
<draftCube name="MTGO Vintage Cube December 2018" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeDecember2018"/>
<draftCube name="MTGO Vintage Cube June 2019" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeJune2019"/>
<draftCube name="MTGO Vintage Cube December 2019" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeDecember2019"/>
<draftCube name="SCG Con Cube 2018 December" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.ScgConCube2018December"/>
<draftCube name="The Peasant's Toolbox" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.PeasantsToolboxCube"/>
<draftCube name="www.MTGCube.com" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.MTGCube"/>

View file

@ -6,7 +6,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-server</artifactId>
@ -136,6 +136,12 @@
<version>${project.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>mage-player-ai-mcts</artifactId>
<version>${project.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>mage-tournament-boosterdraft</artifactId>

View file

@ -134,6 +134,7 @@
<draftCube name="MTGO Vintage Cube June 2018" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeJune2018"/>
<draftCube name="MTGO Vintage Cube December 2018" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeDecember2018"/>
<draftCube name="MTGO Vintage Cube June 2019" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeJune2019"/>
<draftCube name="MTGO Vintage Cube December 2019" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeDecember2019"/>
<draftCube name="SCG Con Cube 2018 December" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.ScgConCube2018December"/>
<draftCube name="The Peasant's Toolbox" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.PeasantsToolboxCube"/>
<draftCube name="www.MTGCube.com" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.MTGCube"/>

View file

@ -483,12 +483,18 @@ public final class SystemUtil {
gameZone = Zone.LIBRARY;
} else if ("token".equalsIgnoreCase(command.zone)) {
gameZone = Zone.BATTLEFIELD;
} else if ("exiled".equalsIgnoreCase(command.zone)) {
gameZone = Zone.EXILED;
} else if ("outside".equalsIgnoreCase(command.zone)) {
gameZone = Zone.OUTSIDE;
} else if ("emblem".equalsIgnoreCase(command.zone)) {
gameZone = Zone.COMMAND;
} else if ("plane".equalsIgnoreCase(command.zone)) {
gameZone = Zone.COMMAND;
} else if ("commander".equalsIgnoreCase(command.zone)) {
gameZone = Zone.COMMAND;
} else if ("sideboard".equalsIgnoreCase(command.zone)) {
gameZone = Zone.OUTSIDE;
} else {
logger.warn("Unknown zone [" + command.zone + "]: " + line);
continue;
@ -527,6 +533,11 @@ public final class SystemUtil {
} else {
logger.fatal("Commander card can be used in commander game only: " + command.cardName);
}
} else if ("sideboard".equalsIgnoreCase(command.zone) && cardsToLoad.size() > 0) {
// put to sideboard
for (Card card : cardsToLoad) {
player.getSideboard().add(card);
}
} else {
// as other card
for (Card card : cardsToLoad) {
@ -560,8 +571,17 @@ public final class SystemUtil {
break;
case STACK:
card.cast(game, Zone.EXILED, card.getSpellAbility(), player.getId());
break;
case EXILED:
// nothing to do
break;
case OUTSIDE:
card.setZone(Zone.OUTSIDE, game);
game.getExile().getPermanentExile().remove(card);
break;
default:
card.moveToZone(zone, null, game, false);
break;
}
logger.info("Added card to player's " + zone.toString() + ": " + card.getName() + ", player = " + player.getName());
}

View file

@ -7,7 +7,7 @@
<parent>
<groupId>org.mage</groupId>
<artifactId>mage-root</artifactId>
<version>1.4.40</version>
<version>1.4.41</version>
</parent>
<artifactId>mage-sets</artifactId>

View file

@ -1,14 +1,14 @@
package mage.cards.a;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.DevotionCount;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.SacrificeControllerEffect;
import mage.abilities.hint.ValueHint;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -18,14 +18,16 @@ import mage.constants.SubType;
import mage.constants.TargetController;
import mage.filter.StaticFilters;
import mage.game.permanent.token.TokenImpl;
import mage.game.permanent.token.Token;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class AbhorrentOverlord extends CardImpl {
private static final DynamicValue xValue = new DevotionCount(ColoredManaSymbol.B);
public AbhorrentOverlord(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}{B}");
this.subtype.add(SubType.DEMON);
@ -35,10 +37,12 @@ public final class AbhorrentOverlord extends CardImpl {
// Flying
this.addAbility(FlyingAbility.getInstance());
// When Abhorrent Overlord enters the battlefield, create a number of 1/1 black Harpy creature tokens with flying equal to your devotion to black.
Effect effect = new CreateTokenEffect(new AbhorrentOverlordHarpyToken(), new DevotionCount(ColoredManaSymbol.B));
Effect effect = new CreateTokenEffect(new AbhorrentOverlordHarpyToken(), xValue);
effect.setText("create a number of 1/1 black Harpy creature tokens with flying equal to your devotion to black. <i>(Each {B} in the mana costs of permanents you control counts toward your devotion to black.)</i>");
this.addAbility(new EntersBattlefieldTriggeredAbility(effect));
this.addAbility(new EntersBattlefieldTriggeredAbility(effect).addHint(new ValueHint("Devotion to black", xValue)));
// At the beginning of your upkeep, sacrifice a creature.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new SacrificeControllerEffect(StaticFilters.FILTER_PERMANENT_CREATURE, 1, null), TargetController.YOU, false));
}
@ -65,6 +69,7 @@ class AbhorrentOverlordHarpyToken extends TokenImpl {
this.addAbility(FlyingAbility.getInstance());
}
public AbhorrentOverlordHarpyToken(final AbhorrentOverlordHarpyToken token) {
super(token);
}

View file

@ -1,36 +1,39 @@
package mage.cards.a;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.DevotionCount;
import mage.abilities.effects.PreventionEffectImpl;
import mage.abilities.hint.ValueHint;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.ColoredManaSymbol;
import mage.constants.Duration;
import mage.game.Game;
import mage.game.events.DamageEvent;
import mage.game.events.GameEvent;
import mage.game.events.PreventDamageEvent;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetAnyTarget;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class AcolytesReward extends CardImpl {
public AcolytesReward(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{W}");
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}");
// Prevent the next X damage that would be dealt to target creature this turn, where X is your devotion to white. If damage is prevented this way, Acolyte's Reward deals that much damage to any target.
this.getSpellAbility().addEffect(new AcolytesRewardEffect());
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
this.getSpellAbility().addTarget(new TargetAnyTarget());
this.getSpellAbility().addHint(new ValueHint("Devotion to white", AcolytesRewardEffect.xValue));
}
public AcolytesReward(final AcolytesReward card) {
@ -46,6 +49,7 @@ public final class AcolytesReward extends CardImpl {
class AcolytesRewardEffect extends PreventionEffectImpl {
protected int amount = 0;
static final DynamicValue xValue = new DevotionCount(ColoredManaSymbol.W);
public AcolytesRewardEffect() {
super(Duration.EndOfTurn);
@ -65,7 +69,7 @@ class AcolytesRewardEffect extends PreventionEffectImpl {
@Override
public void init(Ability source, Game game) {
super.init(source, game);
amount = new DevotionCount(ColoredManaSymbol.W).calculate(game, source, this);
amount = xValue.calculate(game, source, this);
}
@Override
@ -83,7 +87,7 @@ class AcolytesRewardEffect extends PreventionEffectImpl {
} else {
amount = 0;
}
GameEvent preventEvent = new GameEvent(GameEvent.EventType.PREVENT_DAMAGE, source.getControllerId(), source.getSourceId(), source.getControllerId(), toPrevent, false);
GameEvent preventEvent = new PreventDamageEvent(source.getControllerId(), source.getSourceId(), source.getControllerId(), toPrevent, ((DamageEvent) event).isCombatDamage());
if (!game.replaceEvent(preventEvent)) {
Permanent targetCreature = game.getPermanent(source.getFirstTarget());
if (targetCreature != null) {

View file

@ -1,7 +1,5 @@
package mage.cards.a;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
@ -20,8 +18,9 @@ import mage.game.events.GameEvent.EventType;
import mage.game.permanent.Permanent;
import mage.target.common.TargetOpponentOrPlaneswalker;
import java.util.UUID;
/**
*
* @author escplan9 (Derek Monturo - dmontur1 at gmail dot com)
*/
public final class AetherCharge extends CardImpl {
@ -69,7 +68,7 @@ class AetherChargeTriggeredAbility extends TriggeredAbilityImpl {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
Permanent permanent = game.getPermanent(event.getTargetId());
if (permanent.isCreature() && permanent.hasSubtype(SubType.BEAST, game)
if (permanent != null && permanent.isCreature() && permanent.hasSubtype(SubType.BEAST, game)
&& permanent.isControlledBy(this.controllerId)) {
Effect effect = this.getEffects().get(0);
effect.setValue("damageSource", event.getTargetId());

View file

@ -1,4 +1,3 @@
package mage.cards.a;
import mage.abilities.Ability;
@ -21,13 +20,12 @@ import java.util.List;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class Aetherspouts extends CardImpl {
public Aetherspouts(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{U}{U}");
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{U}{U}");
// For each attacking creature, its owner puts it on the top or bottom of their library.
@ -73,14 +71,14 @@ class AetherspoutsEffect extends OneShotEffect {
game.getPlayerList();
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
PlayerList playerList = game.getPlayerList();
PlayerList playerList = game.getPlayerList().copy();
playerList.setCurrent(game.getActivePlayerId());
Player player = game.getPlayer(game.getActivePlayerId());
Player activePlayer = player;
do {
List<Permanent> permanentsToTop = new ArrayList<>();
List<Permanent> permanentsToBottom = new ArrayList<>();
for (Permanent permanent:game.getState().getBattlefield().getActivePermanents(new FilterAttackingCreature(), player.getId(), source.getSourceId(), game)) {
for (Permanent permanent : game.getState().getBattlefield().getActivePermanents(new FilterAttackingCreature(), player.getId(), source.getSourceId(), game)) {
if (permanent.isOwnedBy(player.getId())) {
if (player.chooseUse(outcome, "Put " + permanent.getLogName() + " to the top? (else it goes to bottom)", source, game)) {
permanentsToTop.add(permanent);
@ -94,7 +92,7 @@ class AetherspoutsEffect extends OneShotEffect {
// cards to top
Cards cards = new CardsImpl();
List<Permanent> toLibrary = new ArrayList<>();
for (Permanent permanent: permanentsToTop) {
for (Permanent permanent : permanentsToTop) {
if (permanent instanceof PermanentToken) {
toLibrary.add(permanent);
} else {
@ -128,13 +126,13 @@ class AetherspoutsEffect extends OneShotEffect {
}
}
// move all permanents to lib at the same time
for(Permanent permanent: toLibrary) {
for (Permanent permanent : toLibrary) {
player.moveCardToLibraryWithInfo(permanent, source.getSourceId(), game, Zone.BATTLEFIELD, true, false);
}
// cards to bottom
cards.clear();
toLibrary.clear();
for (Permanent permanent: permanentsToBottom) {
for (Permanent permanent : permanentsToBottom) {
if (permanent instanceof PermanentToken) {
toLibrary.add(permanent);
} else {
@ -161,15 +159,15 @@ class AetherspoutsEffect extends OneShotEffect {
if (cards.size() == 1) {
Card card = cards.get(cards.iterator().next(), game);
Permanent permanent = game.getPermanent(card.getId());
if (permanent != null) {
if (permanent != null) {
toLibrary.add(permanent);
}
}
// move all permanents to lib at the same time
for(Permanent permanent: toLibrary) {
for (Permanent permanent : toLibrary) {
player.moveCardToLibraryWithInfo(permanent, source.getSourceId(), game, Zone.BATTLEFIELD, false, false);
}
player = playerList.getNext(game);
player = playerList.getNext(game, false);
} while (player != null && !player.getId().equals(game.getActivePlayerId()) && activePlayer.canRespond());
return true;
}

View file

@ -1,4 +1,3 @@
package mage.cards.a;
import java.util.UUID;
@ -19,7 +18,7 @@ import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.filter.common.FilterCreatureCard;
import mage.filter.StaticFilters;
import mage.target.common.TargetCreaturePermanent;
/**
@ -41,7 +40,7 @@ public final class AjaniValiantProtector extends CardImpl {
this.addAbility(ability);
// +1: Reveal cards from the top of your library until you reveal a creature card. Put that card into your hand and the rest on the bottom of your library in a random order.
this.addAbility(new LoyaltyAbility(new RevealCardsFromLibraryUntilEffect(new FilterCreatureCard(), Zone.HAND, Zone.LIBRARY), 1));
this.addAbility(new LoyaltyAbility(new RevealCardsFromLibraryUntilEffect(StaticFilters.FILTER_CARD_CREATURE, Zone.HAND, Zone.LIBRARY), 1));
// -11: Put X +1/+1 counters on target creature, where X is your life total. That creature gains trample until end of turn.
Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance(), ControllerLifeCount.instance);

View file

@ -1,4 +1,3 @@
package mage.cards.a;
import java.util.UUID;
@ -7,8 +6,8 @@ import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.filter.StaticFilters;
import static mage.filter.StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT;
import mage.filter.common.FilterCreatureCard;
import mage.target.common.TargetCardInLibrary;
import mage.target.common.TargetControlledCreaturePermanent;
@ -24,7 +23,7 @@ public final class AltarOfBone extends CardImpl {
// As an additional cost to cast Altar of Bone, sacrifice a creature.
this.getSpellAbility().addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT)));
// Search your library for a creature card, reveal that card, and put it into your hand. Then shuffle your library.
this.getSpellAbility().addEffect(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(new FilterCreatureCard()), true));
this.getSpellAbility().addEffect(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_CREATURE), true));
}
public AltarOfBone(final AltarOfBone card) {

View file

@ -1,6 +1,5 @@
package mage.cards.a;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
@ -13,18 +12,21 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.filter.common.FilterCreatureCard;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardIdPredicate;
import mage.target.Target;
import mage.target.common.TargetCardInGraveyardOrBattlefield;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class AngelOfSerenity extends CardImpl {
private static final String rule = "you may exile up to three other target creatures from the battlefield and/or creature cards from graveyards.";
public AngelOfSerenity(UUID ownerId, CardSetInfo setInfo) {
@ -38,10 +40,11 @@ public final class AngelOfSerenity extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
// When Angel of Serenity enters the battlefield, you may exile up to three other target creatures from the battlefield and/or creature cards from graveyards.
FilterCreatureCard filter = new FilterCreatureCard("creatures from the battlefield and/or a graveyard");
filter.add(Predicates.not(new CardIdPredicate(this.getId())));
FilterCreaturePermanent filterBattle = new FilterCreaturePermanent("other target creatures");
filterBattle.add(Predicates.not(new CardIdPredicate(this.getId())));
FilterCreatureCard filterGrave = StaticFilters.FILTER_CARD_CREATURE;
Ability ability = new EntersBattlefieldTriggeredAbility(new ExileTargetForSourceEffect().setText(rule), true);
Target target = new TargetCardInGraveyardOrBattlefield(0, 3, filter);
Target target = new TargetCardInGraveyardOrBattlefield(0, 3, filterGrave, filterBattle);
ability.addTarget(target);
this.addAbility(ability);

View file

@ -1,7 +1,5 @@
package mage.cards.a;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.OneShotEffect;
@ -16,14 +14,15 @@ import mage.game.events.GameEvent.EventType;
import mage.game.permanent.Permanent;
import mage.players.Player;
import java.util.UUID;
/**
*
* @author Backfir3
*/
public final class AngelicChorus extends CardImpl {
public AngelicChorus(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{W}{W}");
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}{W}");
// Whenever a creature enters the battlefield under your control, you gain life equal to its toughness.
this.addAbility(new AngelicChorusTriggeredAbility());
@ -57,7 +56,8 @@ class AngelicChorusTriggeredAbility extends TriggeredAbilityImpl {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
Permanent permanent = game.getPermanent(event.getTargetId());
if (permanent.isCreature()
if (permanent != null
&& permanent.isCreature()
&& permanent.isControlledBy(this.controllerId)) {
this.getEffects().get(0).setValue("lifeSource", event.getTargetId());
return true;

View file

@ -1,4 +1,3 @@
package mage.cards.a;
import java.util.Set;
@ -10,7 +9,7 @@ import mage.cards.*;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.common.FilterCreatureCard;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.players.Player;
import mage.target.Target;
@ -24,7 +23,7 @@ import mage.target.common.TargetOpponent;
public final class AnimalMagnetism extends CardImpl {
public AnimalMagnetism(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{G}");
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{G}");
// Reveal the top five cards of your library. An opponent chooses a creature card from among them. Put that card onto the battlefield and the rest into your graveyard.
this.getSpellAbility().addEffect(new AnimalMagnetismEffect());
@ -76,7 +75,7 @@ class AnimalMagnetismEffect extends OneShotEffect {
controller.chooseTarget(Outcome.Detriment, target, source, game);
opponent = game.getPlayer(target.getFirstTarget());
}
TargetCard target = new TargetCard(1, Zone.LIBRARY, new FilterCreatureCard());
TargetCard target = new TargetCard(1, Zone.LIBRARY, StaticFilters.FILTER_CARD_CREATURE);
opponent.chooseTarget(outcome, cards, target, source, game);
cardToBattlefield = game.getCard(target.getFirstTarget());
}

View file

@ -43,16 +43,16 @@ public final class AnimatingFaerie extends AdventureCard {
// Bring to Life
// Target noncreature artifact you control becomes a 0/0 artifact creature. Put four +1/+1 counters on it.
this.getAdventureSpellAbility().addEffect(new AddCardTypeTargetEffect(
this.getSpellCard().getSpellAbility().addEffect(new AddCardTypeTargetEffect(
Duration.EndOfGame, CardType.ARTIFACT, CardType.CREATURE
).setText("Target noncreature artifact you control becomes"));
this.getAdventureSpellAbility().addEffect(new SetPowerToughnessTargetEffect(
this.getSpellCard().getSpellAbility().addEffect(new SetPowerToughnessTargetEffect(
0, 0, Duration.EndOfGame
).setText("a 0/0 artifact creature."));
this.getAdventureSpellAbility().addEffect(new AddCountersTargetEffect(
this.getSpellCard().getSpellAbility().addEffect(new AddCountersTargetEffect(
CounterType.P1P1.createInstance(4)
).setText("Put four +1/+1 counters on it."));
this.getAdventureSpellAbility().addTarget(new TargetPermanent(filter));
this.getSpellCard().getSpellAbility().addTarget(new TargetPermanent(filter));
}
private AnimatingFaerie(final AnimatingFaerie card) {

View file

@ -1,7 +1,5 @@
package mage.cards.a;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.common.GainLifeEffect;
@ -16,6 +14,8 @@ import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.permanent.Permanent;
import java.util.UUID;
/**
* @author Loki
*/
@ -66,7 +66,8 @@ class ArchonOfRedemptionTriggeredAbility extends TriggeredAbilityImpl {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
Permanent permanent = game.getPermanent(event.getTargetId());
if (permanent.isControlledBy(getControllerId())
if (permanent != null
&& permanent.isControlledBy(getControllerId())
&& permanent.isCreature()
&& (permanent.getId().equals(getSourceId())
|| (permanent.getAbilities().contains(FlyingAbility.getInstance())))) {

View file

@ -29,8 +29,8 @@ public final class ArdenvaleTactician extends AdventureCard {
// Dizzying Swoop
// Tap up to two target creatures.
this.getAdventureSpellAbility().addEffect(new TapTargetEffect());
this.getAdventureSpellAbility().addTarget(new TargetCreaturePermanent(0, 2));
this.getSpellCard().getSpellAbility().addEffect(new TapTargetEffect());
this.getSpellCard().getSpellAbility().addTarget(new TargetCreaturePermanent(0, 2));
}
private ArdenvaleTactician(final ArdenvaleTactician card) {

View file

@ -0,0 +1,147 @@
package mage.cards.a;
import mage.abilities.Ability;
import mage.abilities.LoyaltyAbility;
import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.FilterCard;
import mage.filter.predicate.other.OwnerPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.permanent.token.AshiokNightmareMuseToken;
import mage.players.Player;
import mage.target.common.TargetCardInExile;
import mage.target.common.TargetCardInHand;
import mage.target.common.TargetNonlandPermanent;
import java.util.UUID;
import mage.MageObject;
import mage.MageObjectReference;
import mage.cards.Card;
/**
* @author TheElk801
*/
public final class AshiokNightmareMuse extends CardImpl {
public AshiokNightmareMuse(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{3}{U}{B}");
this.addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.ASHIOK);
this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5));
// +1: Create a 2/3 blue and black Nightmare creature token with "Whenever this creature attacks or blocks, each opponent exiles the top two cards of their library."
this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new AshiokNightmareMuseToken()), 1));
// 3: Return target nonland permanent to its owner's hand, then that player exiles a card from their hand.
Ability ability = new LoyaltyAbility(new AshiokNightmareMuseBounceEffect(), -3);
ability.addTarget(new TargetNonlandPermanent());
this.addAbility(ability);
// 7: You may cast up to three face-up cards your opponents own from exile without paying their mana costs.
this.addAbility(new LoyaltyAbility(new AshiokNightmareMuseCastEffect(), -7));
}
private AshiokNightmareMuse(final AshiokNightmareMuse card) {
super(card);
}
@Override
public AshiokNightmareMuse copy() {
return new AshiokNightmareMuse(this);
}
}
class AshiokNightmareMuseBounceEffect extends OneShotEffect {
AshiokNightmareMuseBounceEffect() {
super(Outcome.Discard);
staticText = "return target nonland permanent to its owner's hand, "
+ "then that player exiles a card from their hand";
}
private AshiokNightmareMuseBounceEffect(final AshiokNightmareMuseBounceEffect effect) {
super(effect);
}
@Override
public AshiokNightmareMuseBounceEffect copy() {
return new AshiokNightmareMuseBounceEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getFirstTarget());
Player player = game.getPlayer(game.getOwnerId(source.getFirstTarget()));
if (permanent == null || player == null) {
return false;
}
player.moveCards(permanent, Zone.HAND, source, game);
if (player.getHand().isEmpty()) {
return true;
}
TargetCardInHand target = new TargetCardInHand();
if (!player.choose(outcome, player.getHand(), target, game)) {
return false;
}
return player.moveCards(game.getCard(target.getFirstTarget()), Zone.EXILED, source, game);
}
}
class AshiokNightmareMuseCastEffect extends OneShotEffect {
private static final FilterCard filter = new FilterCard("face-up cards your opponents own from exile");
static {
filter.add(new OwnerPredicate(TargetController.OPPONENT));
}
AshiokNightmareMuseCastEffect() {
super(Outcome.Discard);
staticText = "You may cast up to three face-up cards your opponents own from exile without paying their mana costs.";
}
private AshiokNightmareMuseCastEffect(final AshiokNightmareMuseCastEffect effect) {
super(effect);
}
@Override
public AshiokNightmareMuseCastEffect copy() {
return new AshiokNightmareMuseCastEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = game.getObject(source.getSourceId());
if (controller == null
|| sourceObject == null) {
return false;
}
TargetCardInExile target = new TargetCardInExile(0, 3, filter, null);
target.setNotTarget(true);
if (!controller.chooseTarget(outcome, target, source, game)) { // method is fine, controller is still choosing the card
return false;
}
for (UUID targetId : target.getTargets()) {
if (targetId != null) {
Card chosenCard = game.getCard(targetId);
if (chosenCard != null
&& game.getState().getZone(chosenCard.getId()) == Zone.EXILED // must be exiled
&& game.getOpponents(controller.getId()).contains(chosenCard.getOwnerId()) // must be owned by an opponent
&& controller.chooseUse(outcome, "Cast " + chosenCard.getName() + " without paying its mana cost?", source, game)) {
game.getState().setValue("CastFromExileEnabled" + chosenCard.getId(), Boolean.TRUE); // enable the card to be cast from the exile zone
controller.cast(controller.chooseAbilityForCast(chosenCard, game, true),
game, true, new MageObjectReference(sourceObject, game));
game.getState().setValue("CastFromExileEnabled" + chosenCard.getId(), null); // reset to null
}
}
}
return true;
}
}

View file

@ -0,0 +1,91 @@
package mage.cards.a;
import mage.abilities.Ability;
import mage.abilities.LoyaltyAbility;
import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.PutTopCardOfLibraryIntoGraveEachPlayerEffect;
import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect;
import mage.abilities.effects.common.continuous.GainControlAllEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.FilterCard;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreatureCard;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.permanent.ControllerIdPredicate;
import mage.game.Game;
import mage.target.common.TargetCardInGraveyard;
import mage.target.common.TargetOpponent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AshiokSculptorOfFears extends CardImpl {
private static final FilterCard filter = new FilterCreatureCard("creature card from a graveyard");
public AshiokSculptorOfFears(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{4}{U}{B}");
this.addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.ASHIOK);
this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4));
// +2: Draw a card. Each player puts the top two cards of their library into their graveyard.
Ability ability = new LoyaltyAbility(
new DrawCardSourceControllerEffect(1).setText("draw a card."), 2
);
ability.addEffect(new PutTopCardOfLibraryIntoGraveEachPlayerEffect(2, TargetController.ANY));
this.addAbility(ability);
// 5: Put target creature card from a graveyard onto the battlefield under you control.
ability = new LoyaltyAbility(new ReturnFromGraveyardToBattlefieldTargetEffect()
.setText("put target creature card from a graveyard onto the battlefield under you control"), -5);
ability.addTarget(new TargetCardInGraveyard(filter));
this.addAbility(ability);
// 11: Gain control of all creatures target opponent controls.
ability = new LoyaltyAbility(new AshiokSculptorOfFearsEffect(), -11);
ability.addTarget(new TargetOpponent());
this.addAbility(ability);
}
private AshiokSculptorOfFears(final AshiokSculptorOfFears card) {
super(card);
}
@Override
public AshiokSculptorOfFears copy() {
return new AshiokSculptorOfFears(this);
}
}
class AshiokSculptorOfFearsEffect extends OneShotEffect {
AshiokSculptorOfFearsEffect() {
super(Outcome.Benefit);
staticText = "gain control of all creatures target opponent controls";
}
private AshiokSculptorOfFearsEffect(final AshiokSculptorOfFearsEffect effect) {
super(effect);
}
@Override
public AshiokSculptorOfFearsEffect copy() {
return new AshiokSculptorOfFearsEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
FilterPermanent filter = new FilterCreaturePermanent();
filter.add(new ControllerIdPredicate(source.getFirstTarget()));
game.addEffect(new GainControlAllEffect(Duration.Custom, filter), source);
return true;
}
}

View file

@ -1,11 +1,10 @@
package mage.cards.a;
import java.util.UUID;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.DevotionCount;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.abilities.hint.ValueHint;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
@ -13,22 +12,24 @@ import mage.constants.ColoredManaSymbol;
import mage.constants.Duration;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class AspectOfHydra extends CardImpl {
public AspectOfHydra(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{G}");
private static final DynamicValue xValue = new DevotionCount(ColoredManaSymbol.G);
public AspectOfHydra(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{G}");
// Target creature gets +X/+X until end of turn, where X is your devotion to green.
DynamicValue greenDevotion = new DevotionCount(ColoredManaSymbol.G);
Effect effect = new BoostTargetEffect(greenDevotion, greenDevotion, Duration.EndOfTurn, true);
Effect effect = new BoostTargetEffect(xValue, xValue, Duration.EndOfTurn, true);
effect.setText("Target creature gets +X/+X until end of turn, where X is your devotion to green");
this.getSpellAbility().addEffect(effect);
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
this.getSpellAbility().addHint(new ValueHint("Devotion to green", xValue));
}
public AspectOfHydra(final AspectOfHydra card) {

View file

@ -1,17 +1,17 @@
package mage.cards.a;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.Cost;
import mage.abilities.costs.common.PayLifeCost;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.DevotionCount;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.LoseCreatureTypeSourceEffect;
import mage.abilities.hint.ValueHint;
import mage.abilities.keyword.IndestructibleAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
@ -27,13 +27,15 @@ import mage.game.events.ZoneChangeEvent;
import mage.players.Player;
import mage.target.common.TargetOpponent;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class AthreosGodOfPassage extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature you own");
private static final DynamicValue xValue = new DevotionCount(ColoredManaSymbol.W, ColoredManaSymbol.B);
static {
filter.add(AnotherPredicate.instance);
@ -50,10 +52,12 @@ public final class AthreosGodOfPassage extends CardImpl {
// Indestructible
this.addAbility(IndestructibleAbility.getInstance());
// As long as your devotion to white and black is less than seven, Athreos isn't a creature.
Effect effect = new LoseCreatureTypeSourceEffect(new DevotionCount(ColoredManaSymbol.W, ColoredManaSymbol.B), 7);
Effect effect = new LoseCreatureTypeSourceEffect(xValue, 7);
effect.setText("As long as your devotion to white and black is less than seven, Athreos isn't a creature");
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect));
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect).addHint(new ValueHint("Devotion to white and black", xValue)));
// Whenever another creature you own dies, return it to your hand unless target opponent pays 3 life.
Ability ability = new AthreosDiesCreatureTriggeredAbility(new AthreosGodOfPassageReturnEffect(), false, filter);
ability.addTarget(new TargetOpponent());

View file

@ -0,0 +1,161 @@
package mage.cards.a;
import mage.MageInt;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.BeginningOfEndStepTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.DevotionCount;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.LoseCreatureTypeSourceEffect;
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
import mage.abilities.hint.ValueHint;
import mage.abilities.keyword.IndestructibleAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.counters.CounterType;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.permanent.AnotherPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.TargetPermanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AthreosShroudVeiled extends CardImpl {
private static final DynamicValue xValue = new DevotionCount(ColoredManaSymbol.W, ColoredManaSymbol.B);
private static final FilterPermanent filter = new FilterCreaturePermanent("another target creature");
static {
filter.add(AnotherPredicate.instance);
}
public AthreosShroudVeiled(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "{4}{W}{B}");
this.addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.GOD);
this.power = new MageInt(4);
this.toughness = new MageInt(7);
// Indestructible
this.addAbility(IndestructibleAbility.getInstance());
// As long as your devotion to white and black is less than seven, Athreos isn't a creature.
Effect effect = new LoseCreatureTypeSourceEffect(xValue, 7);
effect.setText("As long as your devotion to white and black is less than seven, {this} isn't a creature");
this.addAbility(new SimpleStaticAbility(effect)
.addHint(new ValueHint("Devotion to white and black", xValue)));
// At the beginning of your end step, put a coin counter on another target creature.
Ability ability = new BeginningOfEndStepTriggeredAbility(
new AddCountersTargetEffect(CounterType.COIN.createInstance()),
TargetController.YOU, false
);
ability.addTarget(new TargetPermanent(filter));
this.addAbility(ability);
// Whenever a creature with a coin counter on it dies or is put into exile, return that card to the battlefield under your control.
this.addAbility(new AthreosShroudVeiledTriggeredAbility());
}
private AthreosShroudVeiled(final AthreosShroudVeiled card) {
super(card);
}
@Override
public AthreosShroudVeiled copy() {
return new AthreosShroudVeiled(this);
}
}
class AthreosShroudVeiledTriggeredAbility extends TriggeredAbilityImpl {
AthreosShroudVeiledTriggeredAbility() {
super(Zone.BATTLEFIELD, null, false);
}
private AthreosShroudVeiledTriggeredAbility(final AthreosShroudVeiledTriggeredAbility ability) {
super(ability);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
if (event.getType() != GameEvent.EventType.ZONE_CHANGE) {
return false;
}
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
return zEvent.getFromZone() == Zone.BATTLEFIELD
&& (zEvent.getToZone() == Zone.GRAVEYARD
|| zEvent.getToZone() == Zone.EXILED);
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
Permanent permanent = zEvent.getTarget();
if (permanent == null
|| !permanent.isCreature()
|| !permanent.getCounters(game).containsKey(CounterType.COIN)) {
return false;
}
this.getEffects().clear();
this.addEffect(new AthreosShroudVeiledEffect(new MageObjectReference(zEvent.getTarget(), game)));
return true;
}
@Override
public AthreosShroudVeiledTriggeredAbility copy() {
return new AthreosShroudVeiledTriggeredAbility(this);
}
@Override
public String getRule() {
return "Whenever a creature with a coin counter on it dies or is put into exile, " +
"return that card to the battlefield under your control.";
}
}
class AthreosShroudVeiledEffect extends OneShotEffect {
private final MageObjectReference mor;
AthreosShroudVeiledEffect(MageObjectReference mor) {
super(Outcome.Benefit);
this.mor = mor;
}
private AthreosShroudVeiledEffect(final AthreosShroudVeiledEffect effect) {
super(effect);
this.mor = effect.mor;
}
@Override
public AthreosShroudVeiledEffect copy() {
return new AthreosShroudVeiledEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player == null) {
return false;
}
Card card = game.getCard(mor.getSourceId());
return card.getZoneChangeCounter(game) - 1 == mor.getZoneChangeCounter()
&& player.moveCards(card, Zone.BATTLEFIELD, source, game);
}
}

View file

@ -1,8 +1,5 @@
package mage.cards.a;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
@ -16,17 +13,20 @@ import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.DamageEvent;
import mage.game.events.GameEvent;
import mage.game.events.PreventDamageEvent;
import mage.target.TargetSource;
import java.util.UUID;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public final class AuriokReplica extends CardImpl {
public AuriokReplica(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{3}");
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}");
this.subtype.add(SubType.CLERIC);
this.power = new MageInt(2);
this.toughness = new MageInt(2);
@ -77,7 +77,7 @@ class AuriokReplicaEffect extends PreventionEffectImpl {
}
private void preventDamage(GameEvent event, Ability source, UUID target, Game game) {
GameEvent preventEvent = new GameEvent(GameEvent.EventType.PREVENT_DAMAGE, target, source.getSourceId(), source.getControllerId(), event.getAmount(), false);
GameEvent preventEvent = new PreventDamageEvent(target, source.getSourceId(), source.getControllerId(), event.getAmount(), ((DamageEvent) event).isCombatDamage());
if (!game.replaceEvent(preventEvent)) {
int damage = event.getAmount();
event.setAmount(0);
@ -88,9 +88,7 @@ class AuriokReplicaEffect extends PreventionEffectImpl {
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (super.applies(event, source, game)) {
if (event.getTargetId().equals(source.getControllerId()) && event.getSourceId().equals(this.getTargetPointer().getFirst(game, source))) {
return true;
}
return event.getTargetId().equals(source.getControllerId()) && event.getSourceId().equals(this.getTargetPointer().getFirst(game, source));
}
return false;
}

View file

@ -1,4 +1,3 @@
package mage.cards.a;
import java.util.UUID;
@ -7,18 +6,19 @@ import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.AdjustingSourceCosts;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.effects.common.cost.CostModificationEffectImpl;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.CostModificationType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterLandPermanent;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.util.CardUtil;
@ -36,7 +36,7 @@ public final class AvatarOfFury extends CardImpl {
this.toughness = new MageInt(6);
// If an opponent controls seven or more lands, Avatar of Fury costs {6} less to cast.
this.addAbility(new AvatarOfFuryAdjustingCostsAbility());
this.addAbility(new SimpleStaticAbility(Zone.ALL, new AvatarOfFuryAdjustingCostsEffect()));
// Flying
this.addAbility(FlyingAbility.getInstance());
// {R}: Avatar of Fury gets +1/+0 until end of turn.
@ -53,36 +53,39 @@ public final class AvatarOfFury extends CardImpl {
}
}
class AvatarOfFuryAdjustingCostsAbility extends SimpleStaticAbility implements AdjustingSourceCosts {
class AvatarOfFuryAdjustingCostsEffect extends CostModificationEffectImpl {
public AvatarOfFuryAdjustingCostsAbility() {
super(Zone.OUTSIDE, null /*new AvatarOfFuryAdjustingCostsEffect()*/);
AvatarOfFuryAdjustingCostsEffect() {
super(Duration.EndOfGame, Outcome.Benefit, CostModificationType.REDUCE_COST);
staticText = "If an opponent controls seven or more lands, {this} costs {6} less to cast";
}
public AvatarOfFuryAdjustingCostsAbility(final AvatarOfFuryAdjustingCostsAbility ability) {
super(ability);
AvatarOfFuryAdjustingCostsEffect(AvatarOfFuryAdjustingCostsEffect effect) {
super(effect);
}
@Override
public SimpleStaticAbility copy() {
return new AvatarOfFuryAdjustingCostsAbility(this);
public boolean apply(Game game, Ability source, Ability abilityToModify) {
CardUtil.reduceCost(abilityToModify, 6);
return true;
}
@Override
public String getRule() {
return "If an opponent controls seven or more lands, Avatar of Fury costs {6} less to cast";
}
@Override
public void adjustCosts(Ability ability, Game game) {
if (ability instanceof SpellAbility) { // Prevent adjustment of activated ability
FilterPermanent filter = new FilterLandPermanent();
for (UUID playerId : game.getOpponents(ability.getControllerId())) {
if (game.getBattlefield().countAll(filter, playerId, game) > 6) {
CardUtil.adjustCost((SpellAbility) ability, 6);
break;
public boolean applies(Ability abilityToModify, Ability source, Game game) {
if (abilityToModify.getSourceId().equals(source.getSourceId())
&& (abilityToModify instanceof SpellAbility)) {
for (UUID playerId : game.getOpponents(abilityToModify.getControllerId())) {
if (game.getBattlefield().countAll(StaticFilters.FILTER_LAND, playerId, game) > 6) {
return true;
}
}
}
return false;
}
}
@Override
public AvatarOfFuryAdjustingCostsEffect copy() {
return new AvatarOfFuryAdjustingCostsEffect(this);
}
}

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