Merge pull request #6 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

View file

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

View file

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

View file

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

View file

@ -36,12 +36,17 @@
<DimensionLayout dim="0"> <DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0"> <Group type="102" attributes="0">
<Component id="pnlSelect" min="-2" pref="241" max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<EmptySpace pref="300" max="32767" attributes="0"/> <Group type="103" groupAlignment="0" attributes="0">
<Component id="pnlApply" min="-2" max="-2" attributes="0"/> <Group type="102" attributes="0">
</Group> <Component id="pnlSelect" min="-2" pref="196" max="-2" attributes="0"/>
<Group type="102" attributes="0"> <EmptySpace pref="402" max="32767" attributes="0"/>
<Component id="pnlPacks" 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"/> <EmptySpace max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
@ -49,11 +54,13 @@
<DimensionLayout dim="1"> <DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0">
<Component id="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"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Component id="pnlApply" min="-2" pref="32" max="-2" 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="pnlSelect" min="-2" pref="32" max="-2" attributes="0"/>
<Component id="btnApply" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<EmptySpace max="32767" attributes="0"/> <EmptySpace max="32767" attributes="0"/>
</Group> </Group>
@ -64,8 +71,8 @@
<Container class="java.awt.Panel" name="pnlPacks"> <Container class="java.awt.Panel" name="pnlPacks">
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridLayout"> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridLayout">
<Property name="columns" type="int" value="12"/> <Property name="columns" type="int" value="13"/>
<Property name="rows" type="int" value="11"/> <Property name="rows" type="int" value="12"/>
</Layout> </Layout>
</Container> </Container>
<Container class="javax.swing.JPanel" name="pnlSelect"> <Container class="javax.swing.JPanel" name="pnlSelect">
@ -94,17 +101,15 @@
<Container class="javax.swing.JPanel" name="pnlApply"> <Container class="javax.swing.JPanel" name="pnlApply">
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout"/> <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> </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> </SubComponents>
</Form> </Form>

View file

@ -58,25 +58,25 @@ public class RandomPacksSelectorDialog extends javax.swing.JDialog {
this.setModal(true); this.setModal(true);
} }
public void setSelectedPacks(ArrayList<String> packs){ public void setSelectedPacks(ArrayList<String> packs) {
if (!boxesCreated){ if (!boxesCreated) {
createCheckboxes(); createCheckboxes();
} }
for (Component pack : pnlPacks.getComponents()) { for (Component pack : pnlPacks.getComponents()) {
JCheckBox thePack = (JCheckBox) pack; JCheckBox thePack = (JCheckBox) pack;
if (packs.contains(thePack.getText())) { if (packs.contains(thePack.getText())) {
thePack.setSelected(true); thePack.setSelected(true);
} else{ } else {
thePack.setSelected(false); thePack.setSelected(false);
} }
} }
} }
public ArrayList<String> getSelectedPacks() { public ArrayList<String> getSelectedPacks() {
ArrayList<String> returnVal = new ArrayList<>(); ArrayList<String> returnVal = new ArrayList<>();
for (Component pack: pnlPacks.getComponents()){ for (Component pack : pnlPacks.getComponents()) {
JCheckBox thePack = (JCheckBox) pack; JCheckBox thePack = (JCheckBox) pack;
if (thePack.isSelected()){ if (thePack.isSelected()) {
returnVal.add(thePack.getText()); 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. * 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 * 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(); btnApply = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE); setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
setTitle(title); setTitle("Random Booster Draft Packs Selector");
setModal(true); setModal(true);
setModalExclusionType(java.awt.Dialog.ModalExclusionType.APPLICATION_EXCLUDE); setModalExclusionType(java.awt.Dialog.ModalExclusionType.APPLICATION_EXCLUDE);
setPreferredSize(new java.awt.Dimension(600, 450)); 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)); pnlSelect.setLayout(new javax.swing.BoxLayout(pnlSelect, javax.swing.BoxLayout.LINE_AXIS));
btnNone.setText("Select none"); btnNone.setText("Select none");
btnNone.setActionCommand("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); pnlSelect.add(btnNone);
btnAll.setText("Select all"); 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); pnlSelect.add(btnAll);
pnlApply.setLayout(new javax.swing.BoxLayout(pnlApply, javax.swing.BoxLayout.LINE_AXIS)); pnlApply.setLayout(new javax.swing.BoxLayout(pnlApply, javax.swing.BoxLayout.LINE_AXIS));
btnApply.setText("Apply"); btnApply.setText("Apply");
if (isRandomDraft) { btnApply.setToolTipText("At least two packs must be selected");
btnApply.setToolTipText("At least 2 packs must be selected"); btnApply.addActionListener(new java.awt.event.ActionListener() {
} else if (isRichManDraft) { public void actionPerformed(java.awt.event.ActionEvent evt) {
btnApply.setToolTipText("At least 1 pack must be selected"); btnApplyActionPerformed(evt);
} }
btnApply.addActionListener(evt -> btnApplyActionPerformed(evt)); });
pnlApply.add(btnApply);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout); getContentPane().setLayout(layout);
layout.setHorizontalGroup( layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addComponent(pnlSelect, javax.swing.GroupLayout.PREFERRED_SIZE, 241, javax.swing.GroupLayout.PREFERRED_SIZE) .addContainerGap()
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 300, Short.MAX_VALUE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(pnlApply, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGroup(layout.createSequentialGroup()
.addGroup(layout.createSequentialGroup() .addComponent(pnlSelect, javax.swing.GroupLayout.PREFERRED_SIZE, 196, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(pnlPacks, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .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()) .addContainerGap())
); );
layout.setVerticalGroup( layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup() .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) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(pnlApply, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE) .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)) .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 java.awt.Panel pnlPacks;
private javax.swing.JPanel pnlSelect; private javax.swing.JPanel pnlSelect;
// End of variables declaration//GEN-END:variables // End of variables declaration//GEN-END:variables
} }

View file

@ -1205,11 +1205,11 @@ public final class GamePanel extends javax.swing.JPanel {
needSelectable = new HashSet<>(); needSelectable = new HashSet<>();
} }
Set<UUID> needPlayable; Map<UUID, Integer> needPlayable;
if (showPlayable && gameView.getCanPlayObjects() != null) { if (showPlayable && gameView.getCanPlayObjects() != null) {
needPlayable = gameView.getCanPlayObjects(); needPlayable = gameView.getCanPlayObjects();
} else { } else {
needPlayable = new HashSet<>(); needPlayable = new HashMap<>();
} }
if (needChoosen.isEmpty() && needSelectable.isEmpty() && needPlayable.isEmpty()) { if (needChoosen.isEmpty() && needSelectable.isEmpty() && needPlayable.isEmpty()) {
@ -1225,8 +1225,9 @@ public final class GamePanel extends javax.swing.JPanel {
if (needChoosen.contains(card.getId())) { if (needChoosen.contains(card.getId())) {
card.setSelected(true); card.setSelected(true);
} }
if (needPlayable.contains(card.getId())) { if (needPlayable.containsKey(card.getId())) {
card.setPlayable(true); 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())) { if (needChoosen.contains(perm.getKey())) {
perm.getValue().setSelected(true); perm.getValue().setSelected(true);
} }
if (needPlayable.contains(perm.getKey())) { if (needPlayable.containsKey(perm.getKey())) {
perm.getValue().setPlayable(true); 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())) { if (needChoosen.contains(card.getKey())) {
card.getValue().setSelected(true); card.getValue().setSelected(true);
} }
if (needPlayable.contains(card.getKey())) { if (needPlayable.containsKey(card.getKey())) {
card.getValue().setPlayable(true); 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())) { if (needChoosen.contains(card.getKey())) {
card.getValue().setSelected(true); card.getValue().setSelected(true);
} }
if (needPlayable.contains(card.getKey())) { if (needPlayable.containsKey(card.getKey())) {
card.getValue().setPlayable(true); 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())) { if (needChoosen.contains(com.getId())) {
com.setSelected(true); com.setSelected(true);
} }
if (needPlayable.contains(com.getId())) { if (needPlayable.containsKey(com.getId())) {
com.setPlayable(true); 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())) { if (needChoosen.contains(card.getKey())) {
card.getValue().setSelected(true); card.getValue().setSelected(true);
} }
if (needPlayable.contains(card.getKey())) { if (needPlayable.containsKey(card.getKey())) {
card.getValue().setPlayable(true); 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 // can play
if (gameView != null && gameView.getCanPlayObjects() != null && !gameView.getCanPlayObjects().isEmpty()) { if (gameView != null && gameView.getCanPlayObjects() != null && !gameView.getCanPlayObjects().isEmpty()) {
for (CardView card : cards) { for (CardView card : cards) {
if (gameView.getCanPlayObjects().contains(card.getId())) { if (gameView.getCanPlayObjects().containsKey(card.getId())) {
return true; return true;
} }
} }
@ -239,7 +239,7 @@ public class PlayerPanelExt extends javax.swing.JPanel {
Color commandColor = Color.BLACK; Color commandColor = Color.BLACK;
for (CommandObjectView com : player.getCommandObjectList()) { 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; commandColor = activeValueColor;
break; break;
} }
@ -269,7 +269,7 @@ public class PlayerPanelExt extends javax.swing.JPanel {
if (!MageFrame.isLite()) { if (!MageFrame.isLite()) {
int id = player.getUserData().getAvatarId(); 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; id = DEFAULT_AVATAR_ID;
} }
if (id != avatarId) { if (id != avatarId) {

View file

@ -20,7 +20,7 @@ public final class CardsViewUtil {
CardInfo cardInfo = CardRepository.instance.findCard(simple.getExpansionSetCode(), simple.getCardNumber()); CardInfo cardInfo = CardRepository.instance.findCard(simple.getExpansionSetCode(), simple.getCardNumber());
Card card = cardInfo != null ? cardInfo.getMockCard() : null; Card card = cardInfo != null ? cardInfo.getMockCard() : null;
if (card != 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); loadedCards.put(key, card);
} }
if (card != null) { 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(); public static final Standard STANDARD_CARDS = new Standard();
// Attention -Month is 0 Based so Feb = 1 for example. // // 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 extendedDate = new GregorianCalendar(2009, Calendar.AUGUST, 20).getTime();
private static final Date frontierDate = new GregorianCalendar(2014, 6, 17).getTime(); private static final Date frontierDate = new GregorianCalendar(2014, Calendar.JULY, 17).getTime();
private static final Date pioneerDate = new GregorianCalendar(2012, 10, 5).getTime(); private static final Date pioneerDate = new GregorianCalendar(2012, Calendar.NOVEMBER, 5).getTime();
private static final Date modernDate = new GregorianCalendar(2003, 6, 20).getTime(); private static final Date modernDate = new GregorianCalendar(2003, Calendar.JULY, 20).getTime();
// for all sets just return empty list // for all sets just return empty list
private static final List<String> all = new ArrayList<>(); private static final List<String> all = new ArrayList<>();

View file

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

View file

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>
<artifactId>mage-root</artifactId> <artifactId>mage-root</artifactId>
<version>1.4.40</version> <version>1.4.41</version>
</parent> </parent>
<artifactId>mage-common</artifactId> <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_MAJOR = 1;
public static final int MAGE_VERSION_MINOR = 4; 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_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 // 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) 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 * @author BetaSteward_at_googlemail.com
*/ */
public class CardView extends SimpleCardView implements SelectableObjectView { public class CardView extends SimpleCardView {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -104,9 +104,6 @@ public class CardView extends SimpleCardView implements SelectableObjectView {
protected boolean rotate; protected boolean rotate;
protected boolean hideInfo; // controls if the tooltip window is shown (eg. controlled face down morph card) 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 canAttack;
protected boolean canBlock; protected boolean canBlock;
protected boolean inViewerOnly; protected boolean inViewerOnly;
@ -117,9 +114,13 @@ public class CardView extends SimpleCardView implements SelectableObjectView {
this(card, null, false); this(card, null, false);
} }
public CardView(Card card, UUID cardId) { public CardView(Card card, SimpleCardView simpleCardView) {
this(card, null, false); 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) { public CardView(Card card, Game game, UUID cardId) {
@ -128,10 +129,12 @@ public class CardView extends SimpleCardView implements SelectableObjectView {
} }
public CardView(CardView cardView) { 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; this.originalCard = cardView.originalCard;
// generetate new ID
this.id = UUID.randomUUID(); this.id = UUID.randomUUID();
this.parentId = cardView.parentId; this.parentId = cardView.parentId;
this.name = cardView.name; this.name = cardView.name;
this.displayName = cardView.displayName; this.displayName = cardView.displayName;
@ -198,9 +201,6 @@ public class CardView extends SimpleCardView implements SelectableObjectView {
this.rotate = cardView.rotate; this.rotate = cardView.rotate;
this.hideInfo = cardView.hideInfo; this.hideInfo = cardView.hideInfo;
this.isPlayable = cardView.isPlayable;
this.isChoosable = cardView.isChoosable;
this.selected = cardView.selected;
this.canAttack = cardView.canAttack; this.canAttack = cardView.canAttack;
this.canBlock = cardView.canBlock; this.canBlock = cardView.canBlock;
this.inViewerOnly = cardView.inViewerOnly; this.inViewerOnly = cardView.inViewerOnly;
@ -468,8 +468,6 @@ public class CardView extends SimpleCardView implements SelectableObjectView {
// Get starting loyalty // Get starting loyalty
this.startingLoyalty = "" + card.getStartingLoyalty(); this.startingLoyalty = "" + card.getStartingLoyalty();
} }
public CardView(MageObject object) { public CardView(MageObject object) {
@ -964,30 +962,6 @@ public class CardView extends SimpleCardView implements SelectableObjectView {
return hideInfo; 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() { public boolean isCanAttack() {
return canAttack; return canAttack;
} }

View file

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

View file

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

View file

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

View file

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

View file

@ -1,5 +1,3 @@
package mage.view; package mage.view;
import com.google.gson.annotations.Expose; import com.google.gson.annotations.Expose;
@ -8,10 +6,9 @@ import java.io.Serializable;
import java.util.UUID; import java.util.UUID;
/** /**
*
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
*/ */
public class SimpleCardView implements Serializable { public class SimpleCardView implements Serializable, SelectableObjectView {
@Expose @Expose
protected UUID id; protected UUID id;
protected String expansionSetCode; protected String expansionSetCode;
@ -21,9 +18,30 @@ public class SimpleCardView implements Serializable {
protected boolean usesVariousArt; protected boolean usesVariousArt;
protected boolean gameObject; 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) { public SimpleCardView(UUID id, String expansionSetCode, String cardNumber, boolean usesVariousArt, String tokenSetCode, String tokenDescriptor) {
this(id, expansionSetCode, cardNumber, usesVariousArt, tokenSetCode, false, 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) { public SimpleCardView(UUID id, String expansionSetCode, String cardNumber, boolean usesVariousArt, String tokenSetCode, boolean isGameObject, String tokenDescriptor) {
this.id = id; this.id = id;
this.expansionSetCode = expansionSetCode; this.expansionSetCode = expansionSetCode;
@ -53,12 +71,52 @@ public class SimpleCardView implements Serializable {
public String getTokenSetCode() { public String getTokenSetCode() {
return tokenSetCode; return tokenSetCode;
} }
public String getTokenDescriptor() { public String getTokenDescriptor() {
return tokenDescriptor; return tokenDescriptor;
} }
public boolean isGameObject() { public boolean isGameObject() {
return gameObject; 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> <parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>
<artifactId>mage-plugins</artifactId> <artifactId>mage-plugins</artifactId>
<version>1.4.40</version> <version>1.4.41</version>
</parent> </parent>
<artifactId>mage-counter-plugin</artifactId> <artifactId>mage-counter-plugin</artifactId>

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -4,6 +4,7 @@ import mage.cards.ExpansionSet;
import mage.cards.Sets; import mage.cards.Sets;
import mage.cards.decks.Constructed; import mage.cards.decks.Constructed;
import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
@ -15,7 +16,7 @@ public class Frontier extends Constructed {
public Frontier() { public Frontier() {
super("Constructed - 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()) { for (ExpansionSet set : Sets.getInstance().values()) {
if (set.getSetType().isStandardLegal() && (set.getReleaseDate().after(cutoff) || set.getReleaseDate().equals(cutoff))) { if (set.getSetType().isStandardLegal() && (set.getReleaseDate().after(cutoff) || set.getReleaseDate().equals(cutoff))) {
setCodes.add(set.getCode()); setCodes.add(set.getCode());

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -4,6 +4,7 @@ import mage.cards.ExpansionSet;
import mage.cards.Sets; import mage.cards.Sets;
import mage.cards.decks.Constructed; import mage.cards.decks.Constructed;
import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
@ -15,7 +16,7 @@ public class Modern extends Constructed {
public Modern() { public Modern() {
super("Constructed - 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()) { for (ExpansionSet set : Sets.getInstance().values()) {
if (set.getSetType().isModernLegal() && (set.getReleaseDate().after(cutoff) || set.getReleaseDate().equals(cutoff))) { if (set.getSetType().isModernLegal() && (set.getReleaseDate().after(cutoff) || set.getReleaseDate().equals(cutoff))) {
setCodes.add(set.getCode()); setCodes.add(set.getCode());

View file

@ -4,6 +4,7 @@ import mage.cards.ExpansionSet;
import mage.cards.Sets; import mage.cards.Sets;
import mage.cards.decks.Constructed; import mage.cards.decks.Constructed;
import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
@ -15,7 +16,7 @@ public class ModernNoBannedList extends Constructed {
public ModernNoBannedList() { public ModernNoBannedList() {
super("Constructed - Modern - No Banned List"); 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()) { for (ExpansionSet set : Sets.getInstance().values()) {
if (set.getSetType().isModernLegal() && (set.getReleaseDate().after(cutoff) || set.getReleaseDate().equals(cutoff))) { if (set.getSetType().isModernLegal() && (set.getReleaseDate().after(cutoff) || set.getReleaseDate().equals(cutoff))) {
setCodes.add(set.getCode()); setCodes.add(set.getCode());

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -12,9 +12,9 @@ public class TherosBlock extends Constructed {
public TherosBlock() { public TherosBlock() {
super("Constructed - Theros Block"); super("Constructed - Theros Block");
setCodes.add("THS"); setCodes.add(mage.sets.Theros.getInstance().getCode());
setCodes.add("BNG"); setCodes.add(mage.sets.BornOfTheGods.getInstance().getCode());
setCodes.add("JOU"); 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("Wheel of Fortune");
banned.add("Yawgmoth's Will"); 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 //Additionally, these Legendary creatures cannot be used as Commanders
bannedCommander.add("Erayo, Soratami Ascendant"); bannedCommander.add("Erayo, Soratami Ascendant");
bannedCommander.add("Rofellos, Llanowar Emissary"); bannedCommander.add("Rofellos, Llanowar Emissary");

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>
<artifactId>mage-server-plugins</artifactId> <artifactId>mage-server-plugins</artifactId>
<version>1.4.40</version> <version>1.4.41</version>
</parent> </parent>
<artifactId>mage-player-ai-ma</artifactId> <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); val = minimaxAB(node, depth - 1, alpha, beta);
} else { } 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 (allPassed(game)) {
if (!game.getStack().isEmpty()) { if (!game.getStack().isEmpty()) {
resolve(node, depth, game); resolve(node, depth, game);

View file

@ -1,14 +1,14 @@
package mage.player.ai; package mage.player.ai;
import java.util.LinkedList;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.constants.RangeOfInfluence; import mage.constants.RangeOfInfluence;
import mage.game.Game; import mage.game.Game;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import java.util.Date;
import java.util.LinkedList;
/** /**
*
* @author ayratn * @author ayratn
*/ */
public class ComputerPlayer7 extends ComputerPlayer6 { public class ComputerPlayer7 extends ComputerPlayer6 {
@ -107,6 +107,7 @@ public class ComputerPlayer7 extends ComputerPlayer6 {
protected void calculateActions(Game game) { protected void calculateActions(Game game) {
if (!getNextAction(game)) { if (!getNextAction(game)) {
Date startTime = new Date();
currentScore = GameStateEvaluator2.evaluate(playerId, game); currentScore = GameStateEvaluator2.evaluate(playerId, game);
Game sim = createSimulation(game); Game sim = createSimulation(game);
SimulationNode2.resetCount(); SimulationNode2.resetCount();
@ -137,6 +138,15 @@ public class ComputerPlayer7 extends ComputerPlayer6 {
} else { } else {
logger.info('[' + game.getPlayer(playerId).getName() + "][pre] Action: skip"); 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 { } else {
logger.debug("Next Action exists!"); logger.debug("Next Action exists!");
} }

View file

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

View file

@ -70,6 +70,7 @@ import java.util.Map.Entry;
public class ComputerPlayer extends PlayerImpl implements Player { public class ComputerPlayer extends PlayerImpl implements Player {
private static final Logger log = Logger.getLogger(ComputerPlayer.class); 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 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 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 @Override
public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game, Map<String, Serializable> options) { public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game, Map<String, Serializable> options) {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("chooseTarget: " + outcome.toString() + ':' + target.toString()); 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 // sometimes a target selection can be made from a player that does not control the ability
UUID abilityControllerId = playerId; UUID abilityControllerId = playerId;
if (target.getTargetController() != null if (target.getTargetController() != null
@ -138,6 +146,12 @@ public class ComputerPlayer extends PlayerImpl implements Player {
abilityControllerId = target.getAbilityController(); 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; UUID randomOpponentId;
if (target.getTargetController() != null) { if (target.getTargetController() != null) {
randomOpponentId = getRandomOpponent(target.getTargetController(), game); randomOpponentId = getRandomOpponent(target.getTargetController(), game);
@ -148,14 +162,14 @@ public class ComputerPlayer extends PlayerImpl implements Player {
} }
if (target.getOriginalTarget() instanceof TargetPlayer) { 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) { if (target.getOriginalTarget() instanceof TargetDiscard) {
findPlayables(game); findPlayables(game);
if (!unplayable.isEmpty()) { if (!unplayable.isEmpty()) {
for (int i = unplayable.size() - 1; i >= 0; i--) { 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); target.add(unplayable.values().toArray(new Card[0])[i].getId(), game);
if (target.isChosen()) { if (target.isChosen()) {
return true; return true;
@ -165,7 +179,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
} }
if (!hand.isEmpty()) { if (!hand.isEmpty()) {
for (int i = 0; i < hand.size(); i++) { 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); target.add(hand.toArray(new UUID[0])[i], game);
if (target.isChosen()) { if (target.isChosen()) {
return true; return true;
@ -244,7 +258,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
} }
while ((outcome.isGood() ? target.getTargets().size() < target.getMaxNumberOfTargets() : !target.isChosen()) while ((outcome.isGood() ? target.getTargets().size() < target.getMaxNumberOfTargets() : !target.isChosen())
&& !cards.isEmpty()) { && !cards.isEmpty()) {
Card pick = pickTarget(cards, outcome, target, null, game); Card pick = pickTarget(abilityControllerId, cards, outcome, target, null, game);
if (pick != null) { if (pick != null) {
target.addTarget(pick.getId(), null, game); target.addTarget(pick.getId(), null, game);
cards.remove(pick); cards.remove(pick);
@ -271,15 +285,15 @@ public class ComputerPlayer extends PlayerImpl implements Player {
} }
} }
if (outcome.isGood()) { if (outcome.isGood()) {
if (target.canTarget(abilityControllerId, null, game)) { if (target.canTarget(abilityControllerId, abilityControllerId, null, game)) {
target.add(abilityControllerId, game); target.add(abilityControllerId, game);
return true; return true;
} }
} else if (target.canTarget(randomOpponentId, null, game)) { } else if (target.canTarget(abilityControllerId, randomOpponentId, null, game)) {
target.add(randomOpponentId, game); target.add(randomOpponentId, game);
return true; return true;
} }
if (!target.isRequired(sourceId, game)) { if (!required) {
return false; return false;
} }
} }
@ -302,15 +316,15 @@ public class ComputerPlayer extends PlayerImpl implements Player {
} }
} }
if (outcome.isGood()) { if (outcome.isGood()) {
if (target.canTarget(abilityControllerId, null, game)) { if (target.canTarget(abilityControllerId, abilityControllerId, null, game)) {
target.add(abilityControllerId, game); target.add(abilityControllerId, game);
return true; return true;
} }
} else if (target.canTarget(randomOpponentId, null, game)) { } else if (target.canTarget(abilityControllerId, randomOpponentId, null, game)) {
target.add(randomOpponentId, game); target.add(randomOpponentId, game);
return true; return true;
} }
if (!target.isRequired(sourceId, game)) { if (!required) {
return false; return false;
} }
} }
@ -327,7 +341,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
} }
for (Permanent permanent : targets) { for (Permanent permanent : targets) {
List<UUID> alreadyTargeted = target.getTargets(); 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())) { if (alreadyTargeted != null && !alreadyTargeted.contains(permanent.getId())) {
target.add(permanent.getId(), game); target.add(permanent.getId(), game);
return true; return true;
@ -335,22 +349,22 @@ public class ComputerPlayer extends PlayerImpl implements Player {
} }
} }
if (outcome.isGood()) { if (outcome.isGood()) {
if (target.canTarget(abilityControllerId, null, game)) { if (target.canTarget(abilityControllerId, abilityControllerId, null, game)) {
target.add(abilityControllerId, game); target.add(abilityControllerId, game);
return true; return true;
} }
} else if (target.canTarget(randomOpponentId, null, game)) { } else if (target.canTarget(abilityControllerId, randomOpponentId, null, game)) {
target.add(randomOpponentId, game); target.add(randomOpponentId, game);
return true; return true;
} }
if (!target.isRequired(sourceId, game) || target.getNumberOfTargets() == 0) { if (!target.isRequired(sourceId, game) || target.getNumberOfTargets() == 0) {
return false; return false;
} }
if (target.canTarget(randomOpponentId, null, game)) { if (target.canTarget(abilityControllerId, randomOpponentId, null, game)) {
target.add(randomOpponentId, game); target.add(randomOpponentId, game);
return true; return true;
} }
if (target.canTarget(abilityControllerId, null, game)) { if (target.canTarget(abilityControllerId, abilityControllerId, null, game)) {
target.add(abilityControllerId, game); target.add(abilityControllerId, game);
return true; return true;
} }
@ -361,7 +375,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
} }
for (Permanent permanent : targets) { for (Permanent permanent : targets) {
List<UUID> alreadyTargeted = target.getTargets(); 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())) { if (alreadyTargeted != null && !alreadyTargeted.contains(permanent.getId())) {
target.add(permanent.getId(), game); target.add(permanent.getId(), game);
return true; return true;
@ -371,30 +385,36 @@ public class ComputerPlayer extends PlayerImpl implements Player {
return false; 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<>(); List<Card> cards = new ArrayList<>();
for (Player player : game.getPlayers().values()) { for (Player player : game.getPlayers().values()) {
for (Card card : player.getGraveyard().getCards(game)) { for (Card card : player.getGraveyard().getCards(game)) {
if (target.canTarget(card.getId(), game)) { if (target.canTarget(abilityControllerId, card.getId(), null, game)) {
cards.add(card); cards.add(card);
} }
} }
} }
for (Card card : cards) {
target.add(card.getId(), game); while ((outcome.isGood() ? target.getTargets().size() < target.getMaxNumberOfTargets() : !target.isChosen())
if (target.isChosen()) { && !cards.isEmpty()) {
return true; Card pick = pickTarget(abilityControllerId, cards, outcome, target, null, game);
if (pick != null) {
target.addTarget(pick.getId(), null, game);
cards.remove(pick);
} }
} }
return target.isChosen(); return target.isChosen();
} }
if (target.getOriginalTarget() instanceof TargetCardInYourGraveyard if (target.getOriginalTarget() instanceof TargetCardInYourGraveyard
|| target.getOriginalTarget() instanceof TargetCardInASingleGraveyard) { || target.getOriginalTarget() instanceof TargetCardInASingleGraveyard) {
List<UUID> alreadyTargeted = target.getTargets(); 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()) { 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())) { if (card != null && alreadyTargeted != null && !alreadyTargeted.contains(card.getId())) {
target.add(card.getId(), game); target.add(card.getId(), game);
if (target.isChosen()) { if (target.isChosen()) {
@ -412,7 +432,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
MageObject targetObject = game.getObject(targetId); MageObject targetObject = game.getObject(targetId);
if (targetObject != null) { if (targetObject != null) {
List<UUID> alreadyTargeted = target.getTargets(); 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())) { if (alreadyTargeted != null && !alreadyTargeted.contains(targetObject.getId())) {
target.add(targetObject.getId(), game); target.add(targetObject.getId(), game);
return true; return true;
@ -420,13 +440,13 @@ public class ComputerPlayer extends PlayerImpl implements Player {
} }
} }
} }
if (!target.isRequired(sourceId, game)) { if (!required) {
return false; 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 } //end of choose method
@Override @Override
@ -434,12 +454,34 @@ public class ComputerPlayer extends PlayerImpl implements Player {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("chooseTarget: " + outcome.toString() + ':' + target.toString()); 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 // sometimes a target selection can be made from a player that does not control the ability
UUID abilityControllerId = playerId; UUID abilityControllerId = playerId;
if (target.getAbilityController() != null) { if (target.getAbilityController() != null) {
abilityControllerId = target.getAbilityController(); 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 // TODO: improve to process multiple opponents instead random
UUID randomOpponentId; UUID randomOpponentId;
if (target.getTargetController() != null) { if (target.getTargetController() != null) {
@ -451,21 +493,21 @@ public class ComputerPlayer extends PlayerImpl implements Player {
} }
if (target.getOriginalTarget() instanceof TargetPlayer) { 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 if (target.getOriginalTarget() instanceof TargetDiscard
|| target.getOriginalTarget() instanceof TargetCardInHand) { || target.getOriginalTarget() instanceof TargetCardInHand) {
if (outcome.isGood()) { if (outcome.isGood()) {
// good // 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)); ArrayList<Card> cardsInHand = new ArrayList<>(cards.getCards(game));
while (!target.isChosen() while (!target.isChosen()
&& !target.possibleTargets(source.getSourceId(), getId(), game).isEmpty() && !target.possibleTargets(sourceId, getId(), game).isEmpty()
&& target.getMaxNumberOfTargets() > target.getTargets().size()) { && target.getMaxNumberOfTargets() > target.getTargets().size()) {
Card card = pickBestCard(cardsInHand, null, target, source, game); Card card = pickBestCard(cardsInHand, null, target, source, game);
if (card != null) { 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); target.addTarget(card.getId(), source, game);
cardsInHand.remove(card); cardsInHand.remove(card);
if (target.isChosen()) { if (target.isChosen()) {
@ -479,7 +521,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
findPlayables(game); findPlayables(game);
if (!unplayable.isEmpty()) { if (!unplayable.isEmpty()) {
for (int i = unplayable.size() - 1; i >= 0; i--) { 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); target.addTarget(unplayable.values().toArray(new Card[0])[i].getId(), source, game);
if (target.isChosen()) { if (target.isChosen()) {
return true; return true;
@ -489,7 +531,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
} }
if (!hand.isEmpty()) { if (!hand.isEmpty()) {
for (int i = 0; i < hand.size(); i++) { 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); target.addTarget(hand.toArray(new UUID[0])[i], source, game);
if (target.isChosen()) { if (target.isChosen()) {
return true; return true;
@ -504,7 +546,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
if (target.getOriginalTarget() instanceof TargetControlledPermanent) { if (target.getOriginalTarget() instanceof TargetControlledPermanent) {
TargetControlledPermanent origTarget = (TargetControlledPermanent) target.getOriginalTarget(); TargetControlledPermanent origTarget = (TargetControlledPermanent) target.getOriginalTarget();
List<Permanent> targets; 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()) { if (!outcome.isGood()) {
Collections.reverse(targets); 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) { if (target.getOriginalTarget() instanceof TargetPermanent) {
List<Permanent> targets;
TargetPermanent origTarget = (TargetPermanent) target.getOriginalTarget(); TargetPermanent origTarget = (TargetPermanent) target.getOriginalTarget();
boolean outcomeTargets = true; findBestPermanentTargets(outcome, abilityControllerId, sourceId, origTarget.getFilter(),
if (outcome.isGood()) { game, target, goodList, badList, allList);
targets = threats(abilityControllerId, source == null ? null : source.getSourceId(), ((TargetPermanent) target).getFilter(), game, target.getTargets());
} else { // use good list all the time and add maximum targets
targets = threats(randomOpponentId, source == null ? null : source.getSourceId(), ((TargetPermanent) target).getFilter(), game, target.getTargets()); for (Permanent permanent : goodList) {
}
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) {
if (target.canTarget(abilityControllerId, permanent.getId(), source, game)) { if (target.canTarget(abilityControllerId, permanent.getId(), source, game)) {
target.addTarget(permanent.getId(), source, game); if (target.getTargets().size() >= target.getMaxNumberOfTargets()) {
if (!outcomeTargets || target.getMaxNumberOfTargets() <= target.getTargets().size()) { break;
return true;
} }
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(); return target.isChosen();
@ -551,19 +593,19 @@ public class ComputerPlayer extends PlayerImpl implements Player {
if (target.getOriginalTarget() instanceof TargetCreatureOrPlayer) { if (target.getOriginalTarget() instanceof TargetCreatureOrPlayer) {
List<Permanent> targets; List<Permanent> targets;
TargetCreatureOrPlayer origTarget = ((TargetCreatureOrPlayer) target); TargetCreatureOrPlayer origTarget = ((TargetCreatureOrPlayer) target.getOriginalTarget());
if (outcome.isGood()) { 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 { } 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 (targets.isEmpty()) {
if (outcome.isGood()) { if (outcome.isGood()) {
if (target.canTarget(getId(), abilityControllerId, source, game)) { if (target.canTarget(abilityControllerId, abilityControllerId, source, game)) {
return tryAddTarget(target, 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); return tryAddTarget(target, randomOpponentId, source, game);
} }
} }
@ -581,37 +623,36 @@ public class ComputerPlayer extends PlayerImpl implements Player {
} }
if (outcome.isGood()) { if (outcome.isGood()) {
if (target.canTarget(getId(), abilityControllerId, source, game)) { if (target.canTarget(abilityControllerId, abilityControllerId, source, game)) {
return tryAddTarget(target, 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); return tryAddTarget(target, randomOpponentId, source, game);
} }
//if (!target.isRequired())
return false; return false;
} }
if (target.getOriginalTarget() instanceof TargetAnyTarget) { if (target.getOriginalTarget() instanceof TargetAnyTarget) {
List<Permanent> targets; List<Permanent> targets;
TargetAnyTarget origTarget = ((TargetAnyTarget) target); TargetAnyTarget origTarget = ((TargetAnyTarget) target.getOriginalTarget());
if (outcome.isGood()) { 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 { } 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 (targets.isEmpty()) {
if (outcome.isGood()) { if (outcome.isGood()) {
if (target.canTarget(getId(), abilityControllerId, source, game)) { if (target.canTarget(abilityControllerId, abilityControllerId, source, game)) {
return tryAddTarget(target, 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); 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); targets = game.getBattlefield().getActivePermanents(((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getCreatureFilter(), playerId, game);
} }
for (Permanent permanent : targets) { for (Permanent permanent : targets) {
@ -624,10 +665,10 @@ public class ComputerPlayer extends PlayerImpl implements Player {
} }
if (outcome.isGood()) { if (outcome.isGood()) {
if (target.canTarget(getId(), abilityControllerId, source, game)) { if (target.canTarget(abilityControllerId, abilityControllerId, source, game)) {
return tryAddTarget(target, 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); return tryAddTarget(target, randomOpponentId, source, game);
} }
@ -637,7 +678,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
if (target.getOriginalTarget() instanceof TargetPermanentOrPlayer) { if (target.getOriginalTarget() instanceof TargetPermanentOrPlayer) {
List<Permanent> targets; List<Permanent> targets;
TargetPermanentOrPlayer origTarget = ((TargetPermanentOrPlayer) target); TargetPermanentOrPlayer origTarget = ((TargetPermanentOrPlayer) target.getOriginalTarget());
if (outcome.isGood()) { if (outcome.isGood()) {
targets = threats(abilityControllerId, source.getSourceId(), ((FilterPermanentOrPlayer) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets()); targets = threats(abilityControllerId, source.getSourceId(), ((FilterPermanentOrPlayer) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets());
} else { } else {
@ -646,10 +687,10 @@ public class ComputerPlayer extends PlayerImpl implements Player {
if (targets.isEmpty()) { if (targets.isEmpty()) {
if (outcome.isGood()) { if (outcome.isGood()) {
if (target.canTarget(getId(), abilityControllerId, source, game)) { if (target.canTarget(abilityControllerId, abilityControllerId, source, game)) {
return tryAddTarget(target, 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); return tryAddTarget(target, randomOpponentId, source, game);
} }
} }
@ -669,7 +710,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
if (target.getOriginalTarget() instanceof TargetPlayerOrPlaneswalker) { if (target.getOriginalTarget() instanceof TargetPlayerOrPlaneswalker) {
List<Permanent> targets; 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 // 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 // possible good/bad players
if (targets.isEmpty()) { if (targets.isEmpty()) {
if (outcome.isGood()) { if (outcome.isGood()) {
if (target.canTarget(getId(), abilityControllerId, source, game)) { if (target.canTarget(abilityControllerId, abilityControllerId, source, game)) {
return tryAddTarget(target, 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); return tryAddTarget(target, randomOpponentId, source, game);
} }
} }
// can't find targets (e.g. effect is bad, but you need take targets from yourself) // 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); targets = game.getBattlefield().getActivePermanents(origTarget.getFilterPermanent(), playerId, game);
} }
@ -717,14 +758,13 @@ public class ComputerPlayer extends PlayerImpl implements Player {
// try target player as normal // try target player as normal
if (outcome.isGood()) { if (outcome.isGood()) {
if (target.canTarget(getId(), abilityControllerId, source, game)) { if (target.canTarget(abilityControllerId, abilityControllerId, source, game)) {
return tryAddTarget(target, 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); return tryAddTarget(target, randomOpponentId, source, game);
} }
//if (!target.isRequired())
return false; return false;
} }
@ -733,7 +773,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
for (Player player : game.getPlayers().values()) { for (Player player : game.getPlayers().values()) {
cards.addAll(player.getGraveyard().getCards(game)); 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) { if (card != null) {
return tryAddTarget(target, card.getId(), source, game); return tryAddTarget(target, card.getId(), source, game);
} }
@ -743,7 +783,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
if (target.getOriginalTarget() instanceof TargetCardInLibrary) { if (target.getOriginalTarget() instanceof TargetCardInLibrary) {
List<Card> cards = new ArrayList<>(game.getPlayer(abilityControllerId).getLibrary().getCards(game)); 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) { if (card != null) {
return tryAddTarget(target, card.getId(), source, game); return tryAddTarget(target, card.getId(), source, game);
} }
@ -753,7 +793,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
if (target.getOriginalTarget() instanceof TargetCardInYourGraveyard) { if (target.getOriginalTarget() instanceof TargetCardInYourGraveyard) {
List<Card> cards = new ArrayList<>(game.getPlayer(abilityControllerId).getGraveyard().getCards((FilterCard) target.getFilter(), game)); List<Card> cards = new ArrayList<>(game.getPlayer(abilityControllerId).getGraveyard().getCards((FilterCard) target.getFilter(), game));
while (!target.isChosen() && !cards.isEmpty()) { 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) { if (card != null) {
target.addTarget(card.getId(), source, game); target.addTarget(card.getId(), source, game);
cards.remove(card); // pickTarget don't remove cards (only on second+ tries) cards.remove(card); // pickTarget don't remove cards (only on second+ tries)
@ -783,7 +823,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
} else { } else {
targets = threats(randomOpponentId, source == null ? null : source.getSourceId(), origTarget.getPermanentFilter(), game, target.getTargets()); 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()); targets = threats(null, source == null ? null : source.getSourceId(), origTarget.getPermanentFilter(), game, target.getTargets());
Collections.reverse(targets); Collections.reverse(targets);
outcomeTargets = false; outcomeTargets = false;
@ -816,7 +856,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
cards.addAll(player.getGraveyard().getCards(game)); 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) { if (card != null) {
return tryAddTarget(target, card.getId(), source, game); 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); targets = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_PLANESWALKER, randomOpponentId, game);
if (targets != null && !targets.isEmpty()) { if (targets != null && !targets.isEmpty()) {
for (Permanent planeswalker : targets) { 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); target.addTarget(planeswalker.getId(), source, game);
} }
if (target.isChosen()) { if (target.isChosen()) {
@ -839,7 +879,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
} }
} }
if (!target.isChosen()) { if (!target.isChosen()) {
if (target.canTarget(getId(), randomOpponentId, source, game)) { if (target.canTarget(abilityControllerId, randomOpponentId, source, game)) {
target.addTarget(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)); cards.addAll(player.getGraveyard().getCards(game));
} }
while (!target.isChosen() && !cards.isEmpty()) { 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) { if (pick != null) {
target.addTarget(pick.getId(), source, game); target.addTarget(pick.getId(), source, game);
cards.remove(pick); // pickTarget don't remove cards (only on second+ tries) 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()) { 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) { if (pick != null) {
target.addTarget(pick.getId(), source, game); target.addTarget(pick.getId(), source, game);
cards.remove(pick); // pickTarget don't remove cards (only on second+ tries) 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(player.getGraveyard().getCards(game));
cards.addAll(game.getBattlefield().getAllActivePermanents(new FilterPermanent(), player.getId(), 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) { if (card != null) {
return tryAddTarget(target, card.getId(), source, game); 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()); throw new IllegalStateException("Target wasn't handled. class:" + target.getClass().toString());
} //end of chooseTarget method } //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; Card card;
while (!cards.isEmpty()) { while (!cards.isEmpty()) {
@ -923,7 +963,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
} }
if (!target.getTargets().contains(card.getId())) { if (!target.getTargets().contains(card.getId())) {
if (source != null) { if (source != null) {
if (target.canTarget(getId(), card.getId(), source, game)) { if (target.canTarget(abilityControllerId, card.getId(), source, game)) {
return card; return card;
} }
} else { } 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 (Permanent permanent : game.getBattlefield().getAllActivePermanents(playerId)) {
for (ActivatedAbility ability : permanent.getAbilities().getActivatedAbilities(Zone.BATTLEFIELD)) { for (ActivatedAbility ability : permanent.getAbilities().getActivatedAbilities(Zone.BATTLEFIELD)) {
if (!(ability instanceof ActivatedManaAbilityImpl) && ability.canActivate(playerId, game).canActivate()) { if (!(ability instanceof ActivatedManaAbilityImpl) && ability.canActivate(playerId, game).canActivate()) {
@ -1728,9 +1769,16 @@ public class ComputerPlayer extends PlayerImpl implements Player {
return target.isRequired(source); 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)); ArrayList<Card> cardChoices = new ArrayList<>(cards.getCards(target.getFilter(), game));
while (!target.doneChosing()) { while (!target.doneChosing()) {
Card card = pickTarget(cardChoices, outcome, target, source, game); Card card = pickTarget(abilityControllerId, cardChoices, outcome, target, source, game);
if (card != null) { if (card != null) {
target.addTarget(card.getId(), source, game); target.addTarget(card.getId(), source, game);
cardChoices.remove(card); cardChoices.remove(card);
@ -1752,9 +1800,16 @@ public class ComputerPlayer extends PlayerImpl implements Player {
return true; 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)); ArrayList<Card> cardChoices = new ArrayList<>(cards.getCards(target.getFilter(), game));
while (!target.doneChosing()) { while (!target.doneChosing()) {
Card card = pickTarget(cardChoices, outcome, target, null, game); Card card = pickTarget(abilityControllerId, cardChoices, outcome, target, null, game);
if (card != null) { if (card != null) {
target.add(card.getId(), game); target.add(card.getId(), game);
cardChoices.remove(card); cardChoices.remove(card);
@ -2421,6 +2476,58 @@ public class ComputerPlayer extends PlayerImpl implements Player {
return worst; 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) { protected List<Permanent> threats(UUID playerId, UUID sourceId, FilterPermanent filter, Game game, List<UUID> targets) {
return threats(playerId, sourceId, filter, game, targets, true); return threats(playerId, sourceId, filter, game, targets, true);
} }
@ -2550,7 +2657,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
/** /**
* Sets a possible target 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 (target.getOriginalTarget() instanceof TargetOpponent) {
if (source == null) { if (source == null) {
if (target.canTarget(randomOpponentId, game)) { if (target.canTarget(randomOpponentId, game)) {
@ -2617,7 +2724,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
target.add(randomOpponentId, game); target.add(randomOpponentId, game);
return true; return true;
} }
if (target.isRequired(sourceId, game)) { if (required) {
if (target.canTarget(abilityControllerId, game)) { if (target.canTarget(abilityControllerId, game)) {
target.add(abilityControllerId, game); target.add(abilityControllerId, game);
return true; return true;
@ -2689,4 +2796,12 @@ public class ComputerPlayer extends PlayerImpl implements Player {
// all human players converted to computer and analyse // all human players converted to computer and analyse
this.human = false; this.human = false;
} }
public long getLastThinkTime() {
return lastThinkTime;
}
public void setLastThinkTime(long lastThinkTime) {
this.lastThinkTime = lastThinkTime;
}
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>
<artifactId>mage-root</artifactId> <artifactId>mage-root</artifactId>
<version>1.4.40</version> <version>1.4.41</version>
</parent> </parent>
<artifactId>mage-server-plugins</artifactId> <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 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 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 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="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="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"/> <draftCube name="www.MTGCube.com" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.MTGCube"/>

View file

@ -6,7 +6,7 @@
<parent> <parent>
<groupId>org.mage</groupId> <groupId>org.mage</groupId>
<artifactId>mage-root</artifactId> <artifactId>mage-root</artifactId>
<version>1.4.40</version> <version>1.4.41</version>
</parent> </parent>
<artifactId>mage-server</artifactId> <artifactId>mage-server</artifactId>
@ -136,6 +136,12 @@
<version>${project.version}</version> <version>${project.version}</version>
<scope>runtime</scope> <scope>runtime</scope>
</dependency> </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>mage-player-ai-mcts</artifactId>
<version>${project.version}</version>
<scope>runtime</scope>
</dependency>
<dependency> <dependency>
<groupId>${project.groupId}</groupId> <groupId>${project.groupId}</groupId>
<artifactId>mage-tournament-boosterdraft</artifactId> <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 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 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 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="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="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"/> <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; gameZone = Zone.LIBRARY;
} else if ("token".equalsIgnoreCase(command.zone)) { } else if ("token".equalsIgnoreCase(command.zone)) {
gameZone = Zone.BATTLEFIELD; 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)) { } else if ("emblem".equalsIgnoreCase(command.zone)) {
gameZone = Zone.COMMAND; gameZone = Zone.COMMAND;
} else if ("plane".equalsIgnoreCase(command.zone)) { } else if ("plane".equalsIgnoreCase(command.zone)) {
gameZone = Zone.COMMAND; gameZone = Zone.COMMAND;
} else if ("commander".equalsIgnoreCase(command.zone)) { } else if ("commander".equalsIgnoreCase(command.zone)) {
gameZone = Zone.COMMAND; gameZone = Zone.COMMAND;
} else if ("sideboard".equalsIgnoreCase(command.zone)) {
gameZone = Zone.OUTSIDE;
} else { } else {
logger.warn("Unknown zone [" + command.zone + "]: " + line); logger.warn("Unknown zone [" + command.zone + "]: " + line);
continue; continue;
@ -527,6 +533,11 @@ public final class SystemUtil {
} else { } else {
logger.fatal("Commander card can be used in commander game only: " + command.cardName); 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 { } else {
// as other card // as other card
for (Card card : cardsToLoad) { for (Card card : cardsToLoad) {
@ -560,8 +571,17 @@ public final class SystemUtil {
break; break;
case STACK: case STACK:
card.cast(game, Zone.EXILED, card.getSpellAbility(), player.getId()); 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: default:
card.moveToZone(zone, null, game, false); card.moveToZone(zone, null, game, false);
break;
} }
logger.info("Added card to player's " + zone.toString() + ": " + card.getName() + ", player = " + player.getName()); logger.info("Added card to player's " + zone.toString() + ": " + card.getName() + ", player = " + player.getName());
} }

View file

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

View file

@ -1,14 +1,14 @@
package mage.cards.a; package mage.cards.a;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.DevotionCount; import mage.abilities.dynamicvalue.common.DevotionCount;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.SacrificeControllerEffect; import mage.abilities.effects.common.SacrificeControllerEffect;
import mage.abilities.hint.ValueHint;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
@ -18,14 +18,16 @@ import mage.constants.SubType;
import mage.constants.TargetController; import mage.constants.TargetController;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.game.permanent.token.TokenImpl; import mage.game.permanent.token.TokenImpl;
import mage.game.permanent.token.Token;
import java.util.UUID;
/** /**
*
* @author LevelX2 * @author LevelX2
*/ */
public final class AbhorrentOverlord extends CardImpl { public final class AbhorrentOverlord extends CardImpl {
private static final DynamicValue xValue = new DevotionCount(ColoredManaSymbol.B);
public AbhorrentOverlord(UUID ownerId, CardSetInfo setInfo) { public AbhorrentOverlord(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}{B}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}{B}");
this.subtype.add(SubType.DEMON); this.subtype.add(SubType.DEMON);
@ -35,10 +37,12 @@ public final class AbhorrentOverlord extends CardImpl {
// Flying // Flying
this.addAbility(FlyingAbility.getInstance()); 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. // 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>"); 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. // At the beginning of your upkeep, sacrifice a creature.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new SacrificeControllerEffect(StaticFilters.FILTER_PERMANENT_CREATURE, 1, null), TargetController.YOU, false)); 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()); this.addAbility(FlyingAbility.getInstance());
} }
public AbhorrentOverlordHarpyToken(final AbhorrentOverlordHarpyToken token) { public AbhorrentOverlordHarpyToken(final AbhorrentOverlordHarpyToken token) {
super(token); super(token);
} }

View file

@ -1,36 +1,39 @@
package mage.cards.a; package mage.cards.a;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.DevotionCount; import mage.abilities.dynamicvalue.common.DevotionCount;
import mage.abilities.effects.PreventionEffectImpl; import mage.abilities.effects.PreventionEffectImpl;
import mage.abilities.hint.ValueHint;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.ColoredManaSymbol; import mage.constants.ColoredManaSymbol;
import mage.constants.Duration; import mage.constants.Duration;
import mage.game.Game; import mage.game.Game;
import mage.game.events.DamageEvent;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.game.events.PreventDamageEvent;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetAnyTarget; import mage.target.common.TargetAnyTarget;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/** /**
*
* @author LevelX2 * @author LevelX2
*/ */
public final class AcolytesReward extends CardImpl { public final class AcolytesReward extends CardImpl {
public AcolytesReward(UUID ownerId, CardSetInfo setInfo) { 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. // 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().addEffect(new AcolytesRewardEffect());
this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addTarget(new TargetCreaturePermanent());
this.getSpellAbility().addTarget(new TargetAnyTarget()); this.getSpellAbility().addTarget(new TargetAnyTarget());
this.getSpellAbility().addHint(new ValueHint("Devotion to white", AcolytesRewardEffect.xValue));
} }
public AcolytesReward(final AcolytesReward card) { public AcolytesReward(final AcolytesReward card) {
@ -46,6 +49,7 @@ public final class AcolytesReward extends CardImpl {
class AcolytesRewardEffect extends PreventionEffectImpl { class AcolytesRewardEffect extends PreventionEffectImpl {
protected int amount = 0; protected int amount = 0;
static final DynamicValue xValue = new DevotionCount(ColoredManaSymbol.W);
public AcolytesRewardEffect() { public AcolytesRewardEffect() {
super(Duration.EndOfTurn); super(Duration.EndOfTurn);
@ -65,7 +69,7 @@ class AcolytesRewardEffect extends PreventionEffectImpl {
@Override @Override
public void init(Ability source, Game game) { public void init(Ability source, Game game) {
super.init(source, game); super.init(source, game);
amount = new DevotionCount(ColoredManaSymbol.W).calculate(game, source, this); amount = xValue.calculate(game, source, this);
} }
@Override @Override
@ -83,7 +87,7 @@ class AcolytesRewardEffect extends PreventionEffectImpl {
} else { } else {
amount = 0; 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)) { if (!game.replaceEvent(preventEvent)) {
Permanent targetCreature = game.getPermanent(source.getFirstTarget()); Permanent targetCreature = game.getPermanent(source.getFirstTarget());
if (targetCreature != null) { if (targetCreature != null) {

View file

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

View file

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

View file

@ -1,4 +1,3 @@
package mage.cards.a; package mage.cards.a;
import java.util.UUID; import java.util.UUID;
@ -19,7 +18,7 @@ import mage.constants.SubType;
import mage.constants.SuperType; import mage.constants.SuperType;
import mage.constants.Zone; import mage.constants.Zone;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.filter.common.FilterCreatureCard; import mage.filter.StaticFilters;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
/** /**
@ -41,7 +40,7 @@ public final class AjaniValiantProtector extends CardImpl {
this.addAbility(ability); 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. // +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. // -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); Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance(), ControllerLifeCount.instance);

View file

@ -1,4 +1,3 @@
package mage.cards.a; package mage.cards.a;
import java.util.UUID; import java.util.UUID;
@ -7,8 +6,8 @@ import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.filter.StaticFilters;
import static mage.filter.StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT; import static mage.filter.StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT;
import mage.filter.common.FilterCreatureCard;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import mage.target.common.TargetControlledCreaturePermanent; 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. // As an additional cost to cast Altar of Bone, sacrifice a creature.
this.getSpellAbility().addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT))); 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. // 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) { public AltarOfBone(final AltarOfBone card) {

View file

@ -1,6 +1,5 @@
package mage.cards.a; package mage.cards.a;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
@ -13,18 +12,21 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.filter.common.FilterCreatureCard; import mage.filter.common.FilterCreatureCard;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardIdPredicate; import mage.filter.predicate.mageobject.CardIdPredicate;
import mage.target.Target; import mage.target.Target;
import mage.target.common.TargetCardInGraveyardOrBattlefield; import mage.target.common.TargetCardInGraveyardOrBattlefield;
import java.util.UUID;
/** /**
*
* @author LevelX2 * @author LevelX2
*/ */
public final class AngelOfSerenity extends CardImpl { 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."; 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) { public AngelOfSerenity(UUID ownerId, CardSetInfo setInfo) {
@ -38,10 +40,11 @@ public final class AngelOfSerenity extends CardImpl {
this.addAbility(FlyingAbility.getInstance()); 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. // 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"); FilterCreaturePermanent filterBattle = new FilterCreaturePermanent("other target creatures");
filter.add(Predicates.not(new CardIdPredicate(this.getId()))); filterBattle.add(Predicates.not(new CardIdPredicate(this.getId())));
FilterCreatureCard filterGrave = StaticFilters.FILTER_CARD_CREATURE;
Ability ability = new EntersBattlefieldTriggeredAbility(new ExileTargetForSourceEffect().setText(rule), true); 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); ability.addTarget(target);
this.addAbility(ability); this.addAbility(ability);

View file

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

View file

@ -1,4 +1,3 @@
package mage.cards.a; package mage.cards.a;
import java.util.Set; import java.util.Set;
@ -10,7 +9,7 @@ import mage.cards.*;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.common.FilterCreatureCard; import mage.filter.StaticFilters;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
import mage.target.Target; import mage.target.Target;
@ -24,7 +23,7 @@ import mage.target.common.TargetOpponent;
public final class AnimalMagnetism extends CardImpl { public final class AnimalMagnetism extends CardImpl {
public AnimalMagnetism(UUID ownerId, CardSetInfo setInfo) { 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. // 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()); this.getSpellAbility().addEffect(new AnimalMagnetismEffect());
@ -76,7 +75,7 @@ class AnimalMagnetismEffect extends OneShotEffect {
controller.chooseTarget(Outcome.Detriment, target, source, game); controller.chooseTarget(Outcome.Detriment, target, source, game);
opponent = game.getPlayer(target.getFirstTarget()); 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); opponent.chooseTarget(outcome, cards, target, source, game);
cardToBattlefield = game.getCard(target.getFirstTarget()); cardToBattlefield = game.getCard(target.getFirstTarget());
} }

View file

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

View file

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

View file

@ -29,8 +29,8 @@ public final class ArdenvaleTactician extends AdventureCard {
// Dizzying Swoop // Dizzying Swoop
// Tap up to two target creatures. // Tap up to two target creatures.
this.getAdventureSpellAbility().addEffect(new TapTargetEffect()); this.getSpellCard().getSpellAbility().addEffect(new TapTargetEffect());
this.getAdventureSpellAbility().addTarget(new TargetCreaturePermanent(0, 2)); this.getSpellCard().getSpellAbility().addTarget(new TargetCreaturePermanent(0, 2));
} }
private ArdenvaleTactician(final ArdenvaleTactician card) { 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; package mage.cards.a;
import java.util.UUID;
import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.DevotionCount; import mage.abilities.dynamicvalue.common.DevotionCount;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.abilities.hint.ValueHint;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
@ -13,22 +12,24 @@ import mage.constants.ColoredManaSymbol;
import mage.constants.Duration; import mage.constants.Duration;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/** /**
*
* @author LevelX2 * @author LevelX2
*/ */
public final class AspectOfHydra extends CardImpl { public final class AspectOfHydra extends CardImpl {
public AspectOfHydra(UUID ownerId, CardSetInfo setInfo) { private static final DynamicValue xValue = new DevotionCount(ColoredManaSymbol.G);
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{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. // 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(xValue, xValue, Duration.EndOfTurn, true);
Effect effect = new BoostTargetEffect(greenDevotion, greenDevotion, Duration.EndOfTurn, true);
effect.setText("Target creature gets +X/+X until end of turn, where X is your devotion to green"); effect.setText("Target creature gets +X/+X until end of turn, where X is your devotion to green");
this.getSpellAbility().addEffect(effect); this.getSpellAbility().addEffect(effect);
this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addTarget(new TargetCreaturePermanent());
this.getSpellAbility().addHint(new ValueHint("Devotion to green", xValue));
} }
public AspectOfHydra(final AspectOfHydra card) { public AspectOfHydra(final AspectOfHydra card) {

View file

@ -1,17 +1,17 @@
package mage.cards.a; package mage.cards.a;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl; import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.Cost; import mage.abilities.costs.Cost;
import mage.abilities.costs.common.PayLifeCost; import mage.abilities.costs.common.PayLifeCost;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.DevotionCount; import mage.abilities.dynamicvalue.common.DevotionCount;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.LoseCreatureTypeSourceEffect; import mage.abilities.effects.common.continuous.LoseCreatureTypeSourceEffect;
import mage.abilities.hint.ValueHint;
import mage.abilities.keyword.IndestructibleAbility; import mage.abilities.keyword.IndestructibleAbility;
import mage.cards.Card; import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
@ -27,13 +27,15 @@ import mage.game.events.ZoneChangeEvent;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetOpponent; import mage.target.common.TargetOpponent;
import java.util.UUID;
/** /**
*
* @author LevelX2 * @author LevelX2
*/ */
public final class AthreosGodOfPassage extends CardImpl { public final class AthreosGodOfPassage extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature you own"); private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature you own");
private static final DynamicValue xValue = new DevotionCount(ColoredManaSymbol.W, ColoredManaSymbol.B);
static { static {
filter.add(AnotherPredicate.instance); filter.add(AnotherPredicate.instance);
@ -50,10 +52,12 @@ public final class AthreosGodOfPassage extends CardImpl {
// Indestructible // Indestructible
this.addAbility(IndestructibleAbility.getInstance()); this.addAbility(IndestructibleAbility.getInstance());
// As long as your devotion to white and black is less than seven, Athreos isn't a creature. // 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"); 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. // 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 ability = new AthreosDiesCreatureTriggeredAbility(new AthreosGodOfPassageReturnEffect(), false, filter);
ability.addTarget(new TargetOpponent()); 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; package mage.cards.a;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
@ -16,17 +13,20 @@ import mage.constants.Duration;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.game.events.DamageEvent;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.game.events.PreventDamageEvent;
import mage.target.TargetSource; import mage.target.TargetSource;
import java.util.UUID;
/** /**
*
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
*/ */
public final class AuriokReplica extends CardImpl { public final class AuriokReplica extends CardImpl {
public AuriokReplica(UUID ownerId, CardSetInfo setInfo) { 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.subtype.add(SubType.CLERIC);
this.power = new MageInt(2); this.power = new MageInt(2);
this.toughness = 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) { 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)) { if (!game.replaceEvent(preventEvent)) {
int damage = event.getAmount(); int damage = event.getAmount();
event.setAmount(0); event.setAmount(0);
@ -88,9 +88,7 @@ class AuriokReplicaEffect extends PreventionEffectImpl {
@Override @Override
public boolean applies(GameEvent event, Ability source, Game game) { public boolean applies(GameEvent event, Ability source, Game game) {
if (super.applies(event, source, game)) { if (super.applies(event, source, game)) {
if (event.getTargetId().equals(source.getControllerId()) && event.getSourceId().equals(this.getTargetPointer().getFirst(game, source))) { return event.getTargetId().equals(source.getControllerId()) && event.getSourceId().equals(this.getTargetPointer().getFirst(game, source));
return true;
}
} }
return false; return false;
} }

View file

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